(
    data,
    graph,
    n_components,
    initial_alpha,
    a,
    b,
    gamma,
    negative_sample_rate,
    n_epochs,
    init,
    random_state,
    metric,
    metric_kwds,
    densmap,
    densmap_kwds,
    output_dens,
    output_metric=dist.named_distances_with_gradients["euclidean"],
    output_metric_kwds={},
    euclidean_output=True,
    parallel=False,
    verbose=False,
    tqdm_kwds=None,
)
return embedding, aux_data
Perform a fuzzy simplicial set embedding, using a specified
    initialisation method and then minimizing the fuzzy set cross entropy
    between the 1-skeletons of the high and low dimensional fuzzy simplicial
    sets.

    Parameters
    ----------
    data: array of shape (n_samples, n_features)
        The source data to be embedded by UMAP.

    graph: sparse matrix
        The 1-skeleton of the high dimensional fuzzy simplicial set as
        represented by a graph for which we require a sparse matrix for the
        (weighted) adjacency matrix.

    n_components: int
        The dimensionality of the euclidean space into which to embed the data.

    initial_alpha: float
        Initial learning rate for the SGD.

    a: float
        Parameter of differentiable approximation of right adjoint functor

    b: float
        Parameter of differentiable approximation of right adjoint functor

    gamma: float
        Weight to apply to negative samples.

    negative_sample_rate: int (optional, default 5)
        The number of negative samples to select per positive sample
        in the optimization process. Increasing this value will result
        in greater repulsive force being applied, greater optimization
        cost, but slightly more accuracy.

    n_epochs: int (optional, default 0)
        The number of training epochs to be used in optimizing the
        low dimensional embedding. Larger values result in more accurate
        embeddings. If 0 is specified a value will be selected based on
        the size of the input dataset (200 for large datasets, 500 for small).

    init: string
        How to initialize the low dimensional embedding. Options are:
            * 'spectral': use a spectral embedding of the fuzzy 1-skeleton
            * 'random': assign initial embedding positions at random.
            * A numpy array of initial embedding positions.

    random_state: numpy RandomState or equivalent
        A state capable being used as a numpy random state.

    metric: string or callable
        The metric used to measure distance in high dimensional space; used if
        multiple connected components need to be layed out.

    metric_kwds: dict
        Key word arguments to be passed to the metric function; used if
        multiple connected components need to be layed out.

    densmap: bool
        Whether to use the density-augmented objective function to optimize
        the embedding according to the densMAP algorithm.

    densmap_kwds: dict
        Key word arguments to be used by the densMAP optimization.

    output_dens: bool
        Whether to output local radii in the original data and the embedding.

    output_metric: function
        Function returning the distance between two points in embedding space and
        the gradient of the distance wrt the first argument.

    output_metric_kwds: dict
        Key word arguments to be passed to the output_metric function.

    euclidean_output: bool
        Whether to use the faster code specialised for euclidean output metrics

    parallel: bool (optional, default False)
        Whether to run the computation using numba parallel.
        Running in parallel is non-deterministic, and is not used
        if a random seed has been set, to ensure reproducibility.

    verbose: bool (optional, default False)
        Whether to report information on the current progress of the algorithm.

    tqdm_kwds: dict
        Key word arguments to be used by the tqdm progress bar.

    Returns
    -------
    embedding: array of shape (n_samples, n_components)
        The optimized of ``graph`` into an ``n_components`` dimensional
        euclidean space.

    aux_data: dict
        Auxiliary output returned with the embedding. When densMAP extension
        is turned on, this dictionary includes local radii in the original
        data (``rad_orig``) and in the embedding (``rad_emb``).
Perform a fuzzy simplicial set embedding, using a specified
    initialisation method and then minimizing the fuzzy set cross entropy
    between the 1-skeletons of the high and low dimensional fuzzy simplicial
    sets.
Perform a fuzzy simplicial set embedding using a specified initialisation method and then minimizing the fuzzy set cross entropy between the 1 - skeletons of the high and low dimensional fuzzy simplicial sets .
def simplicial_set_embedding(
    data,
    graph,
    n_components,
    initial_alpha,
    a,
    b,
    gamma,
    negative_sample_rate,
    n_epochs,
    init,
    random_state,
    metric,
    metric_kwds,
    densmap,
    densmap_kwds,
    output_dens,
    output_metric=dist.named_distances_with_gradients["euclidean"],
    output_metric_kwds={},
    euclidean_output=True,
    parallel=False,
    verbose=False,
    tqdm_kwds=None,
):
    """Perform a fuzzy simplicial set embedding, using a specified
    initialisation method and then minimizing the fuzzy set cross entropy
    between the 1-skeletons of the high and low dimensional fuzzy simplicial
    sets.

    Parameters
    ----------
    data: array of shape (n_samples, n_features)
        The source data to be embedded by UMAP.

    graph: sparse matrix
        The 1-skeleton of the high dimensional fuzzy simplicial set as
        represented by a graph for which we require a sparse matrix for the
        (weighted) adjacency matrix.

    n_components: int
        The dimensionality of the euclidean space into which to embed the data.

    initial_alpha: float
        Initial learning rate for the SGD.

    a: float
        Parameter of differentiable approximation of right adjoint functor

    b: float
        Parameter of differentiable approximation of right adjoint functor

    gamma: float
        Weight to apply to negative samples.

    negative_sample_rate: int (optional, default 5)
        The number of negative samples to select per positive sample
        in the optimization process. Increasing this value will result
        in greater repulsive force being applied, greater optimization
        cost, but slightly more accuracy.

    n_epochs: int (optional, default 0)
        The number of training epochs to be used in optimizing the
        low dimensional embedding. Larger values result in more accurate
        embeddings. If 0 is specified a value will be selected based on
        the size of the input dataset (200 for large datasets, 500 for small).

    init: string
        How to initialize the low dimensional embedding. Options are:
            * 'spectral': use a spectral embedding of the fuzzy 1-skeleton
            * 'random': assign initial embedding positions at random.
            * A numpy array of initial embedding positions.

    random_state: numpy RandomState or equivalent
        A state capable being used as a numpy random state.

    metric: string or callable
        The metric used to measure distance in high dimensional space; used if
        multiple connected components need to be layed out.

    metric_kwds: dict
        Key word arguments to be passed to the metric function; used if
        multiple connected components need to be layed out.

    densmap: bool
        Whether to use the density-augmented objective function to optimize
        the embedding according to the densMAP algorithm.

    densmap_kwds: dict
        Key word arguments to be used by the densMAP optimization.

    output_dens: bool
        Whether to output local radii in the original data and the embedding.

    output_metric: function
        Function returning the distance between two points in embedding space and
        the gradient of the distance wrt the first argument.

    output_metric_kwds: dict
        Key word arguments to be passed to the output_metric function.

    euclidean_output: bool
        Whether to use the faster code specialised for euclidean output metrics

    parallel: bool (optional, default False)
        Whether to run the computation using numba parallel.
        Running in parallel is non-deterministic, and is not used
        if a random seed has been set, to ensure reproducibility.

    verbose: bool (optional, default False)
        Whether to report information on the current progress of the algorithm.

    tqdm_kwds: dict
        Key word arguments to be used by the tqdm progress bar.

    Returns
    -------
    embedding: array of shape (n_samples, n_components)
        The optimized of ``graph`` into an ``n_components`` dimensional
        euclidean space.

    aux_data: dict
        Auxiliary output returned with the embedding. When densMAP extension
        is turned on, this dictionary includes local radii in the original
        data (``rad_orig``) and in the embedding (``rad_emb``).
    """
    graph = graph.tocoo()
    graph.sum_duplicates()
    n_vertices = graph.shape[1]

    # For smaller datasets we can use more epochs
    if graph.shape[0] <= 10000:
        default_epochs = 500
    else:
        default_epochs = 200

    # Use more epochs for densMAP
    if densmap:
        default_epochs += 200

    if n_epochs is None:
        n_epochs = default_epochs

    if n_epochs > 10:
        graph.data[graph.data < (graph.data.max() / float(n_epochs))] = 0.0
    else:
        graph.data[graph.data < (graph.data.max() / float(default_epochs))] = 0.0

    graph.eliminate_zeros()

    if isinstance(init, str) and init == "random":
        embedding = random_state.uniform(
            low=-10.0, high=10.0, size=(graph.shape[0], n_components)
        ).astype(np.float32)
    elif isinstance(init, str) and init == "spectral":
        # We add a little noise to avoid local minima for optimization to come
        initialisation = spectral_layout(
            data,
            graph,
            n_components,
            random_state,
            metric=metric,
            metric_kwds=metric_kwds,
        )
        expansion = 10.0 / np.abs(initialisation).max()
        embedding = (initialisation * expansion).astype(
            np.float32
        ) + random_state.normal(
            scale=0.0001, size=[graph.shape[0], n_components]
        ).astype(
            np.float32
        )
    else:
        init_data = np.array(init)
        if len(init_data.shape) == 2:
            if np.unique(init_data, axis=0).shape[0] < init_data.shape[0]:
                tree = KDTree(init_data)
                dist, ind = tree.query(init_data, k=2)
                nndist = np.mean(dist[:, 1])
                embedding = init_data + random_state.normal(
                    scale=0.001 * nndist, size=init_data.shape
                ).astype(np.float32)
            else:
                embedding = init_data

    epochs_per_sample = make_epochs_per_sample(graph.data, n_epochs)

    head = graph.row
    tail = graph.col
    weight = graph.data

    rng_state = random_state.randint(INT32_MIN, INT32_MAX, 3).astype(np.int64)

    aux_data = {}

    if densmap or output_dens:
        if verbose:
            print(ts() + " Computing original densities")

        dists = densmap_kwds["graph_dists"]

        mu_sum = np.zeros(n_vertices, dtype=np.float32)
        ro = np.zeros(n_vertices, dtype=np.float32)
        for i in range(len(head)):
            j = head[i]
            k = tail[i]

            D = dists[j, k] * dists[j, k]  # match sq-Euclidean used for embedding
            mu = graph.data[i]

            ro[j] += mu * D
            ro[k] += mu * D
            mu_sum[j] += mu
            mu_sum[k] += mu

        epsilon = 1e-8
        ro = np.log(epsilon + (ro / mu_sum))

        if densmap:
            R = (ro - np.mean(ro)) / np.std(ro)
            densmap_kwds["mu"] = graph.data
            densmap_kwds["mu_sum"] = mu_sum
            densmap_kwds["R"] = R

        if output_dens:
            aux_data["rad_orig"] = ro

    embedding = (
        10.0
        * (embedding - np.min(embedding, 0))
        / (np.max(embedding, 0) - np.min(embedding, 0))
    ).astype(np.float32, order="C")

    if euclidean_output:
        embedding = optimize_layout_euclidean(
            embedding,
            embedding,
            head,
            tail,
            n_epochs,
            n_vertices,
            epochs_per_sample,
            a,
            b,
            rng_state,
            gamma,
            initial_alpha,
            negative_sample_rate,
            parallel=parallel,
            verbose=verbose,
            densmap=densmap,
            densmap_kwds=densmap_kwds,
            tqdm_kwds=tqdm_kwds,
            move_other=True,
        )
    else:
        embedding = optimize_layout_generic(
            embedding,
            embedding,
            head,
            tail,
            n_epochs,
            n_vertices,
            epochs_per_sample,
            a,
            b,
            rng_state,
            gamma,
            initial_alpha,
            negative_sample_rate,
            output_metric,
            tuple(output_metric_kwds.values()),
            verbose=verbose,
            tqdm_kwds=tqdm_kwds,
            move_other=True,
        )
    if output_dens:
        if verbose:
            print(ts() + " Computing embedding densities")

        # Compute graph in embedding
        (knn_indices, knn_dists, rp_forest,) = nearest_neighbors(
            embedding,
            densmap_kwds["n_neighbors"],
            "euclidean",
            {},
            False,
            random_state,
            verbose=verbose,
        )

        emb_graph, emb_sigmas, emb_rhos, emb_dists = fuzzy_simplicial_set(
            embedding,
            densmap_kwds["n_neighbors"],
            random_state,
            "euclidean",
            {},
            knn_indices,
            knn_dists,
            verbose=verbose,
            return_dists=True,
        )

        emb_graph = emb_graph.tocoo()
        emb_graph.sum_duplicates()
        emb_graph.eliminate_zeros()

        n_vertices = emb_graph.shape[1]

        mu_sum = np.zeros(n_vertices, dtype=np.float32)
        re = np.zeros(n_vertices, dtype=np.float32)

        head = emb_graph.row
        tail = emb_graph.col
        for i in range(len(head)):
            j = head[i]
            k = tail[i]

            D = emb_dists[j, k]
            mu = emb_graph.data[i]

            re[j] += mu * D
            re[k] += mu * D
            mu_sum[j] += mu
            mu_sum[k] += mu

        epsilon = 1e-8
        re = np.log(epsilon + (re / mu_sum))

        aux_data["rad_emb"] = re

    return embedding, aux_data
def simplicial_set_embedding ( data , graph , n_components , initial_alpha , a , b , gamma , negative_sample_rate , n_epochs , init , random_state , metric , metric_kwds , densmap , densmap_kwds , output_dens , output_metric = dist . named_distances_with_gradients [ "euclidean" ] , output_metric_kwds = { } , euclidean_output = True , parallel = False , verbose = False , tqdm_kwds = None , ) : graph = graph . tocoo ( ) graph . sum_duplicates ( ) n_vertices = graph . shape [ 1 ] # For smaller datasets we can use more epochs if graph . shape [ 0 ] <= 10000 : default_epochs = 500 else : default_epochs = 200 # Use more epochs for densMAP if densmap : default_epochs += 200 if n_epochs is None : n_epochs = default_epochs if n_epochs > 10 : graph . data [ graph . data < ( graph . data . max ( ) / float ( n_epochs ) ) ] = 0.0 else : graph . data [ graph . data < ( graph . data . max ( ) / float ( default_epochs ) ) ] = 0.0 graph . eliminate_zeros ( ) if isinstance ( init , str ) and init == "random" : embedding = random_state . uniform ( low = - 10.0 , high = 10.0 , size = ( graph . shape [ 0 ] , n_components ) ) . astype ( np . float32 ) elif isinstance ( init , str ) and init == "spectral" : # We add a little noise to avoid local minima for optimization to come initialisation = spectral_layout ( data , graph , n_components , random_state , metric = metric , metric_kwds = metric_kwds , ) expansion = 10.0 / np . abs ( initialisation ) . max ( ) embedding = ( initialisation * expansion ) . astype ( np . float32 ) + random_state . normal ( scale = 0.0001 , size = [ graph . shape [ 0 ] , n_components ] ) . astype ( np . float32 ) else : init_data = np . array ( init ) if len ( init_data . shape ) == 2 : if np . unique ( init_data , axis = 0 ) . shape [ 0 ] < init_data . shape [ 0 ] : tree = KDTree ( init_data ) dist , ind = tree . query ( init_data , k = 2 ) nndist = np . mean ( dist [ : , 1 ] ) embedding = init_data + random_state . normal ( scale = 0.001 * nndist , size = init_data . shape ) . astype ( np . float32 ) else : embedding = init_data epochs_per_sample = make_epochs_per_sample ( graph . data , n_epochs ) head = graph . row tail = graph . col weight = graph . data rng_state = random_state . randint ( INT32_MIN , INT32_MAX , 3 ) . astype ( np . int64 ) aux_data = { } if densmap or output_dens : if verbose : print ( ts ( ) + " Computing original densities" ) dists = densmap_kwds [ "graph_dists" ] mu_sum = np . zeros ( n_vertices , dtype = np . float32 ) ro = np . zeros ( n_vertices , dtype = np . float32 ) for i in range ( len ( head ) ) : j = head [ i ] k = tail [ i ] D = dists [ j , k ] * dists [ j , k ] # match sq-Euclidean used for embedding mu = graph . data [ i ] ro [ j ] += mu * D ro [ k ] += mu * D mu_sum [ j ] += mu mu_sum [ k ] += mu epsilon = 1e-8 ro = np . log ( epsilon + ( ro / mu_sum ) ) if densmap : R = ( ro - np . mean ( ro ) ) / np . std ( ro ) densmap_kwds [ "mu" ] = graph . data densmap_kwds [ "mu_sum" ] = mu_sum densmap_kwds [ "R" ] = R if output_dens : aux_data [ "rad_orig" ] = ro embedding = ( 10.0 * ( embedding - np . min ( embedding , 0 ) ) / ( np . max ( embedding , 0 ) - np . min ( embedding , 0 ) ) ) . astype ( np . float32 , order = "C" ) if euclidean_output : embedding = optimize_layout_euclidean ( embedding , embedding , head , tail , n_epochs , n_vertices , epochs_per_sample , a , b , rng_state , gamma , initial_alpha , negative_sample_rate , parallel = parallel , verbose = verbose , densmap = densmap , densmap_kwds = densmap_kwds , tqdm_kwds = tqdm_kwds , move_other = True , ) else : embedding = optimize_layout_generic ( embedding , embedding , head , tail , n_epochs , n_vertices , epochs_per_sample , a , b , rng_state , gamma , initial_alpha , negative_sample_rate , output_metric , tuple ( output_metric_kwds . values ( ) ) , verbose = verbose , tqdm_kwds = tqdm_kwds , move_other = True , ) if output_dens : if verbose : print ( ts ( ) + " Computing embedding densities" ) # Compute graph in embedding ( knn_indices , knn_dists , rp_forest , ) = nearest_neighbors ( embedding , densmap_kwds [ "n_neighbors" ] , "euclidean" , { } , False , random_state , verbose = verbose , ) emb_graph , emb_sigmas , emb_rhos , emb_dists = fuzzy_simplicial_set ( embedding , densmap_kwds [ "n_neighbors" ] , random_state , "euclidean" , { } , knn_indices , knn_dists , verbose = verbose , return_dists = True , ) emb_graph = emb_graph . tocoo ( ) emb_graph . sum_duplicates ( ) emb_graph . eliminate_zeros ( ) n_vertices = emb_graph . shape [ 1 ] mu_sum = np . zeros ( n_vertices , dtype = np . float32 ) re = np . zeros ( n_vertices , dtype = np . float32 ) head = emb_graph . row tail = emb_graph . col for i in range ( len ( head ) ) : j = head [ i ] k = tail [ i ] D = emb_dists [ j , k ] mu = emb_graph . data [ i ] re [ j ] += mu * D re [ k ] += mu * D mu_sum [ j ] += mu mu_sum [ k ] += mu epsilon = 1e-8 re = np . log ( epsilon + ( re / mu_sum ) ) aux_data [ "rad_emb" ] = re return embedding , aux_data