umap-web 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +98 -0
- package/LICENSE +29 -0
- package/NOTICE +19 -0
- package/README.md +205 -0
- package/dist/chunk-Bp6m_JJh.js +13 -0
- package/dist/core-BPpH5_PW.js +2816 -0
- package/dist/core-BPpH5_PW.js.map +1 -0
- package/dist/core-IHdw-3yY.d.ts +373 -0
- package/dist/core.d.ts +3 -0
- package/dist/core.js +4 -0
- package/dist/index.d.ts +261 -0
- package/dist/index.js +2991 -0
- package/dist/index.js.map +1 -0
- package/dist/init-DLiEtGpx.js +802 -0
- package/dist/init-DLiEtGpx.js.map +1 -0
- package/dist/sparse-BxSeVhO4.d.ts +150 -0
- package/dist/webgpu.d.ts +111 -0
- package/dist/webgpu.js +955 -0
- package/dist/webgpu.js.map +1 -0
- package/dist/worker.d.ts +1 -0
- package/dist/worker.js +1095 -0
- package/dist/worker.js.map +1 -0
- package/package.json +76 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.2.0 — 2026-07-12
|
|
4
|
+
|
|
5
|
+
Production-hardening release: worker packaging that survives real bundlers, typed
|
|
6
|
+
and recoverable GPU failures, untrusted-input deserialization, complete option
|
|
7
|
+
validation, and airtight estimator lifecycle. **Behavior-compatible for all valid
|
|
8
|
+
inputs** — seeded CPU embeddings are byte-identical to 0.1.0 (full parity matrix
|
|
9
|
+
re-verified; D-012).
|
|
10
|
+
|
|
11
|
+
### Workers & bundlers (D-016)
|
|
12
|
+
|
|
13
|
+
- `dist/worker.js` is now a single **self-contained** file (31.5 KB raw / 8.2 KB
|
|
14
|
+
gzip); the spawn uses the inline `new Worker(new URL(...), ...)` pattern that
|
|
15
|
+
webpack 5 / Vite build / Rollup detect. Cross-origin (CDN) use retries via a
|
|
16
|
+
`blob:` URL. New `workerUrl` option pins a custom location. See README
|
|
17
|
+
"Workers & bundlers" (Vite dev needs one line of config).
|
|
18
|
+
- Worker failures can no longer hang `fit()` or crash Node: spawn/init errors and a
|
|
19
|
+
10 s init timeout reject all pending calls with `UmapBackendError` (worker stacks
|
|
20
|
+
preserved), and the run continues single-threaded with one actionable warning.
|
|
21
|
+
|
|
22
|
+
### WebGPU robustness (D-017)
|
|
23
|
+
|
|
24
|
+
- Buffer sizes are validated against granted device limits before allocation;
|
|
25
|
+
kernels run under validation/out-of-memory error scopes; device loss is tracked —
|
|
26
|
+
GPU failures now throw `UmapBackendError` instead of returning zero-filled
|
|
27
|
+
(silently wrong) embeddings.
|
|
28
|
+
- Under `backend: 'auto'`, a typed GPU failure falls back to the CPU for that stage
|
|
29
|
+
with the rng restored (seeded results byte-identical to CPU-only runs); explicit
|
|
30
|
+
`backend: 'webgpu'` propagates the error. Device acquisition times out after 5 s.
|
|
31
|
+
- All GPU buffers are released on every path (including abort); `gpuKnn` and
|
|
32
|
+
`gpuSpectralInit` now honor `AbortSignal` per chunk/iteration.
|
|
33
|
+
- `transform()` on a large GPU-fitted model now builds the pynndescent search index
|
|
34
|
+
lazily on first call (previously brute-forced every query; D-018).
|
|
35
|
+
|
|
36
|
+
### Estimator lifecycle
|
|
37
|
+
|
|
38
|
+
- `fit`/`update` snapshot the fitted state: an aborted or failed call restores the
|
|
39
|
+
previous model (a failed first fit stays unfitted) and always releases its worker
|
|
40
|
+
pool / GPU device. Concurrent operations on one estimator throw `UmapError`.
|
|
41
|
+
- `transform` validates query width against the training data; the same-data
|
|
42
|
+
fast path byte-confirms the input before returning the training embedding.
|
|
43
|
+
- `inverseTransform` and `AlignedUMAP.fit/fitTransform/update` accept `{ signal }`.
|
|
44
|
+
|
|
45
|
+
### Stricter validation (may reject inputs 0.1.0 silently accepted)
|
|
46
|
+
|
|
47
|
+
- `deserialize` fully validates blobs: bounds, dtypes, shape/index cross-checks,
|
|
48
|
+
and search-tree traversal invariants — corrupt or crafted blobs throw
|
|
49
|
+
`UmapValidationError` (previously: silent garbage or raw exceptions).
|
|
50
|
+
- Options: `nComponents`/`nNeighbors`/`negativeSampleRate` must be positive
|
|
51
|
+
integers; range checks on `repulsionStrength`, `localConnectivity`,
|
|
52
|
+
`targetWeight`, `densFrac`, `densVarShift`; `a`/`b` must be set together;
|
|
53
|
+
unknown `metric`/`targetMetric`/`outputMetric` names fail at construction;
|
|
54
|
+
non-empty `outputMetricOptions` is rejected (it was silently ignored);
|
|
55
|
+
`backend` is now `'auto' | 'cpu' | 'webgpu'` (objects rejected with a clear
|
|
56
|
+
message).
|
|
57
|
+
- `metricOptions` sizes are checked against the data width at fit
|
|
58
|
+
(`V`/`w`/`VInv`/`p`) — wrong sizes previously produced silent NaN graphs.
|
|
59
|
+
- Sparse input: CSR column indices must be sorted and duplicate-free (the sparse
|
|
60
|
+
metrics assume it; unsorted input previously produced wrong distances).
|
|
61
|
+
- `precomputedKnn`: `distances` length validated; `disconnectionDistance` masking
|
|
62
|
+
now applied (was skipped on this path).
|
|
63
|
+
|
|
64
|
+
### Other
|
|
65
|
+
|
|
66
|
+
- `angularRpForest` is now honored (ORed with the metric family, matching Python);
|
|
67
|
+
it was previously accepted and ignored.
|
|
68
|
+
- Core exports `exactKnnDense`/`exactKnnSparse` pad with `(-1, Infinity)` when
|
|
69
|
+
`k > n` (previously copied uninitialized slots); `knnFromPrecomputed` throws
|
|
70
|
+
`UmapValidationError` on non-square input.
|
|
71
|
+
- The library never writes to the console (a dead `verbose` console path in
|
|
72
|
+
NN-descent was removed; use the `verbose`/logger option).
|
|
73
|
+
- Auto-seeding masks entropy to 53 bits and throws a typed error when
|
|
74
|
+
`globalThis.crypto` is unavailable (pass `seed` explicitly there).
|
|
75
|
+
|
|
76
|
+
## 0.1.0 — 2026-07-07
|
|
77
|
+
|
|
78
|
+
Initial release.
|
|
79
|
+
|
|
80
|
+
- UMAP estimator with functional parity to `umap-learn 0.5.9.post2` (14-cell
|
|
81
|
+
statistical parity matrix + deterministic stage-parity suites; see PARITY.md).
|
|
82
|
+
- kNN: exact brute force (< 4096 rows), pynndescent-0.6.0-ported RP-forest +
|
|
83
|
+
NN-descent + hub-tree query search; CSR sparse support; `precomputedKnn` and
|
|
84
|
+
`metric: 'precomputed'`.
|
|
85
|
+
- 33 named data metrics (+ custom metric functions on the CPU exact path).
|
|
86
|
+
- Initializations: spectral (matrix-free LOBPCG + multi-component meta layout),
|
|
87
|
+
PCA (randomized SVD), random, user array.
|
|
88
|
+
- Layout: euclidean SGD (+ densMAP), generic path with haversine and hyperboloid
|
|
89
|
+
output metrics; `onEpoch` snapshots and `AbortSignal` support.
|
|
90
|
+
- Estimator semantics: categorical / semi-supervised (−1) / continuous supervision,
|
|
91
|
+
`unique`, `disconnectionDistance`, `transform` (+ `'graph'` mode), `inverseTransform`,
|
|
92
|
+
`update()`, binary serialization with bit-exact reload.
|
|
93
|
+
- Backends: CPU single-thread (seeded runs byte-reproducible), CPU worker pool
|
|
94
|
+
(SharedArrayBuffer or transfer fallback), WebGPU (tiled brute-force kNN +
|
|
95
|
+
fixed-point atomic SGD) with per-stage CPU fallback and backend reporting.
|
|
96
|
+
- `AlignedUMAP` over dataset slices with relations.
|
|
97
|
+
- Benchmarks on Apple M5 Pro: MNIST-70k in 24 s (CPU workers) / 7.8 s (WebGPU);
|
|
98
|
+
500k×128 in 78 s (WebGPU); 1M×256 in 5.5 min (WebGPU).
|
package/LICENSE
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, Jeya Balaji Balasubramanian
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
10
|
+
list of conditions and the following disclaimer.
|
|
11
|
+
|
|
12
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
13
|
+
this list of conditions and the following disclaimer in the documentation
|
|
14
|
+
and/or other materials provided with the distribution.
|
|
15
|
+
|
|
16
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
17
|
+
contributors may be used to endorse or promote products derived from
|
|
18
|
+
this software without specific prior written permission.
|
|
19
|
+
|
|
20
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
21
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
22
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
23
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
24
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
25
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
26
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
27
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
28
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
29
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/NOTICE
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
umap-web
|
|
2
|
+
Copyright (c) 2026 Jeya Balaji Balasubramanian
|
|
3
|
+
|
|
4
|
+
This product is an independent TypeScript implementation of the UMAP
|
|
5
|
+
algorithm. It is derived from and validated against the following
|
|
6
|
+
BSD-3-Clause licensed projects, whose algorithms, constants, and semantics
|
|
7
|
+
it faithfully reimplements:
|
|
8
|
+
|
|
9
|
+
umap-learn (https://github.com/lmcinnes/umap)
|
|
10
|
+
Copyright (c) 2017, Leland McInnes
|
|
11
|
+
Licensed under the BSD 3-Clause License.
|
|
12
|
+
|
|
13
|
+
pynndescent (https://github.com/lmcinnes/pynndescent)
|
|
14
|
+
Copyright (c) 2017, Leland McInnes
|
|
15
|
+
Licensed under the BSD 2-Clause License.
|
|
16
|
+
|
|
17
|
+
Reference: McInnes, L., Healy, J., & Melville, J. (2018). UMAP: Uniform
|
|
18
|
+
Manifold Approximation and Projection for Dimension Reduction.
|
|
19
|
+
arXiv:1802.03426.
|
package/README.md
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# umap-web
|
|
2
|
+
|
|
3
|
+
A standalone, production-grade **TypeScript implementation of UMAP** for browsers and
|
|
4
|
+
Node.js — functionally at parity with Python's `umap-learn` (pinned `0.5.9.post2`),
|
|
5
|
+
with a memory-disciplined CPU backend (typed arrays + worker pool) and a **WebGPU**
|
|
6
|
+
backend for large datasets. **Zero runtime dependencies.**
|
|
7
|
+
|
|
8
|
+
Built for **privacy-preserving, in-browser** dimensionality reduction: your data never
|
|
9
|
+
leaves the device. Everything — kNN construction, fuzzy graph, spectral init, SGD
|
|
10
|
+
layout — runs locally, from a static page if you like.
|
|
11
|
+
|
|
12
|
+
## Quickstart (Node)
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import { UMAP } from 'umap-web';
|
|
16
|
+
|
|
17
|
+
const umap = new UMAP({ nNeighbors: 15, minDist: 0.1, seed: 42 });
|
|
18
|
+
const embedding = await umap.fitTransform({
|
|
19
|
+
data: myFloat32Array, // row-major
|
|
20
|
+
rows: nSamples,
|
|
21
|
+
cols: nFeatures,
|
|
22
|
+
});
|
|
23
|
+
// embedding: { data: Float32Array, rows, cols: 2 }
|
|
24
|
+
|
|
25
|
+
const more = await umap.transform(newPoints); // project held-out rows
|
|
26
|
+
const blob = umap.serialize(); // persist the fitted model
|
|
27
|
+
const restored = UMAP.deserialize(blob); // ... and reload it elsewhere
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`number[][]` inputs and CSR sparse inputs (`{ data, indices, indptr, rows, cols }`)
|
|
31
|
+
work too. Supervision: `await umap.fit(X, labels)` (Int32Array; `-1` = unlabeled) or a
|
|
32
|
+
continuous target with `targetMetric: 'l2'`.
|
|
33
|
+
|
|
34
|
+
## Quickstart (browser)
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import { UMAP } from 'umap-web';
|
|
38
|
+
|
|
39
|
+
// CPU workers (no special headers needed — works on GitHub Pages):
|
|
40
|
+
const umap = new UMAP({ concurrency: 'auto', onEpoch: ({ embedding }) => draw(embedding) });
|
|
41
|
+
|
|
42
|
+
// WebGPU (Chrome/Edge on capable hardware):
|
|
43
|
+
const gpu = new UMAP({ backend: 'webgpu' });
|
|
44
|
+
const embedding = await gpu.fitTransform(X);
|
|
45
|
+
console.log(gpu.backendInfo); // { knn: 'webgpu', layout: 'webgpu' }
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`backend: 'auto'` (default) picks WebGPU when an adapter exists and the configuration
|
|
49
|
+
is GPU-supported, else CPU workers, else single-thread. Every run reports which backend
|
|
50
|
+
actually executed each stage via `umap.backendInfo`.
|
|
51
|
+
|
|
52
|
+
- **Workers without COOP/COEP**: SharedArrayBuffer is used when available
|
|
53
|
+
(`crossOriginIsolated` or Node); otherwise a first-class transfer-fallback path runs
|
|
54
|
+
(that is what executes on GitHub Pages).
|
|
55
|
+
- **Node GPU (device injection)**: pass a `GPUDevice` (e.g. from a Dawn binding such as
|
|
56
|
+
the `webgpu` npm package) via the `device` option; the backend uses it instead of
|
|
57
|
+
`navigator.gpu`. Non-Chromium GPU stacks are best-effort.
|
|
58
|
+
|
|
59
|
+
## Workers & bundlers
|
|
60
|
+
|
|
61
|
+
The CPU worker ships as a **single self-contained ESM file** (`umap-web/worker`,
|
|
62
|
+
31.5 KB raw / 8.2 KB gzip — zero bytes added to your main bundle) and is spawned with
|
|
63
|
+
the inline `new Worker(new URL('./worker.js', import.meta.url), { type: 'module' })`
|
|
64
|
+
pattern that bundlers detect statically:
|
|
65
|
+
|
|
66
|
+
- **webpack 5, Vite (build), Rollup**: zero config — the worker is emitted as an asset
|
|
67
|
+
automatically.
|
|
68
|
+
- **Vite (dev server)**: esbuild's dependency pre-bundling breaks the pattern. Either
|
|
69
|
+
add `optimizeDeps: { exclude: ['umap-web'] }` to `vite.config`, or pass the URL
|
|
70
|
+
explicitly:
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
import workerUrl from 'umap-web/worker?worker&url';
|
|
74
|
+
const umap = new UMAP({ concurrency: 'auto', workerUrl });
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
- **esbuild / anything that doesn't rewrite worker URLs**: copy
|
|
78
|
+
`node_modules/umap-web/dist/worker.js` next to your bundle (it has no imports, so a
|
|
79
|
+
plain copy works), or point `workerUrl` at wherever you host it.
|
|
80
|
+
- **CDN / import maps**: browsers refuse cross-origin workers, so umap-web
|
|
81
|
+
automatically re-fetches the worker and spawns it from a `blob:` URL. With a CSP,
|
|
82
|
+
same-origin needs `worker-src 'self'`; the CDN path needs `worker-src blob:`.
|
|
83
|
+
- **Node**: `worker_threads` are resolved from the installed package automatically;
|
|
84
|
+
`workerUrl` accepts a `file://` URL if you relocate the file.
|
|
85
|
+
|
|
86
|
+
If no worker can be spawned (bad URL, CSP, exotic bundling), **fit never hangs**: the
|
|
87
|
+
pool gives up after a 10 s init timeout, a warning explains what failed and points
|
|
88
|
+
here, and the run completes single-threaded — check `umap.backendInfo.layout`. An
|
|
89
|
+
explicit `workerUrl` is trusted as-is: if it fails, umap-web warns and goes
|
|
90
|
+
single-threaded rather than guessing other locations.
|
|
91
|
+
|
|
92
|
+
## Parity philosophy
|
|
93
|
+
|
|
94
|
+
"Looks right" is not a spec. This library is validated against `umap-learn 0.5.9.post2`
|
|
95
|
+
by a two-layer oracle harness:
|
|
96
|
+
|
|
97
|
+
1. **Deterministic stage parity** — every deterministic pipeline stage (metrics,
|
|
98
|
+
`smooth_knn_dist`, membership strengths, fuzzy set operations, supervised
|
|
99
|
+
intersections, `make_epochs_per_sample`, spectral eigen-invariants, the transform
|
|
100
|
+
stage) is compared against artifacts generated by the pinned Python package on the
|
|
101
|
+
same inputs (tolerances: atol 2e-4 / rtol 1e-3 for float32-derived quantities).
|
|
102
|
+
2. **Statistical embedding parity** — final embeddings are compared against bands
|
|
103
|
+
generated from 8-seed Python runs (trustworthiness, continuity, kNN-label-accuracy,
|
|
104
|
+
Spearman of pairwise-distance ranks, Procrustes disparity). The bar: a umap-web
|
|
105
|
+
embedding must be **indistinguishable from another umap-learn run**. 14 parity
|
|
106
|
+
cells (PARITY.md) cover defaults, cosine/sparse inputs, supervision, densMAP,
|
|
107
|
+
haversine output, transform, inverseTransform, multi-component spectral placement,
|
|
108
|
+
and AlignedUMAP — on CPU and WebGPU backends.
|
|
109
|
+
|
|
110
|
+
Where the pinned wheel's *executed* behavior deviates from its source text (e.g. numba
|
|
111
|
+
`fastmath` folding in `smooth_knn_dist`), umap-web matches the executed oracle;
|
|
112
|
+
every such case is documented in `DECISIONS.md`.
|
|
113
|
+
|
|
114
|
+
## GPU support matrix
|
|
115
|
+
|
|
116
|
+
| Feature | WebGPU | Notes |
|
|
117
|
+
|---------|--------|-------|
|
|
118
|
+
| kNN metrics | euclidean, sqeuclidean, cosine, correlation, manhattan, hamming, jaccard | others fall back to CPU with a logged notice |
|
|
119
|
+
| k (nNeighbors) | ≤ 32 | larger k falls back to CPU |
|
|
120
|
+
| Layout | euclidean output | fixed-point `atomicAdd` SGD (scale 2^20) |
|
|
121
|
+
| densMAP / non-euclidean output / supervision graph ops | CPU | layout falls back per-stage |
|
|
122
|
+
| transform / inverseTransform | CPU | GPU-fitted models build the search structure lazily on first `transform()` |
|
|
123
|
+
|
|
124
|
+
All kernels run under **default WebGPU limits** (≤ 8 storage buffers per stage, 16 KB
|
|
125
|
+
workgroup memory) and request elevated buffer limits when available; candidate
|
|
126
|
+
streaming keeps every dispatch watchdog-safe and no n×n buffer ever exists.
|
|
127
|
+
|
|
128
|
+
GPU failures are **typed, never silent**: buffer sizes are validated against the
|
|
129
|
+
granted device limits before allocation, kernels run under error scopes, and device
|
|
130
|
+
loss is tracked — all surfacing as `UmapBackendError`. Under `backend: 'auto'` a GPU
|
|
131
|
+
failure falls back to the CPU for that stage (seeded results stay reproducible; the
|
|
132
|
+
rng is restored to its pre-stage state); with explicit `backend: 'webgpu'` the typed
|
|
133
|
+
error propagates. Device acquisition is capped at 5 s so a stalled driver cannot hang
|
|
134
|
+
`fit()`.
|
|
135
|
+
|
|
136
|
+
## Performance (Apple M5 Pro, Chromium/Metal — see BENCHMARKS.md)
|
|
137
|
+
|
|
138
|
+
| Workload | Backend | Time |
|
|
139
|
+
|----------|---------|------|
|
|
140
|
+
| digits 1,797×64 | CPU single-thread | 4.5 s |
|
|
141
|
+
| MNIST 70,000×784 | CPU workers | 24 s |
|
|
142
|
+
| MNIST 70,000×784 | WebGPU | **7.8 s** |
|
|
143
|
+
| transform 10k onto 60k model | CPU | 5.3 s |
|
|
144
|
+
| synthetic 500,000×128 | WebGPU | **78 s** |
|
|
145
|
+
| synthetic 1,000,000×256 | WebGPU | 5.5 min |
|
|
146
|
+
|
|
147
|
+
## API surface
|
|
148
|
+
|
|
149
|
+
- `UMAP` — `fit`, `fitTransform`, `transform` (+ `'graph'` mode), `inverseTransform`,
|
|
150
|
+
`update`, `serialize`/`UMAP.deserialize`, `embedding`, `graph`, `densities`,
|
|
151
|
+
`backendInfo`, `phaseTimings`. Full option set mirrors `umap-learn` (camelCase).
|
|
152
|
+
- `AlignedUMAP` — aligned embeddings over dataset slices with `relations`,
|
|
153
|
+
`alignmentRegularisation`, `alignmentWindowSize`; `fit`, `fitTransform`, `update`.
|
|
154
|
+
- `umap-web/core` — the low-level functional layer (`nearestNeighbors*`,
|
|
155
|
+
`smoothKnnDist`, `computeMembershipStrengths`, `fuzzySimplicialSet`,
|
|
156
|
+
`makeEpochsPerSample`, `findABParams`, `initTransform`/`initGraphTransform` internals,
|
|
157
|
+
spectral/LOBPCG, metrics, CSR helpers, PCG32).
|
|
158
|
+
- `umap-web/webgpu` — GPU device management + kernels for advanced integration.
|
|
159
|
+
|
|
160
|
+
Typed errors: `UmapValidationError` (bad input incl. NaN/Infinity — never silently
|
|
161
|
+
filtered), `UmapBackendError` (worker/GPU failures), both extending `UmapError`; plus
|
|
162
|
+
`AbortError` via standard `AbortSignal`:
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
const controller = new AbortController();
|
|
166
|
+
umap.fit(X, null, { signal: controller.signal }); // controller.abort() stops mid-epoch
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
`fit`, `fitTransform`, `transform`, `inverseTransform`, `update`, and
|
|
170
|
+
`AlignedUMAP.fit/fitTransform/update` all accept `{ signal }`; layout aborts
|
|
171
|
+
per-epoch, GPU kNN per chunk, other phases at stage boundaries. An aborted or failed
|
|
172
|
+
`fit` releases its workers/GPU device and restores the previously fitted model (a
|
|
173
|
+
first fit stays unfitted) — the estimator is never left half-fitted.
|
|
174
|
+
|
|
175
|
+
Serialization (`serialize`/`UMAP.deserialize`) is a single versioned binary blob,
|
|
176
|
+
**little-endian** on every platform. `deserialize` treats the blob as untrusted:
|
|
177
|
+
every section is bounds- and type-checked and cross-array invariants are validated,
|
|
178
|
+
so a corrupt or crafted blob throws `UmapValidationError` instead of producing
|
|
179
|
+
garbage.
|
|
180
|
+
|
|
181
|
+
Determinism (§ reproducibility): with `seed` set and `concurrency: 1`, two runs are
|
|
182
|
+
**byte-identical** (PCG32 with published test vectors; `Math.random` is banned in the
|
|
183
|
+
source tree). Parallel CPU and WebGPU paths are documented non-deterministic;
|
|
184
|
+
`deterministic: true` forces the reproducible path.
|
|
185
|
+
|
|
186
|
+
## Demo
|
|
187
|
+
|
|
188
|
+
`apps/demo` — a static Vite app (GitHub Pages-ready, `base: '/umap-web/'`) with a
|
|
189
|
+
WebGL2 point renderer, dataset picker (digits / mnist10k / your own CSV — parsed
|
|
190
|
+
locally), live per-epoch animation, backend selector with actual-backend indicator,
|
|
191
|
+
phase-timing HUD, and CSV export.
|
|
192
|
+
|
|
193
|
+
## Roadmap (deliberate non-goals today)
|
|
194
|
+
|
|
195
|
+
- `ParametricUMAP` (needs a neural-network framework)
|
|
196
|
+
- `umap.plot` (the demo app plays this role)
|
|
197
|
+
- scikit-learn API compatibility / estimator plumbing
|
|
198
|
+
- WASM backend (the `Backend` interface is designed so one can slot in)
|
|
199
|
+
- GPU NN-descent (brute-force GPU kNN is fast through ~1M×256; see BENCHMARKS.md)
|
|
200
|
+
|
|
201
|
+
## License
|
|
202
|
+
|
|
203
|
+
BSD-3-Clause. Reimplements the algorithms of
|
|
204
|
+
[umap-learn](https://github.com/lmcinnes/umap) and
|
|
205
|
+
[pynndescent](https://github.com/lmcinnes/pynndescent) (see NOTICE).
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region rolldown:runtime
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __export = (all) => {
|
|
4
|
+
let target = {};
|
|
5
|
+
for (var name in all) __defProp(target, name, {
|
|
6
|
+
get: all[name],
|
|
7
|
+
enumerable: true
|
|
8
|
+
});
|
|
9
|
+
return target;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
//#endregion
|
|
13
|
+
export { __export as t };
|