This directory vendors several modules from the `mlx-vis` project (mlx-vis 0.7.0):

    nndescent.py  —  copied verbatim from mlx_vis/_nndescent/nndescent.py
    normalize.py  —  copied verbatim from mlx_vis/_normalize.py
    knn.py        —  from mlx_vis/_knn.py; only the internal import was rewritten to be
                     relative (`from .nndescent import NNDescent`)
    tsne.py       —  from mlx_vis/_tsne/tsne.py; internal imports rewritten to be relative,
                     plus a one-line bugfix (bind `X_mx` before the PCA-init block so
                     fit_transform does not raise UnboundLocalError when pca_dim is None or
                     the input dim <= pca_dim). The patch is marked `VENDOR PATCH
                     (metalsinglecell)` in the source.
    umap.py       —  from mlx_vis/_umap/umap.py; only the internal imports were rewritten to
                     be relative (`from .normalize ...`, `from .knn ...`)

Original work Copyright Han Xiao (github.com/hanxiao/mlx-vis), licensed under the
Apache License, Version 2.0 (see the LICENSE file in this directory).

  Project : mlx-vis — GPU-Native Dimensionality Reduction on Apple Silicon
  Author  : Han Xiao <han.xiao@elastic.co>
  Source  : https://github.com/hanxiao/mlx-vis  (PyPI: mlx-vis)
  Paper   : arXiv:2603.04035

Vendored into metal-SingleCell (rather than taken as a runtime dependency) to keep the
dependency footprint minimal. metal-SingleCell also adapts vendored outputs at its own call
sites without modifying these files: `metalsinglecell.neighbors` over-builds + self-prepends
the NNDescent graph, and `metalsinglecell.tools.tsne` calls the vendored TSNE as its default
backend.

`umap.py` is now used only for `_find_ab_params` (the Gauss-Newton fit of the a/b curve
parameters). `metalsinglecell.embedding` supplies both halves of the layout itself:

  * `_initial_embedding` replaces `_spectral_init`, which assumes a connected graph. On a
    disconnected k-NN graph the top eigenspace of the normalized adjacency is spanned by the
    component indicator vectors, so the power iteration returns a piecewise-constant vector.
  * `_optimize_layout` replaces `_optimize`, which clipped each edge's gradient to ±4 and
    then scatter-added every incident edge onto the same positions, with no feedback between
    them. A high-degree node could move hundreds of units in one epoch, tearing the layout
    apart (github issue #1). Ours is a port of umap-learn's `optimize_layout_euclidean` that
    keeps the parallel evaluation and adds a per-node trust region in its place.

Neither is a criticism of mlx-vis at the scale it targets; both failure modes need a large,
structurally heterogeneous graph to show up.

Changes to the vendored files: as itemized above (relative-import rewrites throughout; the
tsne.py UnboundLocalError bugfix). No algorithmic changes.
