Visualization parity

August 8, 2026 ยท View on GitHub

kodama-cpp tracks the UMAP and openTSNE implementation at fastEmbedR commit 814350a5ca69b0c26e6df40377636f109055f84b. The audited upstream source hashes are recorded in PROVENANCE.md.

On 8 August 2026, fastEmbedR main advanced to 5248ee02376c01bd6e1be788280db4e978623eed. A follow-up source audit found no changed native UMAP optimizer file. The complete exported float32 knn_tsne_opentsne_float_cpp function had the identical SHA-256 7fc28f97762cc9a0163a0702a2c03159244a5f0cb1899238d7e0e1a22d688887 in both revisions. The newer commit reorganizes R-level t-SNE controls, adds native PCA orchestration, removes the unused double t-SNE path, and adds graph-clustering backends. None changes the KODAMA UMAP/openTSNE kernels validated below, so the parity snapshot remains pinned rather than importing unrelated code.

Initialization contract

The C++ core exposes KODAMAVisualizationPCAInit(). It calculates one backend-native float32 PCA and derives both starts:

  • openTSNE centers the scores and scales the largest component standard deviation to 1e-4, matching fastEmbedR;
  • UMAP centers the scores, scales the largest absolute coordinate to 10, adds deterministic float32 jitter with standard deviation 1e-4, and recenters.

R and Python use explicit coordinates first, then a stored initialization when its backend matches the requested CPU, CUDA, or Metal visualization backend, then explicit raw data. Graph-only initialization is the final fallback.

Implementation comparison

The port includes fuzzy UMAP graph construction and stochastic optimization, and openTSNE sparse affinities, exact/FFT repulsion, persistent CPU workers, cached FFT plans, CUDA graph chunking, and native Metal FFT-grid optimization.

In controlled CPU openTSNE tests with identical KNN input, raw-data PCA initialization, seed, perplexity, iteration count, and optimizer settings, the fastEmbedR and kodama-cpp coordinates had zero maximum and mean absolute difference on MetRef, USPS, and TabulaMuris.

Native Metal openTSNE uses fastEmbedR's FFT-grid optimizer, layout-statistic reductions, sparse attractive forces, momentum/gain schedule, and centering. For compatibility with Metal compilers that do not expose atomic_float, its grid accumulators use atomic_uint storage plus float-bit compare-and-swap addition. This preserves float32 values and equations, but parallel accumulation order remains nondeterministic. On MetRef, USPS, and full TabulaMuris (873, 11,000, and 100,102 samples), pair-distance correlation with fastEmbedR Metal was 0.9863, 0.9981, and 0.9928. Correlation with the exact CPU trajectory was 1.0000, 0.9997, and 0.9990. Warm KODAMA Metal optimizer times were 0.054, 0.201, and 0.556 seconds; corresponding fastEmbedR Metal times were 0.047, 0.224, and 0.606 seconds.

UMAP parity is backend-specific, as it is in the audited fastEmbedR source. CPU uses the CSR epoch-schedule optimizer, CUDA uses its atomic COO/CSR epoch-schedule optimizer, and Metal uses the clean row sampler with Bernoulli edge acceptance and negative sampling. KODAMA copies those three execution strategies separately rather than forcing all devices through one sampler. The Metal implementation uses fixed-point atomic coordinate updates because the supported Metal compiler does not expose portable atomic_float addition.

With one identical fuzzy graph and CPU spectral initialization, the current source comparison had exactly matching graph edge counts and maximum weights on MetRef, USPS, and TabulaMuris: 42,410, 361,242, and 4,390,614 directed entries, each with maximum weight 1. Pair-distance correlations between KODAMA and fastEmbedR were 0.9574, 0.8580, and 0.9535 for CPU and 0.9842, 0.7943, and 0.9572 for Metal. All layouts were finite. Stochastic trajectories are not expected to be bitwise identical because storage layout, float32 reduction order, and parallel atomic update order differ; graph identity and explicit optimizer metadata distinguish those numerical effects from graph mismatch.

In a second fixed-200-epoch CPU/Metal screen using the same graph and start, Metal optimizer speedups were 1.08x, 6.10x, and 6.52x on MetRef, USPS, and TabulaMuris. Truth-label edge agreement@15 was 0.6225/0.6309, 0.7077/0.7084, and 0.8828/0.8828 for CPU/Metal. These are exploratory local worktree measurements, not frozen release benchmarks.

R and Python expose the same diagnostics on returned layouts: selected backend, optimizer, initialization source and backend, runtime, and UMAP fuzzy-graph edge count and maximum weight. The graph fields are zero for openTSNE because its sparse probability matrix is not the UMAP fuzzy graph.

The reproducible drivers, CSV files, and plots are under benchmarks/run_visualization_fastembedr_parity.R, benchmarks/run_umap_fastembedr_parity.R, benchmarks/visualization_fastembedr_parity_20260807/, and benchmarks/umap_fastembedr_source_parity_20260808_final/.