def SHAPr(  # pylint: disable=invalid-name
    target_estimator: "CLASSIFIER_TYPE",
    x_train: np.ndarray,
    y_train: np.ndarray,
    x_test: np.ndarray,
    y_test: np.ndarray,
    knn_metric: str | None = None,
) -> np.ndarray:
    """
    Compute the SHAPr membership privacy risk metric for the given classifier and training set.

    | Paper link: http://arxiv.org/abs/2112.02230

    :param target_estimator: The classifier to be analyzed.
    :param x_train: The training data of the classifier.
    :param y_train: Target values (class labels) of `x_train`, one-hot-encoded of shape (nb_samples, nb_classes) or
                    indices of shape (nb_samples,).
    :param x_test: The test data of the classifier.
    :param y_test: Target values (class labels) of `x_test`, one-hot-encoded of shape (nb_samples, nb_classes) or
                    indices of shape (nb_samples,).
    :param knn_metric: The distance metric to use for the KNN classifier (default is 'minkowski', which represents
                       Euclidean distance).
    :return: an array containing the SHAPr scores for each sample in the training set. The higher the value,
             the higher the privacy leakage for that sample. Any value above 0 should be considered a privacy leak.
    """
    if target_estimator.input_shape[0] != x_train.shape[1]:
        raise ValueError("Shape of x_train does not match input_shape of classifier")

    if x_test.shape[1] != x_train.shape[1]:
        raise ValueError("Shape of x_train does not match the shape of x_test")

    y_train = check_and_transform_label_format(y_train, target_estimator.nb_classes)
    if y_train.shape[0] != x_train.shape[0]:
        raise ValueError("Number of rows in x_train and y_train do not match")

    y_test = check_and_transform_label_format(y_test, target_estimator.nb_classes)
    if y_test.shape[0] != x_test.shape[0]:
        raise ValueError("Number of rows in x_test and y_test do not match")

    n_train_samples = x_train.shape[0]
    pred_train = target_estimator.predict(x_train)
    pred_test = target_estimator.predict(x_test)

    if knn_metric:
        knn = KNeighborsClassifier(metric=knn_metric)
    else:
        knn = KNeighborsClassifier()
    knn.fit(pred_train, y_train)

    results = []

    n_test = pred_test.shape[0]
    for i_test in range(n_test):
        results_test = []
        pred = pred_test[i_test]
        y_0 = y_test[i_test]
        # returns sorted indexes, from closest to farthest
        n_indexes = knn.kneighbors([pred], n_neighbors=n_train_samples, return_distance=False)
        # reverse - from farthest to closest
        n_indexes = n_indexes.reshape(-1)[::-1]
        sorted_y_train = y_train[n_indexes]
        sorted_indexes = np.argsort(n_indexes)
        # compute partial contribution incrementally
        first = True
        phi_y_prev: float = 0.0
        y_indicator_prev = 0
        for i_train in range(sorted_y_train.shape[0]):
            y = sorted_y_train[i_train]
            y_indicator = 1 if np.all(y == y_0) else 0
            if first:
                phi_y = y_indicator / n_train_samples
                first = False
            else:
                phi_y = phi_y_prev + ((y_indicator - y_indicator_prev) / (n_train_samples - i_train))
            results_test.append(phi_y)
            phi_y_prev = phi_y
            y_indicator_prev = y_indicator
        # return to original order of training samples
        results_test_sorted = np.array(results_test)[sorted_indexes]
        results.append(results_test_sorted.tolist())

    # need to sum across test samples (outer list) for each train sample (inner list)
    per_sample = list(map(list, zip(*results)))
    # normalize so it's comparable across different sizes of train and test datasets
    sum_per_sample = np.array([sum(val) for val in per_sample], dtype=np.float32) * n_train_samples / n_test

    return sum_per_sample

    Compute the SHAPr membership privacy risk metric for the given classifier and training set.

    | Paper link: http://arxiv.org/abs/2112.02230

    :param target_estimator: The classifier to be analyzed.
    :param x_train: The training data of the classifier.
    :param y_train: Target values (class labels) of `x_train`, one-hot-encoded of shape (nb_samples, nb_classes) or
                    indices of shape (nb_samples,).
    :param x_test: The test data of the classifier.
    :param y_test: Target values (class labels) of `x_test`, one-hot-encoded of shape (nb_samples, nb_classes) or
                    indices of shape (nb_samples,).
    :param knn_metric: The distance metric to use for the KNN classifier (default is 'minkowski', which represents
                       Euclidean distance).
    :return: an array containing the SHAPr scores for each sample in the training set. The higher the value,
             the higher the privacy leakage for that sample. Any value above 0 should be considered a privacy leak.
    
art/metrics/privacy/membership_leakage.py