Usage And API

July 26, 2026 ยท View on GitHub

Home | Installation | Bioconductor | Implementation | Examples | Benchmarks | API | Reproducibility | References

This page gives the main KNN-first workflows and the public API.

Which Function Should I Use?

SituationUse
You want to precompute fastEmbedR's native neighboursprecompute_knn()
You already computed nearest neighboursumap_knn() or opentsne_knn()
You want one call from a data matrixumap() or opentsne()
You want reusable PCA scores or t-SNE initializationpca() or opentsne_pca_init()
You want to compare UMAP and openTSNE fairlycompute one host KNN list once, then reuse it
You want Apple GPUset backend = "metal" explicitly
You want NVIDIA GPUbuild with CUDA/cuVS, then set embedding backend = "cuda"
You want a fast approximation for very large datause landmark_umap() or landmark_tsne() and report it as landmarking
You want quality metricsevaluate_embedding(x, layout)
You want a clustering graphknn_graph()
You want native graph communitiesgraph_cluster(graph, method = "leiden")

The recommended workflow is KNN first:

knn <- precompute_knn(
  x,
  k = 50L,
  metric = "euclidean",
  backend = "cpu",
  n_threads = 4L
)
layout_umap <- umap_knn(knn, seed = 1)
layout_tsne <- opentsne_knn(knn, init_data = x, seed = 1)

This keeps nearest-neighbour time separate from embedding time and makes benchmarks easier to interpret.

The one-call functions and precompute_knn() intentionally hide the KNN algorithm choice. Their backend accepts only "cpu", "metal", or "cuda". CPU KNN uses native HNSW; Metal uses native exact/IVF-Flat; CUDA uses direct FAISS GPU exact search or RAPIDS cuVS IVF-Flat and keeps its output resident on the device. A CUDA KNN object should therefore be reused with a CUDA embedding backend. A host KNN result from another tool may still be supplied as a plain list containing indices and distances; fastEmbedR never calls that tool itself.

Distance Metrics

The default distance is Euclidean:

fit <- umap(x, n_neighbors = 50, metric = "euclidean", n_threads = 4)

Cosine distance is available through exact CPU KNN:

fit_cosine <- umap(x, n_neighbors = 50, metric = "cosine", n_threads = 4)

Current metric support is deliberately explicit:

metricsupported backendsnotes
euclideannative CPU/Metal and optional direct CUDA/cuVSRecommended default for large UMAP/openTSNE benchmarks.
cosinenative CPU/Metal and compiled CUDARows are normalized internally.
correlationnative CPU/Metal and compiled CUDARows are centered and normalized internally.
inner_productcompiled CUDA onlyUnsupported CPU/Metal requests fail explicitly.

Basic KNN-First UMAP

library(fastEmbedR)

set.seed(1)
x <- scale(as.matrix(iris[, 1:4]))
labels <- iris$Species

fit <- umap(x, n_neighbors = 30, n_threads = 4)
layout <- fit$layout

plot(layout, pch = 21, bg = labels)

The one-call interface computes KNN internally:

fit <- umap(
  x,
  n_neighbors = 30,
  seed = 1
)
plot(fit)

openTSNE From The Same KNN

Y_init <- opentsne_pca_init(x, seed = 1)
layout_tsne <- opentsne_knn(
  knn,
  Y_init = Y_init,
  perplexity = 10,
  early_exaggeration_iter = 100,
  n_iter = 250
)

plot(layout_tsne, pch = 21, bg = labels)

Y_init can be computed once and reused across runs. init_data is still available as a convenience; it is used only to compute PCA initialization for KNN-input runs and is not used for neighbour search or optimization.

PCA API

fastEmbedR::pca() exposes the backend-native truncated PCA used internally for openTSNE initialization:

pca_fit <- pca(
  x,
  ncomp = 2,
  backend = "cpu",
  seed = 1,
  opentsne_init = TRUE
)
Y_init <- pca_fit$opentsne_init
layout <- opentsne_knn(knn, Y_init = Y_init, perplexity = 30)

The public pca() helper is intentionally simple: there is no irlba or ARPACK method menu and no Python bridge. For openTSNE initialization, CUDA uses native RAPIDS RAFT TSVD compiled into the package CUDA backend and fails loudly if that support is unavailable. Metal uses a native float32 block-subspace TSVD with MPS matrix products and a resident workspace. CPU uses the fastPLS-style RSVD family available to the package build.

The ordinary PCA scores are always retained in pca_fit$scores. opentsne_init = TRUE adds a second matrix, centered and scaled so that its largest component standard deviation is 1e-4; no second decomposition is performed.

The argument order follows fastPLS::pca() for x, ncomp, xtest, center, scale, and backend, but fastEmbedR intentionally omits the SVD method selector. Supplying xtest adds projected test coordinates in pca_fit$scores_test.

Explicit GPU Use

GPU use is explicit. A request for Metal or CUDA must run that backend or fail clearly.

fit <- opentsne(x, perplexity = 30, backend = "metal", seed = 1)
layout <- fit$layout

For CUDA builds with RAPIDS cuVS available:

fit <- opentsne(x, perplexity = 50, backend = "cuda", seed = 1)

The package does not silently run these examples on CPU and report them as GPU results.

Graph Clustering

Build a graph from raw data, an embedding result, or a reusable KNN object:

graph <- knn_graph(x, k = 20, weight = "snn", n_threads = 4)
communities <- graph_cluster(graph, method = "leiden", seed = 1)
table(communities$membership)

For an embedding-space graph, pass the fit directly:

fit <- opentsne(x, perplexity = 15, backend = "cpu", seed = 1)
graph <- knn_graph(fit, k = 20, weight = "snn", n_threads = 4)
communities <- graph_cluster(graph, method = "leiden", seed = 1)

knn_graph() uses the selected backend only when it must compute neighbours. graph_cluster() is native CPU code and does not call igraph, cuGraph, or an external clustering routine. Walktrap is intended for small and moderate graphs because its transition matrix is quadratic; use Leiden or Louvain for large graphs.

Landmark Workflow

For reusable landmark models, keep the three stages explicit:

selection <- select_landmarks(x, landmarks = 0.5, seed = 1)

model <- fit_landmark_model(
  x,
  selection,
  method = "umap",
  n_neighbors = 30,
  graph_mode = "fuzzy",
  backend = "cpu",
  n_threads = 4,
  seed = 1
)

fit <- project_landmark_model(
  model,
  x,
  refinement_epochs = 50,
  n_threads = 4
)

The reference fit uses the same umap() implementation, graph construction, optimizer, and parameter values as an ordinary full UMAP run. For openTSNE, set method = "opentsne" and pass perplexity. The resulting model can also project a separate matrix of new observations in the same feature space.

precompute_query_knn(reference, query, ...) exposes the query-only search used by the projection stage. It searches the fixed reference only and avoids constructing unnecessary query-to-query neighbours.

The one-call wrapper remains available:

fit <- landmark_tsne(
  x,
  landmarks = 0.5,
  n_neighbors = 30,
  perplexity = 10,
  early_exaggeration_iter = 100,
  n_iter = 250,
  transform_iter = 100,
  seed = 1
)
plot(fit)

UMAP has the same landmark pattern:

fit <- landmark_umap(
  x,
  landmarks = 0.5,
  n_neighbors = 30,
  graph_mode = "fuzzy",
  backend = "cpu",
  seed = 1
)
plot(fit)

CPU projection uses native recall-tuned HNSW. Metal uses native exact search for small references and recall-tuned IVF-Flat for larger references, followed by native fixed-reference transform kernels. CUDA uses native exact search for smaller references and IVF-Flat for larger references; its KNN result remains device resident for the projection and refinement stages.

Automatic Parameters

opentsne() and opentsne_knn() use auto_config = TRUE by default. Missing t-SNE settings are resolved in native C++ using the opt-SNE strategy:

  • "auto" learning rate becomes n / early_exaggeration.
  • Early exaggeration can stop at the local maximum of KLD relative change.
  • The normal phase can stop when KLD improvement drops below the opt-SNE threshold.

The KLD monitor is enabled only where it is computationally honest: CPU/small exact runs. Large FFT and GPU runs keep opt-SNE's learning-rate/default-limit policy but do not perform a hidden CPU O(n^2) KLD poll or report it as GPU work.

umap() and umap_knn() also choose internal defaults from the supplied KNN distance profile in C++. This keeps the public API small while preserving the supplied neighbour graph.

Public API

FunctionPurpose
precompute_knn()Package-native non-self KNN search with CPU, Metal, or CUDA backend.
umap_knn()UMAP from a supplied KNN object or matrices.
umap()One-call preprocessing, KNN, and UMAP embedding.
pca()Backend-native truncated PCA scores/loadings.
embed_knn()KNN dispatcher; UMAP by default, openTSNE with method = "opentsne".
opentsne_knn()Direct native openTSNE-style optimizer from KNN.
opentsne()One-call preprocessing, KNN, and openTSNE-style embedding.
transform_tsne()Fixed-reference openTSNE-style transform for query points.
landmark_tsne()Embed landmarks, then transform remaining rows.
landmark_umap()Embed landmarks with UMAP, then project/refine remaining rows.
evaluate_embedding()Embedding quality metrics.
knn_graph()Compact graph from data, an embedding, or supplied KNN.
graph_cluster()Native Louvain, Leiden, or Pons-Latapy Walktrap communities.