@elarsaks/umap-wasm 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +349 -0
  3. package/dist/src/heap.d.ts +12 -0
  4. package/dist/src/heap.js +226 -0
  5. package/dist/src/index.d.ts +1 -0
  6. package/dist/src/index.js +5 -0
  7. package/dist/src/lib.d.ts +1 -0
  8. package/dist/src/lib.js +5 -0
  9. package/dist/src/matrix.d.ts +41 -0
  10. package/dist/src/matrix.js +360 -0
  11. package/dist/src/nn_descent.d.ts +17 -0
  12. package/dist/src/nn_descent.js +204 -0
  13. package/dist/src/tree.d.ts +16 -0
  14. package/dist/src/tree.js +320 -0
  15. package/dist/src/umap.d.ts +102 -0
  16. package/dist/src/umap.js +842 -0
  17. package/dist/src/utils.d.ts +16 -0
  18. package/dist/src/utils.js +137 -0
  19. package/dist/src/wasmBridge.d.ts +57 -0
  20. package/dist/src/wasmBridge.js +290 -0
  21. package/dist/test/matrix.test.d.ts +1 -0
  22. package/dist/test/matrix.test.js +169 -0
  23. package/dist/test/nn_descent.test.d.ts +1 -0
  24. package/dist/test/nn_descent.test.js +58 -0
  25. package/dist/test/test_data.d.ts +13 -0
  26. package/dist/test/test_data.js +1054 -0
  27. package/dist/test/tree.test.d.ts +1 -0
  28. package/dist/test/tree.test.js +60 -0
  29. package/dist/test/umap.test.d.ts +1 -0
  30. package/dist/test/umap.test.js +293 -0
  31. package/dist/test/utils.test.d.ts +1 -0
  32. package/dist/test/utils.test.js +128 -0
  33. package/dist/test/wasmDistance.test.d.ts +1 -0
  34. package/dist/test/wasmDistance.test.js +124 -0
  35. package/dist/test/wasmMatrix.test.d.ts +1 -0
  36. package/dist/test/wasmMatrix.test.js +389 -0
  37. package/dist/test/wasmTree.test.d.ts +1 -0
  38. package/dist/test/wasmTree.test.js +212 -0
  39. package/lib/umap-js.js +8657 -0
  40. package/lib/umap-js.min.js +1 -0
  41. package/package.json +58 -0
@@ -0,0 +1,389 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
+ return new (P || (P = Promise))(function (resolve, reject) {
38
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
42
+ });
43
+ };
44
+ var __generator = (this && this.__generator) || function (thisArg, body) {
45
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
46
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
47
+ function verb(n) { return function (v) { return step([n, v]); }; }
48
+ function step(op) {
49
+ if (f) throw new TypeError("Generator is already executing.");
50
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
51
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
52
+ if (y = 0, t) op = [op[0] & 2, t.value];
53
+ switch (op[0]) {
54
+ case 0: case 1: t = op; break;
55
+ case 4: _.label++; return { value: op[1], done: false };
56
+ case 5: _.label++; y = op[1]; op = [0]; continue;
57
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
58
+ default:
59
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
60
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
61
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
62
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
63
+ if (t[2]) _.ops.pop();
64
+ _.trys.pop(); continue;
65
+ }
66
+ op = body.call(thisArg, _);
67
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
68
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
69
+ }
70
+ };
71
+ Object.defineProperty(exports, "__esModule", { value: true });
72
+ var vitest_1 = require("vitest");
73
+ var matrix_1 = require("../src/matrix");
74
+ var wasmBridge = __importStar(require("../src/wasmBridge"));
75
+ var wasmBridge_1 = require("../src/wasmBridge");
76
+ function expectArraysClose(actual, expected, precision) {
77
+ if (precision === void 0) { precision = 10; }
78
+ expect(actual.length).toBe(expected.length);
79
+ for (var i = 0; i < actual.length; i++) {
80
+ expect(actual[i].length).toBe(expected[i].length);
81
+ for (var j = 0; j < actual[i].length; j++) {
82
+ expect(actual[i][j]).toBeCloseTo(expected[i][j], precision);
83
+ }
84
+ }
85
+ }
86
+ describe('WASM SparseMatrix vs JS SparseMatrix', function () {
87
+ var testMatrix2x2 = {
88
+ rows: [0, 0, 1, 1],
89
+ cols: [0, 1, 0, 1],
90
+ vals: [1, 2, 3, 4],
91
+ dims: [2, 2],
92
+ };
93
+ beforeAll(function () { return __awaiter(void 0, void 0, void 0, function () {
94
+ return __generator(this, function (_a) {
95
+ switch (_a.label) {
96
+ case 0: return [4, (0, wasmBridge_1.initWasm)()];
97
+ case 1:
98
+ _a.sent();
99
+ expect((0, wasmBridge_1.isWasmAvailable)()).toBe(true);
100
+ return [2];
101
+ }
102
+ });
103
+ }); });
104
+ describe('basic operations', function () {
105
+ test('constructs identical sparse matrix and compares dimensions/values', function () {
106
+ var rows = testMatrix2x2.rows, cols = testMatrix2x2.cols, vals = testMatrix2x2.vals, dims = testMatrix2x2.dims;
107
+ var jsMatrix = new matrix_1.SparseMatrix(rows, cols, vals, dims);
108
+ var wasmMatrix = (0, wasmBridge_1.createSparseMatrixWasm)(rows, cols, vals, dims[0], dims[1]);
109
+ expect(wasmMatrix.n_rows).toEqual(jsMatrix.nRows);
110
+ expect(wasmMatrix.n_cols).toEqual(jsMatrix.nCols);
111
+ expect((0, wasmBridge_1.wasmSparseMatrixToArray)(wasmMatrix)).toEqual(jsMatrix.toArray());
112
+ wasmMatrix.free();
113
+ });
114
+ test('get/set methods produce identical results', function () {
115
+ var rows = testMatrix2x2.rows, cols = testMatrix2x2.cols, vals = testMatrix2x2.vals, dims = testMatrix2x2.dims;
116
+ var jsMatrix = new matrix_1.SparseMatrix(rows, cols, vals, dims);
117
+ var wasmMatrix = (0, wasmBridge_1.createSparseMatrixWasm)(rows, cols, vals, dims[0], dims[1]);
118
+ expect(wasmMatrix.get(0, 1, 0)).toEqual(jsMatrix.get(0, 1));
119
+ expect(wasmMatrix.get(1, 0, 0)).toEqual(jsMatrix.get(1, 0));
120
+ jsMatrix.set(0, 1, 9);
121
+ wasmMatrix.set(0, 1, 9);
122
+ expect(wasmMatrix.get(0, 1, 0)).toEqual(jsMatrix.get(0, 1));
123
+ expect((0, wasmBridge_1.wasmSparseMatrixToArray)(wasmMatrix)).toEqual(jsMatrix.toArray());
124
+ wasmMatrix.free();
125
+ });
126
+ test('getAll returns identical ordered entries', function () {
127
+ var rows = testMatrix2x2.rows, cols = testMatrix2x2.cols, vals = testMatrix2x2.vals, dims = testMatrix2x2.dims;
128
+ var jsMatrix = new matrix_1.SparseMatrix(rows, cols, vals, dims);
129
+ var wasmMatrix = (0, wasmBridge_1.createSparseMatrixWasm)(rows, cols, vals, dims[0], dims[1]);
130
+ var jsEntries = jsMatrix.getAll();
131
+ var wasmEntries = (0, wasmBridge_1.wasmSparseMatrixGetAll)(wasmMatrix);
132
+ expect(wasmEntries).toEqual(jsEntries);
133
+ wasmMatrix.free();
134
+ });
135
+ });
136
+ describe('matrix operations', function () {
137
+ var jsA;
138
+ var jsB;
139
+ var wasmA;
140
+ var wasmB;
141
+ beforeEach(function () {
142
+ var rows = testMatrix2x2.rows, cols = testMatrix2x2.cols, vals = testMatrix2x2.vals, dims = testMatrix2x2.dims;
143
+ jsA = new matrix_1.SparseMatrix(rows, cols, vals, dims);
144
+ jsB = new matrix_1.SparseMatrix(rows, cols, vals, dims);
145
+ wasmA = (0, wasmBridge_1.createSparseMatrixWasm)(rows, cols, vals, dims[0], dims[1]);
146
+ wasmB = (0, wasmBridge_1.createSparseMatrixWasm)(rows, cols, vals, dims[0], dims[1]);
147
+ });
148
+ afterEach(function () {
149
+ wasmA.free();
150
+ wasmB.free();
151
+ });
152
+ test('transpose produces identical results', function () {
153
+ var jsT = (0, matrix_1.transpose)(jsA);
154
+ var wasmT = (0, wasmBridge_1.sparseTransposeWasm)(wasmA);
155
+ expect((0, wasmBridge_1.wasmSparseMatrixToArray)(wasmT)).toEqual(jsT.toArray());
156
+ wasmT.free();
157
+ });
158
+ test('identity produces identical results', function () {
159
+ var jsI = (0, matrix_1.identity)([3, 3]);
160
+ var wasmI = (0, wasmBridge_1.sparseIdentityWasm)(3);
161
+ expect((0, wasmBridge_1.wasmSparseMatrixToArray)(wasmI)).toEqual(jsI.toArray());
162
+ wasmI.free();
163
+ });
164
+ test('pairwise multiply produces identical results', function () {
165
+ var jsResult = (0, matrix_1.pairwiseMultiply)(jsA, jsB);
166
+ var wasmResult = (0, wasmBridge_1.sparsePairwiseMultiplyWasm)(wasmA, wasmB);
167
+ expect((0, wasmBridge_1.wasmSparseMatrixToArray)(wasmResult)).toEqual(jsResult.toArray());
168
+ wasmResult.free();
169
+ });
170
+ test('add produces identical results', function () {
171
+ var jsResult = (0, matrix_1.add)(jsA, jsB);
172
+ var wasmResult = (0, wasmBridge_1.sparseAddWasm)(wasmA, wasmB);
173
+ expect((0, wasmBridge_1.wasmSparseMatrixToArray)(wasmResult)).toEqual(jsResult.toArray());
174
+ wasmResult.free();
175
+ });
176
+ test('subtract produces identical results', function () {
177
+ var jsResult = (0, matrix_1.subtract)(jsA, jsB);
178
+ var wasmResult = (0, wasmBridge_1.sparseSubtractWasm)(wasmA, wasmB);
179
+ expect((0, wasmBridge_1.wasmSparseMatrixToArray)(wasmResult)).toEqual(jsResult.toArray());
180
+ wasmResult.free();
181
+ });
182
+ test('element-wise maximum produces identical results', function () {
183
+ var jsI = (0, matrix_1.multiplyScalar)((0, matrix_1.identity)([2, 2]), 8);
184
+ var wasmI = (0, wasmBridge_1.sparseMultiplyScalarWasm)((0, wasmBridge_1.sparseIdentityWasm)(2), 8);
185
+ var jsResult = (0, matrix_1.maximum)(jsA, jsI);
186
+ var wasmResult = (0, wasmBridge_1.sparseMaximumWasm)(wasmA, wasmI);
187
+ expect((0, wasmBridge_1.wasmSparseMatrixToArray)(wasmResult)).toEqual(jsResult.toArray());
188
+ wasmI.free();
189
+ wasmResult.free();
190
+ });
191
+ test('scalar multiply produces identical results', function () {
192
+ var jsResult = (0, matrix_1.multiplyScalar)(jsA, 3);
193
+ var wasmResult = (0, wasmBridge_1.sparseMultiplyScalarWasm)(wasmA, 3);
194
+ expect((0, wasmBridge_1.wasmSparseMatrixToArray)(wasmResult)).toEqual(jsResult.toArray());
195
+ wasmResult.free();
196
+ });
197
+ test('eliminateZeros produces identical results', function () {
198
+ var rows = [0, 1, 1];
199
+ var cols = [0, 0, 1];
200
+ var vals = [0, 1, 3];
201
+ var dims = [2, 2];
202
+ var jsMatrix = new matrix_1.SparseMatrix(rows, cols, vals, dims);
203
+ var wasmMatrix = (0, wasmBridge_1.createSparseMatrixWasm)(rows, cols, vals, dims[0], dims[1]);
204
+ var jsResult = (0, matrix_1.eliminateZeros)(jsMatrix);
205
+ var wasmResult = (0, wasmBridge_1.sparseEliminateZerosWasm)(wasmMatrix);
206
+ expect((0, wasmBridge_1.wasmSparseMatrixToArray)(wasmResult)).toEqual(jsResult.toArray());
207
+ wasmMatrix.free();
208
+ wasmResult.free();
209
+ });
210
+ });
211
+ describe('normalization', function () {
212
+ var jsA;
213
+ var wasmA;
214
+ beforeEach(function () {
215
+ var rows = [0, 0, 0, 1, 1, 1, 2, 2, 2];
216
+ var cols = [0, 1, 2, 0, 1, 2, 0, 1, 2];
217
+ var vals = [1, 2, 3, 4, 5, 6, 7, 8, 9];
218
+ var dims = [3, 3];
219
+ jsA = new matrix_1.SparseMatrix(rows, cols, vals, dims);
220
+ wasmA = (0, wasmBridge_1.createSparseMatrixWasm)(rows, cols, vals, dims[0], dims[1]);
221
+ });
222
+ afterEach(function () {
223
+ wasmA.free();
224
+ });
225
+ test.each([
226
+ ['max', "max"],
227
+ ['l1', "l1"],
228
+ ['l2', "l2"],
229
+ ])('%s normalization produces identical results', function (normName, normType) {
230
+ var jsResult = (0, matrix_1.normalize)(jsA, normType);
231
+ var wasmResult = (0, wasmBridge_1.sparseNormalizeWasm)(wasmA, normName);
232
+ expectArraysClose((0, wasmBridge_1.wasmSparseMatrixToArray)(wasmResult), jsResult.toArray());
233
+ wasmResult.free();
234
+ });
235
+ });
236
+ describe('CSR conversion', function () {
237
+ test('getCSR produces identical results', function () {
238
+ var rows = [0, 0, 0, 1, 1, 1, 2, 2, 2];
239
+ var cols = [0, 1, 2, 0, 1, 2, 0, 1, 2];
240
+ var vals = [1, 2, 3, 4, 5, 6, 7, 8, 9];
241
+ var dims = [3, 3];
242
+ var jsA = new matrix_1.SparseMatrix(rows, cols, vals, dims);
243
+ var wasmA = (0, wasmBridge_1.createSparseMatrixWasm)(rows, cols, vals, dims[0], dims[1]);
244
+ var jsCSR = (0, matrix_1.getCSR)(jsA);
245
+ var wasmCSR = (0, wasmBridge_1.sparseGetCSRWasm)(wasmA);
246
+ expect(wasmCSR.indices).toEqual(jsCSR.indices);
247
+ expect(wasmCSR.values).toEqual(jsCSR.values);
248
+ expect(wasmCSR.indptr).toEqual(jsCSR.indptr);
249
+ wasmA.free();
250
+ });
251
+ });
252
+ describe('edge cases', function () {
253
+ test('handles empty matrix', function () {
254
+ var rows = [];
255
+ var cols = [];
256
+ var vals = [];
257
+ var dims = [3, 3];
258
+ var jsMatrix = new matrix_1.SparseMatrix(rows, cols, vals, dims);
259
+ var wasmMatrix = (0, wasmBridge_1.createSparseMatrixWasm)(rows, cols, vals, dims[0], dims[1]);
260
+ expect(wasmMatrix.nnz()).toEqual(0);
261
+ expect((0, wasmBridge_1.wasmSparseMatrixToArray)(wasmMatrix)).toEqual(jsMatrix.toArray());
262
+ wasmMatrix.free();
263
+ });
264
+ test('handles single element matrix', function () {
265
+ var rows = [0];
266
+ var cols = [0];
267
+ var vals = [42];
268
+ var dims = [1, 1];
269
+ var jsMatrix = new matrix_1.SparseMatrix(rows, cols, vals, dims);
270
+ var wasmMatrix = (0, wasmBridge_1.createSparseMatrixWasm)(rows, cols, vals, dims[0], dims[1]);
271
+ expect(wasmMatrix.get(0, 0, 0)).toEqual(jsMatrix.get(0, 0));
272
+ expect((0, wasmBridge_1.wasmSparseMatrixToArray)(wasmMatrix)).toEqual(jsMatrix.toArray());
273
+ wasmMatrix.free();
274
+ });
275
+ test('handles sparse matrix with gaps', function () {
276
+ var rows = [0, 2];
277
+ var cols = [0, 2];
278
+ var vals = [1, 9];
279
+ var dims = [3, 3];
280
+ var jsMatrix = new matrix_1.SparseMatrix(rows, cols, vals, dims);
281
+ var wasmMatrix = (0, wasmBridge_1.createSparseMatrixWasm)(rows, cols, vals, dims[0], dims[1]);
282
+ expect((0, wasmBridge_1.wasmSparseMatrixToArray)(wasmMatrix)).toEqual(jsMatrix.toArray());
283
+ expect(wasmMatrix.get(1, 1, -1)).toEqual(jsMatrix.get(1, 1, -1));
284
+ wasmMatrix.free();
285
+ });
286
+ test('handles non-square matrices and transpose', function () {
287
+ var rows = [0, 0, 0, 1, 1, 1];
288
+ var cols = [0, 1, 2, 0, 1, 2];
289
+ var vals = [1, 2, 3, 4, 5, 6];
290
+ var dims = [2, 3];
291
+ var jsMatrix = new matrix_1.SparseMatrix(rows, cols, vals, dims);
292
+ var wasmMatrix = (0, wasmBridge_1.createSparseMatrixWasm)(rows, cols, vals, dims[0], dims[1]);
293
+ expect(wasmMatrix.n_rows).toEqual(jsMatrix.nRows);
294
+ expect(wasmMatrix.n_cols).toEqual(jsMatrix.nCols);
295
+ expect((0, wasmBridge_1.wasmSparseMatrixToArray)(wasmMatrix)).toEqual(jsMatrix.toArray());
296
+ var jsT = (0, matrix_1.transpose)(jsMatrix);
297
+ var wasmT = (0, wasmBridge_1.sparseTransposeWasm)(wasmMatrix);
298
+ expect(wasmT.n_rows).toEqual(jsT.nRows);
299
+ expect(wasmT.n_cols).toEqual(jsT.nCols);
300
+ expect((0, wasmBridge_1.wasmSparseMatrixToArray)(wasmT)).toEqual(jsT.toArray());
301
+ wasmMatrix.free();
302
+ wasmT.free();
303
+ });
304
+ test('handles large sparse matrix', function () {
305
+ var size = 100;
306
+ var nnz = 500;
307
+ var rows = [];
308
+ var cols = [];
309
+ var vals = [];
310
+ var rng = function (seed) {
311
+ var x = seed;
312
+ return function () {
313
+ x = (x * 1103515245 + 12345) & 0x7fffffff;
314
+ return x;
315
+ };
316
+ };
317
+ var random = rng(12345);
318
+ for (var i = 0; i < nnz; i++) {
319
+ rows.push(random() % size);
320
+ cols.push(random() % size);
321
+ vals.push(random() % 100);
322
+ }
323
+ var dims = [size, size];
324
+ var jsMatrix = new matrix_1.SparseMatrix(rows, cols, vals, dims);
325
+ var wasmMatrix = (0, wasmBridge_1.createSparseMatrixWasm)(rows, cols, vals, dims[0], dims[1]);
326
+ expect((0, wasmBridge_1.wasmSparseMatrixToArray)(wasmMatrix)).toEqual(jsMatrix.toArray());
327
+ wasmMatrix.free();
328
+ });
329
+ });
330
+ });
331
+ describe('useWasmMatrix toggle', function () {
332
+ var UMAP;
333
+ beforeAll(function () { return __awaiter(void 0, void 0, void 0, function () {
334
+ var umap;
335
+ return __generator(this, function (_a) {
336
+ switch (_a.label) {
337
+ case 0: return [4, Promise.resolve().then(function () { return __importStar(require('../src/umap')); })];
338
+ case 1:
339
+ umap = _a.sent();
340
+ UMAP = umap.UMAP;
341
+ return [2];
342
+ }
343
+ });
344
+ }); });
345
+ var testData = [[1, 2], [3, 4], [5, 6]];
346
+ test('uses JS matrix operations when useWasmMatrix is false', function () {
347
+ var umap = new UMAP({ useWasmMatrix: false, nNeighbors: 2, nEpochs: 5 });
348
+ var embedding = umap.fit(testData);
349
+ expect(embedding).toBeDefined();
350
+ expect(embedding.length).toBe(testData.length);
351
+ expect(embedding[0].length).toBe(2);
352
+ });
353
+ test('delegates to wasm when useWasmMatrix is true', function () { return __awaiter(void 0, void 0, void 0, function () {
354
+ var createMatrixMock, isWasmAvailableMock, sparseAddMock, sparseSubtractMock, sparseTransposeMock, sparsePairwiseMultiplyMock, sparseMultiplyScalarMock, wasmSparseMatrixGetAllMock, umap, embedding;
355
+ return __generator(this, function (_a) {
356
+ createMatrixMock = vitest_1.vi.spyOn(wasmBridge, 'createSparseMatrixWasm').mockImplementation(function () {
357
+ return {
358
+ free: function () { },
359
+ n_rows: 3,
360
+ n_cols: 3,
361
+ nnz: function () { return 4; },
362
+ get: function () { return 0; },
363
+ set: function () { },
364
+ };
365
+ });
366
+ isWasmAvailableMock = vitest_1.vi.spyOn(wasmBridge, 'isWasmAvailable').mockImplementation(function () { return true; });
367
+ sparseAddMock = vitest_1.vi.spyOn(wasmBridge, 'sparseAddWasm').mockImplementation(function (a, b) { return a; });
368
+ sparseSubtractMock = vitest_1.vi.spyOn(wasmBridge, 'sparseSubtractWasm').mockImplementation(function (a, b) { return a; });
369
+ sparseTransposeMock = vitest_1.vi.spyOn(wasmBridge, 'sparseTransposeWasm').mockImplementation(function (a) { return a; });
370
+ sparsePairwiseMultiplyMock = vitest_1.vi.spyOn(wasmBridge, 'sparsePairwiseMultiplyWasm').mockImplementation(function (a, b) { return a; });
371
+ sparseMultiplyScalarMock = vitest_1.vi.spyOn(wasmBridge, 'sparseMultiplyScalarWasm').mockImplementation(function (a, s) { return a; });
372
+ wasmSparseMatrixGetAllMock = vitest_1.vi.spyOn(wasmBridge, 'wasmSparseMatrixGetAll').mockImplementation(function () { return []; });
373
+ umap = new UMAP({ useWasmMatrix: true, nNeighbors: 2, nEpochs: 5 });
374
+ embedding = umap.fit(testData);
375
+ expect(createMatrixMock).toHaveBeenCalled();
376
+ expect(sparseTransposeMock).toHaveBeenCalled();
377
+ expect(embedding).toBeDefined();
378
+ createMatrixMock.mockRestore();
379
+ isWasmAvailableMock.mockRestore();
380
+ sparseAddMock.mockRestore();
381
+ sparseSubtractMock.mockRestore();
382
+ sparseTransposeMock.mockRestore();
383
+ sparsePairwiseMultiplyMock.mockRestore();
384
+ sparseMultiplyScalarMock.mockRestore();
385
+ wasmSparseMatrixGetAllMock.mockRestore();
386
+ return [2];
387
+ });
388
+ }); });
389
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,212 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
+ return new (P || (P = Promise))(function (resolve, reject) {
38
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
42
+ });
43
+ };
44
+ var __generator = (this && this.__generator) || function (thisArg, body) {
45
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
46
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
47
+ function verb(n) { return function (v) { return step([n, v]); }; }
48
+ function step(op) {
49
+ if (f) throw new TypeError("Generator is already executing.");
50
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
51
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
52
+ if (y = 0, t) op = [op[0] & 2, t.value];
53
+ switch (op[0]) {
54
+ case 0: case 1: t = op; break;
55
+ case 4: _.label++; return { value: op[1], done: false };
56
+ case 5: _.label++; y = op[1]; op = [0]; continue;
57
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
58
+ default:
59
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
60
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
61
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
62
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
63
+ if (t[2]) _.ops.pop();
64
+ _.trys.pop(); continue;
65
+ }
66
+ op = body.call(thisArg, _);
67
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
68
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
69
+ }
70
+ };
71
+ var __importDefault = (this && this.__importDefault) || function (mod) {
72
+ return (mod && mod.__esModule) ? mod : { "default": mod };
73
+ };
74
+ Object.defineProperty(exports, "__esModule", { value: true });
75
+ var tree = __importStar(require("../src/tree"));
76
+ var wasmBridge_1 = require("../src/wasmBridge");
77
+ var test_data_1 = require("./test_data");
78
+ var prando_1 = __importDefault(require("prando"));
79
+ describe('WASM random projection tree', function () {
80
+ var STANDARD_NEIGHBORS = 15;
81
+ var STANDARD_TREES = 3;
82
+ var prando = new prando_1.default(42);
83
+ var random = function () { return prando.next(); };
84
+ beforeAll(function () { return __awaiter(void 0, void 0, void 0, function () {
85
+ return __generator(this, function (_a) {
86
+ switch (_a.label) {
87
+ case 0: return [4, (0, wasmBridge_1.initWasm)()];
88
+ case 1:
89
+ _a.sent();
90
+ if (!(0, wasmBridge_1.isWasmAvailable)()) {
91
+ throw new Error('WASM module failed to initialize; tests require WASM');
92
+ }
93
+ return [2];
94
+ }
95
+ });
96
+ }); });
97
+ test('WASM module can be initialized', function () {
98
+ expect((0, wasmBridge_1.isWasmAvailable)()).toBe(true);
99
+ });
100
+ test('makeForest with WASM creates correct number of trees', function () {
101
+ var nTrees = 6;
102
+ var forest = tree.makeForest(test_data_1.testData, STANDARD_NEIGHBORS, nTrees, random, true);
103
+ expect(forest.length).toEqual(nTrees);
104
+ expect(forest[0]).toBeInstanceOf(tree.FlatTree);
105
+ });
106
+ test('WASM forest has valid tree structure', function () {
107
+ prando.reset();
108
+ var jsForest = tree.makeForest(test_data_1.testData, STANDARD_NEIGHBORS, STANDARD_TREES, random, false);
109
+ prando.reset();
110
+ var wasmForest = tree.makeForest(test_data_1.testData, STANDARD_NEIGHBORS, STANDARD_TREES, random, true);
111
+ expect(wasmForest.length).toEqual(jsForest.length);
112
+ wasmForest.forEach(function (tree) {
113
+ expect(tree.hyperplanes.length).toBeGreaterThan(0);
114
+ expect(tree.offsets.length).toBeGreaterThan(0);
115
+ expect(tree.children.length).toBeGreaterThan(0);
116
+ expect(tree.indices.length).toBeGreaterThan(0);
117
+ });
118
+ });
119
+ test('searchFlatTree returns valid indices within bounds', function () {
120
+ prando.reset();
121
+ var forest = tree.makeForest(test_data_1.testData, STANDARD_NEIGHBORS, STANDARD_TREES, random, true);
122
+ var queryPoint = test_data_1.testData[0];
123
+ prando.reset();
124
+ var result = tree.searchFlatTree(queryPoint, forest[0], random);
125
+ expect(result).toBeDefined();
126
+ expect(Array.isArray(result)).toBe(true);
127
+ expect(result.length).toBeGreaterThan(0);
128
+ expect(result.length).toBeLessThanOrEqual(Math.max(10, STANDARD_NEIGHBORS));
129
+ result.forEach(function (idx) {
130
+ expect(idx).toBeGreaterThanOrEqual(0);
131
+ expect(idx).toBeLessThan(test_data_1.testData.length);
132
+ });
133
+ });
134
+ test('makeLeafArray concatenates tree indices correctly', function () {
135
+ prando.reset();
136
+ var forest = tree.makeForest(test_data_1.testData, STANDARD_NEIGHBORS, STANDARD_TREES, random, true);
137
+ var leafArray = tree.makeLeafArray(forest);
138
+ expect(leafArray).toBeDefined();
139
+ expect(leafArray.length).toBeGreaterThan(0);
140
+ var firstTreeIndices = forest[0].indices;
141
+ expect(leafArray.slice(0, firstTreeIndices.length)).toEqual(firstTreeIndices);
142
+ });
143
+ test('WASM and JS implementations both produce valid search results', function () {
144
+ var nTrees = 2;
145
+ var queryPoint = test_data_1.testData[5];
146
+ prando.reset();
147
+ var jsForest = tree.makeForest(test_data_1.testData, STANDARD_NEIGHBORS, nTrees, random, false);
148
+ prando.reset();
149
+ var wasmForest = tree.makeForest(test_data_1.testData, STANDARD_NEIGHBORS, nTrees, random, true);
150
+ prando.reset();
151
+ var jsResults = tree.searchFlatTree(queryPoint, jsForest[0], random);
152
+ prando.reset();
153
+ var wasmResults = tree.searchFlatTree(queryPoint, wasmForest[0], random);
154
+ expect(jsResults.length).toBeGreaterThan(0);
155
+ expect(wasmResults.length).toBeGreaterThan(0);
156
+ expect(wasmResults.length).toBeLessThanOrEqual(Math.max(10, STANDARD_NEIGHBORS));
157
+ expect(jsResults.length).toBeLessThanOrEqual(Math.max(10, STANDARD_NEIGHBORS));
158
+ });
159
+ test('FlatTree dispose cleans up WASM resources', function () {
160
+ prando.reset();
161
+ var forest = tree.makeForest(test_data_1.testData, STANDARD_NEIGHBORS, 1, random, true);
162
+ var flatTree = forest[0];
163
+ expect(flatTree.getWasmTree()).toBeDefined();
164
+ flatTree.dispose();
165
+ expect(flatTree.getWasmTree()).toBeUndefined();
166
+ });
167
+ });
168
+ describe('useWasmTree toggle', function () {
169
+ var UMAP;
170
+ beforeAll(function () { return __awaiter(void 0, void 0, void 0, function () {
171
+ var umap;
172
+ return __generator(this, function (_a) {
173
+ switch (_a.label) {
174
+ case 0: return [4, Promise.resolve().then(function () { return __importStar(require('../src/umap')); })];
175
+ case 1:
176
+ umap = _a.sent();
177
+ UMAP = umap.UMAP;
178
+ return [2];
179
+ }
180
+ });
181
+ }); });
182
+ var testData = [[1, 2], [3, 4], [5, 6]];
183
+ test('uses JS tree when useWasmTree is false', function () {
184
+ var umap = new UMAP({ useWasmTree: false, nNeighbors: 2, nEpochs: 5 });
185
+ var embedding = umap.fit(testData);
186
+ expect(embedding).toBeDefined();
187
+ expect(embedding.length).toBe(testData.length);
188
+ var rpForest = umap.rpForest;
189
+ expect(rpForest.length).toBeGreaterThan(0);
190
+ expect(rpForest[0].getWasmTree()).toBeUndefined();
191
+ });
192
+ test('delegates to wasm when useWasmTree is true', function () { return __awaiter(void 0, void 0, void 0, function () {
193
+ var umap, embedding, rpForest;
194
+ return __generator(this, function (_a) {
195
+ switch (_a.label) {
196
+ case 0: return [4, (0, wasmBridge_1.initWasm)()];
197
+ case 1:
198
+ _a.sent();
199
+ if (!(0, wasmBridge_1.isWasmAvailable)()) {
200
+ throw new Error('WASM module failed to initialize; tests require WASM');
201
+ }
202
+ umap = new UMAP({ useWasmTree: true, nNeighbors: 2, nEpochs: 5 });
203
+ embedding = umap.fit(testData);
204
+ rpForest = umap.rpForest;
205
+ expect(rpForest.length).toBeGreaterThan(0);
206
+ expect(rpForest[0].getWasmTree()).toBeDefined();
207
+ expect(embedding).toBeDefined();
208
+ return [2];
209
+ }
210
+ });
211
+ }); });
212
+ });