# Path: umap/distances.py
# def pairwise_special_metric(X, Y=None, metric="hellinger", kwds=None):
#     if callable(metric):
#         if kwds is not None:
#             kwd_vals = tuple(kwds.values())
#         else:
#             kwd_vals = ()
# 
#         @numba.njit(fastmath=True)
#         def _partial_metric(_X, _Y=None):
#             return metric(_X, _Y, *kwd_vals)
# 
#         return pairwise_distances(X, Y, metric=_partial_metric)
#     else:
#         special_metric_func = named_distances[metric]
#     return parallel_special_metric(X, Y, metric=special_metric_func)
# 
# SPECIAL_METRICS = (
#     "hellinger",
#     "ll_dirichlet",
#     "symmetric_kl",
#     "poincare",
#     hellinger,
#     ll_dirichlet,
#     symmetric_kl,
#     poincare,
# )
# 
# Path: umap/sparse.py
# def arr_unique(arr):
# def arr_union(ar1, ar2):
# def arr_intersect(ar1, ar2):
# def sparse_sum(ind1, data1, ind2, data2):
# def sparse_diff(ind1, data1, ind2, data2):
# def sparse_mul(ind1, data1, ind2, data2):
# def general_sset_intersection(
#     indptr1,
#     indices1,
#     data1,
#     indptr2,
#     indices2,
#     data2,
#     result_row,
#     result_col,
#     result_val,
#     right_complement=False,
#     mix_weight=0.5,
# ):
# def general_sset_union(
#     indptr1,
#     indices1,
#     data1,
#     indptr2,
#     indices2,
#     data2,
#     result_row,
#     result_col,
#     result_val,
# ):
# def sparse_euclidean(ind1, data1, ind2, data2):
# def sparse_manhattan(ind1, data1, ind2, data2):
# def sparse_chebyshev(ind1, data1, ind2, data2):
# def sparse_minkowski(ind1, data1, ind2, data2, p=2.0):
# def sparse_hamming(ind1, data1, ind2, data2, n_features):
# def sparse_canberra(ind1, data1, ind2, data2):
# def sparse_bray_curtis(ind1, data1, ind2, data2):  # pragma: no cover
# def sparse_jaccard(ind1, data1, ind2, data2):
# def sparse_matching(ind1, data1, ind2, data2, n_features):
# def sparse_dice(ind1, data1, ind2, data2):
# def sparse_kulsinski(ind1, data1, ind2, data2, n_features):
# def sparse_rogers_tanimoto(ind1, data1, ind2, data2, n_features):
# def sparse_russellrao(ind1, data1, ind2, data2, n_features):
# def sparse_sokal_michener(ind1, data1, ind2, data2, n_features):
# def sparse_sokal_sneath(ind1, data1, ind2, data2):
# def sparse_cosine(ind1, data1, ind2, data2):
# def sparse_hellinger(ind1, data1, ind2, data2):
# def sparse_correlation(ind1, data1, ind2, data2, n_features):
# def approx_log_Gamma(x):
# def log_beta(x, y):
# def log_single_beta(x):
# def sparse_ll_dirichlet(ind1, data1, ind2, data2):
# SPARSE_SPECIAL_METRICS = {
#     sparse_hellinger: "hellinger",
#     sparse_ll_dirichlet: "ll_dirichlet",
# }


from warnings import warn
from sklearn.manifold import SpectralEmbedding
from sklearn.metrics import pairwise_distances
from sklearn.metrics.pairwise import _VALID_METRICS as SKLEARN_PAIRWISE_VALID_METRICS
from umap.distances import pairwise_special_metric, SPECIAL_METRICS
from umap.sparse import SPARSE_SPECIAL_METRICS, sparse_named_distances
import numpy as np
import scipy.sparse
import scipy.sparse.csgraph
                distance_matrix[c_i, c_j] = dist
                distance_matrix[c_j, c_i] = dist
    else:
        for label in range(n_components):
            component_centroids[label] = data[component_labels == label].mean(axis=0)

        if scipy.sparse.isspmatrix(component_centroids):
            warn(
                "Forcing component centroids to dense; if you are running out of "
                "memory then consider increasing n_neighbors."
            )
            component_centroids = component_centroids.toarray()

        if metric in SPECIAL_METRICS:
            distance_matrix = pairwise_special_metric(
                component_centroids,
                metric=metric,
                kwds=metric_kwds,
            )
        elif metric in SPARSE_SPECIAL_METRICS:
            distance_matrix = pairwise_special_metric(
                component_centroids,
                metric=SPARSE_SPECIAL_METRICS[metric],
                kwds=metric_kwds,
            )
        else:
            if callable(metric) and scipy.sparse.isspmatrix(data):
                function_to_name_mapping = {
                    sparse_named_distances[k]: k
                    for k in set(SKLEARN_PAIRWISE_VALID_METRICS)

# Path: umap/distances.py
# def pairwise_special_metric(X, Y=None, metric="hellinger", kwds=None):
#     if callable(metric):
#         if kwds is not None:
#             kwd_vals = tuple(kwds.values())
#         else:
#             kwd_vals = ()
# 
#         @numba.njit(fastmath=True)
#         def _partial_metric(_X, _Y=None):
#             return metric(_X, _Y, *kwd_vals)
# 
#         return pairwise_distances(X, Y, metric=_partial_metric)
#     else:
#         special_metric_func = named_distances[metric]
#     return parallel_special_metric(X, Y, metric=special_metric_func)
# 
# SPECIAL_METRICS = (
#     "hellinger",
#     "ll_dirichlet",
#     "symmetric_kl",
#     "poincare",
#     hellinger,
#     ll_dirichlet,
#     symmetric_kl,
#     poincare,
# )
# 
# Path: umap/sparse.py
# def arr_unique(arr):
# def arr_union(ar1, ar2):
# def arr_intersect(ar1, ar2):
# def sparse_sum(ind1, data1, ind2, data2):
# def sparse_diff(ind1, data1, ind2, data2):
# def sparse_mul(ind1, data1, ind2, data2):
# def general_sset_intersection(
#     indptr1,
#     indices1,
#     data1,
#     indptr2,
#     indices2,
#     data2,
#     result_row,
#     result_col,
#     result_val,
#     right_complement=False,
#     mix_weight=0.5,
# ):
# def general_sset_union(
#     indptr1,
#     indices1,
#     data1,
#     indptr2,
#     indices2,
#     data2,
#     result_row,
#     result_col,
#     result_val,
# ):
# def sparse_euclidean(ind1, data1, ind2, data2):
# def sparse_manhattan(ind1, data1, ind2, data2):
# def sparse_chebyshev(ind1, data1, ind2, data2):
# def sparse_minkowski(ind1, data1, ind2, data2, p=2.0):
# def sparse_hamming(ind1, data1, ind2, data2, n_features):
# def sparse_canberra(ind1, data1, ind2, data2):
# def sparse_bray_curtis(ind1, data1, ind2, data2):  # pragma: no cover
# def sparse_jaccard(ind1, data1, ind2, data2):
# def sparse_matching(ind1, data1, ind2, data2, n_features):
# def sparse_dice(ind1, data1, ind2, data2):
# def sparse_kulsinski(ind1, data1, ind2, data2, n_features):
# def sparse_rogers_tanimoto(ind1, data1, ind2, data2, n_features):
# def sparse_russellrao(ind1, data1, ind2, data2, n_features):
# def sparse_sokal_michener(ind1, data1, ind2, data2, n_features):
# def sparse_sokal_sneath(ind1, data1, ind2, data2):
# def sparse_cosine(ind1, data1, ind2, data2):
# def sparse_hellinger(ind1, data1, ind2, data2):
# def sparse_correlation(ind1, data1, ind2, data2, n_features):
# def approx_log_Gamma(x):
# def log_beta(x, y):
# def log_single_beta(x):
# def sparse_ll_dirichlet(ind1, data1, ind2, data2):
# SPARSE_SPECIAL_METRICS = {
#     sparse_hellinger: "hellinger",
#     sparse_ll_dirichlet: "ll_dirichlet",
# }


# Path: umap/spectral.py
from warnings import warn
from sklearn.manifold import SpectralEmbedding
from sklearn.metrics import pairwise_distances
from sklearn.metrics.pairwise import _VALID_METRICS as SKLEARN_PAIRWISE_VALID_METRICS
from umap.distances import pairwise_special_metric, SPECIAL_METRICS
from umap.sparse import SPARSE_SPECIAL_METRICS, sparse_named_distances
import numpy as np
import scipy.sparse
import scipy.sparse.csgraph

                distance_matrix[c_i, c_j] = dist
                distance_matrix[c_j, c_i] = dist
    else:
        for label in range(n_components):
            component_centroids[label] = data[component_labels == label].mean(axis=0)

        if scipy.sparse.isspmatrix(component_centroids):
            warn(
                "Forcing component centroids to dense; if you are running out of "
                "memory then consider increasing n_neighbors."
            )
            component_centroids = component_centroids.toarray()

        if metric in SPECIAL_METRICS:
            distance_matrix = pairwise_special_metric(
                component_centroids,
                metric=metric,
                kwds=metric_kwds,
            )
        elif metric in SPARSE_SPECIAL_METRICS:
            distance_matrix = pairwise_special_metric(
                component_centroids,
                metric=SPARSE_SPECIAL_METRICS[metric],
                kwds=metric_kwds,
            )
        else:
            if callable(metric) and scipy.sparse.isspmatrix(data):
                function_to_name_mapping = {
                    sparse_named_distances[k]: k
                    for k in set(SKLEARN_PAIRWISE_VALID_METRICS)

                    & set(sparse_named_distances.keys())