umap-gpu 0.2.15 → 0.2.16
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/README.md +0 -2
- package/dist/fallback/cpu-sgd.d.ts +2 -2
- package/dist/gpu/sgd.d.ts +1 -1
- package/dist/index.js +313 -349
- package/dist/rng.d.ts +2 -0
- package/dist/umap.d.ts +6 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ export interface CPUSgdParams {
|
|
|
9
9
|
* CPU fallback SGD optimizer for environments without WebGPU.
|
|
10
10
|
* Mirrors the GPU shader logic: per-edge attraction + negative-sample repulsion.
|
|
11
11
|
*/
|
|
12
|
-
export declare function cpuSgd(embedding: Float32Array, graph: FuzzyGraph, epochsPerSample: Float32Array, nVertices: number, nComponents: number, nEpochs: number, params: CPUSgdParams, onProgress?: (epoch: number, nEpochs: number) => void): Float32Array;
|
|
12
|
+
export declare function cpuSgd(embedding: Float32Array, graph: FuzzyGraph, epochsPerSample: Float32Array, nVertices: number, nComponents: number, nEpochs: number, params: CPUSgdParams, onProgress?: (epoch: number, nEpochs: number) => void, rng?: () => number): Float32Array;
|
|
13
13
|
/**
|
|
14
14
|
* CPU SGD for UMAP.transform(): optimizes only the new-point embeddings.
|
|
15
15
|
* The training embedding is read-only; attraction pulls new points toward
|
|
@@ -26,4 +26,4 @@ export declare function cpuSgd(embedding: Float32Array, graph: FuzzyGraph, epoch
|
|
|
26
26
|
* @param nEpochs - Number of optimization epochs
|
|
27
27
|
* @param params - UMAP curve parameters
|
|
28
28
|
*/
|
|
29
|
-
export declare function cpuSgdTransform(embeddingNew: Float32Array, embeddingTrain: Float32Array, graph: FuzzyGraph, epochsPerSample: Float32Array, nNew: number, nTrain: number, nComponents: number, nEpochs: number, params: CPUSgdParams, onProgress?: (epoch: number, nEpochs: number) => void): Float32Array;
|
|
29
|
+
export declare function cpuSgdTransform(embeddingNew: Float32Array, embeddingTrain: Float32Array, graph: FuzzyGraph, epochsPerSample: Float32Array, nNew: number, nTrain: number, nComponents: number, nEpochs: number, params: CPUSgdParams, onProgress?: (epoch: number, nEpochs: number) => void, rng?: () => number): Float32Array;
|
package/dist/gpu/sgd.d.ts
CHANGED
|
@@ -37,6 +37,6 @@ export declare class GPUSgd {
|
|
|
37
37
|
* @param params - UMAP curve parameters and repulsion settings
|
|
38
38
|
* @returns Optimized embedding as Float32Array
|
|
39
39
|
*/
|
|
40
|
-
optimize(embedding: Float32Array, head: Uint32Array, tail: Uint32Array, epochsPerSample: Float32Array, nVertices: number, nComponents: number, nEpochs: number, params: SGDParams, onProgress?: (epoch: number, nEpochs: number) => void): Promise<Float32Array>;
|
|
40
|
+
optimize(embedding: Float32Array, head: Uint32Array, tail: Uint32Array, epochsPerSample: Float32Array, nVertices: number, nComponents: number, nEpochs: number, params: SGDParams, onProgress?: (epoch: number, nEpochs: number) => void, rng?: () => number): Promise<Float32Array>;
|
|
41
41
|
private makeBuffer;
|
|
42
42
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,93 +1,83 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
import { loadHnswlib as
|
|
5
|
-
async function
|
|
6
|
-
const { M:
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
for (let
|
|
10
|
-
const
|
|
11
|
-
|
|
1
|
+
var X = Object.defineProperty;
|
|
2
|
+
var Z = (t, e, s) => e in t ? X(t, e, { enumerable: !0, configurable: !0, writable: !0, value: s }) : t[e] = s;
|
|
3
|
+
var G = (t, e, s) => Z(t, typeof e != "symbol" ? e + "" : e, s);
|
|
4
|
+
import { loadHnswlib as $ } from "hnswlib-wasm";
|
|
5
|
+
async function ee(t, e, s = {}) {
|
|
6
|
+
const { M: r = 16, efConstruction: n = 200, efSearch: u = 50 } = s, o = await $(), f = t[0].length, c = t.length, a = new o.HierarchicalNSW("l2", f, "");
|
|
7
|
+
a.initIndex(c, r, n, 200), a.setEfSearch(Math.max(u, e)), a.addItems(t, !1);
|
|
8
|
+
const d = [], i = [];
|
|
9
|
+
for (let l = 0; l < c; l++) {
|
|
10
|
+
const g = a.searchKnn(t[l], e + 1, void 0), _ = g.neighbors.map((w, x) => ({ idx: w, dist: g.distances[x] })).filter(({ idx: w }) => w !== l).slice(0, e);
|
|
11
|
+
d.push(_.map(({ idx: w }) => w)), i.push(_.map(({ dist: w }) => Math.sqrt(w)));
|
|
12
12
|
}
|
|
13
|
-
return { indices:
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
for (let l = 0; l < o; l++) {
|
|
20
|
-
const p = n.searchKnn(e[l], t + 1, void 0), g = p.neighbors.map((_, m) => ({ idx: _, dist: p.distances[m] })).filter(({ idx: _ }) => _ !== l).slice(0, t);
|
|
21
|
-
r.push(g.map(({ idx: _ }) => _)), i.push(g.map(({ dist: _ }) => Math.sqrt(_)));
|
|
22
|
-
}
|
|
23
|
-
return { knn: { indices: r, distances: i }, index: {
|
|
24
|
-
searchKnn(l, p) {
|
|
25
|
-
const g = [], _ = [];
|
|
26
|
-
for (const m of l) {
|
|
27
|
-
const b = n.searchKnn(m, p, void 0), y = b.neighbors.map((x, v) => ({ idx: x, dist: b.distances[v] })).sort((x, v) => x.dist - v.dist).slice(0, p);
|
|
28
|
-
g.push(y.map(({ idx: x }) => x)), _.push(y.map(({ dist: x }) => Math.sqrt(x)));
|
|
13
|
+
return { knn: { indices: d, distances: i }, index: {
|
|
14
|
+
searchKnn(l, g) {
|
|
15
|
+
const _ = [], w = [];
|
|
16
|
+
for (const x of l) {
|
|
17
|
+
const m = a.searchKnn(x, g, void 0), F = m.neighbors.map((p, M) => ({ idx: p, dist: m.distances[M] })).sort((p, M) => p.dist - M.dist).slice(0, g);
|
|
18
|
+
_.push(F.map(({ idx: p }) => p)), w.push(F.map(({ dist: p }) => Math.sqrt(p)));
|
|
29
19
|
}
|
|
30
|
-
return { indices:
|
|
20
|
+
return { indices: _, distances: w };
|
|
31
21
|
}
|
|
32
22
|
} };
|
|
33
23
|
}
|
|
34
|
-
function
|
|
35
|
-
const
|
|
36
|
-
for (let i = 0; i <
|
|
37
|
-
for (let h = 0; h <
|
|
38
|
-
const l =
|
|
39
|
-
|
|
24
|
+
function te(t, e, s, r = 1) {
|
|
25
|
+
const n = t.length, { sigmas: u, rhos: o } = H(e, s), f = [], c = [], a = [];
|
|
26
|
+
for (let i = 0; i < n; i++)
|
|
27
|
+
for (let h = 0; h < t[i].length; h++) {
|
|
28
|
+
const l = e[i][h], g = l <= o[i] ? 1 : Math.exp(-((l - o[i]) / u[i]));
|
|
29
|
+
f.push(i), c.push(t[i][h]), a.push(g);
|
|
40
30
|
}
|
|
41
|
-
return { ...
|
|
31
|
+
return { ...se(f, c, a, n, r), nVertices: n };
|
|
42
32
|
}
|
|
43
|
-
function
|
|
44
|
-
const
|
|
45
|
-
for (let
|
|
46
|
-
for (let
|
|
47
|
-
const i =
|
|
48
|
-
|
|
33
|
+
function ne(t, e, s) {
|
|
34
|
+
const r = t.length, { sigmas: n, rhos: u } = H(e, s), o = [], f = [], c = [];
|
|
35
|
+
for (let a = 0; a < r; a++)
|
|
36
|
+
for (let d = 0; d < t[a].length; d++) {
|
|
37
|
+
const i = e[a][d], h = i <= u[a] ? 1 : Math.exp(-((i - u[a]) / n[a]));
|
|
38
|
+
o.push(a), f.push(t[a][d]), c.push(h);
|
|
49
39
|
}
|
|
50
40
|
return {
|
|
51
|
-
rows: new Uint32Array(
|
|
52
|
-
cols: new Uint32Array(
|
|
53
|
-
vals: new Float32Array(
|
|
54
|
-
nVertices:
|
|
41
|
+
rows: new Uint32Array(o),
|
|
42
|
+
cols: new Uint32Array(f),
|
|
43
|
+
vals: new Float32Array(c),
|
|
44
|
+
nVertices: r
|
|
55
45
|
};
|
|
56
46
|
}
|
|
57
|
-
function
|
|
58
|
-
const
|
|
59
|
-
for (let
|
|
60
|
-
const
|
|
61
|
-
u[
|
|
62
|
-
let
|
|
63
|
-
const i = Math.log2(
|
|
47
|
+
function H(t, e) {
|
|
48
|
+
const r = t.length, n = new Float32Array(r), u = new Float32Array(r);
|
|
49
|
+
for (let o = 0; o < r; o++) {
|
|
50
|
+
const f = t[o];
|
|
51
|
+
u[o] = f.find((h) => h > 0) ?? 0;
|
|
52
|
+
let c = 0, a = 1 / 0, d = 1;
|
|
53
|
+
const i = Math.log2(e);
|
|
64
54
|
for (let h = 0; h < 64; h++) {
|
|
65
55
|
let l = 0;
|
|
66
|
-
for (let
|
|
67
|
-
l += Math.exp(-Math.max(0,
|
|
56
|
+
for (let g = 0; g < f.length; g++)
|
|
57
|
+
l += Math.exp(-Math.max(0, f[g] - u[o]) / d);
|
|
68
58
|
if (Math.abs(l - i) < 1e-5) break;
|
|
69
|
-
l > i ? (
|
|
59
|
+
l > i ? (a = d, d = (c + a) / 2) : (c = d, d = a === 1 / 0 ? d * 2 : (c + a) / 2);
|
|
70
60
|
}
|
|
71
|
-
|
|
61
|
+
n[o] = d;
|
|
72
62
|
}
|
|
73
|
-
return { sigmas:
|
|
63
|
+
return { sigmas: n, rhos: u };
|
|
74
64
|
}
|
|
75
|
-
function
|
|
65
|
+
function se(t, e, s, r, n) {
|
|
76
66
|
const u = /* @__PURE__ */ new Map();
|
|
77
|
-
for (let
|
|
78
|
-
u.set(
|
|
79
|
-
const
|
|
80
|
-
for (const [
|
|
81
|
-
const i = Math.floor(
|
|
82
|
-
|
|
67
|
+
for (let a = 0; a < t.length; a++)
|
|
68
|
+
u.set(t[a] * r + e[a], s[a]);
|
|
69
|
+
const o = [], f = [], c = [];
|
|
70
|
+
for (const [a, d] of u) {
|
|
71
|
+
const i = Math.floor(a / r), h = a % r, l = u.get(h * r + i) ?? 0, g = d + l - d * l, _ = d * l;
|
|
72
|
+
o.push(i), f.push(h), c.push(n * g + (1 - n) * _);
|
|
83
73
|
}
|
|
84
74
|
return {
|
|
85
|
-
rows: new Uint32Array(
|
|
86
|
-
cols: new Uint32Array(
|
|
87
|
-
vals: new Float32Array(
|
|
75
|
+
rows: new Uint32Array(o),
|
|
76
|
+
cols: new Uint32Array(f),
|
|
77
|
+
vals: new Float32Array(c)
|
|
88
78
|
};
|
|
89
79
|
}
|
|
90
|
-
const
|
|
80
|
+
const ae = `// UMAP SGD compute shader — processes one graph edge per GPU thread.
|
|
91
81
|
// Computes attraction and repulsion forces and accumulates them atomically
|
|
92
82
|
// into a forces buffer. A separate apply-forces pass then updates embeddings,
|
|
93
83
|
// eliminating write-write races on shared vertex positions.
|
|
@@ -207,7 +197,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
207
197
|
}
|
|
208
198
|
}
|
|
209
199
|
}
|
|
210
|
-
`,
|
|
200
|
+
`, re = `// Apply-forces shader — second pass of the two-pass GPU SGD.
|
|
211
201
|
//
|
|
212
202
|
// After the SGD pass has atomically accumulated all gradients into the forces
|
|
213
203
|
// buffer, this shader applies each element's accumulated force to the
|
|
@@ -236,40 +226,40 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
236
226
|
}
|
|
237
227
|
`;
|
|
238
228
|
let z = null;
|
|
239
|
-
async function
|
|
229
|
+
async function Y() {
|
|
240
230
|
if (z) return z;
|
|
241
231
|
if (typeof navigator > "u" || !navigator.gpu)
|
|
242
232
|
return null;
|
|
243
|
-
const
|
|
244
|
-
return
|
|
233
|
+
const t = await navigator.gpu.requestAdapter();
|
|
234
|
+
return t ? (z = await t.requestDevice(), z.lost.then(() => {
|
|
245
235
|
z = null;
|
|
246
236
|
}), z) : null;
|
|
247
237
|
}
|
|
248
|
-
function
|
|
238
|
+
function ie() {
|
|
249
239
|
return typeof navigator < "u" && !!navigator.gpu;
|
|
250
240
|
}
|
|
251
|
-
async function
|
|
252
|
-
return await
|
|
241
|
+
async function pe() {
|
|
242
|
+
return await Y() !== null;
|
|
253
243
|
}
|
|
254
|
-
class
|
|
244
|
+
class oe {
|
|
255
245
|
constructor() {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
246
|
+
G(this, "device");
|
|
247
|
+
G(this, "sgdPipeline");
|
|
248
|
+
G(this, "applyForcesPipeline");
|
|
259
249
|
}
|
|
260
250
|
async init() {
|
|
261
|
-
const
|
|
262
|
-
if (!
|
|
263
|
-
this.device =
|
|
251
|
+
const e = await Y();
|
|
252
|
+
if (!e) throw new Error("WebGPU not supported");
|
|
253
|
+
this.device = e, this.sgdPipeline = this.device.createComputePipeline({
|
|
264
254
|
layout: "auto",
|
|
265
255
|
compute: {
|
|
266
|
-
module: this.device.createShaderModule({ code:
|
|
256
|
+
module: this.device.createShaderModule({ code: ae }),
|
|
267
257
|
entryPoint: "main"
|
|
268
258
|
}
|
|
269
259
|
}), this.applyForcesPipeline = this.device.createComputePipeline({
|
|
270
260
|
layout: "auto",
|
|
271
261
|
compute: {
|
|
272
|
-
module: this.device.createShaderModule({ code:
|
|
262
|
+
module: this.device.createShaderModule({ code: re }),
|
|
273
263
|
entryPoint: "main"
|
|
274
264
|
}
|
|
275
265
|
});
|
|
@@ -287,254 +277,225 @@ class X {
|
|
|
287
277
|
* @param params - UMAP curve parameters and repulsion settings
|
|
288
278
|
* @returns Optimized embedding as Float32Array
|
|
289
279
|
*/
|
|
290
|
-
async optimize(
|
|
291
|
-
const { device:
|
|
292
|
-
|
|
280
|
+
async optimize(e, s, r, n, u, o, f, c, a, d = Math.random) {
|
|
281
|
+
const { device: i } = this, h = s.length, l = u * o, g = this.makeBuffer(
|
|
282
|
+
e,
|
|
293
283
|
GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC
|
|
294
|
-
),
|
|
295
|
-
for (let
|
|
296
|
-
y
|
|
297
|
-
const
|
|
298
|
-
for (let
|
|
299
|
-
|
|
300
|
-
const
|
|
301
|
-
size:
|
|
284
|
+
), _ = this.makeBuffer(s, GPUBufferUsage.STORAGE), w = this.makeBuffer(r, GPUBufferUsage.STORAGE), x = this.makeBuffer(n, GPUBufferUsage.STORAGE), m = new Float32Array(n), F = this.makeBuffer(m, GPUBufferUsage.STORAGE), p = new Float32Array(h);
|
|
285
|
+
for (let y = 0; y < h; y++)
|
|
286
|
+
p[y] = n[y] / c.negativeSampleRate;
|
|
287
|
+
const M = this.makeBuffer(p, GPUBufferUsage.STORAGE), B = new Uint32Array(h);
|
|
288
|
+
for (let y = 0; y < h; y++)
|
|
289
|
+
B[y] = d() * 4294967295 | 0;
|
|
290
|
+
const S = this.makeBuffer(B, GPUBufferUsage.STORAGE), v = i.createBuffer({
|
|
291
|
+
size: l * 4,
|
|
302
292
|
usage: GPUBufferUsage.STORAGE,
|
|
303
293
|
mappedAtCreation: !0
|
|
304
294
|
});
|
|
305
|
-
new Int32Array(
|
|
306
|
-
const
|
|
295
|
+
new Int32Array(v.getMappedRange()).fill(0), v.unmap();
|
|
296
|
+
const R = i.createBuffer({
|
|
307
297
|
size: 40,
|
|
308
298
|
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
|
|
309
|
-
}),
|
|
299
|
+
}), O = i.createBuffer({
|
|
310
300
|
size: 16,
|
|
311
301
|
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
|
|
312
|
-
}),
|
|
302
|
+
}), C = i.createBindGroup({
|
|
313
303
|
layout: this.sgdPipeline.getBindGroupLayout(0),
|
|
314
304
|
entries: [
|
|
315
|
-
{ binding: 0, resource: { buffer:
|
|
316
|
-
{ binding: 1, resource: { buffer:
|
|
317
|
-
{ binding: 2, resource: { buffer:
|
|
318
|
-
{ binding: 3, resource: { buffer:
|
|
319
|
-
{ binding: 4, resource: { buffer:
|
|
320
|
-
{ binding: 5, resource: { buffer:
|
|
321
|
-
{ binding: 6, resource: { buffer:
|
|
322
|
-
{ binding: 7, resource: { buffer:
|
|
323
|
-
{ binding: 8, resource: { buffer:
|
|
305
|
+
{ binding: 0, resource: { buffer: x } },
|
|
306
|
+
{ binding: 1, resource: { buffer: _ } },
|
|
307
|
+
{ binding: 2, resource: { buffer: w } },
|
|
308
|
+
{ binding: 3, resource: { buffer: g } },
|
|
309
|
+
{ binding: 4, resource: { buffer: F } },
|
|
310
|
+
{ binding: 5, resource: { buffer: M } },
|
|
311
|
+
{ binding: 6, resource: { buffer: R } },
|
|
312
|
+
{ binding: 7, resource: { buffer: S } },
|
|
313
|
+
{ binding: 8, resource: { buffer: v } }
|
|
324
314
|
]
|
|
325
|
-
}),
|
|
315
|
+
}), U = i.createBindGroup({
|
|
326
316
|
layout: this.applyForcesPipeline.getBindGroupLayout(0),
|
|
327
317
|
entries: [
|
|
328
|
-
{ binding: 0, resource: { buffer:
|
|
329
|
-
{ binding: 1, resource: { buffer:
|
|
330
|
-
{ binding: 2, resource: { buffer:
|
|
318
|
+
{ binding: 0, resource: { buffer: g } },
|
|
319
|
+
{ binding: 1, resource: { buffer: v } },
|
|
320
|
+
{ binding: 2, resource: { buffer: O } }
|
|
331
321
|
]
|
|
332
322
|
});
|
|
333
|
-
for (let
|
|
334
|
-
const
|
|
335
|
-
|
|
336
|
-
const
|
|
337
|
-
|
|
338
|
-
const
|
|
339
|
-
|
|
340
|
-
const
|
|
341
|
-
|
|
323
|
+
for (let y = 0; y < f; y++) {
|
|
324
|
+
const N = 1 - y / f, k = new ArrayBuffer(40), P = new Uint32Array(k), q = new Float32Array(k);
|
|
325
|
+
P[0] = h, P[1] = u, P[2] = o, P[3] = y, P[4] = f, q[5] = N, q[6] = c.a, q[7] = c.b, q[8] = c.gamma, P[9] = c.negativeSampleRate, i.queue.writeBuffer(R, 0, k);
|
|
326
|
+
const I = new ArrayBuffer(16), Q = new Uint32Array(I), J = new Float32Array(I);
|
|
327
|
+
Q[0] = l, J[1] = N, i.queue.writeBuffer(O, 0, I);
|
|
328
|
+
const D = i.createCommandEncoder(), L = D.beginComputePass();
|
|
329
|
+
L.setPipeline(this.sgdPipeline), L.setBindGroup(0, C), L.dispatchWorkgroups(Math.ceil(h / 256)), L.end();
|
|
330
|
+
const j = D.beginComputePass();
|
|
331
|
+
j.setPipeline(this.applyForcesPipeline), j.setBindGroup(0, U), j.dispatchWorkgroups(Math.ceil(l / 256)), j.end(), i.queue.submit([D.finish()]), y % 10 === 0 && (await i.queue.onSubmittedWorkDone(), a == null || a(y, f));
|
|
342
332
|
}
|
|
343
|
-
const
|
|
344
|
-
size:
|
|
333
|
+
const A = i.createBuffer({
|
|
334
|
+
size: e.byteLength,
|
|
345
335
|
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
|
|
346
|
-
}),
|
|
347
|
-
|
|
348
|
-
const
|
|
349
|
-
return
|
|
336
|
+
}), b = i.createCommandEncoder();
|
|
337
|
+
b.copyBufferToBuffer(g, 0, A, 0, e.byteLength), i.queue.submit([b.finish()]), await A.mapAsync(GPUMapMode.READ);
|
|
338
|
+
const E = new Float32Array(A.getMappedRange().slice(0));
|
|
339
|
+
return A.unmap(), g.destroy(), _.destroy(), w.destroy(), x.destroy(), F.destroy(), M.destroy(), S.destroy(), v.destroy(), R.destroy(), O.destroy(), A.destroy(), E;
|
|
350
340
|
}
|
|
351
|
-
makeBuffer(
|
|
352
|
-
const
|
|
353
|
-
size:
|
|
354
|
-
usage:
|
|
341
|
+
makeBuffer(e, s) {
|
|
342
|
+
const r = this.device.createBuffer({
|
|
343
|
+
size: e.byteLength,
|
|
344
|
+
usage: s,
|
|
355
345
|
mappedAtCreation: !0
|
|
356
346
|
});
|
|
357
|
-
return
|
|
347
|
+
return e instanceof Float32Array ? new Float32Array(r.getMappedRange()).set(e) : new Uint32Array(r.getMappedRange()).set(e), r.unmap(), r;
|
|
358
348
|
}
|
|
359
349
|
}
|
|
360
|
-
function
|
|
361
|
-
return Math.max(-4, Math.min(4,
|
|
350
|
+
function T(t) {
|
|
351
|
+
return Math.max(-4, Math.min(4, t));
|
|
362
352
|
}
|
|
363
|
-
function
|
|
364
|
-
const { a
|
|
365
|
-
for (let m = 0; m <
|
|
366
|
-
|
|
353
|
+
function W(t, e, s, r, n, u, o, f, c = Math.random) {
|
|
354
|
+
const { a, b: d, gamma: i = 1, negativeSampleRate: h = 5 } = o, l = e.rows.length, g = new Uint32Array(e.rows), _ = new Uint32Array(e.cols), w = new Float32Array(s), x = new Float32Array(l);
|
|
355
|
+
for (let m = 0; m < l; m++)
|
|
356
|
+
x[m] = s[m] / h;
|
|
367
357
|
for (let m = 0; m < u; m++) {
|
|
368
|
-
|
|
369
|
-
const
|
|
370
|
-
for (let
|
|
371
|
-
if (
|
|
372
|
-
const
|
|
373
|
-
let
|
|
374
|
-
for (let
|
|
375
|
-
const
|
|
376
|
-
|
|
358
|
+
f == null || f(m, u);
|
|
359
|
+
const F = 1 - m / u;
|
|
360
|
+
for (let p = 0; p < l; p++) {
|
|
361
|
+
if (w[p] > m) continue;
|
|
362
|
+
const M = g[p], B = _[p];
|
|
363
|
+
let S = 0;
|
|
364
|
+
for (let U = 0; U < n; U++) {
|
|
365
|
+
const A = t[M * n + U] - t[B * n + U];
|
|
366
|
+
S += A * A;
|
|
377
367
|
}
|
|
378
|
-
const
|
|
379
|
-
for (let
|
|
380
|
-
const
|
|
381
|
-
|
|
368
|
+
const v = Math.pow(S, d), R = -2 * a * d * (S > 0 ? v / S : 0) / (a * v + 1);
|
|
369
|
+
for (let U = 0; U < n; U++) {
|
|
370
|
+
const A = t[M * n + U] - t[B * n + U], b = T(R * A);
|
|
371
|
+
t[M * n + U] += F * b, t[B * n + U] -= F * b;
|
|
382
372
|
}
|
|
383
|
-
|
|
384
|
-
const
|
|
385
|
-
(m -
|
|
373
|
+
w[p] += s[p];
|
|
374
|
+
const O = s[p] / h, C = Math.max(0, Math.floor(
|
|
375
|
+
(m - x[p]) / O
|
|
386
376
|
));
|
|
387
|
-
|
|
388
|
-
for (let
|
|
389
|
-
const
|
|
390
|
-
if (
|
|
391
|
-
let
|
|
392
|
-
for (let
|
|
393
|
-
const
|
|
394
|
-
|
|
377
|
+
x[p] += C * O;
|
|
378
|
+
for (let U = 0; U < C; U++) {
|
|
379
|
+
const A = Math.floor(c() * r);
|
|
380
|
+
if (A === M) continue;
|
|
381
|
+
let b = 0;
|
|
382
|
+
for (let N = 0; N < n; N++) {
|
|
383
|
+
const k = t[M * n + N] - t[A * n + N];
|
|
384
|
+
b += k * k;
|
|
395
385
|
}
|
|
396
|
-
const
|
|
397
|
-
for (let
|
|
398
|
-
const
|
|
399
|
-
|
|
386
|
+
const E = Math.pow(b, d), y = 2 * i * d / ((1e-3 + b) * (a * E + 1));
|
|
387
|
+
for (let N = 0; N < n; N++) {
|
|
388
|
+
const k = t[M * n + N] - t[A * n + N], P = T(y * k);
|
|
389
|
+
t[M * n + N] += F * P;
|
|
400
390
|
}
|
|
401
391
|
}
|
|
402
392
|
}
|
|
403
393
|
}
|
|
404
|
-
return
|
|
394
|
+
return t;
|
|
405
395
|
}
|
|
406
|
-
function
|
|
407
|
-
const { a:
|
|
408
|
-
for (let
|
|
409
|
-
|
|
410
|
-
for (let
|
|
411
|
-
const
|
|
412
|
-
for (let
|
|
413
|
-
if (m[
|
|
414
|
-
const
|
|
415
|
-
let
|
|
416
|
-
for (let
|
|
417
|
-
const
|
|
418
|
-
|
|
396
|
+
function ce(t, e, s, r, n, u, o, f, c, a, d = Math.random) {
|
|
397
|
+
const { a: i, b: h, gamma: l = 1, negativeSampleRate: g = 5 } = c, _ = s.rows.length, w = new Uint32Array(s.rows), x = new Uint32Array(s.cols), m = new Float32Array(r), F = new Float32Array(_);
|
|
398
|
+
for (let p = 0; p < _; p++)
|
|
399
|
+
F[p] = r[p] / g;
|
|
400
|
+
for (let p = 0; p < f; p++) {
|
|
401
|
+
const M = 1 - p / f;
|
|
402
|
+
for (let B = 0; B < _; B++) {
|
|
403
|
+
if (m[B] > p) continue;
|
|
404
|
+
const S = w[B], v = x[B];
|
|
405
|
+
let R = 0;
|
|
406
|
+
for (let b = 0; b < o; b++) {
|
|
407
|
+
const E = t[S * o + b] - e[v * o + b];
|
|
408
|
+
R += E * E;
|
|
419
409
|
}
|
|
420
|
-
const
|
|
421
|
-
for (let
|
|
422
|
-
const
|
|
423
|
-
|
|
410
|
+
const O = Math.pow(R, h), C = -2 * i * h * (R > 0 ? O / R : 0) / (i * O + 1);
|
|
411
|
+
for (let b = 0; b < o; b++) {
|
|
412
|
+
const E = t[S * o + b] - e[v * o + b];
|
|
413
|
+
t[S * o + b] += M * T(C * E);
|
|
424
414
|
}
|
|
425
|
-
m[
|
|
426
|
-
const
|
|
427
|
-
(
|
|
415
|
+
m[B] += r[B];
|
|
416
|
+
const U = r[B] / g, A = Math.max(0, Math.floor(
|
|
417
|
+
(p - F[B]) / U
|
|
428
418
|
));
|
|
429
|
-
|
|
430
|
-
for (let
|
|
431
|
-
const
|
|
432
|
-
if (
|
|
433
|
-
let
|
|
434
|
-
for (let
|
|
435
|
-
const
|
|
436
|
-
|
|
419
|
+
F[B] += A * U;
|
|
420
|
+
for (let b = 0; b < A; b++) {
|
|
421
|
+
const E = Math.floor(d() * u);
|
|
422
|
+
if (E === v) continue;
|
|
423
|
+
let y = 0;
|
|
424
|
+
for (let P = 0; P < o; P++) {
|
|
425
|
+
const q = t[S * o + P] - e[E * o + P];
|
|
426
|
+
y += q * q;
|
|
437
427
|
}
|
|
438
|
-
const
|
|
439
|
-
for (let
|
|
440
|
-
const
|
|
441
|
-
|
|
428
|
+
const N = Math.pow(y, h), k = 2 * l * h / ((1e-3 + y) * (i * N + 1));
|
|
429
|
+
for (let P = 0; P < o; P++) {
|
|
430
|
+
const q = t[S * o + P] - e[E * o + P];
|
|
431
|
+
t[S * o + P] += M * T(k * q);
|
|
442
432
|
}
|
|
443
433
|
}
|
|
444
434
|
}
|
|
445
435
|
}
|
|
446
|
-
return
|
|
436
|
+
return t;
|
|
447
437
|
}
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
}
|
|
456
|
-
console.time("knn");
|
|
457
|
-
const { indices: n, distances: r } = await se(e, s, {
|
|
458
|
-
M: d.M ?? 16,
|
|
459
|
-
efConstruction: d.efConstruction ?? 200,
|
|
460
|
-
efSearch: d.efSearch ?? 50
|
|
461
|
-
});
|
|
462
|
-
console.timeEnd("knn"), console.time("fuzzy-set");
|
|
463
|
-
const i = V(n, r, s);
|
|
464
|
-
console.timeEnd("fuzzy-set");
|
|
465
|
-
const { a: h, b: l } = Z(u, c), p = W(i.vals), g = e.length, _ = new Float32Array(g * a);
|
|
466
|
-
for (let b = 0; b < _.length; b++)
|
|
467
|
-
_[b] = Math.random() * 20 - 10;
|
|
468
|
-
console.time("sgd");
|
|
469
|
-
let m;
|
|
470
|
-
if (J())
|
|
471
|
-
try {
|
|
472
|
-
const b = new X();
|
|
473
|
-
await b.init(), m = await b.optimize(
|
|
474
|
-
_,
|
|
475
|
-
new Uint32Array(i.rows),
|
|
476
|
-
new Uint32Array(i.cols),
|
|
477
|
-
p,
|
|
478
|
-
g,
|
|
479
|
-
a,
|
|
480
|
-
o,
|
|
481
|
-
{ a: h, b: l, gamma: 1, negativeSampleRate: 5 },
|
|
482
|
-
f
|
|
483
|
-
);
|
|
484
|
-
} catch (b) {
|
|
485
|
-
console.warn("WebGPU SGD failed, falling back to CPU:", b), m = j(_, i, p, g, a, o, { a: h, b: l }, f);
|
|
486
|
-
}
|
|
487
|
-
else
|
|
488
|
-
m = j(_, i, p, g, a, o, { a: h, b: l }, f);
|
|
489
|
-
return console.timeEnd("sgd"), m;
|
|
438
|
+
function fe(t) {
|
|
439
|
+
if (t === void 0) return Math.random;
|
|
440
|
+
let e = t | 0;
|
|
441
|
+
return () => {
|
|
442
|
+
e = e + 1831565813 | 0;
|
|
443
|
+
let s = Math.imul(e ^ e >>> 15, 1 | e);
|
|
444
|
+
return s = s + Math.imul(s ^ s >>> 7, 61 | s) ^ s, ((s ^ s >>> 14) >>> 0) / 4294967296;
|
|
445
|
+
};
|
|
490
446
|
}
|
|
491
|
-
function
|
|
492
|
-
return
|
|
447
|
+
async function _e(t, e = {}, s) {
|
|
448
|
+
return new ue(e).fit_transform(t, s);
|
|
493
449
|
}
|
|
494
|
-
function de(
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
450
|
+
function de(t, e) {
|
|
451
|
+
return Math.abs(e - 1) < 1e-6 && Math.abs(t - 0.1) < 1e-6 ? { a: 1.9292, b: 0.7915 } : Math.abs(e - 1) < 1e-6 && Math.abs(t - 0) < 1e-6 ? { a: 1.8956, b: 0.8006 } : Math.abs(e - 1) < 1e-6 && Math.abs(t - 0.5) < 1e-6 ? { a: 1.5769, b: 0.8951 } : le(t, e);
|
|
452
|
+
}
|
|
453
|
+
function le(t, e) {
|
|
454
|
+
const r = [], n = [];
|
|
455
|
+
for (let c = 0; c < 299; c++) {
|
|
456
|
+
const a = (c + 1) / 299 * e * 3;
|
|
457
|
+
r.push(a), n.push(a < t ? 1 : Math.exp(-(a - t) / e));
|
|
499
458
|
}
|
|
500
|
-
let u = 1,
|
|
501
|
-
for (let
|
|
502
|
-
let
|
|
503
|
-
for (let
|
|
504
|
-
const
|
|
505
|
-
|
|
506
|
-
const
|
|
507
|
-
|
|
459
|
+
let u = 1, o = 1, f = 1e-3;
|
|
460
|
+
for (let c = 0; c < 500; c++) {
|
|
461
|
+
let a = 0, d = 0, i = 0, h = 0, l = 0, g = 0;
|
|
462
|
+
for (let v = 0; v < 299; v++) {
|
|
463
|
+
const R = r[v], O = Math.pow(R, 2 * o), C = 1 + u * O, A = 1 / C - n[v];
|
|
464
|
+
g += A * A;
|
|
465
|
+
const b = C * C, E = -O / b, y = R > 0 ? -2 * Math.log(R) * u * O / b : 0;
|
|
466
|
+
a += E * A, d += y * A, i += E * E, h += y * y, l += E * y;
|
|
508
467
|
}
|
|
509
|
-
const
|
|
510
|
-
if (Math.abs(
|
|
511
|
-
const
|
|
512
|
-
let
|
|
513
|
-
for (let
|
|
514
|
-
const
|
|
515
|
-
|
|
468
|
+
const _ = i + f, w = h + f, x = l, m = _ * w - x * x;
|
|
469
|
+
if (Math.abs(m) < 1e-20) break;
|
|
470
|
+
const F = -(w * a - x * d) / m, p = -(_ * d - x * a) / m, M = Math.max(1e-4, u + F), B = Math.max(1e-4, o + p);
|
|
471
|
+
let S = 0;
|
|
472
|
+
for (let v = 0; v < 299; v++) {
|
|
473
|
+
const R = Math.pow(r[v], 2 * B), O = 1 / (1 + M * R) - n[v];
|
|
474
|
+
S += O * O;
|
|
516
475
|
}
|
|
517
|
-
if (
|
|
476
|
+
if (S < g ? (u = M, o = B, f = Math.max(1e-10, f / 10)) : f = Math.min(1e10, f * 10), Math.abs(F) < 1e-8 && Math.abs(p) < 1e-8) break;
|
|
518
477
|
}
|
|
519
|
-
return { a: u, b:
|
|
478
|
+
return { a: u, b: o };
|
|
520
479
|
}
|
|
521
|
-
class
|
|
522
|
-
constructor(
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
480
|
+
class ue {
|
|
481
|
+
constructor(e = {}) {
|
|
482
|
+
G(this, "_nComponents");
|
|
483
|
+
G(this, "_nNeighbors");
|
|
484
|
+
G(this, "_minDist");
|
|
485
|
+
G(this, "_spread");
|
|
486
|
+
G(this, "_nEpochs");
|
|
487
|
+
G(this, "_hnswOpts");
|
|
488
|
+
G(this, "_a");
|
|
489
|
+
G(this, "_b");
|
|
490
|
+
G(this, "_debug");
|
|
491
|
+
G(this, "_rng");
|
|
531
492
|
/** The low-dimensional embedding produced by the last fit() call. */
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
this._nComponents =
|
|
536
|
-
const { a:
|
|
537
|
-
this._a =
|
|
493
|
+
G(this, "embedding", null);
|
|
494
|
+
G(this, "_hnswIndex", null);
|
|
495
|
+
G(this, "_nTrain", 0);
|
|
496
|
+
this._nComponents = e.nComponents ?? 2, this._nNeighbors = e.nNeighbors ?? 15, this._minDist = e.minDist ?? 0.1, this._spread = e.spread ?? 1, this._nEpochs = e.nEpochs, this._hnswOpts = e.hnsw ?? {}, this._debug = e.debug ?? !1, this._rng = fe(e.seed);
|
|
497
|
+
const { a: s, b: r } = de(this._minDist, this._spread);
|
|
498
|
+
this._a = s, this._b = r;
|
|
538
499
|
}
|
|
539
500
|
/**
|
|
540
501
|
* Train UMAP on `vectors`.
|
|
@@ -542,46 +503,47 @@ class ge {
|
|
|
542
503
|
* index so that transform() can project new points later.
|
|
543
504
|
* Returns `this` for chaining.
|
|
544
505
|
*/
|
|
545
|
-
async fit(
|
|
546
|
-
const
|
|
547
|
-
console.time("knn");
|
|
548
|
-
const { knn:
|
|
506
|
+
async fit(e, s) {
|
|
507
|
+
const r = e.length, n = this._nEpochs ?? (r > 1e4 ? 200 : 500), { M: u = 16, efConstruction: o = 200, efSearch: f = 50 } = this._hnswOpts;
|
|
508
|
+
this._debug && console.time("knn");
|
|
509
|
+
const { knn: c, index: a } = await ee(e, this._nNeighbors, {
|
|
549
510
|
M: u,
|
|
550
|
-
efConstruction:
|
|
551
|
-
efSearch:
|
|
511
|
+
efConstruction: o,
|
|
512
|
+
efSearch: f
|
|
552
513
|
});
|
|
553
|
-
this._hnswIndex =
|
|
554
|
-
const
|
|
555
|
-
console.timeEnd("fuzzy-set");
|
|
556
|
-
const i =
|
|
514
|
+
this._hnswIndex = a, this._nTrain = r, this._debug && console.timeEnd("knn"), this._debug && console.time("fuzzy-set");
|
|
515
|
+
const d = te(c.indices, c.distances, this._nNeighbors);
|
|
516
|
+
this._debug && console.timeEnd("fuzzy-set");
|
|
517
|
+
const i = V(d.vals), h = new Float32Array(r * this._nComponents);
|
|
557
518
|
for (let l = 0; l < h.length; l++)
|
|
558
|
-
h[l] =
|
|
559
|
-
if (console.time("sgd"),
|
|
519
|
+
h[l] = this._rng() * 20 - 10;
|
|
520
|
+
if (this._debug && console.time("sgd"), ie())
|
|
560
521
|
try {
|
|
561
|
-
const l = new
|
|
522
|
+
const l = new oe();
|
|
562
523
|
await l.init(), this.embedding = await l.optimize(
|
|
563
524
|
h,
|
|
564
|
-
new Uint32Array(
|
|
565
|
-
new Uint32Array(
|
|
525
|
+
new Uint32Array(d.rows),
|
|
526
|
+
new Uint32Array(d.cols),
|
|
566
527
|
i,
|
|
567
|
-
|
|
528
|
+
r,
|
|
568
529
|
this._nComponents,
|
|
569
|
-
|
|
530
|
+
n,
|
|
570
531
|
{ a: this._a, b: this._b, gamma: 1, negativeSampleRate: 5 },
|
|
571
|
-
|
|
532
|
+
s,
|
|
533
|
+
this._rng
|
|
572
534
|
);
|
|
573
535
|
} catch (l) {
|
|
574
|
-
console.warn("WebGPU SGD failed, falling back to CPU:", l), this.embedding =
|
|
536
|
+
console.warn("WebGPU SGD failed, falling back to CPU:", l), this.embedding = W(h, d, i, r, this._nComponents, n, {
|
|
575
537
|
a: this._a,
|
|
576
538
|
b: this._b
|
|
577
|
-
},
|
|
539
|
+
}, s, this._rng);
|
|
578
540
|
}
|
|
579
541
|
else
|
|
580
|
-
this.embedding =
|
|
542
|
+
this.embedding = W(h, d, i, r, this._nComponents, n, {
|
|
581
543
|
a: this._a,
|
|
582
544
|
b: this._b
|
|
583
|
-
},
|
|
584
|
-
return console.timeEnd("sgd"), this;
|
|
545
|
+
}, s, this._rng);
|
|
546
|
+
return this._debug && console.timeEnd("sgd"), this;
|
|
585
547
|
}
|
|
586
548
|
/**
|
|
587
549
|
* Project new (unseen) `vectors` into the embedding space learned by fit().
|
|
@@ -594,35 +556,37 @@ class ge {
|
|
|
594
556
|
* returned embedding to [0, 1]. The stored training embedding is never
|
|
595
557
|
* mutated. Defaults to `false`.
|
|
596
558
|
*/
|
|
597
|
-
async transform(
|
|
559
|
+
async transform(e, s = !1) {
|
|
598
560
|
if (!this._hnswIndex || !this.embedding)
|
|
599
561
|
throw new Error("UMAP.transform() must be called after fit()");
|
|
600
|
-
const
|
|
601
|
-
for (let
|
|
602
|
-
const
|
|
603
|
-
|
|
604
|
-
for (let
|
|
605
|
-
i[
|
|
562
|
+
const r = e.length, n = this._nEpochs ?? (this._nTrain > 1e4 ? 200 : 500), u = Math.max(100, Math.floor(n / 4)), o = this._hnswIndex.searchKnn(e, this._nNeighbors), f = ne(o.indices, o.distances, this._nNeighbors), c = new Uint32Array(f.rows), a = new Uint32Array(f.cols), d = new Float32Array(r), i = new Float32Array(r * this._nComponents);
|
|
563
|
+
for (let g = 0; g < c.length; g++) {
|
|
564
|
+
const _ = c[g], w = a[g], x = f.vals[g];
|
|
565
|
+
d[_] += x;
|
|
566
|
+
for (let m = 0; m < this._nComponents; m++)
|
|
567
|
+
i[_ * this._nComponents + m] += x * this.embedding[w * this._nComponents + m];
|
|
606
568
|
}
|
|
607
|
-
for (let
|
|
608
|
-
if (
|
|
609
|
-
for (let
|
|
610
|
-
i[
|
|
569
|
+
for (let g = 0; g < r; g++)
|
|
570
|
+
if (d[g] > 0)
|
|
571
|
+
for (let _ = 0; _ < this._nComponents; _++)
|
|
572
|
+
i[g * this._nComponents + _] /= d[g];
|
|
611
573
|
else
|
|
612
|
-
for (let
|
|
613
|
-
i[
|
|
614
|
-
const h =
|
|
574
|
+
for (let _ = 0; _ < this._nComponents; _++)
|
|
575
|
+
i[g * this._nComponents + _] = this._rng() * 20 - 10;
|
|
576
|
+
const h = V(f.vals), l = ce(
|
|
615
577
|
i,
|
|
616
578
|
this.embedding,
|
|
617
|
-
|
|
579
|
+
f,
|
|
618
580
|
h,
|
|
619
|
-
|
|
581
|
+
r,
|
|
620
582
|
this._nTrain,
|
|
621
583
|
this._nComponents,
|
|
622
584
|
u,
|
|
623
|
-
{ a: this._a, b: this._b }
|
|
585
|
+
{ a: this._a, b: this._b },
|
|
586
|
+
void 0,
|
|
587
|
+
this._rng
|
|
624
588
|
);
|
|
625
|
-
return
|
|
589
|
+
return s ? K(l, r, this._nComponents) : l;
|
|
626
590
|
}
|
|
627
591
|
/**
|
|
628
592
|
* Convenience method equivalent to `fit(vectors)` followed by
|
|
@@ -633,38 +597,38 @@ class ge {
|
|
|
633
597
|
* returned embedding to [0, 1]. `this.embedding` is never mutated.
|
|
634
598
|
* Defaults to `false`.
|
|
635
599
|
*/
|
|
636
|
-
async fit_transform(
|
|
637
|
-
return await this.fit(
|
|
600
|
+
async fit_transform(e, s, r = !1) {
|
|
601
|
+
return await this.fit(e, s), r ? K(this.embedding, e.length, this._nComponents) : this.embedding;
|
|
638
602
|
}
|
|
639
603
|
}
|
|
640
|
-
function K(
|
|
641
|
-
const
|
|
642
|
-
for (let
|
|
643
|
-
let u = 1 / 0,
|
|
644
|
-
for (let
|
|
645
|
-
const
|
|
646
|
-
|
|
604
|
+
function K(t, e, s) {
|
|
605
|
+
const r = new Float32Array(t.length);
|
|
606
|
+
for (let n = 0; n < s; n++) {
|
|
607
|
+
let u = 1 / 0, o = -1 / 0;
|
|
608
|
+
for (let c = 0; c < e; c++) {
|
|
609
|
+
const a = t[c * s + n];
|
|
610
|
+
a < u && (u = a), a > o && (o = a);
|
|
647
611
|
}
|
|
648
|
-
const
|
|
649
|
-
for (let
|
|
650
|
-
|
|
612
|
+
const f = o - u;
|
|
613
|
+
for (let c = 0; c < e; c++)
|
|
614
|
+
r[c * s + n] = f > 0 ? (t[c * s + n] - u) / f : 0;
|
|
651
615
|
}
|
|
652
|
-
return
|
|
616
|
+
return r;
|
|
653
617
|
}
|
|
654
|
-
function
|
|
655
|
-
let
|
|
656
|
-
for (let
|
|
657
|
-
|
|
658
|
-
const
|
|
659
|
-
for (let
|
|
660
|
-
const u =
|
|
661
|
-
|
|
618
|
+
function V(t, e) {
|
|
619
|
+
let s = -1 / 0;
|
|
620
|
+
for (let n = 0; n < t.length; n++)
|
|
621
|
+
t[n] > s && (s = t[n]);
|
|
622
|
+
const r = new Float32Array(t.length);
|
|
623
|
+
for (let n = 0; n < t.length; n++) {
|
|
624
|
+
const u = t[n] / s;
|
|
625
|
+
r[n] = u > 0 ? 1 / u : -1;
|
|
662
626
|
}
|
|
663
|
-
return
|
|
627
|
+
return r;
|
|
664
628
|
}
|
|
665
629
|
export {
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
630
|
+
ue as UMAP,
|
|
631
|
+
pe as checkWebGPUAvailable,
|
|
632
|
+
_e as fit,
|
|
633
|
+
ie as isWebGPUAvailable
|
|
670
634
|
};
|
package/dist/rng.d.ts
ADDED
package/dist/umap.d.ts
CHANGED
|
@@ -15,6 +15,10 @@ export interface UMAPOptions {
|
|
|
15
15
|
efConstruction?: number;
|
|
16
16
|
efSearch?: number;
|
|
17
17
|
};
|
|
18
|
+
/** Enable timing instrumentation via console.time/timeEnd (default: false) */
|
|
19
|
+
debug?: boolean;
|
|
20
|
+
/** Random seed for reproducible results. When omitted, Math.random() is used. */
|
|
21
|
+
seed?: number;
|
|
18
22
|
}
|
|
19
23
|
/**
|
|
20
24
|
* Called after each completed SGD epoch (or every 10 epochs on the GPU path,
|
|
@@ -71,6 +75,8 @@ export declare class UMAP {
|
|
|
71
75
|
private readonly _hnswOpts;
|
|
72
76
|
private readonly _a;
|
|
73
77
|
private readonly _b;
|
|
78
|
+
private readonly _debug;
|
|
79
|
+
private readonly _rng;
|
|
74
80
|
/** The low-dimensional embedding produced by the last fit() call. */
|
|
75
81
|
embedding: Float32Array | null;
|
|
76
82
|
private _hnswIndex;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "umap-gpu",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.16",
|
|
4
4
|
"description": "UMAP with HNSW kNN and WebGPU-accelerated SGD",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"build": "vite build && tsc",
|
|
41
41
|
"dev": "vite",
|
|
42
42
|
"test": "vitest run",
|
|
43
|
+
"bench": "npx vitest run --config vitest.bench.config.ts",
|
|
43
44
|
"prepublishOnly": "bun test && bun run build",
|
|
44
45
|
"docs:dev": "vitepress dev docs",
|
|
45
46
|
"docs:build": "vitepress build docs",
|