usearch 2.6.1 → 2.7.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.
- package/. npmignore +14 -0
- package/.cmake-format.py +19 -0
- package/.github/workflows/Dockerfile.libs +3 -3
- package/.github/workflows/prerelease.yml +85 -64
- package/.github/workflows/release.yml +18 -16
- package/.gitignore +1 -1
- package/.vscode/launch.json +47 -14
- package/.vscode/settings.json +7 -0
- package/.vscode/tasks.json +44 -8
- package/CITATION.cff +1 -1
- package/CMakeLists.txt +218 -67
- package/Cargo.toml +1 -1
- package/README.md +1 -1
- package/binding.gyp +3 -2
- package/build.gradle +19 -10
- package/c/CMakeLists.txt +21 -48
- package/c/README.md +5 -5
- package/c/lib.cpp +52 -7
- package/c/test.c +137 -94
- package/c/usearch.h +42 -0
- package/cmake/clipp.cmake +0 -1
- package/cmake/jemalloc.cmake +21 -37
- package/conanfile.py +1 -1
- package/cpp/CMakeLists.txt +14 -123
- package/cpp/bench.cpp +0 -12
- package/cpp/test.cpp +29 -1
- package/csharp/nuget/nuget-package.props +1 -1
- package/docs/compilation.md +23 -16
- package/docs/conf.py +1 -1
- package/golang/README.md +52 -51
- package/golang/lib.go +1 -1
- package/golang/lib_test.go +4 -1
- package/include/usearch/index.hpp +2 -2
- package/include/usearch/index_plugins.hpp +345 -160
- package/javascript/lib.cpp +204 -250
- package/javascript/usearch.js +440 -2
- package/javascript/usearch.test.js +37 -0
- package/package.json +10 -5
- package/python/lib.cpp +96 -225
- package/python/scripts/bench_exact.py +2 -2
- package/python/scripts/test_jit.py +2 -13
- package/python/scripts/test_sparse.py +1 -1
- package/python/scripts/test_tooling.py +26 -5
- package/rust/lib.cpp +12 -4
- package/rust/lib.hpp +7 -0
- package/rust/lib.rs +170 -10
- package/setup.py +14 -4
- package/wasm/CMakeLists.txt +4 -12
- package/wasm/lib.cpp +1 -1
- package/wasmer.toml +1 -1
- package/javascript/docs.js +0 -111
- package/javascript/test.js +0 -32
- package/javascript/usearch.d.ts +0 -110
- package/tsconfig.json +0 -8
package/rust/lib.rs
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
#[cxx::bridge]
|
|
2
2
|
pub mod ffi {
|
|
3
|
-
|
|
4
3
|
// Shared structs with fields visible to both languages.
|
|
4
|
+
#[derive(Debug)]
|
|
5
5
|
struct Matches {
|
|
6
6
|
keys: Vec<u64>,
|
|
7
7
|
distances: Vec<f32>,
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
#[derive(Debug)]
|
|
10
11
|
enum MetricKind {
|
|
11
12
|
IP,
|
|
12
13
|
L2sq,
|
|
@@ -18,6 +19,7 @@ pub mod ffi {
|
|
|
18
19
|
Sorensen,
|
|
19
20
|
}
|
|
20
21
|
|
|
22
|
+
#[derive(Debug)]
|
|
21
23
|
enum ScalarKind {
|
|
22
24
|
F64,
|
|
23
25
|
F32,
|
|
@@ -26,6 +28,7 @@ pub mod ffi {
|
|
|
26
28
|
B1,
|
|
27
29
|
}
|
|
28
30
|
|
|
31
|
+
#[derive(Debug, PartialEq)]
|
|
29
32
|
struct IndexOptions {
|
|
30
33
|
dimensions: usize,
|
|
31
34
|
metric: MetricKind,
|
|
@@ -40,9 +43,14 @@ pub mod ffi {
|
|
|
40
43
|
unsafe extern "C++" {
|
|
41
44
|
include!("lib.hpp");
|
|
42
45
|
|
|
43
|
-
/// Low-level C++ interface
|
|
46
|
+
/// Low-level C++ interface that is further wrapped into the high-level `Index`
|
|
44
47
|
type NativeIndex;
|
|
45
48
|
|
|
49
|
+
pub fn expansion_add(self: &NativeIndex) -> usize;
|
|
50
|
+
pub fn expansion_search(self: &NativeIndex) -> usize;
|
|
51
|
+
pub fn change_expansion_add(self: &NativeIndex, n: usize) -> Result<()>;
|
|
52
|
+
pub fn change_expansion_search(self: &NativeIndex, n: usize) -> Result<()>;
|
|
53
|
+
|
|
46
54
|
pub fn new_native_index(options: &IndexOptions) -> Result<UniquePtr<NativeIndex>>;
|
|
47
55
|
pub fn reserve(self: &NativeIndex, capacity: usize) -> Result<()>;
|
|
48
56
|
pub fn dimensions(self: &NativeIndex) -> usize;
|
|
@@ -74,6 +82,9 @@ pub mod ffi {
|
|
|
74
82
|
pub fn save(self: &NativeIndex, path: &str) -> Result<()>;
|
|
75
83
|
pub fn load(self: &NativeIndex, path: &str) -> Result<()>;
|
|
76
84
|
pub fn view(self: &NativeIndex, path: &str) -> Result<()>;
|
|
85
|
+
pub fn reset(self: &NativeIndex) -> Result<()>;
|
|
86
|
+
pub fn memory_usage(self: &NativeIndex) -> usize;
|
|
87
|
+
|
|
77
88
|
pub fn save_to_buffer(self: &NativeIndex, buffer: &mut [u8]) -> Result<()>;
|
|
78
89
|
pub fn load_from_buffer(self: &NativeIndex, buffer: &[u8]) -> Result<()>;
|
|
79
90
|
pub fn view_from_buffer(self: &NativeIndex, buffer: &[u8]) -> Result<()>;
|
|
@@ -100,6 +111,20 @@ impl Default for ffi::IndexOptions {
|
|
|
100
111
|
}
|
|
101
112
|
}
|
|
102
113
|
|
|
114
|
+
impl Clone for ffi::IndexOptions {
|
|
115
|
+
fn clone(&self) -> Self {
|
|
116
|
+
ffi::IndexOptions {
|
|
117
|
+
dimensions: (self.dimensions),
|
|
118
|
+
metric: (self.metric),
|
|
119
|
+
quantization: (self.quantization),
|
|
120
|
+
connectivity: (self.connectivity),
|
|
121
|
+
expansion_add: (self.expansion_add),
|
|
122
|
+
expansion_search: (self.expansion_search),
|
|
123
|
+
multi: (self.multi),
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
103
128
|
pub trait VectorType {
|
|
104
129
|
fn add(index: &Index, key: u64, vector: &[Self]) -> Result<(), cxx::Exception>
|
|
105
130
|
where
|
|
@@ -156,6 +181,26 @@ impl Index {
|
|
|
156
181
|
}
|
|
157
182
|
}
|
|
158
183
|
|
|
184
|
+
/// Retrieves the expansion value used during index creation.
|
|
185
|
+
pub fn expansion_add(self: &Index) -> usize {
|
|
186
|
+
self.inner.expansion_add()
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/// Retrieves the expansion value used during search.
|
|
190
|
+
pub fn expansion_search(self: &Index) -> usize {
|
|
191
|
+
self.inner.expansion_search()
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/// Updates the expansion value used during index creation. Rarely used.
|
|
195
|
+
pub fn change_expansion_add(self: &Index, n: usize) -> Result<(), cxx::Exception> {
|
|
196
|
+
self.inner.change_expansion_add(n)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/// Updates the expansion value used during search operations.
|
|
200
|
+
pub fn change_expansion_search(self: &Index, n: usize) -> Result<(), cxx::Exception> {
|
|
201
|
+
self.inner.change_expansion_search(n)
|
|
202
|
+
}
|
|
203
|
+
|
|
159
204
|
/// Performs k-Approximate Nearest Neighbors (kANN) Search for closest vectors to the provided query.
|
|
160
205
|
///
|
|
161
206
|
/// # Arguments
|
|
@@ -184,7 +229,12 @@ impl Index {
|
|
|
184
229
|
T::add(self, key, vector)
|
|
185
230
|
}
|
|
186
231
|
|
|
187
|
-
/// Extracts one or more vectors matching specified key.
|
|
232
|
+
/// Extracts one or more vectors matching the specified key.
|
|
233
|
+
/// The `vector` slice must be a multiple of the number of dimensions in the index.
|
|
234
|
+
/// After the execution, return the number `X` of vectors found.
|
|
235
|
+
/// The vector slice's first `X * dimensions` elements will be filled.
|
|
236
|
+
///
|
|
237
|
+
/// If you are a novice user, consider `export`.
|
|
188
238
|
///
|
|
189
239
|
/// # Arguments
|
|
190
240
|
///
|
|
@@ -198,11 +248,34 @@ impl Index {
|
|
|
198
248
|
T::get(self, key, vector)
|
|
199
249
|
}
|
|
200
250
|
|
|
251
|
+
/// Extracts one or more vectors matching specified key into supplied resizable vector.
|
|
252
|
+
/// The `vector` is resized to a multiple of the number of dimensions in the index.
|
|
253
|
+
///
|
|
254
|
+
/// # Arguments
|
|
255
|
+
///
|
|
256
|
+
/// * `key` - The key associated with the vector.
|
|
257
|
+
/// * `vector` - A mutable vector containing the vector data.
|
|
258
|
+
pub fn export<T: VectorType + Default + Clone>(
|
|
259
|
+
self: &Index,
|
|
260
|
+
key: u64,
|
|
261
|
+
vector: &mut Vec<T>,
|
|
262
|
+
) -> Result<usize, cxx::Exception> {
|
|
263
|
+
let dim = self.dimensions();
|
|
264
|
+
let max_matches = self.count(key);
|
|
265
|
+
vector.resize(dim * max_matches, T::default());
|
|
266
|
+
let matches = T::get(self, key, &mut vector[..]);
|
|
267
|
+
if matches.is_err() {
|
|
268
|
+
return matches;
|
|
269
|
+
}
|
|
270
|
+
vector.resize(dim * matches.as_ref().unwrap(), T::default());
|
|
271
|
+
return matches;
|
|
272
|
+
}
|
|
273
|
+
|
|
201
274
|
/// Reserves memory for a specified number of incoming vectors.
|
|
202
275
|
///
|
|
203
276
|
/// # Arguments
|
|
204
277
|
///
|
|
205
|
-
/// * `capacity` - The desired total capacity including the current size.
|
|
278
|
+
/// * `capacity` - The desired total capacity, including the current size.
|
|
206
279
|
pub fn reserve(self: &Index, capacity: usize) -> Result<(), cxx::Exception> {
|
|
207
280
|
self.inner.reserve(capacity)
|
|
208
281
|
}
|
|
@@ -245,7 +318,7 @@ impl Index {
|
|
|
245
318
|
self.inner.remove(key)
|
|
246
319
|
}
|
|
247
320
|
|
|
248
|
-
/// Renames the vector under a
|
|
321
|
+
/// Renames the vector under a specific key.
|
|
249
322
|
///
|
|
250
323
|
/// # Arguments
|
|
251
324
|
///
|
|
@@ -254,7 +327,7 @@ impl Index {
|
|
|
254
327
|
///
|
|
255
328
|
/// # Returns
|
|
256
329
|
///
|
|
257
|
-
/// `true` if the vector is
|
|
330
|
+
/// `true` if the vector is renamed, `false` otherwise.
|
|
258
331
|
pub fn rename(self: &Index, from: u64, to: u64) -> Result<usize, cxx::Exception> {
|
|
259
332
|
self.inner.rename(from, to)
|
|
260
333
|
}
|
|
@@ -272,7 +345,7 @@ impl Index {
|
|
|
272
345
|
self.inner.contains(key)
|
|
273
346
|
}
|
|
274
347
|
|
|
275
|
-
/// Count the count of
|
|
348
|
+
/// Count the count of vectors with the same specified key.
|
|
276
349
|
///
|
|
277
350
|
/// # Arguments
|
|
278
351
|
///
|
|
@@ -312,6 +385,17 @@ impl Index {
|
|
|
312
385
|
self.inner.view(path)
|
|
313
386
|
}
|
|
314
387
|
|
|
388
|
+
/// Erases all members from the index, closes files, and returns RAM to OS.
|
|
389
|
+
pub fn reset(self: &Index) -> Result<(), cxx::Exception> {
|
|
390
|
+
self.inner.reset()
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/// A relatively accurate lower bound on the amount of memory consumed by the system.
|
|
394
|
+
/// In practice, its error will be below 10%.
|
|
395
|
+
pub fn memory_usage(self: &Index) -> usize {
|
|
396
|
+
self.inner.memory_usage()
|
|
397
|
+
}
|
|
398
|
+
|
|
315
399
|
/// Saves the index to a specified file.
|
|
316
400
|
///
|
|
317
401
|
/// # Arguments
|
|
@@ -352,6 +436,36 @@ mod tests {
|
|
|
352
436
|
use crate::new_index;
|
|
353
437
|
use crate::Index;
|
|
354
438
|
|
|
439
|
+
#[test]
|
|
440
|
+
fn test_add_get_vector() {
|
|
441
|
+
let mut options = IndexOptions::default();
|
|
442
|
+
options.dimensions = 5;
|
|
443
|
+
let index = Index::new(&options).unwrap();
|
|
444
|
+
assert!(index.reserve(10).is_ok());
|
|
445
|
+
|
|
446
|
+
let first: [f32; 5] = [0.2, 0.1, 0.2, 0.1, 0.3];
|
|
447
|
+
let second: [f32; 5] = [0.3, 0.2, 0.4, 0.0, 0.1];
|
|
448
|
+
assert!(index.add(1, &first).is_ok());
|
|
449
|
+
assert!(index.add(2, &second).is_ok());
|
|
450
|
+
assert_eq!(index.size(), 2);
|
|
451
|
+
|
|
452
|
+
// Test using Vec<T>
|
|
453
|
+
let mut found_vec: Vec<f32> = Vec::new();
|
|
454
|
+
assert_eq!(index.export(1, &mut found_vec).unwrap(), 1);
|
|
455
|
+
assert_eq!(found_vec.len(), 5);
|
|
456
|
+
assert_eq!(found_vec, first.to_vec());
|
|
457
|
+
|
|
458
|
+
// Test using slice
|
|
459
|
+
let mut found_slice = [0.0 as f32; 5];
|
|
460
|
+
assert_eq!(index.get(1, &mut found_slice).unwrap(), 1);
|
|
461
|
+
assert_eq!(found_slice, first);
|
|
462
|
+
|
|
463
|
+
// Create a slice with incorrect size
|
|
464
|
+
let mut found = [0.0 as f32; 6]; // This isn't a multiple of the index's dimensions.
|
|
465
|
+
let result = index.get(1, &mut found);
|
|
466
|
+
assert!(result.is_err());
|
|
467
|
+
}
|
|
468
|
+
|
|
355
469
|
#[test]
|
|
356
470
|
fn integration() {
|
|
357
471
|
let mut options = IndexOptions::default();
|
|
@@ -359,6 +473,9 @@ mod tests {
|
|
|
359
473
|
|
|
360
474
|
let index = Index::new(&options).unwrap();
|
|
361
475
|
|
|
476
|
+
assert!(index.expansion_add() > 0);
|
|
477
|
+
assert!(index.expansion_search() > 0);
|
|
478
|
+
|
|
362
479
|
assert!(index.reserve(10).is_ok());
|
|
363
480
|
assert!(index.capacity() >= 10);
|
|
364
481
|
assert!(index.connectivity() != 0);
|
|
@@ -366,14 +483,41 @@ mod tests {
|
|
|
366
483
|
assert_eq!(index.size(), 0);
|
|
367
484
|
|
|
368
485
|
let first: [f32; 5] = [0.2, 0.1, 0.2, 0.1, 0.3];
|
|
369
|
-
let second: [f32; 5] = [0.
|
|
370
|
-
|
|
486
|
+
let second: [f32; 5] = [0.3, 0.2, 0.4, 0.0, 0.1];
|
|
487
|
+
|
|
488
|
+
println!(
|
|
489
|
+
"before add, memory_usage: {} \
|
|
490
|
+
cap: {} \
|
|
491
|
+
",
|
|
492
|
+
index.memory_usage(),
|
|
493
|
+
index.capacity(),
|
|
494
|
+
);
|
|
495
|
+
assert!(index.change_expansion_add(10).is_ok());
|
|
496
|
+
assert_eq!(index.expansion_add(), 10);
|
|
371
497
|
assert!(index.add(42, &first).is_ok());
|
|
498
|
+
assert!(index.change_expansion_add(12).is_ok());
|
|
499
|
+
assert_eq!(index.expansion_add(), 12);
|
|
372
500
|
assert!(index.add(43, &second).is_ok());
|
|
373
501
|
assert_eq!(index.size(), 2);
|
|
374
|
-
|
|
502
|
+
println!(
|
|
503
|
+
"after add, memory_usage: {} \
|
|
504
|
+
cap: {} \
|
|
505
|
+
",
|
|
506
|
+
index.memory_usage(),
|
|
507
|
+
index.capacity(),
|
|
508
|
+
);
|
|
509
|
+
|
|
510
|
+
assert!(index.change_expansion_search(10).is_ok());
|
|
511
|
+
assert_eq!(index.expansion_search(), 10);
|
|
375
512
|
// Read back the tags
|
|
376
513
|
let results = index.search(&first, 10).unwrap();
|
|
514
|
+
println!("{:?}", results);
|
|
515
|
+
assert_eq!(results.keys.len(), 2);
|
|
516
|
+
|
|
517
|
+
assert!(index.change_expansion_search(12).is_ok());
|
|
518
|
+
assert_eq!(index.expansion_search(), 12);
|
|
519
|
+
let results = index.search(&first, 10).unwrap();
|
|
520
|
+
println!("{:?}", results);
|
|
377
521
|
assert_eq!(results.keys.len(), 2);
|
|
378
522
|
|
|
379
523
|
// Validate serialization
|
|
@@ -399,5 +543,21 @@ mod tests {
|
|
|
399
543
|
.load_from_buffer(&serialization_buffer)
|
|
400
544
|
.is_ok());
|
|
401
545
|
assert_eq!(index.size(), deserialized_index.size());
|
|
546
|
+
|
|
547
|
+
// reset
|
|
548
|
+
assert_ne!(index.memory_usage(), 0);
|
|
549
|
+
assert!(index.reset().is_ok());
|
|
550
|
+
assert_eq!(index.size(), 0);
|
|
551
|
+
assert_eq!(index.memory_usage(), 0);
|
|
552
|
+
|
|
553
|
+
// clone
|
|
554
|
+
options.metric = MetricKind::Haversine;
|
|
555
|
+
let mut opts = options.clone();
|
|
556
|
+
assert_eq!(opts.metric, options.metric);
|
|
557
|
+
assert_eq!(opts.quantization, options.quantization);
|
|
558
|
+
assert_eq!(opts, options);
|
|
559
|
+
opts.metric = MetricKind::Cos;
|
|
560
|
+
assert_ne!(opts.metric, options.metric);
|
|
561
|
+
assert!(new_index(&opts).is_ok());
|
|
402
562
|
}
|
|
403
563
|
}
|
package/setup.py
CHANGED
|
@@ -12,6 +12,7 @@ macros_args = []
|
|
|
12
12
|
if sys.platform == "linux":
|
|
13
13
|
compile_args.append("-std=c++17")
|
|
14
14
|
compile_args.append("-O3") # Maximize performance
|
|
15
|
+
compile_args.append("-ffast-math") # Maximize floating-point performance
|
|
15
16
|
compile_args.append("-Wno-unknown-pragmas")
|
|
16
17
|
compile_args.append("-fdiagnostics-color=always")
|
|
17
18
|
|
|
@@ -30,20 +31,29 @@ if sys.platform == "darwin":
|
|
|
30
31
|
compile_args.append("-mmacosx-version-min=10.15")
|
|
31
32
|
compile_args.append("-std=c++17")
|
|
32
33
|
compile_args.append("-O3") # Maximize performance
|
|
34
|
+
compile_args.append("-ffast-math") # Maximize floating-point performance
|
|
33
35
|
compile_args.append("-fcolor-diagnostics")
|
|
34
36
|
compile_args.append("-Wno-unknown-pragmas")
|
|
35
37
|
|
|
36
38
|
# Simplify debugging, but the normal `-g` may make builds much longer!
|
|
37
39
|
compile_args.append("-g1")
|
|
38
40
|
|
|
39
|
-
# Linking OpenMP requires additional preparation in CIBuildWheel
|
|
40
|
-
#
|
|
41
|
-
#
|
|
42
|
-
#
|
|
41
|
+
# Linking OpenMP requires additional preparation in CIBuildWheel.
|
|
42
|
+
# We must install `brew install llvm` ahead of time.
|
|
43
|
+
# import subprocess as cli
|
|
44
|
+
# llvm_base = cli.check_output(["brew", "--prefix", "llvm"]).strip().decode("utf-8")
|
|
45
|
+
# if len(llvm_base):
|
|
46
|
+
# compile_args.append(f"-I{llvm_base}/include")
|
|
47
|
+
# compile_args.append("-Xpreprocessor -fopenmp")
|
|
48
|
+
# link_args.append(f"-L{llvm_base}/lib")
|
|
49
|
+
# link_args.append("-lomp")
|
|
50
|
+
# macros_args.append(("USEARCH_USE_OPENMP", "1"))
|
|
43
51
|
|
|
44
52
|
if sys.platform == "win32":
|
|
45
53
|
compile_args.append("/std:c++17")
|
|
46
54
|
compile_args.append("/O2")
|
|
55
|
+
compile_args.append("/fp:fast") # Enable fast math for MSVC
|
|
56
|
+
compile_args.append("/W1") # Reduce warnings verbosity
|
|
47
57
|
|
|
48
58
|
ext_modules = [
|
|
49
59
|
Pybind11Extension(
|
package/wasm/CMakeLists.txt
CHANGED
|
@@ -1,15 +1,7 @@
|
|
|
1
1
|
include(emscripten)
|
|
2
2
|
|
|
3
|
-
set(CMAKE_C_COMPILER emcc)
|
|
4
|
-
set(CMAKE_CXX_COMPILER em++)
|
|
3
|
+
# Setting the compiler globally is never a good idea! set(CMAKE_C_COMPILER emcc) set(CMAKE_CXX_COMPILER em++)
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"${CMAKE_CURRENT_SOURCE_DIR}/../fp16/include"
|
|
10
|
-
)
|
|
11
|
-
|
|
12
|
-
add_executable(index lib.cpp)
|
|
13
|
-
target_include_directories(index PRIVATE ${USEARCH_PUNNED_INCLUDE_DIRS})
|
|
14
|
-
set_target_properties(index PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/wasm)
|
|
15
|
-
set_target_properties(index PROPERTIES CXX_STANDARD 11)
|
|
5
|
+
add_executable(usearch_wasm lib.cpp)
|
|
6
|
+
setup_target(usearch_wasm)
|
|
7
|
+
set_target_properties(usearch_wasm PROPERTIES CXX_STANDARD 11)
|
package/wasm/lib.cpp
CHANGED
package/wasmer.toml
CHANGED
package/javascript/docs.js
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
/** Search result object. */
|
|
2
|
-
class Matches {
|
|
3
|
-
/**
|
|
4
|
-
* @param {BigUint64Array} keys - The keys of the nearest neighbors found.
|
|
5
|
-
* @param {Float32Array} distances - The distances of the nearest neighbors found.
|
|
6
|
-
* @param {bigint} count - The count of nearest neighbors found.
|
|
7
|
-
*/
|
|
8
|
-
constructor(keys, distances, count) {
|
|
9
|
-
this.keys = keys;
|
|
10
|
-
this.distances = distances;
|
|
11
|
-
this.count = count;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/** K-Approximate Nearest Neighbors search index. */
|
|
16
|
-
class Index {
|
|
17
|
-
/**
|
|
18
|
-
* Constructs a new index.
|
|
19
|
-
*
|
|
20
|
-
* @param {bigint} dimensions
|
|
21
|
-
* @param {string} metric
|
|
22
|
-
* @param {string} quantization
|
|
23
|
-
* @param {bigint} capacity
|
|
24
|
-
* @param {bigint} connectivity
|
|
25
|
-
* @param {bigint} expansion_add
|
|
26
|
-
* @param {bigint} expansion_search
|
|
27
|
-
*/
|
|
28
|
-
constructor(
|
|
29
|
-
dimensions,
|
|
30
|
-
metric,
|
|
31
|
-
quantization,
|
|
32
|
-
capacity,
|
|
33
|
-
connectivity,
|
|
34
|
-
expansion_add,
|
|
35
|
-
expansion_search
|
|
36
|
-
) {}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Returns the dimensionality of vectors.
|
|
40
|
-
* @return {bigint} The dimensionality of vectors.
|
|
41
|
-
*/
|
|
42
|
-
dimensions() {}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Returns the bigint of vectors currently indexed.
|
|
46
|
-
* @return {bigint} The bigint of vectors currently indexed.
|
|
47
|
-
*/
|
|
48
|
-
size() {}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Returns index capacity.
|
|
52
|
-
* @return {bigint} The capacity of index.
|
|
53
|
-
*/
|
|
54
|
-
capacity() {}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Returns connectivity.
|
|
58
|
-
* @return {bigint} The connectivity of index.
|
|
59
|
-
*/
|
|
60
|
-
connectivity() {}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Write index to a file.
|
|
64
|
-
* @param {string} path File path to write.
|
|
65
|
-
*/
|
|
66
|
-
save(path) {}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Load index from a file.
|
|
70
|
-
* @param {string} path File path to read.
|
|
71
|
-
*/
|
|
72
|
-
load(path) {}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* View index from a file, without loading into RAM.
|
|
76
|
-
* @param {string} path File path to read.
|
|
77
|
-
*/
|
|
78
|
-
view(path) {}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Add n vectors of dimension d to the index.
|
|
82
|
-
*
|
|
83
|
-
* @param {bigint | bigint[]} keys Input identifiers for every vector.
|
|
84
|
-
* @param {Float32Array | Float32Array[]} mat Input matrix, matrix of size n * d.
|
|
85
|
-
*/
|
|
86
|
-
add(keys, mat) {}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Query n vectors of dimension d to the index. Return at most k vectors for each.
|
|
90
|
-
* If there are not enough results for a query, the result array is padded with -1s.
|
|
91
|
-
*
|
|
92
|
-
* @param {Float32Array} mat Input vectors to search, matrix of size n * d.
|
|
93
|
-
* @param {bigint} k The bigint of nearest neighbors to search for.
|
|
94
|
-
* @return {Matches} Output of the search result.
|
|
95
|
-
*/
|
|
96
|
-
search(mat, k) {}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Check if an entry is contained in the index.
|
|
100
|
-
*
|
|
101
|
-
* @param {bigint} key Identifier to look up.
|
|
102
|
-
*/
|
|
103
|
-
contains(key) {}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Remove a vector from the index.
|
|
107
|
-
*
|
|
108
|
-
* @param {bigint} key Input identifier for every vector to be removed.
|
|
109
|
-
*/
|
|
110
|
-
remove(key) {}
|
|
111
|
-
}
|
package/javascript/test.js
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
var assert = require('assert');
|
|
2
|
-
var usearch = require('bindings')('usearch');
|
|
3
|
-
|
|
4
|
-
// Single-entry operations
|
|
5
|
-
|
|
6
|
-
var index = new usearch.Index({ metric: 'l2sq', connectivity: 16n, dimensions: 2n });
|
|
7
|
-
assert.equal(index.connectivity(), 16n, 'connectivity should be 16');
|
|
8
|
-
assert.equal(index.dimensions(), 2n, 'dimensions should be 2');
|
|
9
|
-
assert.equal(index.size(), 0n, 'initial size should be 0');
|
|
10
|
-
|
|
11
|
-
index.add(15n, new Float32Array([10, 20]));
|
|
12
|
-
index.add(16n, new Float32Array([10, 25]));
|
|
13
|
-
assert.equal(index.size(), 2n, 'size after adding elements should be 2');
|
|
14
|
-
assert.equal(index.contains(15n), true, 'entry must be present after insertion');
|
|
15
|
-
|
|
16
|
-
var results = index.search(new Float32Array([13, 14]), 2n);
|
|
17
|
-
assert.deepEqual(results.keys, new BigUint64Array([15n, 16n]), 'keys should be 15 and 16');
|
|
18
|
-
assert.deepEqual(results.distances, new Float32Array([45, 130]), 'distances should be 45 and 130');
|
|
19
|
-
|
|
20
|
-
// Batch operations
|
|
21
|
-
|
|
22
|
-
var indexBatch = new usearch.Index({ metric: 'l2sq', connectivity: 16n, dimensions: 2n });
|
|
23
|
-
const keys = [15n, 16n];
|
|
24
|
-
const vectors = [new Float32Array([10, 20]), new Float32Array([10, 25])];
|
|
25
|
-
indexBatch.add(keys, vectors);
|
|
26
|
-
assert.equal(indexBatch.size(), 2, 'size after adding batch should be 2');
|
|
27
|
-
|
|
28
|
-
results = indexBatch.search(new Float32Array([13, 14]), 2n);
|
|
29
|
-
assert.deepEqual(results.keys, new BigUint64Array([15n, 16n]), 'keys should be 15 and 16');
|
|
30
|
-
assert.deepEqual(results.distances, new Float32Array([45, 130]), 'distances should be 45 and 130');
|
|
31
|
-
|
|
32
|
-
console.log('JavaScript tests passed!');
|
package/javascript/usearch.d.ts
DELETED
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
/** Search result object. */
|
|
3
|
-
export interface Matches {
|
|
4
|
-
/** The keys of the nearest neighbors found, size n*k. */
|
|
5
|
-
keys: BigUint64Array,
|
|
6
|
-
/** The distances of the nearest neighbors found, size n*k. */
|
|
7
|
-
distances: Float32Array,
|
|
8
|
-
/** The distances of the nearest neighbors found, size n*k. */
|
|
9
|
-
count: bigint
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/** K-Approximate Nearest Neighbors search index. */
|
|
13
|
-
export class Index {
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Constructs a new index.
|
|
17
|
-
*
|
|
18
|
-
* @param {bigint} dimensions
|
|
19
|
-
* @param {string} metric
|
|
20
|
-
* @param {string} quantization
|
|
21
|
-
* @param {bigint} capacity
|
|
22
|
-
* @param {bigint} connectivity
|
|
23
|
-
* @param {bigint} expansion_add
|
|
24
|
-
* @param {bigint} expansion_search
|
|
25
|
-
*/
|
|
26
|
-
constructor(
|
|
27
|
-
dimensions: bigint,
|
|
28
|
-
metric: string,
|
|
29
|
-
quantization: string,
|
|
30
|
-
capacity: bigint,
|
|
31
|
-
connectivity: bigint,
|
|
32
|
-
expansion_add: bigint,
|
|
33
|
-
expansion_search: bigint
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Returns the dimensionality of vectors.
|
|
38
|
-
* @return {bigint} The dimensionality of vectors.
|
|
39
|
-
*/
|
|
40
|
-
dimensions(): bigint;
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Returns the bigint of vectors currently indexed.
|
|
44
|
-
* @return {bigint} The bigint of vectors currently indexed.
|
|
45
|
-
*/
|
|
46
|
-
size(): bigint;
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Returns index capacity.
|
|
50
|
-
* @return {bigints} The capacity of index.
|
|
51
|
-
*/
|
|
52
|
-
capacity(): bigint;
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Returns connectivity.
|
|
56
|
-
* @return {bigint} The connectivity of index.
|
|
57
|
-
*/
|
|
58
|
-
connectivity(): bigint;
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Write index to a file.
|
|
62
|
-
* @param {string} path File path to write.
|
|
63
|
-
*/
|
|
64
|
-
save(path: string): void;
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Load index from a file.
|
|
68
|
-
* @param {string} path File path to read.
|
|
69
|
-
*/
|
|
70
|
-
load(path: string): void;
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* View index from a file, without loading into RAM.
|
|
74
|
-
* @param {string} path File path to read.
|
|
75
|
-
*/
|
|
76
|
-
load(path: string): void;
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Add n vectors of dimension d to the index.
|
|
80
|
-
*
|
|
81
|
-
* @param {bigint | bigint[]} keys Input identifiers for every vector.
|
|
82
|
-
* @param {Float32Array | Float32Array[]} mat Input matrix, matrix of size n * d.
|
|
83
|
-
*/
|
|
84
|
-
add(keys: bigint | bigint[], mat: Float32Array | Float32Array[]): void;
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Query n vectors of dimension d to the index. Return at most k vectors for each.
|
|
88
|
-
* If there are not enough results for a query, the result array is padded with -1s.
|
|
89
|
-
*
|
|
90
|
-
* @param {Float32Array} mat Input vectors to search, matrix of size n * d.
|
|
91
|
-
* @param {bigint} k The bigint of nearest neighbors to search for.
|
|
92
|
-
* @return {Matches} Output of the search result.
|
|
93
|
-
*/
|
|
94
|
-
search(mat: Float32Array, k: bigint): Matches;
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Check if an entry is contained in the index.
|
|
98
|
-
*
|
|
99
|
-
* @param {bigint} key Identifier to look up.
|
|
100
|
-
*/
|
|
101
|
-
contains(key: bigint): boolean;
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Remove a vector from the index.
|
|
105
|
-
*
|
|
106
|
-
* @param {bigint} key Input identifier for every vector to be removed.
|
|
107
|
-
*/
|
|
108
|
-
remove(key: bigint): boolean;
|
|
109
|
-
|
|
110
|
-
}
|