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.
Files changed (93) hide show
  1. package/.github/workflows/prerelease.yml +3 -3
  2. package/.releaserc +10 -2
  3. package/.vscode/launch.json +10 -10
  4. package/.vscode/settings.json +9 -1
  5. package/.vscode/tasks.json +4 -4
  6. package/CMakeLists.txt +6 -1
  7. package/Cargo.toml +2 -2
  8. package/README.md +35 -41
  9. package/build.rs +2 -2
  10. package/c/CMakeLists.txt +48 -0
  11. package/c/README.md +34 -0
  12. package/c/lib.cpp +83 -72
  13. package/c/test.c +20 -20
  14. package/c/usearch.h +132 -32
  15. package/conanfile.py +1 -1
  16. package/cpp/CMakeLists.txt +3 -1
  17. package/cpp/README.md +16 -16
  18. package/cpp/bench.cpp +50 -126
  19. package/cpp/test.cpp +164 -80
  20. package/docs/benchmarks.md +26 -5
  21. package/docs/c/reference.rst +3 -3
  22. package/docs/compilation.md +31 -49
  23. package/docs/cpp/index.rst +1 -1
  24. package/docs/cpp/reference.rst +4 -4
  25. package/golang/lib.go +275 -141
  26. package/golang/lib_test.go +105 -0
  27. package/include/usearch/index.hpp +1681 -1656
  28. package/include/usearch/index_dense.hpp +1400 -0
  29. package/include/usearch/index_plugins.hpp +1263 -0
  30. package/java/README.md +1 -1
  31. package/java/cloud/unum/usearch/Index.java +10 -10
  32. package/java/cloud/unum/usearch/cloud_unum_usearch_Index.cpp +34 -37
  33. package/java/test/IndexTest.java +1 -1
  34. package/javascript/README.md +6 -6
  35. package/javascript/lib.cpp +156 -55
  36. package/javascript/test.js +26 -11
  37. package/javascript/usearch.d.ts +102 -0
  38. package/javascript/usearch.js +2 -118
  39. package/objc/USearchObjective.mm +57 -31
  40. package/objc/include/USearchObjective.h +32 -22
  41. package/package.json +5 -3
  42. package/python/README.md +23 -14
  43. package/python/lib.cpp +468 -444
  44. package/python/scripts/bench.ipynb +3 -2
  45. package/python/scripts/bench.py +4 -4
  46. package/python/scripts/index_faiss.py +5 -5
  47. package/python/scripts/join.py +4 -4
  48. package/python/scripts/test.py +152 -61
  49. package/python/scripts/test_jit.py +10 -12
  50. package/python/scripts/test_sparse.py +32 -0
  51. package/python/usearch/client.py +26 -28
  52. package/python/usearch/eval.py +73 -23
  53. package/python/usearch/index.py +520 -228
  54. package/python/usearch/io.py +57 -25
  55. package/python/usearch/numba.py +4 -4
  56. package/python/usearch/server.py +10 -10
  57. package/rust/lib.cpp +34 -30
  58. package/rust/lib.hpp +14 -12
  59. package/rust/lib.rs +8 -7
  60. package/setup.py +5 -2
  61. package/simsimd/.github/workflows/prerelease.yml +73 -0
  62. package/simsimd/.github/workflows/release.yml +110 -0
  63. package/simsimd/.github/workflows/update_version.sh +3 -0
  64. package/simsimd/.releaserc +77 -0
  65. package/simsimd/.vscode/launch.json +27 -1
  66. package/simsimd/.vscode/settings.json +22 -1
  67. package/simsimd/.vscode/tasks.json +6 -0
  68. package/simsimd/CMakeLists.txt +3 -2
  69. package/simsimd/README.md +82 -46
  70. package/simsimd/bench.cxx +63 -24
  71. package/simsimd/include/simsimd/simsimd.h +88 -66
  72. package/simsimd/include/simsimd/simsimd_chem.h +126 -0
  73. package/simsimd/package.json +8 -0
  74. package/simsimd/pyproject.toml +42 -0
  75. package/simsimd/python/python.c +81 -0
  76. package/simsimd/python/run.sh +1 -0
  77. package/simsimd/python/test.c +109 -0
  78. package/simsimd/python/test.py +23 -0
  79. package/simsimd/setup.py +44 -0
  80. package/swift/Index+Sugar.swift +75 -23
  81. package/swift/README.md +26 -2
  82. package/swift/Test.swift +19 -7
  83. package/swift/USearch.swift +2 -2
  84. package/tsconfig.json +8 -0
  85. package/wasm/CMakeLists.txt +1 -0
  86. package/wasmer.toml +1 -1
  87. package/wolfram/CMakeLists.txt +1 -0
  88. package/wolfram/lib.cpp +11 -13
  89. package/golang/usearch.h +0 -9
  90. package/golang/usearch_par_test.go +0 -40
  91. package/golang/usearch_test.go +0 -82
  92. package/include/usearch/index_punned_dense.hpp +0 -1001
  93. 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
+ }
@@ -1,118 +1,2 @@
1
- const usearch_native = require('bindings')('usearch');
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;
@@ -2,21 +2,19 @@
2
2
 
3
3
  #pragma clang diagnostic push
4
4
  #pragma clang diagnostic ignored "-Wdocumentation"
5
- #import <usearch/index_punned_dense.hpp>
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 metric_t = index_punned_dense_metric_t;
12
- using distance_t = punned_distance_t;
13
- using index_t = punned_small_t;
14
- using add_result_t = typename index_t::add_result_t;
15
- using search_result_t = typename index_t::search_result_t;
16
- using serialization_result_t = typename index_t::serialization_result_t;
17
- using label_t = typename index_t::label_t;
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 USearchScalarF8:
58
- return scalar_kind_t::f8_k;
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) shared_index_t native;
74
+ @property (readonly) shared_index_dense_t native;
77
75
 
78
- - (instancetype)initWithIndex:(shared_index_t)native;
76
+ - (instancetype)initWithIndex:(shared_index_dense_t)native;
79
77
 
80
78
  @end
81
79
 
82
80
  @implementation USearchIndex
83
81
 
84
- - (instancetype)initWithIndex:(shared_index_t)native {
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)metric dimensions:(UInt32)dimensions connectivity:(UInt32)connectivity quantization:(USearchScalar)quantization {
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.connectivity = static_cast<std::size_t>(connectivity);
123
- shared_index_t ptr = std::make_shared<index_t>(index_t::make(dims, to_native_metric(metric), config, to_native_scalar(quantization)));
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:(USearchLabel)label
125
+ - (void)addSingle:(USearchKey)key
128
126
  vector:(Float32 const *_Nonnull)vector {
129
- add_result_t result = _native->add(label, vector);
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
- labels:(USearchLabel *_Nullable)labels
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(labels, distances);
148
+ std::size_t found = result.dump_to(keys, distances);
151
149
  return static_cast<UInt32>(found);
152
150
  }
153
151
 
154
- - (void)addDouble:(USearchLabel)label
152
+ - (void)addDouble:(USearchKey)key
155
153
  vector:(Float64 const *_Nonnull)vector {
156
- add_result_t result = _native->add(label, (f64_t const *)vector);
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
- labels:(USearchLabel *_Nullable)labels
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(labels, distances);
175
+ std::size_t found = result.dump_to(keys, distances);
178
176
  return static_cast<UInt32>(found);
179
177
  }
180
178
 
181
- - (void)addHalf:(USearchLabel)label
179
+ - (void)addHalf:(USearchKey)key
182
180
  vector:(void const *_Nonnull)vector {
183
- add_result_t result = _native->add(label, (f16_t const *)vector);
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
- labels:(USearchLabel *_Nullable)labels
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(labels, distances);
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
- USearchScalarF8,
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 USearchLabel;
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 accuracy, increases memory usage, and reduces construction speed.
50
- * @param quantization Accuracy of internal vector representations. Lower accuracy means higher speed.
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:(USearchLabel)label
64
- vector:(Float32 const *_Nonnull)vector NS_SWIFT_NAME(addSingle(label:vector:));
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 labels Optional output buffer for labels of approximate neighbors.
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 `labels` and `distances`.
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
- labels:(USearchLabel *_Nullable)labels
77
- distances:(Float32 *_Nullable)distances NS_SWIFT_NAME(searchSingle(vector:count:labels:distances:));
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:(USearchLabel)label
84
- vector:(Float64 const *_Nonnull)vector NS_SWIFT_NAME(addDouble(label:vector:));
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 labels Optional output buffer for labels of approximate neighbors.
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 `labels` and `distances`.
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
- labels:(USearchLabel *_Nullable)labels
97
- distances:(Float32 *_Nullable)distances NS_SWIFT_NAME(searchDouble(vector:count:labels:distances:));
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:(USearchLabel)label
104
- vector:(void const *_Nonnull)vector NS_SWIFT_NAME(addHalf(label:vector:));
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 labels Optional output buffer for labels of approximate neighbors.
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 `labels` and `distances`.
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
- labels:(USearchLabel *_Nullable)labels
117
- distances:(Float32 *_Nullable)distances NS_SWIFT_NAME(searchHalf(vector:count:labels:distances:));
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": "0.22.3",
3
+ "version": "1.1.0",
4
4
  "description": "Smaller & Faster Single-File Vector Search Engine from Unum",
5
- "author": "Ashot Vardanian",
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 'f8' if needed, default = 'f32'
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, distances, count = index.search(vector, 10)
26
+ matches: Matches = index.search(vector, 10)
27
27
 
28
28
  assert len(index) == 1
29
- assert count == 1
30
- assert matches[0] == 42
31
- assert distances[0] <= 0.001
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
- labels = np.arange(n)
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(labels, vectors, threads=..., copy=...)
64
- matches, distances, counts = index.search(vectors, 10, threads=...)
63
+ index.add(keys, vectors, threads=..., copy=...)
64
+ matches: BatchMatches = index.search(vectors, 10, threads=...)
65
65
 
66
- assert matches.shape[0] == vectors.shape[0]
67
- assert counts[0] <= 10
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(labels, vectors)
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 recall_members
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
- assert recall_members(index, exact=True) == 1
270
- print(recall_members(index, exact=False))
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: