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