usearch 0.22.3 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/prerelease.yml +3 -3
- package/.releaserc +10 -2
- package/.vscode/launch.json +10 -10
- package/.vscode/settings.json +9 -1
- package/.vscode/tasks.json +4 -4
- package/CMakeLists.txt +6 -1
- package/Cargo.toml +2 -2
- package/README.md +35 -41
- package/build.rs +2 -2
- package/c/CMakeLists.txt +48 -0
- package/c/README.md +34 -0
- package/c/lib.cpp +83 -72
- package/c/test.c +20 -20
- package/c/usearch.h +132 -32
- package/conanfile.py +1 -1
- package/cpp/CMakeLists.txt +3 -1
- package/cpp/README.md +16 -16
- package/cpp/bench.cpp +50 -126
- package/cpp/test.cpp +164 -80
- package/docs/benchmarks.md +26 -5
- package/docs/c/reference.rst +3 -3
- package/docs/compilation.md +31 -49
- package/docs/cpp/index.rst +1 -1
- package/docs/cpp/reference.rst +4 -4
- package/golang/lib.go +275 -141
- package/golang/lib_test.go +105 -0
- package/include/usearch/index.hpp +1681 -1656
- package/include/usearch/index_dense.hpp +1400 -0
- package/include/usearch/index_plugins.hpp +1263 -0
- package/java/README.md +1 -1
- package/java/cloud/unum/usearch/Index.java +10 -10
- package/java/cloud/unum/usearch/cloud_unum_usearch_Index.cpp +34 -37
- package/java/test/IndexTest.java +1 -1
- package/javascript/README.md +6 -6
- package/javascript/lib.cpp +156 -55
- package/javascript/test.js +26 -11
- package/javascript/usearch.d.ts +102 -0
- package/javascript/usearch.js +2 -118
- package/objc/USearchObjective.mm +57 -31
- package/objc/include/USearchObjective.h +32 -22
- package/package.json +5 -3
- package/python/README.md +23 -14
- package/python/lib.cpp +468 -444
- package/python/scripts/bench.ipynb +3 -2
- package/python/scripts/bench.py +4 -4
- package/python/scripts/index_faiss.py +5 -5
- package/python/scripts/join.py +4 -4
- package/python/scripts/test.py +152 -61
- package/python/scripts/test_jit.py +10 -12
- package/python/scripts/test_sparse.py +32 -0
- package/python/usearch/client.py +26 -28
- package/python/usearch/eval.py +73 -23
- package/python/usearch/index.py +520 -228
- package/python/usearch/io.py +57 -25
- package/python/usearch/numba.py +4 -4
- package/python/usearch/server.py +10 -10
- package/rust/lib.cpp +34 -30
- package/rust/lib.hpp +14 -12
- package/rust/lib.rs +8 -7
- package/setup.py +5 -2
- package/simsimd/.github/workflows/prerelease.yml +73 -0
- package/simsimd/.github/workflows/release.yml +110 -0
- package/simsimd/.github/workflows/update_version.sh +3 -0
- package/simsimd/.releaserc +77 -0
- package/simsimd/.vscode/launch.json +27 -1
- package/simsimd/.vscode/settings.json +22 -1
- package/simsimd/.vscode/tasks.json +6 -0
- package/simsimd/CMakeLists.txt +3 -2
- package/simsimd/README.md +82 -46
- package/simsimd/bench.cxx +63 -24
- package/simsimd/include/simsimd/simsimd.h +88 -66
- package/simsimd/include/simsimd/simsimd_chem.h +126 -0
- package/simsimd/package.json +8 -0
- package/simsimd/pyproject.toml +42 -0
- package/simsimd/python/python.c +81 -0
- package/simsimd/python/run.sh +1 -0
- package/simsimd/python/test.c +109 -0
- package/simsimd/python/test.py +23 -0
- package/simsimd/setup.py +44 -0
- package/swift/Index+Sugar.swift +75 -23
- package/swift/README.md +26 -2
- package/swift/Test.swift +19 -7
- package/swift/USearch.swift +2 -2
- package/tsconfig.json +8 -0
- package/wasm/CMakeLists.txt +1 -0
- package/wasmer.toml +1 -1
- package/wolfram/CMakeLists.txt +1 -0
- package/wolfram/lib.cpp +11 -13
- package/golang/usearch.h +0 -9
- package/golang/usearch_par_test.go +0 -40
- package/golang/usearch_test.go +0 -82
- package/include/usearch/index_punned_dense.hpp +0 -1001
- package/include/usearch/index_punned_helpers.hpp +0 -676
|
@@ -0,0 +1,102 @@
|
|
|
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(...args);
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Returns the dimensionality of vectors.
|
|
30
|
+
* @return {bigint} The dimensionality of vectors.
|
|
31
|
+
*/
|
|
32
|
+
dimensions(): bigint;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Returns the bigint of vectors currently indexed.
|
|
36
|
+
* @return {bigint} The bigint of vectors currently indexed.
|
|
37
|
+
*/
|
|
38
|
+
size(): bigint;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Returns index capacity.
|
|
42
|
+
* @return {bigints} The capacity of index.
|
|
43
|
+
*/
|
|
44
|
+
capacity(): bigint;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Returns connectivity.
|
|
48
|
+
* @return {bigint} The connectivity of index.
|
|
49
|
+
*/
|
|
50
|
+
connectivity(): bigint;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Write index to a file.
|
|
54
|
+
* @param {string} path File path to write.
|
|
55
|
+
*/
|
|
56
|
+
save(path: string): void;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Load index from a file.
|
|
60
|
+
* @param {string} path File path to read.
|
|
61
|
+
*/
|
|
62
|
+
load(path: string): void;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* View index from a file, without loading into RAM.
|
|
66
|
+
* @param {string} path File path to read.
|
|
67
|
+
*/
|
|
68
|
+
load(path: string): void;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Add n vectors of dimension d to the index.
|
|
72
|
+
*
|
|
73
|
+
* @param {bigint | bigint[]} keys Input identifiers for every vector.
|
|
74
|
+
* @param {Float32Array | Float32Array[]} mat Input matrix, matrix of size n * d.
|
|
75
|
+
*/
|
|
76
|
+
add(keys: bigint | bigint[], mat: Float32Array | Float32Array[]): void;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Query n vectors of dimension d to the index. Return at most k vectors for each.
|
|
80
|
+
* If there are not enough results for a query, the result array is padded with -1s.
|
|
81
|
+
*
|
|
82
|
+
* @param {Float32Array} mat Input vectors to search, matrix of size n * d.
|
|
83
|
+
* @param {bigint} k The bigint of nearest neighbors to search for.
|
|
84
|
+
* @return {Matches} Output of the search result.
|
|
85
|
+
*/
|
|
86
|
+
search(mat: Float32Array, k: bigint): Matches;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Check if an entry is contained in the index.
|
|
90
|
+
*
|
|
91
|
+
* @param {bigint} key Identifier to look up.
|
|
92
|
+
*/
|
|
93
|
+
contains(key: bigint): boolean;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Remove a vector from the index.
|
|
97
|
+
*
|
|
98
|
+
* @param {bigint} key Input identifier for every vector to be removed.
|
|
99
|
+
*/
|
|
100
|
+
remove(key: bigint): boolean;
|
|
101
|
+
|
|
102
|
+
}
|
package/javascript/usearch.js
CHANGED
|
@@ -1,118 +1,2 @@
|
|
|
1
|
-
const
|
|
2
|
-
|
|
3
|
-
class Index {
|
|
4
|
-
/**
|
|
5
|
-
* Creates an instance of Index.
|
|
6
|
-
* @date 6/7/2023 - 7:32:29 AM
|
|
7
|
-
*
|
|
8
|
-
* @constructor
|
|
9
|
-
* @param {...{}} args
|
|
10
|
-
*/
|
|
11
|
-
constructor(...args) {
|
|
12
|
-
this.native = new usearch_native.Index(...args)
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Description placeholder
|
|
17
|
-
* @date 6/7/2023 - 7:32:28 AM
|
|
18
|
-
*
|
|
19
|
-
* @param {...{}} args
|
|
20
|
-
* @returns {*}
|
|
21
|
-
*/
|
|
22
|
-
dimensions(...args) {
|
|
23
|
-
return this.native.dimensions(...args)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Description placeholder
|
|
28
|
-
* @date 6/7/2023 - 7:32:28 AM
|
|
29
|
-
*
|
|
30
|
-
* @param {...{}} args
|
|
31
|
-
* @returns {*}
|
|
32
|
-
*/
|
|
33
|
-
size(...args) {
|
|
34
|
-
return this.native.size(...args)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Description placeholder
|
|
39
|
-
* @date 6/7/2023 - 7:32:28 AM
|
|
40
|
-
*
|
|
41
|
-
* @param {...{}} args
|
|
42
|
-
* @returns {*}
|
|
43
|
-
*/
|
|
44
|
-
capacity(...args) {
|
|
45
|
-
return this.native.capacity(...args)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Description placeholder
|
|
50
|
-
* @date 6/7/2023 - 7:32:28 AM
|
|
51
|
-
*
|
|
52
|
-
* @param {...{}} args
|
|
53
|
-
* @returns {*}
|
|
54
|
-
*/
|
|
55
|
-
connectivity(...args) {
|
|
56
|
-
return this.native.connectivity(...args)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Description placeholder
|
|
61
|
-
* @date 6/7/2023 - 7:32:28 AM
|
|
62
|
-
*
|
|
63
|
-
* @param {...{}} args
|
|
64
|
-
* @returns {*}
|
|
65
|
-
*/
|
|
66
|
-
save(...args) {
|
|
67
|
-
return this.native.save(...args)
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Description placeholder
|
|
72
|
-
* @date 6/7/2023 - 7:32:27 AM
|
|
73
|
-
*
|
|
74
|
-
* @param {...{}} args
|
|
75
|
-
* @returns {*}
|
|
76
|
-
*/
|
|
77
|
-
load(...args) {
|
|
78
|
-
return this.native.load(...args)
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Description placeholder
|
|
83
|
-
* @date 6/7/2023 - 7:32:27 AM
|
|
84
|
-
*
|
|
85
|
-
* @param {...{}} args
|
|
86
|
-
* @returns {*}
|
|
87
|
-
*/
|
|
88
|
-
view(...args) {
|
|
89
|
-
return this.native.view(...args)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Description placeholder
|
|
94
|
-
* @date 6/7/2023 - 7:32:27 AM
|
|
95
|
-
*
|
|
96
|
-
* @param {...{}} args
|
|
97
|
-
* @returns {*}
|
|
98
|
-
*/
|
|
99
|
-
add(...args) {
|
|
100
|
-
return this.native.add(...args)
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Description placeholder
|
|
105
|
-
* @date 6/7/2023 - 7:32:27 AM
|
|
106
|
-
*
|
|
107
|
-
* @param {...{}} args
|
|
108
|
-
* @returns {*}
|
|
109
|
-
*/
|
|
110
|
-
search(...args) {
|
|
111
|
-
return this.native.search(...args)
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
module.exports = {
|
|
117
|
-
Index: Index
|
|
118
|
-
};
|
|
1
|
+
const usearch = require('bindings')('usearch');
|
|
2
|
+
module.exports = usearch;
|
package/objc/USearchObjective.mm
CHANGED
|
@@ -2,21 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
#pragma clang diagnostic push
|
|
4
4
|
#pragma clang diagnostic ignored "-Wdocumentation"
|
|
5
|
-
#import <usearch/
|
|
5
|
+
#import <usearch/index_dense.hpp>
|
|
6
6
|
#pragma clang diagnostic pop
|
|
7
7
|
|
|
8
8
|
using namespace unum::usearch;
|
|
9
9
|
using namespace unum;
|
|
10
10
|
|
|
11
|
-
using
|
|
12
|
-
using
|
|
13
|
-
using
|
|
14
|
-
using
|
|
15
|
-
using
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
using id_t = typename index_t::id_t;
|
|
19
|
-
using shared_index_t = std::shared_ptr<index_t>;
|
|
11
|
+
using distance_t = distance_punned_t;
|
|
12
|
+
using add_result_t = typename index_dense_t::add_result_t;
|
|
13
|
+
using labeling_result_t = typename index_dense_t::labeling_result_t;
|
|
14
|
+
using search_result_t = typename index_dense_t::search_result_t;
|
|
15
|
+
using shared_index_dense_t = std::shared_ptr<index_dense_t>;
|
|
16
|
+
|
|
17
|
+
static_assert(std::is_same<USearchKey, index_dense_t::key_t>::value, "Type mismatch between Objective-C and C++");
|
|
20
18
|
|
|
21
19
|
metric_kind_t to_native_metric(USearchMetric m) {
|
|
22
20
|
switch (m) {
|
|
@@ -54,8 +52,8 @@ metric_kind_t to_native_metric(USearchMetric m) {
|
|
|
54
52
|
|
|
55
53
|
scalar_kind_t to_native_scalar(USearchScalar m) {
|
|
56
54
|
switch (m) {
|
|
57
|
-
case
|
|
58
|
-
return scalar_kind_t::
|
|
55
|
+
case USearchScalarI8:
|
|
56
|
+
return scalar_kind_t::i8_k;
|
|
59
57
|
|
|
60
58
|
case USearchScalarF16:
|
|
61
59
|
return scalar_kind_t::f16_k;
|
|
@@ -73,15 +71,15 @@ scalar_kind_t to_native_scalar(USearchScalar m) {
|
|
|
73
71
|
|
|
74
72
|
@interface USearchIndex ()
|
|
75
73
|
|
|
76
|
-
@property (readonly)
|
|
74
|
+
@property (readonly) shared_index_dense_t native;
|
|
77
75
|
|
|
78
|
-
- (instancetype)initWithIndex:(
|
|
76
|
+
- (instancetype)initWithIndex:(shared_index_dense_t)native;
|
|
79
77
|
|
|
80
78
|
@end
|
|
81
79
|
|
|
82
80
|
@implementation USearchIndex
|
|
83
81
|
|
|
84
|
-
- (instancetype)initWithIndex:(
|
|
82
|
+
- (instancetype)initWithIndex:(shared_index_dense_t)native {
|
|
85
83
|
self = [super init];
|
|
86
84
|
_native = native;
|
|
87
85
|
return self;
|
|
@@ -115,18 +113,18 @@ scalar_kind_t to_native_scalar(USearchScalar m) {
|
|
|
115
113
|
return static_cast<UInt32>(_native->expansion_search());
|
|
116
114
|
}
|
|
117
115
|
|
|
118
|
-
+ (instancetype)make:(USearchMetric)
|
|
116
|
+
+ (instancetype)make:(USearchMetric)metricKind dimensions:(UInt32)dimensions connectivity:(UInt32)connectivity quantization:(USearchScalar)quantization {
|
|
119
117
|
std::size_t dims = static_cast<std::size_t>(dimensions);
|
|
120
|
-
index_config_t config;
|
|
121
118
|
|
|
122
|
-
config
|
|
123
|
-
|
|
119
|
+
index_config_t config(static_cast<std::size_t>(connectivity));
|
|
120
|
+
metric_punned_t metric(dims, to_native_metric(metricKind), to_native_scalar(quantization));
|
|
121
|
+
shared_index_dense_t ptr = std::make_shared<index_dense_t>(index_dense_t::make(metric, config));
|
|
124
122
|
return [[USearchIndex alloc] initWithIndex:ptr];
|
|
125
123
|
}
|
|
126
124
|
|
|
127
|
-
- (void)addSingle:(
|
|
125
|
+
- (void)addSingle:(USearchKey)key
|
|
128
126
|
vector:(Float32 const *_Nonnull)vector {
|
|
129
|
-
add_result_t result = _native->add(
|
|
127
|
+
add_result_t result = _native->add(key, vector);
|
|
130
128
|
|
|
131
129
|
if (!result) {
|
|
132
130
|
@throw [NSException exceptionWithName:@"Can't add to index"
|
|
@@ -137,7 +135,7 @@ scalar_kind_t to_native_scalar(USearchScalar m) {
|
|
|
137
135
|
|
|
138
136
|
- (UInt32)searchSingle:(Float32 const *_Nonnull)vector
|
|
139
137
|
count:(UInt32)wanted
|
|
140
|
-
|
|
138
|
+
keys:(USearchKey *_Nullable)keys
|
|
141
139
|
distances:(Float32 *_Nullable)distances {
|
|
142
140
|
search_result_t result = _native->search(vector, static_cast<std::size_t>(wanted));
|
|
143
141
|
|
|
@@ -147,13 +145,13 @@ scalar_kind_t to_native_scalar(USearchScalar m) {
|
|
|
147
145
|
userInfo:nil];
|
|
148
146
|
}
|
|
149
147
|
|
|
150
|
-
std::size_t found = result.dump_to(
|
|
148
|
+
std::size_t found = result.dump_to(keys, distances);
|
|
151
149
|
return static_cast<UInt32>(found);
|
|
152
150
|
}
|
|
153
151
|
|
|
154
|
-
- (void)addDouble:(
|
|
152
|
+
- (void)addDouble:(USearchKey)key
|
|
155
153
|
vector:(Float64 const *_Nonnull)vector {
|
|
156
|
-
add_result_t result = _native->add(
|
|
154
|
+
add_result_t result = _native->add(key, (f64_t const *)vector);
|
|
157
155
|
|
|
158
156
|
if (!result) {
|
|
159
157
|
@throw [NSException exceptionWithName:@"Can't add to index"
|
|
@@ -164,7 +162,7 @@ scalar_kind_t to_native_scalar(USearchScalar m) {
|
|
|
164
162
|
|
|
165
163
|
- (UInt32)searchDouble:(Float64 const *_Nonnull)vector
|
|
166
164
|
count:(UInt32)wanted
|
|
167
|
-
|
|
165
|
+
keys:(USearchKey *_Nullable)keys
|
|
168
166
|
distances:(Float32 *_Nullable)distances {
|
|
169
167
|
search_result_t result = _native->search((f64_t const *)vector, static_cast<std::size_t>(wanted));
|
|
170
168
|
|
|
@@ -174,13 +172,13 @@ scalar_kind_t to_native_scalar(USearchScalar m) {
|
|
|
174
172
|
userInfo:nil];
|
|
175
173
|
}
|
|
176
174
|
|
|
177
|
-
std::size_t found = result.dump_to(
|
|
175
|
+
std::size_t found = result.dump_to(keys, distances);
|
|
178
176
|
return static_cast<UInt32>(found);
|
|
179
177
|
}
|
|
180
178
|
|
|
181
|
-
- (void)addHalf:(
|
|
179
|
+
- (void)addHalf:(USearchKey)key
|
|
182
180
|
vector:(void const *_Nonnull)vector {
|
|
183
|
-
add_result_t result = _native->add(
|
|
181
|
+
add_result_t result = _native->add(key, (f16_t const *)vector);
|
|
184
182
|
|
|
185
183
|
if (!result) {
|
|
186
184
|
@throw [NSException exceptionWithName:@"Can't add to index"
|
|
@@ -191,7 +189,7 @@ scalar_kind_t to_native_scalar(USearchScalar m) {
|
|
|
191
189
|
|
|
192
190
|
- (UInt32)searchHalf:(void const *_Nonnull)vector
|
|
193
191
|
count:(UInt32)wanted
|
|
194
|
-
|
|
192
|
+
keys:(USearchKey *_Nullable)keys
|
|
195
193
|
distances:(Float32 *_Nullable)distances {
|
|
196
194
|
search_result_t result = _native->search((f16_t const *)vector, static_cast<std::size_t>(wanted));
|
|
197
195
|
|
|
@@ -201,7 +199,7 @@ scalar_kind_t to_native_scalar(USearchScalar m) {
|
|
|
201
199
|
userInfo:nil];
|
|
202
200
|
}
|
|
203
201
|
|
|
204
|
-
std::size_t found = result.dump_to(
|
|
202
|
+
std::size_t found = result.dump_to(keys, distances);
|
|
205
203
|
return static_cast<UInt32>(found);
|
|
206
204
|
}
|
|
207
205
|
|
|
@@ -213,6 +211,34 @@ scalar_kind_t to_native_scalar(USearchScalar m) {
|
|
|
213
211
|
_native->reserve(static_cast<std::size_t>(count));
|
|
214
212
|
}
|
|
215
213
|
|
|
214
|
+
- (Boolean)contains:(USearchKey)key {
|
|
215
|
+
return _native->contains(key);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
- (UInt32)count:(USearchKey)key {
|
|
219
|
+
return _native->count(key);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
- (void)remove:(USearchKey)key {
|
|
223
|
+
labeling_result_t result = _native->remove(key);
|
|
224
|
+
|
|
225
|
+
if (!result) {
|
|
226
|
+
@throw [NSException exceptionWithName:@"Can't remove an entry"
|
|
227
|
+
reason:[NSString stringWithUTF8String:result.error.what()]
|
|
228
|
+
userInfo:nil];
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
- (void)rename:(USearchKey)key to:(USearchKey)to {
|
|
233
|
+
labeling_result_t result = _native->rename(key, to);
|
|
234
|
+
|
|
235
|
+
if (!result) {
|
|
236
|
+
@throw [NSException exceptionWithName:@"Can't rename the entry"
|
|
237
|
+
reason:[NSString stringWithUTF8String:result.error.what()]
|
|
238
|
+
userInfo:nil];
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
216
242
|
- (void)save:(NSString *)path {
|
|
217
243
|
char const *path_c = [path UTF8String];
|
|
218
244
|
|
|
@@ -8,7 +8,7 @@ typedef NS_ENUM(NSUInteger, USearchScalar) {
|
|
|
8
8
|
USearchScalarF32,
|
|
9
9
|
USearchScalarF16,
|
|
10
10
|
USearchScalarF64,
|
|
11
|
-
|
|
11
|
+
USearchScalarI8,
|
|
12
12
|
USearchScalarB1
|
|
13
13
|
};
|
|
14
14
|
|
|
@@ -25,7 +25,7 @@ typedef NS_ENUM(NSUInteger, USearchMetric) {
|
|
|
25
25
|
USearchMetricSorensen
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
typedef UInt64
|
|
28
|
+
typedef UInt64 USearchKey;
|
|
29
29
|
|
|
30
30
|
API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0))
|
|
31
31
|
@interface USearchIndex : NSObject
|
|
@@ -46,8 +46,8 @@ API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0))
|
|
|
46
46
|
* @param metric The distance function to compare the dis-similarity of vectors.
|
|
47
47
|
* @param dimensions The number of dimensions planned for this index.
|
|
48
48
|
* @param connectivity Number of connections per node in the proximity graph.
|
|
49
|
-
* Higher connectivity improves
|
|
50
|
-
* @param quantization
|
|
49
|
+
* Higher connectivity improves quantization, increases memory usage, and reduces construction speed.
|
|
50
|
+
* @param quantization Quantization of internal vector representations. Lower quantization means higher speed.
|
|
51
51
|
*/
|
|
52
52
|
+ (instancetype)make:(USearchMetric)metric dimensions:(UInt32)dimensions connectivity:(UInt32)connectivity quantization:(USearchScalar)quantization NS_SWIFT_NAME(make(metric:dimensions:connectivity:quantization:));
|
|
53
53
|
|
|
@@ -60,61 +60,71 @@ API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0))
|
|
|
60
60
|
* @brief Adds a labeled vector to the index.
|
|
61
61
|
* @param vector Single-precision vector.
|
|
62
62
|
*/
|
|
63
|
-
- (void)addSingle:(
|
|
64
|
-
vector:(Float32 const *_Nonnull)vector NS_SWIFT_NAME(addSingle(
|
|
63
|
+
- (void)addSingle:(USearchKey)key
|
|
64
|
+
vector:(Float32 const *_Nonnull)vector NS_SWIFT_NAME(addSingle(key:vector:));
|
|
65
65
|
|
|
66
66
|
/**
|
|
67
67
|
* @brief Approximate nearest neighbors search.
|
|
68
68
|
* @param vector Single-precision query vector.
|
|
69
69
|
* @param count Upper limit on the number of matches to retrieve.
|
|
70
|
-
* @param
|
|
70
|
+
* @param keys Optional output buffer for keys of approximate neighbors.
|
|
71
71
|
* @param distances Optional output buffer for (increasing) distances to approximate neighbors.
|
|
72
|
-
* @return Number of matches exported to `
|
|
72
|
+
* @return Number of matches exported to `keys` and `distances`.
|
|
73
73
|
*/
|
|
74
74
|
- (UInt32)searchSingle:(Float32 const *_Nonnull)vector
|
|
75
75
|
count:(UInt32)count
|
|
76
|
-
|
|
77
|
-
distances:(Float32 *_Nullable)distances NS_SWIFT_NAME(searchSingle(vector:count:
|
|
76
|
+
keys:(USearchKey *_Nullable)keys
|
|
77
|
+
distances:(Float32 *_Nullable)distances NS_SWIFT_NAME(searchSingle(vector:count:keys:distances:));
|
|
78
78
|
|
|
79
79
|
/**
|
|
80
80
|
* @brief Adds a labeled vector to the index.
|
|
81
81
|
* @param vector Double-precision vector.
|
|
82
82
|
*/
|
|
83
|
-
- (void)addDouble:(
|
|
84
|
-
vector:(Float64 const *_Nonnull)vector NS_SWIFT_NAME(addDouble(
|
|
83
|
+
- (void)addDouble:(USearchKey)key
|
|
84
|
+
vector:(Float64 const *_Nonnull)vector NS_SWIFT_NAME(addDouble(key:vector:));
|
|
85
85
|
|
|
86
86
|
/**
|
|
87
87
|
* @brief Approximate nearest neighbors search.
|
|
88
88
|
* @param vector Double-precision query vector.
|
|
89
89
|
* @param count Upper limit on the number of matches to retrieve.
|
|
90
|
-
* @param
|
|
90
|
+
* @param keys Optional output buffer for keys of approximate neighbors.
|
|
91
91
|
* @param distances Optional output buffer for (increasing) distances to approximate neighbors.
|
|
92
|
-
* @return Number of matches exported to `
|
|
92
|
+
* @return Number of matches exported to `keys` and `distances`.
|
|
93
93
|
*/
|
|
94
94
|
- (UInt32)searchDouble:(Float64 const *_Nonnull)vector
|
|
95
95
|
count:(UInt32)count
|
|
96
|
-
|
|
97
|
-
distances:(Float32 *_Nullable)distances NS_SWIFT_NAME(searchDouble(vector:count:
|
|
96
|
+
keys:(USearchKey *_Nullable)keys
|
|
97
|
+
distances:(Float32 *_Nullable)distances NS_SWIFT_NAME(searchDouble(vector:count:keys:distances:));
|
|
98
98
|
|
|
99
99
|
/**
|
|
100
100
|
* @brief Adds a labeled vector to the index.
|
|
101
101
|
* @param vector Half-precision vector.
|
|
102
102
|
*/
|
|
103
|
-
- (void)addHalf:(
|
|
104
|
-
vector:(void const *_Nonnull)vector NS_SWIFT_NAME(addHalf(
|
|
103
|
+
- (void)addHalf:(USearchKey)key
|
|
104
|
+
vector:(void const *_Nonnull)vector NS_SWIFT_NAME(addHalf(key:vector:));
|
|
105
105
|
|
|
106
106
|
/**
|
|
107
107
|
* @brief Approximate nearest neighbors search.
|
|
108
108
|
* @param vector Half-precision query vector.
|
|
109
109
|
* @param count Upper limit on the number of matches to retrieve.
|
|
110
|
-
* @param
|
|
110
|
+
* @param keys Optional output buffer for keys of approximate neighbors.
|
|
111
111
|
* @param distances Optional output buffer for (increasing) distances to approximate neighbors.
|
|
112
|
-
* @return Number of matches exported to `
|
|
112
|
+
* @return Number of matches exported to `keys` and `distances`.
|
|
113
113
|
*/
|
|
114
114
|
- (UInt32)searchHalf:(void const *_Nonnull)vector
|
|
115
115
|
count:(UInt32)count
|
|
116
|
-
|
|
117
|
-
distances:(Float32 *_Nullable)distances NS_SWIFT_NAME(searchHalf(vector:count:
|
|
116
|
+
keys:(USearchKey *_Nullable)keys
|
|
117
|
+
distances:(Float32 *_Nullable)distances NS_SWIFT_NAME(searchHalf(vector:count:keys:distances:));
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
- (Boolean)contains:(USearchKey)key NS_SWIFT_NAME(contains(key:));
|
|
121
|
+
|
|
122
|
+
- (UInt32)count:(USearchKey)key NS_SWIFT_NAME(count(key:));
|
|
123
|
+
|
|
124
|
+
- (void)remove:(USearchKey)key NS_SWIFT_NAME(remove(key:));
|
|
125
|
+
|
|
126
|
+
- (void)rename:(USearchKey)key to:(USearchKey)key NS_SWIFT_NAME(rename(from:to:));
|
|
127
|
+
|
|
118
128
|
|
|
119
129
|
/**
|
|
120
130
|
* @brief Saves pre-constructed index to disk.
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "usearch",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Smaller & Faster Single-File Vector Search Engine from Unum",
|
|
5
|
-
"author": "
|
|
5
|
+
"author": "Ash Vardanian",
|
|
6
6
|
"license": "Apache 2.0",
|
|
7
7
|
"main": "javascript/usearch.js",
|
|
8
8
|
"repository": {
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"node": "~10 >=10.20 || >=12.17"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
+
"@types/node": "^20.4.5",
|
|
17
18
|
"bindings": "~1.2.1",
|
|
18
19
|
"node-addon-api": "^3.0.0"
|
|
19
20
|
},
|
|
@@ -24,6 +25,7 @@
|
|
|
24
25
|
"@semantic-release/exec": "^6.0.3",
|
|
25
26
|
"@semantic-release/git": "^10.0.1",
|
|
26
27
|
"conventional-changelog-eslint": "^3.0.9",
|
|
27
|
-
"semantic-release": "^21.0.7"
|
|
28
|
+
"semantic-release": "^21.0.7",
|
|
29
|
+
"typescript": "^5.1.6"
|
|
28
30
|
}
|
|
29
31
|
}
|
package/python/README.md
CHANGED
|
@@ -15,7 +15,7 @@ from usearch.index import Index
|
|
|
15
15
|
index = Index(
|
|
16
16
|
ndim=3, # Define the number of dimensions in input vectors
|
|
17
17
|
metric='cos', # Choose 'l2sq', 'haversine' or other metric, default = 'ip'
|
|
18
|
-
dtype='f32', # Quantize to 'f16' or '
|
|
18
|
+
dtype='f32', # Quantize to 'f16' or 'i8' if needed, default = 'f32'
|
|
19
19
|
connectivity=16, # How frequent should the connections in the graph be, optional
|
|
20
20
|
expansion_add=128, # Control the recall of indexing, optional
|
|
21
21
|
expansion_search=64, # Control the quality of search, optional
|
|
@@ -23,12 +23,12 @@ index = Index(
|
|
|
23
23
|
|
|
24
24
|
vector = np.array([0.2, 0.6, 0.4])
|
|
25
25
|
index.add(42, vector)
|
|
26
|
-
matches
|
|
26
|
+
matches: Matches = index.search(vector, 10)
|
|
27
27
|
|
|
28
28
|
assert len(index) == 1
|
|
29
|
-
assert
|
|
30
|
-
assert matches[0] == 42
|
|
31
|
-
assert
|
|
29
|
+
assert len(matches) == 1
|
|
30
|
+
assert matches[0].key == 42
|
|
31
|
+
assert matches[0].distance <= 0.001
|
|
32
32
|
assert np.allclose(index[42], vector)
|
|
33
33
|
```
|
|
34
34
|
|
|
@@ -57,14 +57,18 @@ The difference would be in the shape of the tensors.
|
|
|
57
57
|
|
|
58
58
|
```py
|
|
59
59
|
n = 100
|
|
60
|
-
|
|
60
|
+
keys = np.arange(n)
|
|
61
61
|
vectors = np.random.uniform(0, 0.3, (n, index.ndim)).astype(np.float32)
|
|
62
62
|
|
|
63
|
-
index.add(
|
|
64
|
-
matches
|
|
63
|
+
index.add(keys, vectors, threads=..., copy=...)
|
|
64
|
+
matches: BatchMatches = index.search(vectors, 10, threads=...)
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
assert
|
|
66
|
+
first_query_matches: Matches = matches[0]
|
|
67
|
+
assert matches[0].key == 0
|
|
68
|
+
assert matches[0].distance <= 0.001
|
|
69
|
+
|
|
70
|
+
assert len(matches) == vectors.shape[0]
|
|
71
|
+
assert len(matches[0]) <= 10
|
|
68
72
|
```
|
|
69
73
|
|
|
70
74
|
You can also override the default `threads` and `copy` arguments in bulk workloads.
|
|
@@ -257,17 +261,22 @@ from usearch.io import load_matrix, save_matrix
|
|
|
257
261
|
|
|
258
262
|
vectors = load_matrix('deep1B.fbin')
|
|
259
263
|
index = Index(ndim=vectors.shape[1])
|
|
260
|
-
index.add(
|
|
264
|
+
index.add(keys, vectors)
|
|
261
265
|
```
|
|
262
266
|
|
|
263
267
|
One may often want to evaluate the quality of the constructed index before running in production.
|
|
264
268
|
The trivial way is to measure `recall@1` on the entries already present in the index.
|
|
265
269
|
|
|
266
270
|
```py
|
|
267
|
-
from usearch.eval import
|
|
271
|
+
from usearch.eval import self_recall
|
|
272
|
+
|
|
273
|
+
stats: SearchStats = self_recall(index, exact=True)
|
|
274
|
+
assert stats.visited_members == 0, "Exact search won't attend index nodes"
|
|
275
|
+
assert stats.computed_distances == len(index), "And will compute the distance to every node"
|
|
268
276
|
|
|
269
|
-
|
|
270
|
-
|
|
277
|
+
stats: SearchStats = self_recall(index, exact=False)
|
|
278
|
+
assert stats.visited_members > 0
|
|
279
|
+
assert stats.computed_distances <= len(index)
|
|
271
280
|
```
|
|
272
281
|
|
|
273
282
|
In case you have some ground-truth data for more than one entry, you compare search results against expected values:
|