def compute_qmean(Y_label, Y_pred):
    pi_array = []
    for i in range(2):
        pi_a = np.count_nonzero(Y_label == i) / len(Y_label)
        pi_array.append(pi_a)

    confusion_matrix = get_confusion_matrix(Y_label, Y_pred)
    sum_sq_form = 0
    for i in range(2):
        sum_sq_form += (1 - (confusion_matrix[i][i] / pi_array[i]))**2
    return np.sqrt(sum_sq_form / 2)
def compute_gmean(Y_label, Y_pred):
    pi_array = []
    for i in range(2):
        pi_a = np.count_nonzero(Y_label == i) / len(Y_label)
        pi_array.append(pi_a)

    confusion_matrix = get_confusion_matrix(Y_label, Y_pred)
    prod_form = 1
    for i in range(2):
        prod_form *= confusion_matrix[i][i] / pi_array[i]
    return 1 - (prod_form)**(1 / 2)
def compute_hmean(Y_label, Y_pred):
    pi_array = []
    for i in range(2):
        pi_a = np.count_nonzero(Y_label == i) / len(Y_label)
        pi_array.append(pi_a)

    confusion_matrix = get_confusion_matrix(Y_label, Y_pred)
    sum_formulae = 0
    for i in range(2):
        sum_formulae += pi_array[i] / confusion_matrix[i][i]
    return 1 - (2 / sum_formulae)
def compute_KLD(Y_label, Y_pred):
    n_class = 2
    cm = get_confusion_matrix(Y_label, Y_pred)
    pi_array = []
    for i in range(n_class):
        pi_a = np.count_nonzero(Y_label == i)
        pi_array.append(pi_a / len(Y_label))

    kld_error = 0
    for i in range(n_class):
        sum_col_i = 0
        for j in range(n_class):
            sum_col_i += cm[j, i]
        kld_error += pi_array[i] * np.log(pi_array[i] / sum_col_i)

    return kld_error
def compute_EOpp(Y_label, Y_pred, X_pro_feature):
    n_class = 2
    final_conf = np.zeros(shape=(n_class, n_class))
    cm = []
    unique_a = len(np.unique(X_pro_feature))

    for a in np.unique(X_pro_feature).astype(int):
        indices_a = X_pro_feature == a
        Y_label_a = Y_label[indices_a]
        Y_pred_a = Y_pred[indices_a]
        cm_a = get_confusion_matrix(Y_label_a, Y_pred_a)
        cm_a = cm_a / (cm_a[1, 0] + cm_a[1, 1])
        final_conf += cm_a
        cm.append(cm_a)
    odds_per_a_1 = np.zeros(unique_a)

    for i in range(unique_a):
        cm_a = cm[i]
        odds_per_a_1[i] = abs(cm_a[1, 1] - (1 / unique_a) * (final_conf[1, 1]))

    return max(odds_per_a_1)
def compute_DP(Y_label, Y_pred, X_pro_feature):
    final_conf = np.zeros(shape=(2, 2))
    cm = []
    unique_a = len(np.unique(X_pro_feature))

    for a in np.unique(X_pro_feature).astype(int):
        indices_a = X_pro_feature == a
        Y_label_a = Y_label[indices_a]
        Y_pred_a = Y_pred[indices_a]
        cm_a = get_confusion_matrix(Y_label_a, Y_pred_a)
        final_conf += cm_a
        cm.append(cm_a)

    parity_per_a = np.zeros(unique_a)

    for i in range(unique_a):
        cm_a = cm[i]
        parity_per_a[i] = abs(cm_a[0, 1] + cm_a[1, 1] - (1 / unique_a) *
                              (final_conf[0, 1] + final_conf[1, 1]))

    return max(parity_per_a)
def compute_linear_loss(Y_label, Y_pred):
    confusion_matrix = get_confusion_matrix(Y_label, Y_pred)
    return 1 - confusion_matrix[0][0] - confusion_matrix[1][1]
def compute_COV(Y_label, Y_pred):
    n_class = 2
    cm = get_confusion_matrix(Y_label, Y_pred)
    return cm[0, 1] + cm[1, 1]