# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/05_mcdm.ipynb.

# %% auto 0
__all__ = ['is_normalized_matrix', 'is_normalized_vector', 'check_scoring_input', 'check_weighting_input',
           'check_normalization_input', 'abspearson', 'dcor', 'squared_dcov_matrix', 'dist_matrix', 'lin_func',
           'squared_dcov', 'squared_dcor', 'pearson', 'correlate', 'em', 'mw', 'sd', 'vic', 'linear1', 'linear2',
           'linear3', 'vector', 'normalize', 'critic', 'weigh', 'topsis', 'cp', 'score']

# %% ../nbs/05_mcdm.ipynb 2
import numpy as np

# %% ../nbs/05_mcdm.ipynb 3
def is_normalized_matrix(z_matrix):
    """
    Return a Boolean value to indicate whether the matrix is normalized or not
    """
    return (
        np.sum(np.less(z_matrix, 0.0)) == 0
        and np.sum(np.greater(z_matrix, 1.0)) == 0
    )

# %% ../nbs/05_mcdm.ipynb 4
def is_normalized_vector(w_vector):
    """
    Return a Boolean value to indicate whether the vector is normalized or not
    """
    return (
        np.sum(np.less(w_vector, 0.0)) == 0
        and np.isclose(np.sum(w_vector), 1.0)
    )

# %% ../nbs/05_mcdm.ipynb 5
def check_scoring_input(z_matrix, w_vector, is_benefit_z, s_method):
    """
    Raise an exception if any argument is inappropriate for the corresponding
    scoring method
    """
    if s_method.upper() in {"SAW", "MEW", "TOPSIS", "MTOPSIS", "CP"}:
        if not is_normalized_matrix(z_matrix):
            raise ValueError(
                "The decision matrix must be normalized in order to apply "
                + "the {} scoring method".format(s_method),
            )
        if not is_normalized_vector(w_vector):
            raise ValueError(
                "The weight vector must be normalized in order to apply "
                + "the {} scoring method".format(s_method),
            )
        if w_vector.shape != (z_matrix.shape[1],):
            raise ValueError(
                "The shape of the weight vector is not appropriate for the "
                + "number of columns in the decision matrix",
            )
        if len(is_benefit_z) != z_matrix.shape[1]:
            raise ValueError(
                "The number of variables in the list that determines whether "
                + "each criterion is a benefit or a cost criterion does not "
                + "match the number of columns in the decision matrix",
            )
    else:
        raise ValueError("Unknown scoring method ({})".format(s_method))

# %% ../nbs/05_mcdm.ipynb 6
def check_weighting_input(z_matrix, c_method, w_method):
    """
    Raise an exception if any argument is inappropriate for the corresponding
    weighting method
    """
    if w_method.upper() in {"MW", "EM", "SD", "CRITIC", "VIC"}:
        if not is_normalized_matrix(z_matrix):
            raise ValueError(
                "The decision matrix must be normalized in order to apply "
                + "the {} weighting method".format(w_method),
            )
        if w_method.upper() == "EM":
            if (
                not np.all(
                    np.isclose(
                        np.sum(z_matrix, axis=0),
                        np.ones(z_matrix.shape[1]),
                    )
                )
            ):
                raise ValueError(
                    "The columns of the decision matrix must sum to 1 in "
                    + "order to apply the EM weighting method",
                )
        elif w_method.upper() == "CRITIC":
            if c_method.upper() not in {"PEARSON", "ABSPEARSON", "DCOR"}:
                raise ValueError(
                    "Unknown compatibility of the CRITIC weighting method "
                    + "with the {} correlation method".format(c_method)
                )
        elif w_method.upper() == "VIC":
            if c_method.upper() in {"PEARSON"}:
                raise ValueError(
                    "The VIC weighting method is not compatible with the "
                    + "{} correlation method".format(c_method),
                )
            if c_method.upper() not in {"ABSPEARSON", "DCOR"}:
                raise ValueError(
                    "Unknown compatibility of the VIC weighting method with "
                    + "the {} correlation method".format(c_method),
                )
    else:
        raise ValueError("Unknown weighting method ({})".format(w_method))

# %% ../nbs/05_mcdm.ipynb 7
def check_normalization_input(x_matrix, is_benefit_x, n_method):
    """
    Raise an exception if any argument is inappropriate for the corresponding
    normalization method
    """
    if (
        n_method is None
        or n_method.upper() in {"LINEAR1", "LINEAR2", "LINEAR3", "VECTOR"}
    ):
        if len(is_benefit_x) != x_matrix.shape[1]:
            raise ValueError(
                "The number of variables in the list that determines whether "
                + "each criterion is a benefit or a cost criterion does not "
                + "match the number of columns in the matrix",
            )
        if n_method is None:
            if not is_normalized_matrix(x_matrix):
                raise ValueError(
                    "The matrix is not normalized such that each element is "
                    + "between 0 and 1",
                )
        elif n_method.upper() in {"LINEAR1", "LINEAR3", "VECTOR"}:
            if np.sum(np.less(x_matrix, 0.0)) > 0:
                raise ValueError(
                    "The matrix must not contain any "
                    + "negative numbers in order to apply the "
                    + "{} normalization method".format(n_method),
                )
    else:
        raise ValueError("Unknown normalization method ({})".format(n_method))

# %% ../nbs/05_mcdm.ipynb 8
def abspearson(z_matrix):
    """
    Return the absolute value of the Pearson correlation coefficients of the
    provided matrix.
    """
    # Make sure that the provided matrix is a float64 NumPy array
    z_matrix = np.array(z_matrix, dtype=np.float64)

    return np.absolute(np.corrcoef(z_matrix, rowvar=False))

# %% ../nbs/05_mcdm.ipynb 9
def dcor(z_matrix):
    """
    Return the distance correlation coefficients of the provided matrix.
    """
    # Make sure that the provided matrix is a float64 NumPy array
    z_matrix = np.array(z_matrix, dtype=np.float64)

    # Initialize the matrix for the distance correlation coefficients
    dcor_matrix = np.ones(
        (z_matrix.shape[1], z_matrix.shape[1]),
        dtype=np.float64,
    )

    # Compute the matrix of squared distance covariances
    dcov2_matrix = squared_dcov_matrix(z_matrix)

    # Compute the distance correlation coefficients
    for j_col in range(z_matrix.shape[1]):
        # Get the squared distance variance of the j-th criterion
        j_dvar2 = dcov2_matrix[j_col, j_col]

        for l_col in range(j_col + 1, z_matrix.shape[1]):
            # Get the squared distance variance of the l-th criterion
            l_dvar2 = dcov2_matrix[l_col, l_col]

            # Compare the product of their squared distance variances
            if j_dvar2 * l_dvar2 == 0.0:
                # The two criteria are independent
                dcor_matrix[j_col, l_col] = 0.0
                dcor_matrix[l_col, j_col] = 0.0
            else:
                # Get the squared distance covariance of the two criteria
                jl_dcov2 = dcov2_matrix[j_col, l_col]

                # Compute the squared distance correlation of the two criteria
                jl_dcor2 = squared_dcor(jl_dcov2, j_dvar2, l_dvar2)

                # Compute the distance correlation of the two criteria
                dcor_matrix[j_col, l_col] = np.sqrt(jl_dcor2)
                dcor_matrix[l_col, j_col] = dcor_matrix[j_col, l_col]

    return dcor_matrix

# %% ../nbs/05_mcdm.ipynb 10
def squared_dcov_matrix(z_matrix):
    """
    Return the matrix of squared distance covariance between the columns of
    the provided matrix.
    """
    # Initialize the distance covariance matrix
    dcov2_matrix = np.zeros(
        (z_matrix.shape[1], z_matrix.shape[1]),
        dtype=np.float64,
    )

    for j_col in range(z_matrix.shape[1]):
        # Compute the Euclidean distance matrix of the j-th criterion
        j_dmatrix = dist_matrix(z_matrix[:, j_col])

        # Compute the linear function of its Euclidean distance matrix
        j_func = lin_func(j_dmatrix)

        for l_col in range(j_col, z_matrix.shape[1]):
            if j_col == l_col:
                # Compute the distance variance of the j-th criterion
                dcov2_matrix[j_col, j_col] = squared_dcov(j_func, j_func)
            else:
                # Compute the Euclidean distance matrix of the l-th criterion
                l_dmatrix = dist_matrix(z_matrix[:, l_col])

                # Compute the linear function of its Euclidean distance matrix
                l_func = lin_func(l_dmatrix)

                # Compute the squared distance covariance of the two criteria
                dcov2_matrix[j_col, l_col] = squared_dcov(j_func, l_func)
                dcov2_matrix[l_col, j_col] = dcov2_matrix[j_col, l_col]

    return dcov2_matrix

# %% ../nbs/05_mcdm.ipynb 11
def dist_matrix(z_vector):
    """
    Return the Euclidean distance matrix of the provided vector.
    """
    # Initialize the Euclidean distance matrix
    dmatrix = np.zeros(
        (z_vector.shape[0], z_vector.shape[0]),
        dtype=np.float64,
    )

    for i_row in range(z_vector.shape[0]):
        for k_row in range(i_row + 1, z_vector.shape[0]):
            # The Euclidean distance of two real-valued scalars corresponds
            # to the absolute value of their difference
            dmatrix[i_row, k_row] = np.fabs(z_vector[i_row] - z_vector[k_row])
            dmatrix[k_row, i_row] = dmatrix[i_row, k_row]

    return dmatrix


def lin_func(dmatrix):
    """
    Return the result of the linear function for the provided distance matrix.
    """
    return (
        dmatrix
        - np.mean(dmatrix, axis=0)
        - np.reshape(np.mean(dmatrix, axis=1), (dmatrix.shape[0], 1))
        + np.mean(dmatrix)
    )


def squared_dcov(j_func, l_func):
    """
    Return the squared distance covariance between the corresponding columns.
    """
    return np.sum(np.multiply(j_func, l_func)) / (j_func.shape[0] ** 2)


def squared_dcor(jl_dcov2, j_dvar2, l_dvar2):
    """
    Return the squared distance correlation between the corresponding columns.
    """
    return jl_dcov2 / np.sqrt(j_dvar2 * l_dvar2)

# %% ../nbs/05_mcdm.ipynb 12
def pearson(z_matrix):
    """
    Return the Pearson correlation coefficients of the provided matrix.
    """
    # Make sure that the provided matrix is a float64 NumPy array
    z_matrix = np.array(z_matrix, dtype=np.float64)

    return np.corrcoef(z_matrix, rowvar=False)


# %% ../nbs/05_mcdm.ipynb 13
def correlate(z_matrix, c_method):
    """
    Return the selected correlation coefficients of the provided matrix.
    """
    # Use the selected correlation method
    if c_method.upper() == "PEARSON":
        return pearson(z_matrix)
    elif c_method.upper() == "ABSPEARSON":
        return abspearson(z_matrix)
    elif c_method.upper() == "DCOR":
        return dcor(z_matrix)
    else:
        raise ValueError("Unknown correlation method ({})".format(c_method))


# %% ../nbs/05_mcdm.ipynb 14
def em(z_matrix):
    """
    Return the weight vector of the provided decision matrix using the Entropy
    Measure method.
    """
    # Perform sanity checks
    z_matrix = np.array(z_matrix, dtype=np.float64)
    check_weighting_input(z_matrix, "", "EM")

    # Compute the normalization constant
    k_constant = 1.0 / np.log(z_matrix.shape[0])

    # Compute the entropy of each criterion
    e_vector = np.zeros(z_matrix.shape[1], dtype=np.float64)
    for j in range(z_matrix.shape[1]):
        tmp_sum = 0.0
        for i in range(z_matrix.shape[0]):
            if z_matrix[i, j] > 0.0:
                tmp_sum += z_matrix[i, j] * np.log(z_matrix[i, j])
        e_vector[j] = -k_constant * tmp_sum

    # The importance of each criterion corresponds to
    # its normalized degree of divergence
    return (1.0 - e_vector) / np.sum(1.0 - e_vector)


# %% ../nbs/05_mcdm.ipynb 15
def mw(z_matrix):
    """
    Return the weight vector of the provided decision matrix using the Mean
    Weights method.
    """
    # Perform sanity checks
    z_matrix = np.array(z_matrix, dtype=np.float64)
    check_weighting_input(z_matrix, "", "MW")

    # Each criterion is considered equally important
    return (
        np.full(z_matrix.shape[1], 1.0 / z_matrix.shape[1], dtype=np.float64)
    )


# %% ../nbs/05_mcdm.ipynb 16
def sd(z_matrix):
    """
    Return the weight vector of the provided decision matrix using the
    Standard Deviation method.
    """
    # Perform sanity checks
    z_matrix = np.array(z_matrix, dtype=np.float64)
    check_weighting_input(z_matrix, "", "SD")

    # Compute the standard deviation of each criterion
    sd_vector = np.std(z_matrix, axis=0, dtype=np.float64)

    # The importance of each criterion corresponds to
    # its normalized standard deviation
    return sd_vector / np.sum(sd_vector)


# %% ../nbs/05_mcdm.ipynb 17
def vic(z_matrix, c_method="dCor"):
    """
    Return the weight vector of the provided decision matrix using the
    Variability and Interdependencies of Criteria method.
    """
    # Perform sanity checks
    z_matrix = np.array(z_matrix, dtype=np.float64)
    if c_method is None:
        c_method = "dCor"
    check_weighting_input(z_matrix, c_method, "VIC")

    # Compute the standard deviation of each criterion
    sd_vector = np.std(z_matrix, axis=0, dtype=np.float64)

    # Compute the correlation coefficients between pairs of criteria
    corr_matrix = correlate(z_matrix, c_method)

    # Compute the importance of each criterion
    imp_vector = np.zeros(z_matrix.shape[1], dtype=np.float64)
    for j_col in range(z_matrix.shape[1]):
        tmp_sum = float(np.sum(corr_matrix[j_col]))
        imp_vector[j_col] = sd_vector[j_col] / tmp_sum

    # Normalize the importance of each criterion
    return imp_vector / np.sum(imp_vector)


# %% ../nbs/05_mcdm.ipynb 18
def linear1(x_matrix, is_benefit_x):
    """
    Return the normalized version of the provided matrix using the Linear
    Normalization (1) method.
    """
    # Perform sanity checks
    x_matrix = np.array(x_matrix, dtype=np.float64)
    check_normalization_input(x_matrix, is_benefit_x, "Linear1")

    # Construct the normalized matrix
    z_matrix = np.zeros(x_matrix.shape, dtype=np.float64)
    for j in range(x_matrix.shape[1]):
        if is_benefit_x[j]:
            max_value = np.amax(x_matrix[:, j])
            if max_value == 0.0:
                raise ValueError(
                    "The maximum value of a benefit criterion must not be "
                    + "zero in order to apply the Linear1 normalization "
                    + "method",
                )
            z_matrix[:, j] = x_matrix[:, j] / max_value
        else:
            min_value = np.amin(x_matrix[:, j])
            if min_value == 0.0:
                raise ValueError(
                    "The minimum value of a cost criterion must not be zero "
                    + "in order to apply the Linear1 normalization method",
                )
            z_matrix[:, j] = min_value / x_matrix[:, j]

    # All criteria have been transformed into benefit criteria
    is_benefit_z = [True for _ in range(x_matrix.shape[1])]

    return z_matrix, is_benefit_z

# %% ../nbs/05_mcdm.ipynb 19
def linear2(x_matrix, is_benefit_x):
    """
    Return the normalized version of the provided matrix using the Linear
    Normalization (2) method.
    """
    # Perform sanity checks
    x_matrix = np.array(x_matrix, dtype=np.float64)
    check_normalization_input(x_matrix, is_benefit_x, "Linear2")

    # Construct the normalized matrix
    z_matrix = np.zeros(x_matrix.shape, dtype=np.float64)
    for j in range(x_matrix.shape[1]):
        denominator = np.amax(x_matrix[:, j]) - np.amin(x_matrix[:, j])
        if denominator == 0.0:
            raise ValueError(
                "The maximum value of a criterion must not be equal to its "
                + "minimum value in order to apply the Linear2 normalization "
                + "method",
            )
        if is_benefit_x[j]:
            z_matrix[:, j] = (
                (x_matrix[:, j] - np.amin(x_matrix[:, j])) / denominator
            )
        else:
            z_matrix[:, j] = (
                (np.amax(x_matrix[:, j]) - x_matrix[:, j]) / denominator
            )

    # All criteria have been transformed into benefit criteria
    is_benefit_z = [True for _ in range(x_matrix.shape[1])]

    return z_matrix, is_benefit_z


# %% ../nbs/05_mcdm.ipynb 20
def linear3(x_matrix, is_benefit_x):
    """
    Return the normalized version of the provided matrix using the Linear
    Normalization (3) method.
    """
    # Perform sanity checks
    x_matrix = np.array(x_matrix, dtype=np.float64)
    check_normalization_input(x_matrix, is_benefit_x, "Linear3")

    # Construct the normalized matrix
    z_matrix = np.zeros(x_matrix.shape, dtype=np.float64)
    for j in range(x_matrix.shape[1]):
        denominator = np.sum(x_matrix[:, j])
        if denominator == 0.0:
            raise ValueError(
                "The sum of a criterion's values must not be equal to zero "
                + "in order to apply the Linear3 normalization method",
            )
        z_matrix[:, j] = x_matrix[:, j] / denominator

    # The criteria have not been transformed into benefit or cost criteria
    is_benefit_z = is_benefit_x.copy()

    return z_matrix, is_benefit_z


# %% ../nbs/05_mcdm.ipynb 21
def vector(x_matrix, is_benefit_x):
    """
    Return the normalized version of the provided matrix using the Vector
    Normalization method.
    """
    # Perform sanity checks
    x_matrix = np.array(x_matrix, dtype=np.float64)
    check_normalization_input(x_matrix, is_benefit_x, "Vector")

    # Construct the normalized matrix
    z_matrix = np.zeros(x_matrix.shape, dtype=np.float64)
    for j in range(x_matrix.shape[1]):
        denominator = np.sqrt(np.sum(x_matrix[:, j] ** 2))
        if denominator == 0.0:
            raise ValueError(
                "The square root of a criterion's sum of squared values must "
                + "not be equal to zero in order to apply the Vector "
                + "normalization method",
            )
        z_matrix[:, j] = x_matrix[:, j] / denominator

    # The criteria have not been transformed into benefit or cost criteria
    is_benefit_z = is_benefit_x.copy()

    return z_matrix, is_benefit_z


# %% ../nbs/05_mcdm.ipynb 22
def normalize(x_matrix, is_benefit_x, n_method):
    """
    Return the normalized version of the provided matrix using the selected
    normalization method.
    """
    # Use the selected normalization method
    if n_method is None:
        # Perform sanity checks
        x_matrix = np.array(x_matrix, dtype=np.float64)
        check_normalization_input(x_matrix, is_benefit_x, None)

        return np.copy(x_matrix), is_benefit_x.copy()
    elif n_method.upper() == "LINEAR1":
        return linear1(x_matrix, is_benefit_x)
    elif n_method.upper() == "LINEAR2":
        return linear2(x_matrix, is_benefit_x)
    elif n_method.upper() == "LINEAR3":
        return linear3(x_matrix, is_benefit_x)
    elif n_method.upper() == "VECTOR":
        return vector(x_matrix, is_benefit_x)
    else:
        raise ValueError("Unknown normalization method ({})".format(n_method))


# %% ../nbs/05_mcdm.ipynb 23
def critic(z_matrix, c_method="Pearson"):
    """
    Return the weight vector of the provided decision matrix using the
    Criteria Importance Through Intercriteria Correlation method.
    """
    # Perform sanity checks
    z_matrix = np.array(z_matrix, dtype=np.float64)
    if c_method is None:
        c_method = "Pearson"
    check_weighting_input(z_matrix, c_method, "CRITIC")

    # Compute the standard deviation of each criterion
    sd_vector = np.std(z_matrix, axis=0, dtype=np.float64)

    # Compute the correlation coefficients between pairs of criteria
    corr_matrix = correlate(z_matrix, c_method)

    # Compute the importance of each criterion
    imp_vector = np.zeros(z_matrix.shape[1], dtype=np.float64)
    for j_col in range(z_matrix.shape[1]):
        tmp_sum = 0.0
        for l_col in range(z_matrix.shape[1]):
            tmp_sum += 1.0 - corr_matrix[j_col, l_col]
        imp_vector[j_col] = sd_vector[j_col] * tmp_sum

    # Normalize the importance of each criterion
    return imp_vector / np.sum(imp_vector)

# %% ../nbs/05_mcdm.ipynb 24
def weigh(z_matrix, w_method, c_method=None):
    """
    Return the weight vector of the provided decision matrix using the
    selected weighting method.
    """
    # Use the selected weighting method
    if w_method.upper() == "MW":
        return mw(z_matrix)
    elif w_method.upper() == "EM":
        return em(z_matrix)
    elif w_method.upper() == "SD":
        return sd(z_matrix)
    elif w_method.upper() == "CRITIC":
        return critic(z_matrix, c_method)
    elif w_method.upper() == "VIC":
        return vic(z_matrix, c_method)
    else:
        raise ValueError("Unknown weighting method ({})".format(w_method))


# %% ../nbs/05_mcdm.ipynb 25
def topsis(z_matrix, w_vector, is_benefit_z):
    """
    Return the Technique for Order Preference by Similarity to Ideal Solution
    scores of the provided decision matrix with the provided weight vector.
    """
    # Perform sanity checks
    z_matrix = np.array(z_matrix, dtype=np.float64)
    w_vector = np.array(w_vector, dtype=np.float64)
    check_scoring_input(z_matrix, w_vector, is_benefit_z, "TOPSIS")

    # TOPSIS scores should always be sorted in descending order
    desc_order = True

    # Construct the weighted normalized decision matrix
    t_matrix = np.multiply(z_matrix, w_vector)

    # Derive the positive and negative ideal solutions
    pos_ideal_sol = np.zeros(t_matrix.shape[1], dtype=np.float64)
    neg_ideal_sol = np.zeros(t_matrix.shape[1], dtype=np.float64)
    for j in range(t_matrix.shape[1]):
        if is_benefit_z[j]:
            pos_ideal_sol[j] = np.amax(t_matrix[:, j])
            neg_ideal_sol[j] = np.amin(t_matrix[:, j])
        else:
            pos_ideal_sol[j] = np.amin(t_matrix[:, j])
            neg_ideal_sol[j] = np.amax(t_matrix[:, j])

    # Compute the score of each alternative
    s_vector = np.zeros(t_matrix.shape[0], dtype=np.float64)
    for i in range(t_matrix.shape[0]):
        pos_ideal_dist = np.linalg.norm(pos_ideal_sol - t_matrix[i, :])
        neg_ideal_dist = np.linalg.norm(t_matrix[i, :] - neg_ideal_sol)
        denominator = neg_ideal_dist + pos_ideal_dist
        if denominator == 0.0:
            raise ValueError(
                "The sum of the negative ideal distance and the positive "
                + "ideal distance must not be equal to zero in order to use "
                + "the TOPSIS method",
            )
        s_vector[i] = neg_ideal_dist / denominator

    return s_vector, desc_order


# %% ../nbs/05_mcdm.ipynb 26
def cp(z_matrix, w_vector, is_benefit_z):
    """
    Return the Technique for Order Preference by Similarity to Ideal Solution
    scores of the provided decision matrix with the provided weight vector.
    """
    # Perform sanity checks
    z_matrix = np.array(z_matrix, dtype=np.float64)
    w_vector = np.array(w_vector, dtype=np.float64)
    check_scoring_input(z_matrix, w_vector, is_benefit_z, "CP")

    # CP scores should always be sorted in descending order
    desc_order = False

    # Construct the weighted normalized decision matrix
    t_matrix = np.multiply(z_matrix, w_vector)

    # Derive the positive and negative ideal solutions
    pos_ideal_sol = np.zeros(t_matrix.shape[1], dtype=np.float64)
    neg_ideal_sol = np.zeros(t_matrix.shape[1], dtype=np.float64)
    for j in range(t_matrix.shape[1]):
        if is_benefit_z[j]:
            pos_ideal_sol[j] = np.amax(t_matrix[:, j])
            neg_ideal_sol[j] = np.amin(t_matrix[:, j])
        else:
            pos_ideal_sol[j] = np.amin(t_matrix[:, j])
            neg_ideal_sol[j] = np.amax(t_matrix[:, j])

    # Compute the score of each alternative
    s_vector = np.zeros(t_matrix.shape[0], dtype=np.float64)
    for i in range(t_matrix.shape[0]):
        pos_ideal_dist = np.linalg.norm(pos_ideal_sol - t_matrix[i, :])
        s_vector[i] = pos_ideal_dist

    return s_vector, desc_order

# %% ../nbs/05_mcdm.ipynb 27
def score(z_matrix, is_benefit_z, w_vector, s_method):
    """
    Return the selected scores of the provided decision matrix with the
    provided weight vector.
    """
    # Use the selected scoring method
    if s_method.upper() == "CP":
        return cp(z_matrix, w_vector, is_benefit_z)
    elif s_method.upper() == "TOPSIS":
        return topsis(z_matrix, w_vector, is_benefit_z)

    else:
        raise ValueError("Unknown scoring method ({})".format(s_method))
