umap-gpu 0.2.14 → 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 +320 -353
- package/dist/rng.d.ts +2 -0
- package/dist/umap.d.ts +6 -0
- package/package.json +4 -2
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 < i; 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: _ }) => _)), o.push(g.map(({ dist: _ }) => Math.sqrt(_)));
|
|
22
|
-
}
|
|
23
|
-
return { knn: { indices: r, distances: o }, index: {
|
|
24
|
-
searchKnn(l, p) {
|
|
25
|
-
const g = [], _ = [];
|
|
26
|
-
for (const m of l) {
|
|
27
|
-
const y = n.searchKnn(m, p, void 0), b = y.neighbors.map((x, v) => ({ idx: x, dist: y.distances[v] })).sort((x, v) => x.dist - v.dist).slice(0, p);
|
|
28
|
-
g.push(b.map(({ idx: x }) => x)), _.push(b.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
|
|
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
|
|
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
|
|
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,
|
|
68
|
-
if (Math.abs(l -
|
|
69
|
-
l >
|
|
56
|
+
for (let g = 0; g < f.length; g++)
|
|
57
|
+
l += Math.exp(-Math.max(0, f[g] - u[o]) / d);
|
|
58
|
+
if (Math.abs(l - i) < 1e-5) break;
|
|
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
|
|
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.
|
|
@@ -181,7 +171,10 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
181
171
|
epoch_of_next_negative_sample[edge_idx] += f32(n_neg) * epochs_per_neg;
|
|
182
172
|
}
|
|
183
173
|
|
|
184
|
-
|
|
174
|
+
// 2654435761u is the 32-bit golden-ratio hash constant (0x9E3779B1),
|
|
175
|
+
// which fits in u32 unlike the 64-bit LCG value 6364136223 used originally.
|
|
176
|
+
// Bug 14 fix: the original constant exceeded u32 range and failed WGSL validation.
|
|
177
|
+
var rng = xorshift(rng_seeds[edge_idx] + params.current_epoch * 2654435761u);
|
|
185
178
|
|
|
186
179
|
for (var s = 0u; s < n_neg; s++) {
|
|
187
180
|
rng = xorshift(rng);
|
|
@@ -204,7 +197,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
204
197
|
}
|
|
205
198
|
}
|
|
206
199
|
}
|
|
207
|
-
`,
|
|
200
|
+
`, re = `// Apply-forces shader — second pass of the two-pass GPU SGD.
|
|
208
201
|
//
|
|
209
202
|
// After the SGD pass has atomically accumulated all gradients into the forces
|
|
210
203
|
// buffer, this shader applies each element's accumulated force to the
|
|
@@ -233,40 +226,40 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
233
226
|
}
|
|
234
227
|
`;
|
|
235
228
|
let z = null;
|
|
236
|
-
async function
|
|
229
|
+
async function Y() {
|
|
237
230
|
if (z) return z;
|
|
238
231
|
if (typeof navigator > "u" || !navigator.gpu)
|
|
239
232
|
return null;
|
|
240
|
-
const
|
|
241
|
-
return
|
|
233
|
+
const t = await navigator.gpu.requestAdapter();
|
|
234
|
+
return t ? (z = await t.requestDevice(), z.lost.then(() => {
|
|
242
235
|
z = null;
|
|
243
236
|
}), z) : null;
|
|
244
237
|
}
|
|
245
|
-
function
|
|
238
|
+
function ie() {
|
|
246
239
|
return typeof navigator < "u" && !!navigator.gpu;
|
|
247
240
|
}
|
|
248
|
-
async function
|
|
249
|
-
return await
|
|
241
|
+
async function pe() {
|
|
242
|
+
return await Y() !== null;
|
|
250
243
|
}
|
|
251
|
-
class
|
|
244
|
+
class oe {
|
|
252
245
|
constructor() {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
246
|
+
G(this, "device");
|
|
247
|
+
G(this, "sgdPipeline");
|
|
248
|
+
G(this, "applyForcesPipeline");
|
|
256
249
|
}
|
|
257
250
|
async init() {
|
|
258
|
-
const
|
|
259
|
-
if (!
|
|
260
|
-
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({
|
|
261
254
|
layout: "auto",
|
|
262
255
|
compute: {
|
|
263
|
-
module: this.device.createShaderModule({ code:
|
|
256
|
+
module: this.device.createShaderModule({ code: ae }),
|
|
264
257
|
entryPoint: "main"
|
|
265
258
|
}
|
|
266
259
|
}), this.applyForcesPipeline = this.device.createComputePipeline({
|
|
267
260
|
layout: "auto",
|
|
268
261
|
compute: {
|
|
269
|
-
module: this.device.createShaderModule({ code:
|
|
262
|
+
module: this.device.createShaderModule({ code: re }),
|
|
270
263
|
entryPoint: "main"
|
|
271
264
|
}
|
|
272
265
|
});
|
|
@@ -284,254 +277,225 @@ class X {
|
|
|
284
277
|
* @param params - UMAP curve parameters and repulsion settings
|
|
285
278
|
* @returns Optimized embedding as Float32Array
|
|
286
279
|
*/
|
|
287
|
-
async optimize(
|
|
288
|
-
const { device:
|
|
289
|
-
|
|
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,
|
|
290
283
|
GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC
|
|
291
|
-
),
|
|
292
|
-
for (let
|
|
293
|
-
|
|
294
|
-
const
|
|
295
|
-
for (let
|
|
296
|
-
|
|
297
|
-
const
|
|
298
|
-
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,
|
|
299
292
|
usage: GPUBufferUsage.STORAGE,
|
|
300
293
|
mappedAtCreation: !0
|
|
301
294
|
});
|
|
302
|
-
new Int32Array(
|
|
303
|
-
const
|
|
295
|
+
new Int32Array(v.getMappedRange()).fill(0), v.unmap();
|
|
296
|
+
const R = i.createBuffer({
|
|
304
297
|
size: 40,
|
|
305
298
|
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
|
|
306
|
-
}),
|
|
299
|
+
}), O = i.createBuffer({
|
|
307
300
|
size: 16,
|
|
308
301
|
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
|
|
309
|
-
}),
|
|
302
|
+
}), C = i.createBindGroup({
|
|
310
303
|
layout: this.sgdPipeline.getBindGroupLayout(0),
|
|
311
304
|
entries: [
|
|
312
|
-
{ binding: 0, resource: { buffer:
|
|
313
|
-
{ binding: 1, resource: { buffer:
|
|
314
|
-
{ binding: 2, resource: { buffer:
|
|
315
|
-
{ binding: 3, resource: { buffer:
|
|
316
|
-
{ binding: 4, resource: { buffer:
|
|
317
|
-
{ binding: 5, resource: { buffer:
|
|
318
|
-
{ binding: 6, resource: { buffer:
|
|
319
|
-
{ binding: 7, resource: { buffer:
|
|
320
|
-
{ 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 } }
|
|
321
314
|
]
|
|
322
|
-
}),
|
|
315
|
+
}), U = i.createBindGroup({
|
|
323
316
|
layout: this.applyForcesPipeline.getBindGroupLayout(0),
|
|
324
317
|
entries: [
|
|
325
|
-
{ binding: 0, resource: { buffer:
|
|
326
|
-
{ binding: 1, resource: { buffer:
|
|
327
|
-
{ binding: 2, resource: { buffer:
|
|
318
|
+
{ binding: 0, resource: { buffer: g } },
|
|
319
|
+
{ binding: 1, resource: { buffer: v } },
|
|
320
|
+
{ binding: 2, resource: { buffer: O } }
|
|
328
321
|
]
|
|
329
322
|
});
|
|
330
|
-
for (let
|
|
331
|
-
const
|
|
332
|
-
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
const
|
|
336
|
-
|
|
337
|
-
const
|
|
338
|
-
|
|
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));
|
|
339
332
|
}
|
|
340
|
-
const
|
|
341
|
-
size:
|
|
333
|
+
const A = i.createBuffer({
|
|
334
|
+
size: e.byteLength,
|
|
342
335
|
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
|
|
343
|
-
}),
|
|
344
|
-
|
|
345
|
-
const
|
|
346
|
-
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;
|
|
347
340
|
}
|
|
348
|
-
makeBuffer(
|
|
349
|
-
const
|
|
350
|
-
size:
|
|
351
|
-
usage:
|
|
341
|
+
makeBuffer(e, s) {
|
|
342
|
+
const r = this.device.createBuffer({
|
|
343
|
+
size: e.byteLength,
|
|
344
|
+
usage: s,
|
|
352
345
|
mappedAtCreation: !0
|
|
353
346
|
});
|
|
354
|
-
return
|
|
347
|
+
return e instanceof Float32Array ? new Float32Array(r.getMappedRange()).set(e) : new Uint32Array(r.getMappedRange()).set(e), r.unmap(), r;
|
|
355
348
|
}
|
|
356
349
|
}
|
|
357
|
-
function
|
|
358
|
-
return Math.max(-4, Math.min(4,
|
|
350
|
+
function T(t) {
|
|
351
|
+
return Math.max(-4, Math.min(4, t));
|
|
359
352
|
}
|
|
360
|
-
function
|
|
361
|
-
const { a
|
|
362
|
-
for (let m = 0; m <
|
|
363
|
-
|
|
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;
|
|
364
357
|
for (let m = 0; m < u; m++) {
|
|
365
|
-
|
|
366
|
-
const
|
|
367
|
-
for (let
|
|
368
|
-
if (
|
|
369
|
-
const
|
|
370
|
-
let
|
|
371
|
-
for (let
|
|
372
|
-
const
|
|
373
|
-
|
|
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;
|
|
374
367
|
}
|
|
375
|
-
const
|
|
376
|
-
for (let
|
|
377
|
-
const
|
|
378
|
-
|
|
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;
|
|
379
372
|
}
|
|
380
|
-
|
|
381
|
-
const
|
|
382
|
-
(m -
|
|
373
|
+
w[p] += s[p];
|
|
374
|
+
const O = s[p] / h, C = Math.max(0, Math.floor(
|
|
375
|
+
(m - x[p]) / O
|
|
383
376
|
));
|
|
384
|
-
|
|
385
|
-
for (let
|
|
386
|
-
const
|
|
387
|
-
if (
|
|
388
|
-
let
|
|
389
|
-
for (let
|
|
390
|
-
const
|
|
391
|
-
|
|
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;
|
|
392
385
|
}
|
|
393
|
-
const
|
|
394
|
-
for (let
|
|
395
|
-
const
|
|
396
|
-
|
|
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;
|
|
397
390
|
}
|
|
398
391
|
}
|
|
399
392
|
}
|
|
400
393
|
}
|
|
401
|
-
return
|
|
394
|
+
return t;
|
|
402
395
|
}
|
|
403
|
-
function
|
|
404
|
-
const { a:
|
|
405
|
-
for (let
|
|
406
|
-
|
|
407
|
-
for (let
|
|
408
|
-
const
|
|
409
|
-
for (let
|
|
410
|
-
if (m[
|
|
411
|
-
const
|
|
412
|
-
let
|
|
413
|
-
for (let
|
|
414
|
-
const
|
|
415
|
-
|
|
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;
|
|
416
409
|
}
|
|
417
|
-
const
|
|
418
|
-
for (let
|
|
419
|
-
const
|
|
420
|
-
|
|
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);
|
|
421
414
|
}
|
|
422
|
-
m[
|
|
423
|
-
const
|
|
424
|
-
(
|
|
415
|
+
m[B] += r[B];
|
|
416
|
+
const U = r[B] / g, A = Math.max(0, Math.floor(
|
|
417
|
+
(p - F[B]) / U
|
|
425
418
|
));
|
|
426
|
-
|
|
427
|
-
for (let
|
|
428
|
-
const
|
|
429
|
-
if (
|
|
430
|
-
let
|
|
431
|
-
for (let
|
|
432
|
-
const
|
|
433
|
-
|
|
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;
|
|
434
427
|
}
|
|
435
|
-
const
|
|
436
|
-
for (let
|
|
437
|
-
const
|
|
438
|
-
|
|
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);
|
|
439
432
|
}
|
|
440
433
|
}
|
|
441
434
|
}
|
|
442
435
|
}
|
|
443
|
-
return
|
|
436
|
+
return t;
|
|
444
437
|
}
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
}
|
|
453
|
-
console.time("knn");
|
|
454
|
-
const { indices: n, distances: r } = await se(e, s, {
|
|
455
|
-
M: d.M ?? 16,
|
|
456
|
-
efConstruction: d.efConstruction ?? 200,
|
|
457
|
-
efSearch: d.efSearch ?? 50
|
|
458
|
-
});
|
|
459
|
-
console.timeEnd("knn"), console.time("fuzzy-set");
|
|
460
|
-
const o = V(n, r, s);
|
|
461
|
-
console.timeEnd("fuzzy-set");
|
|
462
|
-
const { a: h, b: l } = Z(u, c), p = W(o.vals), g = e.length, _ = new Float32Array(g * a);
|
|
463
|
-
for (let y = 0; y < _.length; y++)
|
|
464
|
-
_[y] = Math.random() * 20 - 10;
|
|
465
|
-
console.time("sgd");
|
|
466
|
-
let m;
|
|
467
|
-
if (J())
|
|
468
|
-
try {
|
|
469
|
-
const y = new X();
|
|
470
|
-
await y.init(), m = await y.optimize(
|
|
471
|
-
_,
|
|
472
|
-
new Uint32Array(o.rows),
|
|
473
|
-
new Uint32Array(o.cols),
|
|
474
|
-
p,
|
|
475
|
-
g,
|
|
476
|
-
a,
|
|
477
|
-
i,
|
|
478
|
-
{ a: h, b: l, gamma: 1, negativeSampleRate: 5 },
|
|
479
|
-
f
|
|
480
|
-
);
|
|
481
|
-
} catch (y) {
|
|
482
|
-
console.warn("WebGPU SGD failed, falling back to CPU:", y), m = L(_, o, p, g, a, i, { a: h, b: l }, f);
|
|
483
|
-
}
|
|
484
|
-
else
|
|
485
|
-
m = L(_, o, p, g, a, i, { a: h, b: l }, f);
|
|
486
|
-
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
|
+
};
|
|
487
446
|
}
|
|
488
|
-
function
|
|
489
|
-
return
|
|
447
|
+
async function _e(t, e = {}, s) {
|
|
448
|
+
return new ue(e).fit_transform(t, s);
|
|
490
449
|
}
|
|
491
|
-
function de(
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
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));
|
|
496
458
|
}
|
|
497
|
-
let u = 1,
|
|
498
|
-
for (let
|
|
499
|
-
let
|
|
500
|
-
for (let
|
|
501
|
-
const
|
|
502
|
-
|
|
503
|
-
const
|
|
504
|
-
|
|
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;
|
|
505
467
|
}
|
|
506
|
-
const
|
|
507
|
-
if (Math.abs(
|
|
508
|
-
const
|
|
509
|
-
let
|
|
510
|
-
for (let
|
|
511
|
-
const
|
|
512
|
-
|
|
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;
|
|
513
475
|
}
|
|
514
|
-
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;
|
|
515
477
|
}
|
|
516
|
-
return { a: u, b:
|
|
478
|
+
return { a: u, b: o };
|
|
517
479
|
}
|
|
518
|
-
class
|
|
519
|
-
constructor(
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
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");
|
|
528
492
|
/** The low-dimensional embedding produced by the last fit() call. */
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
this._nComponents =
|
|
533
|
-
const { a:
|
|
534
|
-
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;
|
|
535
499
|
}
|
|
536
500
|
/**
|
|
537
501
|
* Train UMAP on `vectors`.
|
|
@@ -539,46 +503,47 @@ class ge {
|
|
|
539
503
|
* index so that transform() can project new points later.
|
|
540
504
|
* Returns `this` for chaining.
|
|
541
505
|
*/
|
|
542
|
-
async fit(
|
|
543
|
-
const
|
|
544
|
-
console.time("knn");
|
|
545
|
-
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, {
|
|
546
510
|
M: u,
|
|
547
|
-
efConstruction:
|
|
548
|
-
efSearch:
|
|
511
|
+
efConstruction: o,
|
|
512
|
+
efSearch: f
|
|
549
513
|
});
|
|
550
|
-
this._hnswIndex =
|
|
551
|
-
const
|
|
552
|
-
console.timeEnd("fuzzy-set");
|
|
553
|
-
const
|
|
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);
|
|
554
518
|
for (let l = 0; l < h.length; l++)
|
|
555
|
-
h[l] =
|
|
556
|
-
if (console.time("sgd"),
|
|
519
|
+
h[l] = this._rng() * 20 - 10;
|
|
520
|
+
if (this._debug && console.time("sgd"), ie())
|
|
557
521
|
try {
|
|
558
|
-
const l = new
|
|
522
|
+
const l = new oe();
|
|
559
523
|
await l.init(), this.embedding = await l.optimize(
|
|
560
524
|
h,
|
|
561
|
-
new Uint32Array(
|
|
562
|
-
new Uint32Array(
|
|
563
|
-
|
|
564
|
-
|
|
525
|
+
new Uint32Array(d.rows),
|
|
526
|
+
new Uint32Array(d.cols),
|
|
527
|
+
i,
|
|
528
|
+
r,
|
|
565
529
|
this._nComponents,
|
|
566
|
-
|
|
530
|
+
n,
|
|
567
531
|
{ a: this._a, b: this._b, gamma: 1, negativeSampleRate: 5 },
|
|
568
|
-
|
|
532
|
+
s,
|
|
533
|
+
this._rng
|
|
569
534
|
);
|
|
570
535
|
} catch (l) {
|
|
571
|
-
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, {
|
|
572
537
|
a: this._a,
|
|
573
538
|
b: this._b
|
|
574
|
-
},
|
|
539
|
+
}, s, this._rng);
|
|
575
540
|
}
|
|
576
541
|
else
|
|
577
|
-
this.embedding =
|
|
542
|
+
this.embedding = W(h, d, i, r, this._nComponents, n, {
|
|
578
543
|
a: this._a,
|
|
579
544
|
b: this._b
|
|
580
|
-
},
|
|
581
|
-
return console.timeEnd("sgd"), this;
|
|
545
|
+
}, s, this._rng);
|
|
546
|
+
return this._debug && console.timeEnd("sgd"), this;
|
|
582
547
|
}
|
|
583
548
|
/**
|
|
584
549
|
* Project new (unseen) `vectors` into the embedding space learned by fit().
|
|
@@ -591,35 +556,37 @@ class ge {
|
|
|
591
556
|
* returned embedding to [0, 1]. The stored training embedding is never
|
|
592
557
|
* mutated. Defaults to `false`.
|
|
593
558
|
*/
|
|
594
|
-
async transform(
|
|
559
|
+
async transform(e, s = !1) {
|
|
595
560
|
if (!this._hnswIndex || !this.embedding)
|
|
596
561
|
throw new Error("UMAP.transform() must be called after fit()");
|
|
597
|
-
const
|
|
598
|
-
for (let
|
|
599
|
-
const
|
|
600
|
-
|
|
601
|
-
for (let
|
|
602
|
-
|
|
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];
|
|
603
568
|
}
|
|
604
|
-
for (let
|
|
605
|
-
if (
|
|
606
|
-
for (let
|
|
607
|
-
|
|
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];
|
|
608
573
|
else
|
|
609
|
-
for (let
|
|
610
|
-
|
|
611
|
-
const h =
|
|
612
|
-
|
|
574
|
+
for (let _ = 0; _ < this._nComponents; _++)
|
|
575
|
+
i[g * this._nComponents + _] = this._rng() * 20 - 10;
|
|
576
|
+
const h = V(f.vals), l = ce(
|
|
577
|
+
i,
|
|
613
578
|
this.embedding,
|
|
614
|
-
|
|
579
|
+
f,
|
|
615
580
|
h,
|
|
616
|
-
|
|
581
|
+
r,
|
|
617
582
|
this._nTrain,
|
|
618
583
|
this._nComponents,
|
|
619
584
|
u,
|
|
620
|
-
{ a: this._a, b: this._b }
|
|
585
|
+
{ a: this._a, b: this._b },
|
|
586
|
+
void 0,
|
|
587
|
+
this._rng
|
|
621
588
|
);
|
|
622
|
-
return
|
|
589
|
+
return s ? K(l, r, this._nComponents) : l;
|
|
623
590
|
}
|
|
624
591
|
/**
|
|
625
592
|
* Convenience method equivalent to `fit(vectors)` followed by
|
|
@@ -630,38 +597,38 @@ class ge {
|
|
|
630
597
|
* returned embedding to [0, 1]. `this.embedding` is never mutated.
|
|
631
598
|
* Defaults to `false`.
|
|
632
599
|
*/
|
|
633
|
-
async fit_transform(
|
|
634
|
-
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;
|
|
635
602
|
}
|
|
636
603
|
}
|
|
637
|
-
function K(
|
|
638
|
-
const
|
|
639
|
-
for (let
|
|
640
|
-
let u = 1 / 0,
|
|
641
|
-
for (let
|
|
642
|
-
const
|
|
643
|
-
|
|
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);
|
|
644
611
|
}
|
|
645
|
-
const
|
|
646
|
-
for (let
|
|
647
|
-
|
|
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;
|
|
648
615
|
}
|
|
649
|
-
return
|
|
616
|
+
return r;
|
|
650
617
|
}
|
|
651
|
-
function
|
|
652
|
-
let
|
|
653
|
-
for (let
|
|
654
|
-
|
|
655
|
-
const
|
|
656
|
-
for (let
|
|
657
|
-
const u =
|
|
658
|
-
|
|
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;
|
|
659
626
|
}
|
|
660
|
-
return
|
|
627
|
+
return r;
|
|
661
628
|
}
|
|
662
629
|
export {
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
630
|
+
ue as UMAP,
|
|
631
|
+
pe as checkWebGPUAvailable,
|
|
632
|
+
_e as fit,
|
|
633
|
+
ie as isWebGPUAvailable
|
|
667
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",
|
|
@@ -55,7 +56,8 @@
|
|
|
55
56
|
"vite": "^5.0.0",
|
|
56
57
|
"vitepress": "^1.6.4",
|
|
57
58
|
"vitepress-plugin-llms": "^1.11.0",
|
|
58
|
-
"vitest": "^4.0.18"
|
|
59
|
+
"vitest": "^4.0.18",
|
|
60
|
+
"webgpu": "^0.3.8"
|
|
59
61
|
},
|
|
60
62
|
"license": "MIT"
|
|
61
63
|
}
|