usearch 2.9.2 → 2.10.1

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 (172) hide show
  1. package/README.md +39 -38
  2. package/javascript/{types → dist/cjs}/usearch.d.ts +90 -115
  3. package/javascript/dist/cjs/usearch.js +531 -0
  4. package/javascript/dist/esm/usearch.d.ts +212 -0
  5. package/javascript/{usearch.js → dist/esm/usearch.js} +199 -153
  6. package/package.json +25 -23
  7. package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
  8. package/prebuilds/linux-arm64/usearch.node +0 -0
  9. package/prebuilds/linux-x64/usearch.node +0 -0
  10. package/prebuilds/win32-ia32/usearch.node +0 -0
  11. package/prebuilds/win32-x64/usearch.node +0 -0
  12. package/.clang-format +0 -10
  13. package/.clang-tidy +0 -60
  14. package/.cmake-format.py +0 -19
  15. package/.dockerignore +0 -93
  16. package/.gitattributes +0 -9
  17. package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -90
  18. package/.github/ISSUE_TEMPLATE/config.yml +0 -5
  19. package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -64
  20. package/.github/workflows/Dockerfile.libs +0 -36
  21. package/.github/workflows/prerelease.yml +0 -331
  22. package/.github/workflows/release.yml +0 -722
  23. package/.github/workflows/update_version.sh +0 -15
  24. package/.gitmodules +0 -9
  25. package/.releaserc +0 -90
  26. package/CITATION.cff +0 -11
  27. package/CMakeLists.txt +0 -324
  28. package/CODE_OF_CONDUCT.md +0 -128
  29. package/CONTRIBUTING.md +0 -361
  30. package/Cargo.toml +0 -19
  31. package/Dockerfile +0 -16
  32. package/VERSION +0 -1
  33. package/assets/unum.png +0 -0
  34. package/assets/usearch-approaches-transparent.png +0 -0
  35. package/assets/usearch-approaches-white.png +0 -0
  36. package/assets/usearch-neighbor-types.png +0 -0
  37. package/binding.gyp +0 -87
  38. package/build.gradle +0 -204
  39. package/build.rs +0 -18
  40. package/c/CMakeLists.txt +0 -25
  41. package/c/README.md +0 -34
  42. package/c/lib.cpp +0 -358
  43. package/c/test.c +0 -382
  44. package/c/usearch.h +0 -311
  45. package/cmake/clipp.cmake +0 -7
  46. package/cmake/config.cmake.in +0 -15
  47. package/cmake/emscripten.cmake +0 -8
  48. package/cmake/jemalloc.cmake +0 -62
  49. package/cmake/pkg-config.pc.in +0 -4
  50. package/cmake/usearchConfigVersion.cmake.in +0 -20
  51. package/conanfile.py +0 -26
  52. package/cpp/CMakeLists.txt +0 -14
  53. package/cpp/README.md +0 -161
  54. package/cpp/bench.cpp +0 -618
  55. package/cpp/test.cpp +0 -323
  56. package/fp16/CMakeLists.txt +0 -176
  57. package/fp16/LICENSE +0 -11
  58. package/fp16/README.md +0 -20
  59. package/fp16/bench/alt-element.cc +0 -89
  60. package/fp16/bench/from-alt-array.cc +0 -175
  61. package/fp16/bench/from-ieee-array.cc +0 -399
  62. package/fp16/bench/ieee-element.cc +0 -272
  63. package/fp16/bench/to-alt-array.cc +0 -91
  64. package/fp16/bench/to-ieee-array.cc +0 -303
  65. package/fp16/cmake/DownloadGoogleBenchmark.cmake +0 -15
  66. package/fp16/cmake/DownloadGoogleTest.cmake +0 -15
  67. package/fp16/cmake/DownloadPSimd.cmake +0 -15
  68. package/fp16/configure.py +0 -65
  69. package/fp16/confu.yaml +0 -8
  70. package/fp16/include/fp16/__init__.py +0 -0
  71. package/fp16/include/fp16/avx.py +0 -50
  72. package/fp16/include/fp16/avx2.py +0 -53
  73. package/fp16/include/fp16/bitcasts.h +0 -92
  74. package/fp16/include/fp16/fp16.h +0 -451
  75. package/fp16/include/fp16/psimd.h +0 -131
  76. package/fp16/include/fp16.h +0 -11
  77. package/fp16/jni/Android.mk +0 -6
  78. package/fp16/jni/Application.mk +0 -4
  79. package/fp16/test/alt-from-fp32-value.cc +0 -498
  80. package/fp16/test/alt-to-fp32-bits.cc +0 -263
  81. package/fp16/test/alt-to-fp32-psimd.cc +0 -145
  82. package/fp16/test/alt-to-fp32-value.cc +0 -348
  83. package/fp16/test/alt-to-fp32x2-psimd.cc +0 -245
  84. package/fp16/test/bitcasts.cc +0 -56
  85. package/fp16/test/ieee-from-fp32-value.cc +0 -523
  86. package/fp16/test/ieee-to-fp32-bits.cc +0 -333
  87. package/fp16/test/ieee-to-fp32-psimd.cc +0 -312
  88. package/fp16/test/ieee-to-fp32-value.cc +0 -420
  89. package/fp16/test/ieee-to-fp32x2-psimd.cc +0 -541
  90. package/fp16/test/peachpy/alt-xmm-to-fp32-xmm-avx.cc +0 -96
  91. package/fp16/test/peachpy/alt-xmm-to-fp32-ymm-avx2.cc +0 -96
  92. package/fp16/test/peachpy/stubs.py +0 -38
  93. package/fp16/test/tables.cc +0 -530
  94. package/fp16/test/tables.h +0 -13
  95. package/fp16/third-party/THHalf.h +0 -92
  96. package/fp16/third-party/eigen-half.h +0 -170
  97. package/fp16/third-party/float16-compressor.h +0 -80
  98. package/fp16/third-party/half.hpp +0 -2916
  99. package/fp16/third-party/npy-halffloat.h +0 -328
  100. package/include/usearch/index.hpp +0 -3836
  101. package/include/usearch/index_dense.hpp +0 -2004
  102. package/include/usearch/index_plugins.hpp +0 -2213
  103. package/javascript/lib.cpp +0 -341
  104. package/javascript/types/usearch.d.ts.map +0 -1
  105. package/javascript/usearch.test.js +0 -74
  106. package/package-ci.json +0 -10
  107. package/pyproject.toml +0 -51
  108. package/setup.py +0 -201
  109. package/simsimd/.releaserc +0 -86
  110. package/simsimd/CONTRIBUTING.md +0 -88
  111. package/simsimd/Cargo.lock +0 -709
  112. package/simsimd/Cargo.toml +0 -44
  113. package/simsimd/LICENSE +0 -201
  114. package/simsimd/README.md +0 -317
  115. package/simsimd/binding.gyp +0 -36
  116. package/simsimd/build.rs +0 -20
  117. package/simsimd/include/simsimd/binary.h +0 -245
  118. package/simsimd/include/simsimd/complex.h +0 -174
  119. package/simsimd/include/simsimd/probability.h +0 -548
  120. package/simsimd/include/simsimd/simsimd.h +0 -465
  121. package/simsimd/include/simsimd/spatial.h +0 -1267
  122. package/simsimd/include/simsimd/types.h +0 -208
  123. package/simsimd/javascript/bench.js +0 -127
  124. package/simsimd/javascript/fallback.ts +0 -193
  125. package/simsimd/javascript/lib.c +0 -102
  126. package/simsimd/javascript/node-gyp-build.d.ts +0 -1
  127. package/simsimd/javascript/simsimd.ts +0 -124
  128. package/simsimd/javascript/test.mjs +0 -153
  129. package/simsimd/javascript/tsconfig-base.json +0 -25
  130. package/simsimd/javascript/tsconfig-cjs.json +0 -8
  131. package/simsimd/javascript/tsconfig-esm.json +0 -8
  132. package/simsimd/package-lock.json +0 -1688
  133. package/simsimd/package.json +0 -61
  134. package/simsimd/rust/benches/cosine.rs +0 -27
  135. package/simsimd/rust/benches/native.rs +0 -30
  136. package/simsimd/rust/benches/sqeuclidean.rs +0 -27
  137. package/simsimd/rust/lib.c +0 -45
  138. package/simsimd/rust/lib.rs +0 -550
  139. package/sqlite/README.md +0 -178
  140. package/sqlite/lib.cpp +0 -325
  141. package/stringzilla/CONTRIBUTING.md +0 -446
  142. package/stringzilla/Cargo.lock +0 -25
  143. package/stringzilla/Cargo.toml +0 -26
  144. package/stringzilla/LICENSE +0 -201
  145. package/stringzilla/README.md +0 -1422
  146. package/stringzilla/VERSION +0 -1
  147. package/stringzilla/assets/cover-strinzilla.jpeg +0 -0
  148. package/stringzilla/assets/meme-stringzilla-v2.jpeg +0 -0
  149. package/stringzilla/assets/meme-stringzilla-v3.jpeg +0 -0
  150. package/stringzilla/binding.gyp +0 -16
  151. package/stringzilla/build.rs +0 -87
  152. package/stringzilla/c/lib.c +0 -337
  153. package/stringzilla/cli/README.md +0 -65
  154. package/stringzilla/cli/__init__.py +0 -0
  155. package/stringzilla/cli/split.py +0 -105
  156. package/stringzilla/cli/wc.py +0 -117
  157. package/stringzilla/include/stringzilla/experimental.h +0 -845
  158. package/stringzilla/include/stringzilla/module.modulemap +0 -9
  159. package/stringzilla/include/stringzilla/stringzilla.h +0 -5370
  160. package/stringzilla/include/stringzilla/stringzilla.hpp +0 -3838
  161. package/stringzilla/javascript/lib.c +0 -125
  162. package/stringzilla/javascript/stringzilla.js +0 -22
  163. package/stringzilla/package-ci.json +0 -10
  164. package/stringzilla/package.json +0 -32
  165. package/stringzilla/rust/lib.rs +0 -873
  166. package/stringzilla/swift/StringProtocol+StringZilla.swift +0 -280
  167. package/stringzilla/swift/Test.swift +0 -60
  168. package/tsconfig.json +0 -21
  169. package/wasmer.toml +0 -12
  170. package/winlibinstaller.bat +0 -42
  171. /package/{simsimd/javascript/dist-package-cjs.json → javascript/dist/cjs/package.json} +0 -0
  172. /package/{simsimd/javascript/dist-package-esm.json → javascript/dist/esm/package.json} +0 -0
@@ -1,45 +1,50 @@
1
- const compiled = require('bindings')('usearch');
2
-
1
+ import build from "node-gyp-build";
2
+ import * as path from "node:path";
3
+ import { existsSync } from "node:fs";
4
+ import { getFileName, getRoot } from "bindings";
5
+ const compiled = build(getBuildDir(getDirName()));
3
6
  /**
4
7
  * Enumeration representing the various metric kinds used to measure the distance between vectors in the index.
5
8
  * @enum {string}
6
9
  * @readonly
7
10
  */
8
- const MetricKind = {
9
- Unknown: 'unknown',
10
- Cos: 'cos',
11
- IP: 'ip',
12
- L2sq: 'l2sq',
13
- Haversine: 'haversine',
14
- Divergence: 'divergence',
15
- Pearson: 'pearson',
16
- Jaccard: 'jaccard',
17
- Hamming: 'hamming',
18
- Tanimoto: 'tanimoto',
19
- Sorensen: 'sorensen'
20
- };
21
-
11
+ export var MetricKind;
12
+ (function (MetricKind) {
13
+ MetricKind["Unknown"] = "unknown";
14
+ MetricKind["Cos"] = "cos";
15
+ MetricKind["IP"] = "ip";
16
+ MetricKind["L2sq"] = "l2sq";
17
+ MetricKind["Haversine"] = "haversine";
18
+ MetricKind["Divergence"] = "divergence";
19
+ MetricKind["Pearson"] = "pearson";
20
+ MetricKind["Jaccard"] = "jaccard";
21
+ MetricKind["Hamming"] = "hamming";
22
+ MetricKind["Tanimoto"] = "tanimoto";
23
+ MetricKind["Sorensen"] = "sorensen";
24
+ })(MetricKind || (MetricKind = {}));
22
25
  /**
23
26
  * Enumeration representing the various scalar kinds used to define the type of scalar values in vectors.
24
27
  * @enum {string}
25
28
  * @readonly
26
29
  */
27
- const ScalarKind = {
28
- Unknown: 'unknown',
29
- F32: 'f32',
30
- F64: 'f64',
31
- F16: 'f16',
32
- I8: 'i8',
33
- B1: 'b1'
34
- };
35
-
30
+ export var ScalarKind;
31
+ (function (ScalarKind) {
32
+ ScalarKind["Unknown"] = "unknown";
33
+ ScalarKind["F32"] = "f32";
34
+ ScalarKind["F64"] = "f64";
35
+ ScalarKind["F16"] = "f16";
36
+ ScalarKind["I8"] = "i8";
37
+ ScalarKind["B1"] = "b1";
38
+ })(ScalarKind || (ScalarKind = {}));
36
39
  /**
37
40
  * Represents a set of search results.
38
41
  */
39
- class Matches {
42
+ export class Matches {
43
+ keys;
44
+ distances;
40
45
  /**
41
46
  * Constructs a Matches object.
42
- *
47
+ *
43
48
  * @param {BigUint64Array} keys - The keys of the nearest neighbors found.
44
49
  * @param {Float32Array} distances - The distances of the nearest neighbors found.
45
50
  */
@@ -48,18 +53,21 @@ class Matches {
48
53
  this.distances = distances;
49
54
  }
50
55
  }
51
-
52
56
  /**
53
57
  * Represents a set of batched search results.
54
58
  */
55
- class BatchMatches {
59
+ export class BatchMatches {
60
+ keys;
61
+ distances;
62
+ counts;
63
+ k;
56
64
  /**
57
65
  * Constructs a BatchMatches object.
58
- *
66
+ *
59
67
  * @param {BigUint64Array} keys - The keys of the nearest neighbors found in the batch.
60
68
  * @param {Float32Array} distances - The distances of the nearest neighbors found in the batch.
61
69
  * @param {BigUint64Array} counts - The number of neighbors found for each query in the batch.
62
- * @param {bigint} k - The limit for search results per query in the batch.
70
+ * @param {number} k - The limit for search results per query in the batch.
63
71
  */
64
72
  constructor(keys, distances, counts, k) {
65
73
  this.keys = keys;
@@ -67,10 +75,9 @@ class BatchMatches {
67
75
  this.counts = counts;
68
76
  this.k = k;
69
77
  }
70
-
71
78
  /**
72
79
  * Retrieves a Matches object at the specified index in the batch.
73
- *
80
+ *
74
81
  * @param {number} i - The index at which to retrieve the Matches object.
75
82
  * @returns {Matches} - A Matches object representing the search results at the specified index in the batch.
76
83
  */
@@ -82,61 +89,74 @@ class BatchMatches {
82
89
  return new Matches(keysSlice, distancesSlice);
83
90
  }
84
91
  }
85
-
86
92
  function isOneKey(keys) {
87
- return (!Number.isNaN(keys) && typeof keys === 'number') || typeof keys === 'bigint';
93
+ return ((!Number.isNaN(keys) && typeof keys === "number") ||
94
+ typeof keys === "bigint");
88
95
  }
89
-
90
96
  function normalizeKeys(keys) {
91
- if (isOneKey(keys)) {
92
- keys = BigUint64Array.of(BigInt(keys));
93
- } else if (Array.isArray(keys)) {
94
- keys = keys.map(key => {
95
- if ((typeof key !== 'bigint' && typeof key !== 'number') || Number.isNaN(key))
96
- throw new Error("All keys must be integers or bigints.");
97
- return BigInt(key);
97
+ if (keys instanceof BigUint64Array) {
98
+ return keys;
99
+ }
100
+ let normalizedKeys;
101
+ if ((typeof keys === "number" && !Number.isNaN(keys)) ||
102
+ typeof keys === "bigint") {
103
+ normalizedKeys = BigUint64Array.of(BigInt(keys));
104
+ }
105
+ else if (Array.isArray(keys)) {
106
+ const bigintkeys = keys.map((key) => {
107
+ if (typeof key === "bigint") {
108
+ return key;
109
+ }
110
+ else if (typeof key === "number" &&
111
+ !Number.isNaN(key) &&
112
+ Number.isInteger(key) &&
113
+ key >= 0) {
114
+ return BigInt(key);
115
+ }
116
+ throw new Error("All keys must be positive integers or bigints.");
98
117
  });
99
- keys = BigUint64Array.from(keys);
100
- } else if (!(keys instanceof BigUint64Array)) {
118
+ normalizedKeys = BigUint64Array.from(bigintkeys);
119
+ }
120
+ else {
101
121
  throw new Error("Keys must be a number, bigint, an array of numbers or bigints, or a BigUint64Array.");
102
122
  }
103
- return keys;
123
+ return normalizedKeys;
104
124
  }
105
-
106
125
  function isVector(vectors) {
107
- return vectors instanceof Float32Array || vectors instanceof Float64Array || vectors instanceof Int8Array;
126
+ return (vectors instanceof Float32Array ||
127
+ vectors instanceof Float64Array ||
128
+ vectors instanceof Int8Array);
108
129
  }
109
-
110
130
  function normalizeVectors(vectors, dimensions, targetType = Float32Array) {
111
131
  let flattenedVectors;
112
132
  if (isVector(vectors)) {
113
- flattenedVectors = (vectors.constructor === targetType) ? vectors : new targetType(vectors);
114
- } else if (Array.isArray(vectors)) {
133
+ flattenedVectors =
134
+ vectors.constructor === targetType
135
+ ? vectors
136
+ : new targetType(vectors);
137
+ }
138
+ else if (Array.isArray(vectors)) {
115
139
  let totalLength = 0;
116
- for (const vec of vectors) totalLength += vec.length;
117
-
140
+ for (const vec of vectors)
141
+ totalLength += vec.length;
118
142
  flattenedVectors = new targetType(totalLength);
119
143
  let offset = 0;
120
144
  for (const vec of vectors) {
121
145
  flattenedVectors.set(vec, offset);
122
146
  offset += vec.length;
123
147
  }
124
- } else {
148
+ }
149
+ else {
125
150
  throw new Error("Vectors must be a TypedArray or an array of arrays.");
126
151
  }
127
-
128
152
  if (flattenedVectors.length % dimensions !== 0)
129
153
  throw new Error("The size of the flattened vectors must be a multiple of the dimension of the vectors.");
130
-
131
154
  return flattenedVectors;
132
155
  }
133
-
134
-
135
- class Index {
136
-
156
+ export class Index {
137
157
  /**
138
158
  * Constructs a new index.
139
- *
159
+ *
140
160
  * @param {(number | {dimensions: number, metric: MetricKind = MetricKind.Cos, quantization: ScalarKind = ScalarKind.F32, connectivity: number = 0, expansion_add: number = 0, expansion_search: number = 0, multi: boolean = false})} dimensionsOrConfigs
141
161
  * @param {MetricKind} [metric=MetricKind.Cos] - Optional, default is 'cos'.
142
162
  * @param {ScalarKind} [quantization=ScalarKind.F32] - Optional, default is 'f32'.
@@ -148,53 +168,62 @@ class Index {
148
168
  */
149
169
  constructor(dimensionsOrConfigs, metric = MetricKind.Cos, quantization = ScalarKind.F32, connectivity = 0, expansion_add = 0, expansion_search = 0, multi = false) {
150
170
  let dimensions;
151
- if (typeof dimensionsOrConfigs === 'object' && dimensionsOrConfigs !== null) {
152
- // Parameters are provided as an object
153
- ({ dimensions, metric = MetricKind.Cos, quantization = ScalarKind.F32, connectivity = 0, expansion_add = 0, expansion_search = 0, multi = false } = dimensionsOrConfigs);
154
- } else if ((typeof dimensionsOrConfigs === 'number' && !Number.isNaN(dimensionsOrConfigs)) || typeof dimensionsOrConfigs === 'bigint') {
171
+ if ((typeof dimensionsOrConfigs === "number" &&
172
+ !Number.isNaN(dimensionsOrConfigs)) ||
173
+ typeof dimensionsOrConfigs === "bigint") {
155
174
  // Parameters are provided as individual arguments
156
175
  dimensions = dimensionsOrConfigs;
157
- } else {
176
+ }
177
+ else if (typeof dimensionsOrConfigs === "object" &&
178
+ dimensionsOrConfigs !== null) {
179
+ // Parameters are provided as an object
180
+ ({
181
+ dimensions,
182
+ metric = MetricKind.Cos,
183
+ quantization = ScalarKind.F32,
184
+ connectivity = 0,
185
+ expansion_add = 0,
186
+ expansion_search = 0,
187
+ multi = false,
188
+ } = dimensionsOrConfigs);
189
+ }
190
+ else {
158
191
  throw new Error("Invalid arguments. Expected either individual arguments or a single object argument.");
159
192
  }
160
-
161
- if ((typeof dimensions !== 'bigint' && (!Number.isInteger(dimensions) || dimensions <= 0)) ||
193
+ if ((typeof dimensions !== 'bigint' && (!Number.isInteger(dimensions) || dimensions <= 0)) ||
162
194
  (typeof connectivity !== 'bigint' && (!Number.isInteger(connectivity) || connectivity < 0)) ||
163
195
  (typeof expansion_add !== 'bigint' && (!Number.isInteger(expansion_add) || expansion_add < 0)) ||
164
196
  (typeof expansion_search !== 'bigint' && (!Number.isInteger(expansion_search) || expansion_search < 0))) {
165
197
  throw new Error("`dimensions`, `connectivity`, `expansion_add`, and `expansion_search` must be non-negative integers, with `dimensions` being positive.");
166
198
  }
167
-
168
- if (typeof multi !== 'boolean') {
199
+ if (typeof multi !== "boolean") {
169
200
  throw new Error("`multi` must be a boolean value.");
170
201
  }
171
-
172
202
  if (!Object.values(MetricKind).includes(metric)) {
173
- throw new Error(`Invalid metric: ${metric}. It must be one of: ${Object.values(MetricKind).join(', ')}`);
203
+ throw new Error(`Invalid metric: ${metric}. It must be one of: ${Object.values(MetricKind).join(", ")}`);
174
204
  }
175
-
176
205
  if (!Object.values(ScalarKind).includes(quantization)) {
177
- throw new Error(`Invalid quantization: ${quantization}. It must be one of: ${Object.values(ScalarKind).join(', ')}`);
206
+ throw new Error(`Invalid quantization: ${quantization}. It must be one of: ${Object.values(ScalarKind).join(", ")}`);
178
207
  }
179
-
180
- this._compiledIndex = new compiled.CompiledIndex(dimensions, metric, quantization, connectivity, expansion_add, expansion_search, multi);
208
+ // @ts-expect-error
209
+ this.#compiledIndex = new compiled.CompiledIndex(dimensions, metric, quantization, connectivity, expansion_add, expansion_search, multi);
181
210
  }
182
-
211
+ #compiledIndex;
183
212
  /**
184
213
  * Add vectors to the index.
185
- *
214
+ *
186
215
  * This method accepts vectors and their corresponding keys for indexing.
187
216
  * Each key should correspond to a vector. If a single key is provided,
188
217
  * it is broadcasted to match the number of provided vectors.
189
- *
218
+ *
190
219
  * Vectors should be provided as a flat typed array representing a matrix
191
220
  * where each row is a vector to be indexed. The matrix should have a size
192
221
  * of n * d, where n is the number of vectors, and d is the dimensionality
193
222
  * of the vectors.
194
- *
223
+ *
195
224
  * Keys should be provided as a BigInt or an array-like object of BigInts
196
225
  * representing the unique identifier for each vector.
197
- *
226
+ *
198
227
  * @param {bigint|bigint[]|BigUint64Array} keys - Input identifiers for every vector.
199
228
  * If a single key is provided, it is associated with all provided vectors.
200
229
  * @param {Float32Array|Float64Array|Int8Array} vectors - Input matrix representing vectors,
@@ -204,173 +233,169 @@ class Index {
204
233
  */
205
234
  add(keys, vectors) {
206
235
  let normalizedKeys = normalizeKeys(keys);
207
- let normalizedVectors = normalizeVectors(vectors, this._compiledIndex.dimensions());
208
- let countVectors = normalizedVectors.length / this._compiledIndex.dimensions();
209
-
236
+ let normalizedVectors = normalizeVectors(vectors, this.#compiledIndex.dimensions());
237
+ let countVectors = normalizedVectors.length / this.#compiledIndex.dimensions();
210
238
  // If a single key is provided but there are multiple vectors,
211
239
  // broadcast the single key value to match the number of vectors
212
240
  if (normalizedKeys.length === 1 && countVectors > 1) {
213
241
  normalizedKeys = BigUint64Array.from({ length: countVectors }, () => normalizedKeys[0]);
214
- } else if (normalizedKeys.length !== countVectors) {
242
+ }
243
+ else if (normalizedKeys.length !== countVectors) {
215
244
  throw new Error(`The length of keys (${normalizedKeys.length}) must match the number of vectors (${countVectors}) or be a single key.`);
216
245
  }
217
-
218
246
  // Call the compiled method
219
- this._compiledIndex.add(normalizedKeys, normalizedVectors);
247
+ this.#compiledIndex.add(normalizedKeys, normalizedVectors);
220
248
  }
221
-
222
249
  /**
223
250
  * Perform a k-nearest neighbor search on the index.
224
- *
251
+ *
225
252
  * This method accepts a matrix of query vectors and returns the closest vectors
226
253
  * from the index for each query. The method returns an object containing the keys,
227
254
  * distances, and counts of the matches found.
228
- *
255
+ *
229
256
  * Vectors should be provided as a flat typed array representing a matrix where
230
257
  * each row is a vector. The matrix should be of size n * d, where n is the
231
258
  * number of query vectors, and d is their dimensionality.
232
- *
259
+ *
233
260
  * The parameter `k` specifies the number of nearest neighbors to return for each
234
261
  * query vector. If there are not enough results for a query, the result array is
235
262
  * padded with -1s.
236
- *
237
- * @param {Float32Array|Float64Array|Int8Array|Array<Array<number>>} vectors - Input matrix representing query vectors, can be a TypedArray or an array of arrays.
263
+ *
264
+ * @param {Float32Array|Float64Array|Int8Array|Array<Array<number>>} vectors - Input matrix representing query vectors, can be a TypedArray or an array of TypedArray.
238
265
  * @param {number} k - The number of nearest neighbors to search for each query vector.
239
266
  * @return {Matches|BatchMatches} - Search results for one or more queries, containing keys, distances, and counts of the matches found.
240
267
  * @throws Will throw an error if `k` is not a positive integer or if the size of the vectors is not a multiple of dimensions.
241
- * @throws Will throw an error if `vectors` is not a valid input type (TypedArray or an array of arrays) or if its flattened size is not a multiple of dimensions.
268
+ * @throws Will throw an error if `vectors` is not a valid input type (TypedArray or an array of TypedArray) or if its flattened size is not a multiple of dimensions.
242
269
  */
243
270
  search(vectors, k) {
244
- if ((!Number.isNaN(k) && typeof k !== 'number') || k <= 0) {
271
+ if ((!Number.isNaN(k) && typeof k !== "number") || k <= 0) {
245
272
  throw new Error("`k` must be a positive integer representing the number of nearest neighbors to search for.");
246
273
  }
247
-
248
- const normalizedVectors = normalizeVectors(vectors, this._compiledIndex.dimensions());
249
-
274
+ const normalizedVectors = normalizeVectors(vectors, this.#compiledIndex.dimensions());
250
275
  // Call the compiled method and create Matches or BatchMatches object with the result
251
- const result = this._compiledIndex.search(normalizedVectors, k);
252
- const countInQueries = normalizedVectors.length / Number(this._compiledIndex.dimensions());
253
- const batchMatches = new BatchMatches(result[0], result[1], result[2], k);
254
-
276
+ const result = this.#compiledIndex.search(normalizedVectors, k);
277
+ const countInQueries = normalizedVectors.length / Number(this.#compiledIndex.dimensions());
278
+ const batchMatches = new BatchMatches(...result, k);
255
279
  if (countInQueries === 1) {
256
280
  return batchMatches.get(0);
257
- } else {
281
+ }
282
+ else {
258
283
  return batchMatches;
259
284
  }
260
285
  }
261
-
262
286
  /**
263
287
  * Verifies the presence of one or more keys in the index.
264
- *
265
- * This method accepts one or multiple keys as input and returns a boolean or
288
+ *
289
+ * This method accepts one or multiple keys as input and returns a boolean or
266
290
  * an array of booleans indicating whether each key is present in the index.
267
- *
291
+ *
268
292
  * @param {bigint|bigint[]|BigUint64Array} keys - The identifier(s) of the vector(s) to be checked for presence in the index.
269
293
  * @return {boolean|boolean[]} - Returns true if a single key is contained in the index, false otherwise. Returns an array of booleans corresponding to the presence of each key in the index when multiple keys are provided.
270
294
  * @throws Will throw an error if keys are not integers.
271
295
  */
272
296
  contains(keys) {
273
297
  let normalizedKeys = normalizeKeys(keys);
274
- let normalizedResults = this._compiledIndex.contains(normalizedKeys);
298
+ let normalizedResults = this.#compiledIndex.contains(normalizedKeys);
275
299
  if (isOneKey(keys))
276
300
  return normalizedResults[0];
277
301
  else
278
302
  return normalizedResults;
279
303
  }
280
-
281
304
  /**
282
305
  * Counts the number of times keys shows up in the index.
283
- *
306
+ *
284
307
  * @param {bigint|bigint[]|BigUint64Array} keys - The identifier(s) of the vector(s) to be enumerated.
285
308
  * @return {number|number[]} - Returns the number of vectors found when a single key is provided. Returns an array of big integers corresponding to the number of vectors found for each key when multiple keys are provided.
286
309
  * @throws Will throw an error if keys are not integers.
287
310
  */
288
311
  count(keys) {
289
312
  let normalizedKeys = normalizeKeys(keys);
290
- let normalizedResults = this._compiledIndex.count(normalizedKeys);
313
+ let normalizedResults = this.#compiledIndex.count(normalizedKeys);
291
314
  if (isOneKey(keys))
292
315
  return normalizedResults[0];
293
316
  else
294
317
  return normalizedResults;
295
318
  }
296
-
297
319
  /**
298
320
  * Removes one or multiple vectors from the index.
299
- *
321
+ *
300
322
  * This method accepts one or multiple keys as input and removes the corresponding vectors from the index.
301
323
  * It returns the number of vectors actually removed for each key provided.
302
- *
324
+ *
303
325
  * @param {bigint|bigint[]|BigUint64Array} keys - The identifier(s) of the vector(s) to be removed.
304
326
  * @return {number|number[]} - Returns the number of vectors deleted when a single key is provided. Returns an array of big integers corresponding to the number of vectors deleted for each key when multiple keys are provided.
305
327
  * @throws Will throw an error if keys are not integers.
306
328
  */
307
329
  remove(keys) {
308
330
  let normalizedKeys = normalizeKeys(keys);
309
- let normalizedResults = this._compiledIndex.remove(normalizedKeys);
331
+ let normalizedResults = this.#compiledIndex.remove(normalizedKeys);
310
332
  if (isOneKey(keys))
311
333
  return normalizedResults[0];
312
334
  else
313
335
  return normalizedResults;
314
336
  }
315
-
316
337
  /**
317
338
  * Returns the dimensionality of vectors.
318
339
  * @return {number} The dimensionality of vectors.
319
340
  */
320
- dimensions() { return this._compiledIndex.dimensions() }
321
-
341
+ dimensions() {
342
+ return this.#compiledIndex.dimensions();
343
+ }
322
344
  /**
323
345
  * Returns connectivity.
324
346
  * @return {number} The connectivity of index.
325
347
  */
326
- connectivity() { return this._compiledIndex.connectivity() }
327
-
348
+ connectivity() {
349
+ return this.#compiledIndex.connectivity();
350
+ }
328
351
  /**
329
352
  * Returns the number of vectors currently indexed.
330
353
  * @return {number} The number of vectors currently indexed.
331
354
  */
332
- size() { return this._compiledIndex.size() }
333
-
355
+ size() {
356
+ return this.#compiledIndex.size();
357
+ }
334
358
  /**
335
359
  * Returns index capacity.
336
360
  * @return {number} The capacity of index.
337
361
  */
338
- capacity() { return this._compiledIndex.capacity() }
339
-
340
- /**
362
+ capacity() {
363
+ return this.#compiledIndex.capacity();
364
+ }
365
+ /**
341
366
  * Write index to a file.
342
367
  * @param {string} path File path to write.
343
368
  * @throws Will throw an error if `path` is not a string.
344
369
  */
345
370
  save(path) {
346
- if (typeof path !== 'string') throw new Error("`path` must be a string representing the file path to write.");
347
- this._compiledIndex.save(path);
371
+ if (typeof path !== "string")
372
+ throw new Error("`path` must be a string representing the file path to write.");
373
+ this.#compiledIndex.save(path);
348
374
  }
349
-
350
- /**
375
+ /**
351
376
  * Load index from a file.
352
377
  * @param {string} path File path to read.
353
378
  * @throws Will throw an error if `path` is not a string.
354
379
  */
355
380
  load(path) {
356
- if (typeof path !== 'string') throw new Error("`path` must be a string representing the file path to read.");
357
- this._compiledIndex.load(path);
381
+ if (typeof path !== "string")
382
+ throw new Error("`path` must be a string representing the file path to read.");
383
+ this.#compiledIndex.load(path);
358
384
  }
359
-
360
- /**
385
+ /**
361
386
  * View index from a file, without loading into RAM.
362
387
  * @param {string} path File path to read.
363
388
  * @throws Will throw an error if `path` is not a string.
364
389
  */
365
390
  view(path) {
366
- if (typeof path !== 'string') throw new Error("`path` must be a string representing the file path to read.");
367
- this._compiledIndex.view(path);
391
+ if (typeof path !== "string")
392
+ throw new Error("`path` must be a string representing the file path to read.");
393
+ this.#compiledIndex.view(path);
368
394
  }
369
395
  }
370
-
371
396
  /**
372
397
  * Performs an exact search on the given dataset to find the best matching vectors for each query.
373
- *
398
+ *
374
399
  * @param {Float32Array|Float64Array|Int8Array|Array<Array<number>>} dataset - The dataset containing vectors to be searched. It can be a TypedArray or an array of arrays.
375
400
  * @param {Float32Array|Float64Array|Int8Array|Array<Array<number>>} queries - The queries containing vectors to search for in the dataset. It can be a TypedArray or an array of arrays.
376
401
  * @param {number} dimensions - The dimensionality of the vectors in both the dataset and the queries. It defines the number of elements in each vector.
@@ -382,41 +407,40 @@ class Index {
382
407
  * @throws Will throw an error if `dataset` and `queries` are not valid input types (TypedArray or an array of arrays).
383
408
  * @throws Will throw an error if the sizes of the flattened `dataset` and `queries` are not multiples of `dimensions`.
384
409
  * @throws Will throw an error if `count` is greater than the number of vectors in the `dataset`.
385
- *
410
+ *
386
411
  * @example
387
412
  * const dataset = [[1.0, 2.0], [3.0, 4.0]]; // Two vectors: [1.0, 2.0] and [3.0, 4.0]
388
413
  * const queries = [[1.5, 2.5]]; // One vector: [1.5, 2.5]
389
414
  * const dimensions = 2; // The number of elements in each vector.
390
415
  * const count = 1; // The number of nearest neighbors to return for each query.
391
416
  * const metric = MetricKind.IP; // Using the Inner Product distance metric.
392
- *
417
+ *
393
418
  * const result = exactSearch(dataset, queries, dimensions, count, metric);
394
- * // result might be:
419
+ * // result might be:
395
420
  * // {
396
421
  * // keys: BigUint64Array [ 1n ],
397
422
  * // distances: Float32Array [ some_value ],
398
423
  * // }
399
424
  */
400
425
  function exactSearch(dataset, queries, dimensions, count, metric) {
401
-
402
426
  // Validate and normalize the dimensions and count
403
427
  dimensions = Number(dimensions);
404
428
  count = Number(count);
405
429
  if (count <= 0 || dimensions <= 0) {
406
430
  throw new Error("Dimensions and count must be positive integers.");
407
431
  }
408
-
409
432
  // Validate metric
410
433
  if (!Object.values(MetricKind).includes(metric)) {
411
- throw new Error(`Invalid metric: ${metric}. It must be one of: ${Object.values(MetricKind).join(', ')}`);
434
+ throw new Error(`Invalid metric: ${metric}. It must be one of: ${Object.values(MetricKind).join(", ")}`);
412
435
  }
413
-
414
436
  // Flatten and normalize dataset and queries if they are arrays of arrays
415
437
  let targetType;
416
- if (dataset instanceof Float64Array) targetType = Float64Array;
417
- else if (dataset instanceof Int8Array) targetType = Int8Array;
418
- else targetType = Float32Array; // default to Float32Array if dataset is not Float64Array or Int8Array
419
-
438
+ if (dataset instanceof Float64Array)
439
+ targetType = Float64Array;
440
+ else if (dataset instanceof Int8Array)
441
+ targetType = Int8Array;
442
+ else
443
+ targetType = Float32Array; // default to Float32Array if dataset is not Float64Array or Int8Array
420
444
  dataset = normalizeVectors(dataset, dimensions, targetType);
421
445
  queries = normalizeVectors(queries, dimensions, targetType);
422
446
  const countInDataset = dataset.length / dimensions;
@@ -424,18 +448,16 @@ function exactSearch(dataset, queries, dimensions, count, metric) {
424
448
  if (count > countInDataset) {
425
449
  throw new Error("Count must be equal or smaller than the number of vectors in the dataset.");
426
450
  }
427
-
428
451
  // Call the compiled function with the normalized input
429
452
  const result = compiled.exactSearch(dataset, queries, dimensions, count, metric);
430
-
431
453
  // Create and return a Matches or BatchMatches object with the result
432
454
  if (countInQueries == 1) {
433
455
  return new Matches(result[0], result[1]);
434
- } else {
435
- return new BatchMatches(result[0], result[1], result[2], count);
456
+ }
457
+ else {
458
+ return new BatchMatches(...result, count);
436
459
  }
437
460
  }
438
-
439
461
  module.exports = {
440
462
  Index,
441
463
  MetricKind,
@@ -444,3 +466,27 @@ module.exports = {
444
466
  BatchMatches,
445
467
  exactSearch,
446
468
  };
469
+ // utility functions to help find native builds
470
+ function getBuildDir(dir) {
471
+ if (existsSync(path.join(dir, "build")))
472
+ return dir;
473
+ if (existsSync(path.join(dir, "prebuilds")))
474
+ return dir;
475
+ if (path.basename(dir) === ".next") {
476
+ // special case for next.js on custom node (not vercel)
477
+ const sideways = path.join(dir, "..", "node_modules", "usearch");
478
+ if (existsSync(sideways))
479
+ return getBuildDir(sideways);
480
+ }
481
+ if (dir === "/")
482
+ throw new Error("Could not find native build for usearch");
483
+ return getBuildDir(path.join(dir, ".."));
484
+ }
485
+ function getDirName() {
486
+ try {
487
+ if (__dirname)
488
+ return __dirname;
489
+ }
490
+ catch (e) { }
491
+ return getRoot(getFileName());
492
+ }