umap-gpu 0.2.11 → 0.2.13

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.
Files changed (2) hide show
  1. package/dist/index.js +250 -246
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,93 +1,93 @@
1
- var H = Object.defineProperty;
2
- var V = (e, n, r) => n in e ? H(e, n, { enumerable: !0, configurable: !0, writable: !0, value: r }) : e[n] = r;
3
- var G = (e, n, r) => V(e, typeof n != "symbol" ? n + "" : n, r);
4
- import { loadHnswlib as C } from "hnswlib-wasm";
5
- async function Y(e, n, r = {}) {
6
- const { M: s = 16, efConstruction: t = 200, efSearch: p = 50 } = r, f = await C(), l = e[0].length, c = e.length, a = new f.HierarchicalNSW("l2", l, "");
7
- a.initIndex(c, s, t, 200), a.setEfSearch(Math.max(p, n)), a.addItems(e, !1);
1
+ var V = Object.defineProperty;
2
+ var Y = (e, t, r) => t in e ? V(e, t, { enumerable: !0, configurable: !0, writable: !0, value: r }) : e[t] = r;
3
+ var G = (e, t, r) => Y(e, typeof t != "symbol" ? t + "" : t, r);
4
+ import { loadHnswlib as D } from "hnswlib-wasm";
5
+ async function Q(e, t, r = {}) {
6
+ const { M: s = 16, efConstruction: n = 200, efSearch: g = 50 } = r, c = await D(), d = e[0].length, f = e.length, a = new c.HierarchicalNSW("l2", d, "");
7
+ a.initIndex(f, s, n, 200), a.setEfSearch(Math.max(g, t)), a.addItems(e, !1);
8
8
  const o = [], i = [];
9
- for (let h = 0; h < c; h++) {
10
- const d = a.searchKnn(e[h], n + 1, void 0), u = d.neighbors.map((g, m) => ({ idx: g, dist: d.distances[m] })).filter(({ idx: g }) => g !== h).slice(0, n);
11
- o.push(u.map(({ idx: g }) => g)), i.push(u.map(({ dist: g }) => g));
9
+ for (let h = 0; h < f; h++) {
10
+ const l = a.searchKnn(e[h], t + 1, void 0), u = l.neighbors.map((p, m) => ({ idx: p, dist: l.distances[m] })).filter(({ idx: p }) => p !== h).slice(0, t);
11
+ o.push(u.map(({ idx: p }) => p)), i.push(u.map(({ dist: p }) => p));
12
12
  }
13
13
  return { indices: o, distances: i };
14
14
  }
15
- async function Q(e, n, r = {}) {
16
- const { M: s = 16, efConstruction: t = 200, efSearch: p = 50 } = r, f = await C(), l = e[0].length, c = e.length, a = new f.HierarchicalNSW("l2", l, "");
17
- a.initIndex(c, s, t, 200), a.setEfSearch(Math.max(p, n)), a.addItems(e, !1);
15
+ async function J(e, t, r = {}) {
16
+ const { M: s = 16, efConstruction: n = 200, efSearch: g = 50 } = r, c = await D(), d = e[0].length, f = e.length, a = new c.HierarchicalNSW("l2", d, "");
17
+ a.initIndex(f, s, n, 200), a.setEfSearch(Math.max(g, t)), a.addItems(e, !1);
18
18
  const o = [], i = [];
19
- for (let d = 0; d < c; d++) {
20
- const u = a.searchKnn(e[d], n + 1, void 0), g = u.neighbors.map((m, w) => ({ idx: m, dist: u.distances[w] })).filter(({ idx: m }) => m !== d).slice(0, n);
21
- o.push(g.map(({ idx: m }) => m)), i.push(g.map(({ dist: m }) => m));
19
+ for (let l = 0; l < f; l++) {
20
+ const u = a.searchKnn(e[l], t + 1, void 0), p = u.neighbors.map((m, _) => ({ idx: m, dist: u.distances[_] })).filter(({ idx: m }) => m !== l).slice(0, t);
21
+ o.push(p.map(({ idx: m }) => m)), i.push(p.map(({ dist: m }) => m));
22
22
  }
23
23
  return { knn: { indices: o, distances: i }, index: {
24
- searchKnn(d, u) {
25
- const g = [], m = [];
26
- for (const w of d) {
27
- const b = a.searchKnn(w, u, void 0), y = b.neighbors.map((v, x) => ({ idx: v, dist: b.distances[x] })).sort((v, x) => v.dist - x.dist).slice(0, u);
28
- g.push(y.map(({ idx: v }) => v)), m.push(y.map(({ dist: v }) => v));
24
+ searchKnn(l, u) {
25
+ const p = [], m = [];
26
+ for (const _ of l) {
27
+ const w = a.searchKnn(_, u, void 0), b = w.neighbors.map((A, x) => ({ idx: A, dist: w.distances[x] })).sort((A, x) => A.dist - x.dist).slice(0, u);
28
+ p.push(b.map(({ idx: A }) => A)), m.push(b.map(({ dist: A }) => A));
29
29
  }
30
- return { indices: g, distances: m };
30
+ return { indices: p, distances: m };
31
31
  }
32
32
  } };
33
33
  }
34
- function D(e, n, r, s = 1) {
35
- const t = e.length, { sigmas: p, rhos: f } = L(n, r), l = [], c = [], a = [];
36
- for (let i = 0; i < t; i++)
34
+ function L(e, t, r, s = 1) {
35
+ const n = e.length, { sigmas: g, rhos: c } = W(t, r), d = [], f = [], a = [];
36
+ for (let i = 0; i < n; i++)
37
37
  for (let h = 0; h < e[i].length; h++) {
38
- const d = n[i][h], u = d <= f[i] ? 1 : Math.exp(-((d - f[i]) / p[i]));
39
- l.push(i), c.push(e[i][h]), a.push(u);
38
+ const l = t[i][h], u = l <= c[i] ? 1 : Math.exp(-((l - c[i]) / g[i]));
39
+ d.push(i), f.push(e[i][h]), a.push(u);
40
40
  }
41
- return { ...X(l, c, a, t, s), nVertices: t };
41
+ return { ...Z(d, f, a, n, s), nVertices: n };
42
42
  }
43
- function J(e, n, r) {
44
- const s = e.length, { sigmas: t, rhos: p } = L(n, r), f = [], l = [], c = [];
43
+ function X(e, t, r) {
44
+ const s = e.length, { sigmas: n, rhos: g } = W(t, r), c = [], d = [], f = [];
45
45
  for (let a = 0; a < s; a++)
46
46
  for (let o = 0; o < e[a].length; o++) {
47
- const i = n[a][o], h = i <= p[a] ? 1 : Math.exp(-((i - p[a]) / t[a]));
48
- f.push(a), l.push(e[a][o]), c.push(h);
47
+ const i = t[a][o], h = i <= g[a] ? 1 : Math.exp(-((i - g[a]) / n[a]));
48
+ c.push(a), d.push(e[a][o]), f.push(h);
49
49
  }
50
50
  return {
51
- rows: new Float32Array(f),
52
- cols: new Float32Array(l),
53
- vals: new Float32Array(c),
51
+ rows: new Float32Array(c),
52
+ cols: new Float32Array(d),
53
+ vals: new Float32Array(f),
54
54
  nVertices: s
55
55
  };
56
56
  }
57
- function L(e, n) {
58
- const s = e.length, t = new Float32Array(s), p = new Float32Array(s);
59
- for (let f = 0; f < s; f++) {
60
- const l = e[f];
61
- p[f] = l.find((h) => h > 0) ?? 0;
62
- let c = 0, a = 1 / 0, o = 1;
63
- const i = Math.log2(n);
57
+ function W(e, t) {
58
+ const s = e.length, n = new Float32Array(s), g = new Float32Array(s);
59
+ for (let c = 0; c < s; c++) {
60
+ const d = e[c];
61
+ g[c] = d.find((h) => h > 0) ?? 0;
62
+ let f = 0, a = 1 / 0, o = 1;
63
+ const i = Math.log2(t);
64
64
  for (let h = 0; h < 64; h++) {
65
- let d = 0;
66
- for (let u = 0; u < l.length; u++)
67
- d += Math.exp(-Math.max(0, l[u] - p[f]) / o);
68
- if (Math.abs(d - i) < 1e-5) break;
69
- d > i ? (a = o, o = (c + a) / 2) : (c = o, o = a === 1 / 0 ? o * 2 : (c + a) / 2);
65
+ let l = 0;
66
+ for (let u = 0; u < d.length; u++)
67
+ l += Math.exp(-Math.max(0, d[u] - g[c]) / o);
68
+ if (Math.abs(l - i) < 1e-5) break;
69
+ l > i ? (a = o, o = (f + a) / 2) : (f = o, o = a === 1 / 0 ? o * 2 : (f + a) / 2);
70
70
  }
71
- t[f] = o;
71
+ n[c] = o;
72
72
  }
73
- return { sigmas: t, rhos: p };
73
+ return { sigmas: n, rhos: g };
74
74
  }
75
- function X(e, n, r, s, t) {
76
- const p = /* @__PURE__ */ new Map();
75
+ function Z(e, t, r, s, n) {
76
+ const g = /* @__PURE__ */ new Map();
77
77
  for (let a = 0; a < e.length; a++)
78
- p.set(e[a] * s + n[a], r[a]);
79
- const f = [], l = [], c = [];
80
- for (const [a, o] of p) {
81
- const i = Math.floor(a / s), h = a % s, d = p.get(h * s + i) ?? 0, u = o + d - o * d, g = o * d;
82
- f.push(i), l.push(h), c.push(t * u + (1 - t) * g);
78
+ g.set(e[a] * s + t[a], r[a]);
79
+ const c = [], d = [], f = [];
80
+ for (const [a, o] of g) {
81
+ const i = Math.floor(a / s), h = a % s, l = g.get(h * s + i) ?? 0, u = o + l - o * l, p = o * l;
82
+ c.push(i), d.push(h), f.push(n * u + (1 - n) * p);
83
83
  }
84
84
  return {
85
- rows: new Float32Array(f),
86
- cols: new Float32Array(l),
87
- vals: new Float32Array(c)
85
+ rows: new Float32Array(c),
86
+ cols: new Float32Array(d),
87
+ vals: new Float32Array(f)
88
88
  };
89
89
  }
90
- const Z = `// UMAP SGD compute shader — processes one graph edge per GPU thread.
90
+ const $ = `// UMAP SGD compute shader — processes one graph edge per GPU thread.
91
91
  // Applies attraction forces between connected nodes and repulsion forces
92
92
  // against negative samples.
93
93
 
@@ -197,18 +197,18 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
197
197
  epochs_per_sample[edge_idx] / f32(params.negative_sample_rate);
198
198
  }
199
199
  `;
200
- class W {
200
+ class j {
201
201
  constructor() {
202
202
  G(this, "device");
203
203
  G(this, "pipeline");
204
204
  }
205
205
  async init() {
206
- const n = await navigator.gpu.requestAdapter();
207
- if (!n) throw new Error("WebGPU not supported");
208
- this.device = await n.requestDevice(), this.pipeline = this.device.createComputePipeline({
206
+ const t = await navigator.gpu.requestAdapter();
207
+ if (!t) throw new Error("WebGPU not supported");
208
+ this.device = await t.requestDevice(), this.pipeline = this.device.createComputePipeline({
209
209
  layout: "auto",
210
210
  compute: {
211
- module: this.device.createShaderModule({ code: Z }),
211
+ module: this.device.createShaderModule({ code: $ }),
212
212
  entryPoint: "main"
213
213
  }
214
214
  });
@@ -226,203 +226,207 @@ class W {
226
226
  * @param params - UMAP curve parameters and repulsion settings
227
227
  * @returns Optimized embedding as Float32Array
228
228
  */
229
- async optimize(n, r, s, t, p, f, l, c, a) {
229
+ async optimize(t, r, s, n, g, c, d, f, a) {
230
230
  const { device: o } = this, i = r.length, h = this.makeBuffer(
231
- n,
231
+ t,
232
232
  GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC
233
- ), d = this.makeBuffer(r, GPUBufferUsage.STORAGE), u = this.makeBuffer(s, GPUBufferUsage.STORAGE), g = this.makeBuffer(t, GPUBufferUsage.STORAGE), m = new Float32Array(i).fill(0), w = this.makeBuffer(m, GPUBufferUsage.STORAGE), b = new Float32Array(i);
234
- for (let _ = 0; _ < i; _++)
235
- b[_] = t[_] / c.negativeSampleRate;
236
- const y = this.makeBuffer(b, GPUBufferUsage.STORAGE), v = new Uint32Array(i);
237
- for (let _ = 0; _ < i; _++)
238
- v[_] = Math.random() * 4294967295 | 0;
239
- const x = this.makeBuffer(v, GPUBufferUsage.STORAGE), B = o.createBuffer({
233
+ ), l = this.makeBuffer(r, GPUBufferUsage.STORAGE), u = this.makeBuffer(s, GPUBufferUsage.STORAGE), p = this.makeBuffer(n, GPUBufferUsage.STORAGE), m = new Float32Array(i).fill(0), _ = this.makeBuffer(m, GPUBufferUsage.STORAGE), w = new Float32Array(i);
234
+ for (let M = 0; M < i; M++)
235
+ w[M] = n[M] / f.negativeSampleRate;
236
+ const b = this.makeBuffer(w, GPUBufferUsage.STORAGE), A = new Uint32Array(i);
237
+ for (let M = 0; M < i; M++)
238
+ A[M] = Math.random() * 4294967295 | 0;
239
+ const x = this.makeBuffer(A, GPUBufferUsage.STORAGE), U = o.createBuffer({
240
240
  size: 40,
241
241
  usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
242
242
  });
243
- for (let _ = 0; _ < l; _++) {
244
- const F = 1 - _ / l, A = new ArrayBuffer(40), M = new Uint32Array(A), N = new Float32Array(A);
245
- M[0] = i, M[1] = p, M[2] = f, M[3] = _, M[4] = l, N[5] = F, N[6] = c.a, N[7] = c.b, N[8] = c.gamma, M[9] = c.negativeSampleRate, o.queue.writeBuffer(B, 0, A);
246
- const S = o.createBindGroup({
243
+ for (let M = 0; M < d; M++) {
244
+ const v = 1 - M / d, S = new ArrayBuffer(40), y = new Uint32Array(S), B = new Float32Array(S);
245
+ y[0] = i, y[1] = g, y[2] = c, y[3] = M, y[4] = d, B[5] = v, B[6] = f.a, B[7] = f.b, B[8] = f.gamma, y[9] = f.negativeSampleRate, o.queue.writeBuffer(U, 0, S);
246
+ const k = o.createBindGroup({
247
247
  layout: this.pipeline.getBindGroupLayout(0),
248
248
  entries: [
249
- { binding: 0, resource: { buffer: g } },
250
- { binding: 1, resource: { buffer: d } },
249
+ { binding: 0, resource: { buffer: p } },
250
+ { binding: 1, resource: { buffer: l } },
251
251
  { binding: 2, resource: { buffer: u } },
252
252
  { binding: 3, resource: { buffer: h } },
253
- { binding: 4, resource: { buffer: w } },
254
- { binding: 5, resource: { buffer: y } },
255
- { binding: 6, resource: { buffer: B } },
253
+ { binding: 4, resource: { buffer: _ } },
254
+ { binding: 5, resource: { buffer: b } },
255
+ { binding: 6, resource: { buffer: U } },
256
256
  { binding: 7, resource: { buffer: x } }
257
257
  ]
258
- }), O = o.createCommandEncoder(), U = O.beginComputePass();
259
- U.setPipeline(this.pipeline), U.setBindGroup(0, S), U.dispatchWorkgroups(Math.ceil(i / 256)), U.end(), o.queue.submit([O.finish()]), _ % 10 === 0 && (await o.queue.onSubmittedWorkDone(), a == null || a(_, l));
258
+ }), E = o.createCommandEncoder(), P = E.beginComputePass();
259
+ P.setPipeline(this.pipeline), P.setBindGroup(0, k), P.dispatchWorkgroups(Math.ceil(i / 256)), P.end(), o.queue.submit([E.finish()]), M % 10 === 0 && (await o.queue.onSubmittedWorkDone(), a == null || a(M, d));
260
260
  }
261
- const E = o.createBuffer({
262
- size: n.byteLength,
261
+ const N = o.createBuffer({
262
+ size: t.byteLength,
263
263
  usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
264
264
  }), R = o.createCommandEncoder();
265
- R.copyBufferToBuffer(h, 0, E, 0, n.byteLength), o.queue.submit([R.finish()]), await E.mapAsync(GPUMapMode.READ);
266
- const k = new Float32Array(E.getMappedRange().slice(0));
267
- return E.unmap(), h.destroy(), d.destroy(), u.destroy(), g.destroy(), w.destroy(), y.destroy(), x.destroy(), B.destroy(), E.destroy(), k;
265
+ R.copyBufferToBuffer(h, 0, N, 0, t.byteLength), o.queue.submit([R.finish()]), await N.mapAsync(GPUMapMode.READ);
266
+ const O = new Float32Array(N.getMappedRange().slice(0));
267
+ return N.unmap(), h.destroy(), l.destroy(), u.destroy(), p.destroy(), _.destroy(), b.destroy(), x.destroy(), U.destroy(), N.destroy(), O;
268
268
  }
269
- makeBuffer(n, r) {
269
+ makeBuffer(t, r) {
270
270
  const s = this.device.createBuffer({
271
- size: n.byteLength,
271
+ size: t.byteLength,
272
272
  usage: r,
273
273
  mappedAtCreation: !0
274
274
  });
275
- return n instanceof Float32Array ? new Float32Array(s.getMappedRange()).set(n) : new Uint32Array(s.getMappedRange()).set(n), s.unmap(), s;
275
+ return t instanceof Float32Array ? new Float32Array(s.getMappedRange()).set(t) : new Uint32Array(s.getMappedRange()).set(t), s.unmap(), s;
276
276
  }
277
277
  }
278
- function q(e) {
278
+ function z(e) {
279
279
  return Math.max(-4, Math.min(4, e));
280
280
  }
281
- function z(e, n, r, s, t, p, f, l) {
282
- const { a: c, b: a, gamma: o = 1, negativeSampleRate: i = 5 } = f, h = n.rows.length, d = new Uint32Array(n.rows), u = new Uint32Array(n.cols), g = new Float32Array(h).fill(0), m = new Float32Array(h);
283
- for (let w = 0; w < h; w++)
284
- m[w] = r[w] / i;
285
- for (let w = 0; w < p; w++) {
286
- l == null || l(w, p);
287
- const b = 1 - w / p;
288
- for (let y = 0; y < h; y++) {
289
- if (g[y] > w) continue;
290
- const v = d[y], x = u[y];
291
- let B = 0;
292
- for (let _ = 0; _ < t; _++) {
293
- const F = e[v * t + _] - e[x * t + _];
294
- B += F * F;
281
+ function I(e, t, r, s, n, g, c, d) {
282
+ const { a: f, b: a, gamma: o = 1, negativeSampleRate: i = 5 } = c, h = t.rows.length, l = new Uint32Array(t.rows), u = new Uint32Array(t.cols), p = new Float32Array(h).fill(0), m = new Float32Array(h);
283
+ for (let _ = 0; _ < h; _++)
284
+ m[_] = r[_] / i;
285
+ for (let _ = 0; _ < g; _++) {
286
+ d == null || d(_, g);
287
+ const w = 1 - _ / g;
288
+ for (let b = 0; b < h; b++) {
289
+ if (p[b] > _) continue;
290
+ const A = l[b], x = u[b];
291
+ let U = 0;
292
+ for (let v = 0; v < n; v++) {
293
+ const S = e[A * n + v] - e[x * n + v];
294
+ U += S * S;
295
295
  }
296
- const E = Math.pow(B, a), R = -2 * c * a * (B > 0 ? E / B : 0) / (c * E + 1);
297
- for (let _ = 0; _ < t; _++) {
298
- const F = e[v * t + _] - e[x * t + _], A = q(R * F);
299
- e[v * t + _] += b * A, e[x * t + _] -= b * A;
296
+ const N = Math.pow(U, a), R = -2 * f * a * (U > 0 ? N / U : 0) / (f * N + 1);
297
+ for (let v = 0; v < n; v++) {
298
+ const S = e[A * n + v] - e[x * n + v], y = z(R * S);
299
+ e[A * n + v] += w * y, e[x * n + v] -= w * y;
300
300
  }
301
- g[y] += r[y];
302
- const k = m[y] > 0 ? Math.floor(r[y] / m[y]) : 0;
303
- for (let _ = 0; _ < k; _++) {
304
- const F = Math.floor(Math.random() * s);
305
- if (F === v) continue;
306
- let A = 0;
307
- for (let S = 0; S < t; S++) {
308
- const O = e[v * t + S] - e[F * t + S];
309
- A += O * O;
301
+ p[b] += r[b];
302
+ const O = r[b] / i, M = Math.max(0, Math.floor(
303
+ (_ - m[b]) / O
304
+ ));
305
+ m[b] += M * O;
306
+ for (let v = 0; v < M; v++) {
307
+ const S = Math.floor(Math.random() * s);
308
+ if (S === A) continue;
309
+ let y = 0;
310
+ for (let E = 0; E < n; E++) {
311
+ const P = e[A * n + E] - e[S * n + E];
312
+ y += P * P;
310
313
  }
311
- const M = Math.pow(A, a), N = 2 * o * a / ((1e-3 + A) * (c * M + 1));
312
- for (let S = 0; S < t; S++) {
313
- const O = e[v * t + S] - e[F * t + S], U = q(N * O);
314
- e[v * t + S] += b * U;
314
+ const B = Math.pow(y, a), k = 2 * o * a / ((1e-3 + y) * (f * B + 1));
315
+ for (let E = 0; E < n; E++) {
316
+ const P = e[A * n + E] - e[S * n + E], F = z(k * P);
317
+ e[A * n + E] += w * F;
315
318
  }
316
319
  }
317
- m[y] += r[y] / i;
318
320
  }
319
321
  }
320
322
  return e;
321
323
  }
322
- function $(e, n, r, s, t, p, f, l, c, a) {
323
- const { a: o, b: i, gamma: h = 1, negativeSampleRate: d = 5 } = c, u = r.rows.length, g = new Uint32Array(r.rows), m = new Uint32Array(r.cols), w = new Float32Array(u).fill(0), b = new Float32Array(u);
324
- for (let y = 0; y < u; y++)
325
- b[y] = s[y] / d;
326
- for (let y = 0; y < l; y++) {
327
- const v = 1 - y / l;
324
+ function ee(e, t, r, s, n, g, c, d, f, a) {
325
+ const { a: o, b: i, gamma: h = 1, negativeSampleRate: l = 5 } = f, u = r.rows.length, p = new Uint32Array(r.rows), m = new Uint32Array(r.cols), _ = new Float32Array(u).fill(0), w = new Float32Array(u);
326
+ for (let b = 0; b < u; b++)
327
+ w[b] = s[b] / l;
328
+ for (let b = 0; b < d; b++) {
329
+ const A = 1 - b / d;
328
330
  for (let x = 0; x < u; x++) {
329
- if (w[x] > y) continue;
330
- const B = g[x], E = m[x];
331
+ if (_[x] > b) continue;
332
+ const U = p[x], N = m[x];
331
333
  let R = 0;
332
- for (let A = 0; A < f; A++) {
333
- const M = e[B * f + A] - n[E * f + A];
334
- R += M * M;
334
+ for (let y = 0; y < c; y++) {
335
+ const B = e[U * c + y] - t[N * c + y];
336
+ R += B * B;
335
337
  }
336
- const k = Math.pow(R, i), _ = -2 * o * i * (R > 0 ? k / R : 0) / (o * k + 1);
337
- for (let A = 0; A < f; A++) {
338
- const M = e[B * f + A] - n[E * f + A];
339
- e[B * f + A] += v * q(_ * M);
338
+ const O = Math.pow(R, i), M = -2 * o * i * (R > 0 ? O / R : 0) / (o * O + 1);
339
+ for (let y = 0; y < c; y++) {
340
+ const B = e[U * c + y] - t[N * c + y];
341
+ e[U * c + y] += A * z(M * B);
340
342
  }
341
- w[x] += s[x];
342
- const F = b[x] > 0 ? Math.floor(s[x] / b[x]) : 0;
343
- for (let A = 0; A < F; A++) {
344
- const M = Math.floor(Math.random() * p);
345
- if (M === E) continue;
346
- let N = 0;
347
- for (let U = 0; U < f; U++) {
348
- const P = e[B * f + U] - n[M * f + U];
349
- N += P * P;
343
+ _[x] += s[x];
344
+ const v = s[x] / l, S = Math.max(0, Math.floor(
345
+ (b - w[x]) / v
346
+ ));
347
+ w[x] += S * v;
348
+ for (let y = 0; y < S; y++) {
349
+ const B = Math.floor(Math.random() * g);
350
+ if (B === N) continue;
351
+ let k = 0;
352
+ for (let F = 0; F < c; F++) {
353
+ const q = e[U * c + F] - t[B * c + F];
354
+ k += q * q;
350
355
  }
351
- const S = Math.pow(N, i), O = 2 * h * i / ((1e-3 + N) * (o * S + 1));
352
- for (let U = 0; U < f; U++) {
353
- const P = e[B * f + U] - n[M * f + U];
354
- e[B * f + U] += v * q(O * P);
356
+ const E = Math.pow(k, i), P = 2 * h * i / ((1e-3 + k) * (o * E + 1));
357
+ for (let F = 0; F < c; F++) {
358
+ const q = e[U * c + F] - t[B * c + F];
359
+ e[U * c + F] += A * z(P * q);
355
360
  }
356
361
  }
357
- b[x] += s[x] / d;
358
362
  }
359
363
  }
360
364
  return e;
361
365
  }
362
- function j() {
366
+ function K() {
363
367
  return typeof navigator < "u" && !!navigator.gpu;
364
368
  }
365
- async function ae(e, n = {}, r) {
369
+ async function re(e, t = {}, r) {
366
370
  const {
367
371
  nComponents: s = 2,
368
- nNeighbors: t = 15,
369
- minDist: p = 0.1,
370
- spread: f = 1,
371
- hnsw: l = {}
372
- } = n, c = n.nEpochs ?? (e.length > 1e4 ? 200 : 500);
372
+ nNeighbors: n = 15,
373
+ minDist: g = 0.1,
374
+ spread: c = 1,
375
+ hnsw: d = {}
376
+ } = t, f = t.nEpochs ?? (e.length > 1e4 ? 200 : 500);
373
377
  console.time("knn");
374
- const { indices: a, distances: o } = await Y(e, t, {
375
- M: l.M ?? 16,
376
- efConstruction: l.efConstruction ?? 200,
377
- efSearch: l.efSearch ?? 50
378
+ const { indices: a, distances: o } = await Q(e, n, {
379
+ M: d.M ?? 16,
380
+ efConstruction: d.efConstruction ?? 200,
381
+ efSearch: d.efSearch ?? 50
378
382
  });
379
383
  console.timeEnd("knn"), console.time("fuzzy-set");
380
- const i = D(a, o, t);
384
+ const i = L(a, o, n);
381
385
  console.timeEnd("fuzzy-set");
382
- const { a: h, b: d } = K(p, f), u = I(i.vals, c), g = e.length, m = new Float32Array(g * s);
383
- for (let b = 0; b < m.length; b++)
384
- m[b] = Math.random() * 20 - 10;
386
+ const { a: h, b: l } = H(g, c), u = T(i.vals), p = e.length, m = new Float32Array(p * s);
387
+ for (let w = 0; w < m.length; w++)
388
+ m[w] = Math.random() * 20 - 10;
385
389
  console.time("sgd");
386
- let w;
387
- if (j())
390
+ let _;
391
+ if (K())
388
392
  try {
389
- const b = new W();
390
- await b.init(), w = await b.optimize(
393
+ const w = new j();
394
+ await w.init(), _ = await w.optimize(
391
395
  m,
392
396
  new Uint32Array(i.rows),
393
397
  new Uint32Array(i.cols),
394
398
  u,
395
- g,
399
+ p,
396
400
  s,
397
- c,
398
- { a: h, b: d, gamma: 1, negativeSampleRate: 5 },
401
+ f,
402
+ { a: h, b: l, gamma: 1, negativeSampleRate: 5 },
399
403
  r
400
404
  );
401
- } catch (b) {
402
- console.warn("WebGPU SGD failed, falling back to CPU:", b), w = z(m, i, u, g, s, c, { a: h, b: d }, r);
405
+ } catch (w) {
406
+ console.warn("WebGPU SGD failed, falling back to CPU:", w), _ = I(m, i, u, p, s, f, { a: h, b: l }, r);
403
407
  }
404
408
  else
405
- w = z(m, i, u, g, s, c, { a: h, b: d }, r);
406
- return console.timeEnd("sgd"), w;
409
+ _ = I(m, i, u, p, s, f, { a: h, b: l }, r);
410
+ return console.timeEnd("sgd"), _;
407
411
  }
408
- function K(e, n) {
409
- if (Math.abs(n - 1) < 1e-6 && Math.abs(e - 0.1) < 1e-6)
412
+ function H(e, t) {
413
+ if (Math.abs(t - 1) < 1e-6 && Math.abs(e - 0.1) < 1e-6)
410
414
  return { a: 1.9292, b: 0.7915 };
411
- if (Math.abs(n - 1) < 1e-6 && Math.abs(e - 0) < 1e-6)
415
+ if (Math.abs(t - 1) < 1e-6 && Math.abs(e - 0) < 1e-6)
412
416
  return { a: 1.8956, b: 0.8006 };
413
- if (Math.abs(n - 1) < 1e-6 && Math.abs(e - 0.5) < 1e-6)
417
+ if (Math.abs(t - 1) < 1e-6 && Math.abs(e - 0.5) < 1e-6)
414
418
  return { a: 1.5769, b: 0.8951 };
415
- const r = ee(e, n);
416
- return { a: ne(e, n, r), b: r };
419
+ const r = te(e, t);
420
+ return { a: ne(e, t, r), b: r };
417
421
  }
418
- function ee(e, n) {
419
- return 1 / (n * 1.2);
422
+ function te(e, t) {
423
+ return 1 / (t * 1.2);
420
424
  }
421
- function ne(e, n, r) {
425
+ function ne(e, t, r) {
422
426
  return e < 1e-6 ? 1.8956 : (1 / (1 + 1e-3) - 1) / -Math.pow(e, 2 * r);
423
427
  }
424
- class re {
425
- constructor(n = {}) {
428
+ class ie {
429
+ constructor(t = {}) {
426
430
  G(this, "_nComponents");
427
431
  G(this, "_nNeighbors");
428
432
  G(this, "_minDist");
@@ -435,8 +439,8 @@ class re {
435
439
  G(this, "embedding", null);
436
440
  G(this, "_hnswIndex", null);
437
441
  G(this, "_nTrain", 0);
438
- this._nComponents = n.nComponents ?? 2, this._nNeighbors = n.nNeighbors ?? 15, this._minDist = n.minDist ?? 0.1, this._spread = n.spread ?? 1, this._nEpochs = n.nEpochs, this._hnswOpts = n.hnsw ?? {};
439
- const { a: r, b: s } = K(this._minDist, this._spread);
442
+ this._nComponents = t.nComponents ?? 2, this._nNeighbors = t.nNeighbors ?? 15, this._minDist = t.minDist ?? 0.1, this._spread = t.spread ?? 1, this._nEpochs = t.nEpochs, this._hnswOpts = t.hnsw ?? {};
443
+ const { a: r, b: s } = H(this._minDist, this._spread);
440
444
  this._a = r, this._b = s;
441
445
  }
442
446
  /**
@@ -445,42 +449,42 @@ class re {
445
449
  * index so that transform() can project new points later.
446
450
  * Returns `this` for chaining.
447
451
  */
448
- async fit(n, r) {
449
- const s = n.length, t = this._nEpochs ?? (s > 1e4 ? 200 : 500), { M: p = 16, efConstruction: f = 200, efSearch: l = 50 } = this._hnswOpts;
452
+ async fit(t, r) {
453
+ const s = t.length, n = this._nEpochs ?? (s > 1e4 ? 200 : 500), { M: g = 16, efConstruction: c = 200, efSearch: d = 50 } = this._hnswOpts;
450
454
  console.time("knn");
451
- const { knn: c, index: a } = await Q(n, this._nNeighbors, {
452
- M: p,
453
- efConstruction: f,
454
- efSearch: l
455
+ const { knn: f, index: a } = await J(t, this._nNeighbors, {
456
+ M: g,
457
+ efConstruction: c,
458
+ efSearch: d
455
459
  });
456
460
  this._hnswIndex = a, this._nTrain = s, console.timeEnd("knn"), console.time("fuzzy-set");
457
- const o = D(c.indices, c.distances, this._nNeighbors);
461
+ const o = L(f.indices, f.distances, this._nNeighbors);
458
462
  console.timeEnd("fuzzy-set");
459
- const i = I(o.vals, t), h = new Float32Array(s * this._nComponents);
460
- for (let d = 0; d < h.length; d++)
461
- h[d] = Math.random() * 20 - 10;
462
- if (console.time("sgd"), j())
463
+ const i = T(o.vals), h = new Float32Array(s * this._nComponents);
464
+ for (let l = 0; l < h.length; l++)
465
+ h[l] = Math.random() * 20 - 10;
466
+ if (console.time("sgd"), K())
463
467
  try {
464
- const d = new W();
465
- await d.init(), this.embedding = await d.optimize(
468
+ const l = new j();
469
+ await l.init(), this.embedding = await l.optimize(
466
470
  h,
467
471
  new Uint32Array(o.rows),
468
472
  new Uint32Array(o.cols),
469
473
  i,
470
474
  s,
471
475
  this._nComponents,
472
- t,
476
+ n,
473
477
  { a: this._a, b: this._b, gamma: 1, negativeSampleRate: 5 },
474
478
  r
475
479
  );
476
- } catch (d) {
477
- console.warn("WebGPU SGD failed, falling back to CPU:", d), this.embedding = z(h, o, i, s, this._nComponents, t, {
480
+ } catch (l) {
481
+ console.warn("WebGPU SGD failed, falling back to CPU:", l), this.embedding = I(h, o, i, s, this._nComponents, n, {
478
482
  a: this._a,
479
483
  b: this._b
480
484
  }, r);
481
485
  }
482
486
  else
483
- this.embedding = z(h, o, i, s, this._nComponents, t, {
487
+ this.embedding = I(h, o, i, s, this._nComponents, n, {
484
488
  a: this._a,
485
489
  b: this._b
486
490
  }, r);
@@ -497,35 +501,35 @@ class re {
497
501
  * returned embedding to [0, 1]. The stored training embedding is never
498
502
  * mutated. Defaults to `false`.
499
503
  */
500
- async transform(n, r = !1) {
504
+ async transform(t, r = !1) {
501
505
  if (!this._hnswIndex || !this.embedding)
502
506
  throw new Error("UMAP.transform() must be called after fit()");
503
- const s = n.length, t = this._nEpochs ?? (this._nTrain > 1e4 ? 200 : 500), p = Math.max(100, Math.floor(t / 4)), f = this._hnswIndex.searchKnn(n, this._nNeighbors), l = J(f.indices, f.distances, this._nNeighbors), c = new Uint32Array(l.rows), a = new Uint32Array(l.cols), o = new Float32Array(s), i = new Float32Array(s * this._nComponents);
504
- for (let u = 0; u < c.length; u++) {
505
- const g = c[u], m = a[u], w = l.vals[u];
506
- o[g] += w;
507
- for (let b = 0; b < this._nComponents; b++)
508
- i[g * this._nComponents + b] += w * this.embedding[m * this._nComponents + b];
507
+ const s = t.length, n = this._nEpochs ?? (this._nTrain > 1e4 ? 200 : 500), g = Math.max(100, Math.floor(n / 4)), c = this._hnswIndex.searchKnn(t, this._nNeighbors), d = X(c.indices, c.distances, this._nNeighbors), f = new Uint32Array(d.rows), a = new Uint32Array(d.cols), o = new Float32Array(s), i = new Float32Array(s * this._nComponents);
508
+ for (let u = 0; u < f.length; u++) {
509
+ const p = f[u], m = a[u], _ = d.vals[u];
510
+ o[p] += _;
511
+ for (let w = 0; w < this._nComponents; w++)
512
+ i[p * this._nComponents + w] += _ * this.embedding[m * this._nComponents + w];
509
513
  }
510
514
  for (let u = 0; u < s; u++)
511
515
  if (o[u] > 0)
512
- for (let g = 0; g < this._nComponents; g++)
513
- i[u * this._nComponents + g] /= o[u];
516
+ for (let p = 0; p < this._nComponents; p++)
517
+ i[u * this._nComponents + p] /= o[u];
514
518
  else
515
- for (let g = 0; g < this._nComponents; g++)
516
- i[u * this._nComponents + g] = Math.random() * 20 - 10;
517
- const h = I(l.vals, p), d = $(
519
+ for (let p = 0; p < this._nComponents; p++)
520
+ i[u * this._nComponents + p] = Math.random() * 20 - 10;
521
+ const h = T(d.vals), l = ee(
518
522
  i,
519
523
  this.embedding,
520
- l,
524
+ d,
521
525
  h,
522
526
  s,
523
527
  this._nTrain,
524
528
  this._nComponents,
525
- p,
529
+ g,
526
530
  { a: this._a, b: this._b }
527
531
  );
528
- return r ? T(d, s, this._nComponents) : d;
532
+ return r ? C(l, s, this._nComponents) : l;
529
533
  }
530
534
  /**
531
535
  * Convenience method equivalent to `fit(vectors)` followed by
@@ -536,37 +540,37 @@ class re {
536
540
  * returned embedding to [0, 1]. `this.embedding` is never mutated.
537
541
  * Defaults to `false`.
538
542
  */
539
- async fit_transform(n, r, s = !1) {
540
- return await this.fit(n, r), s ? T(this.embedding, n.length, this._nComponents) : this.embedding;
543
+ async fit_transform(t, r, s = !1) {
544
+ return await this.fit(t, r), s ? C(this.embedding, t.length, this._nComponents) : this.embedding;
541
545
  }
542
546
  }
543
- function T(e, n, r) {
547
+ function C(e, t, r) {
544
548
  const s = new Float32Array(e.length);
545
- for (let t = 0; t < r; t++) {
546
- let p = 1 / 0, f = -1 / 0;
547
- for (let c = 0; c < n; c++) {
548
- const a = e[c * r + t];
549
- a < p && (p = a), a > f && (f = a);
549
+ for (let n = 0; n < r; n++) {
550
+ let g = 1 / 0, c = -1 / 0;
551
+ for (let f = 0; f < t; f++) {
552
+ const a = e[f * r + n];
553
+ a < g && (g = a), a > c && (c = a);
550
554
  }
551
- const l = f - p;
552
- for (let c = 0; c < n; c++)
553
- s[c * r + t] = l > 0 ? (e[c * r + t] - p) / l : 0;
555
+ const d = c - g;
556
+ for (let f = 0; f < t; f++)
557
+ s[f * r + n] = d > 0 ? (e[f * r + n] - g) / d : 0;
554
558
  }
555
559
  return s;
556
560
  }
557
- function I(e, n) {
561
+ function T(e, t) {
558
562
  let r = -1 / 0;
559
- for (let t = 0; t < e.length; t++)
560
- e[t] > r && (r = e[t]);
563
+ for (let n = 0; n < e.length; n++)
564
+ e[n] > r && (r = e[n]);
561
565
  const s = new Float32Array(e.length);
562
- for (let t = 0; t < e.length; t++) {
563
- const p = e[t] / r;
564
- s[t] = p > 0 ? n / p : -1;
566
+ for (let n = 0; n < e.length; n++) {
567
+ const g = e[n] / r;
568
+ s[n] = g > 0 ? 1 / g : -1;
565
569
  }
566
570
  return s;
567
571
  }
568
572
  export {
569
- re as UMAP,
570
- ae as fit,
571
- j as isWebGPUAvailable
573
+ ie as UMAP,
574
+ re as fit,
575
+ K as isWebGPUAvailable
572
576
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "umap-gpu",
3
- "version": "0.2.11",
3
+ "version": "0.2.13",
4
4
  "description": "UMAP with HNSW kNN and WebGPU-accelerated SGD",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",