usearch 2.9.0 → 2.9.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/CITATION.cff +1 -1
- package/CONTRIBUTING.md +26 -0
- package/Cargo.toml +1 -1
- package/README.md +1 -1
- package/VERSION +1 -1
- package/c/lib.cpp +19 -17
- package/c/test.c +41 -7
- package/c/usearch.h +15 -15
- package/conanfile.py +1 -1
- package/include/usearch/index.hpp +5 -5
- package/include/usearch/index_dense.hpp +8 -4
- package/include/usearch/index_plugins.hpp +32 -22
- package/package.json +3 -2
- package/wasmer.toml +1 -1
package/CITATION.cff
CHANGED
package/CONTRIBUTING.md
CHANGED
|
@@ -291,6 +291,32 @@ cp cloud/unum/usearch/libusearch.* .
|
|
|
291
291
|
java -cp . -Djava.library.path="$(pwd)" cloud.unum.usearch.Index
|
|
292
292
|
```
|
|
293
293
|
|
|
294
|
+
## C#
|
|
295
|
+
|
|
296
|
+
Setup the .NET environment:
|
|
297
|
+
|
|
298
|
+
```sh
|
|
299
|
+
dotnet nuget add source https://api.nuget.org/v3/index.json -n nuget.org
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
USearch provides CSharp bindings, that depend on the C library that must be installed beforehand.
|
|
303
|
+
So one should first compile the C library, link it with CSharp, and only then run tests.
|
|
304
|
+
|
|
305
|
+
```sh
|
|
306
|
+
cmake -B ./build_artifacts -DUSEARCH_BUILD_LIB_C=1 -DUSEARCH_BUILD_TEST_C=1 -DUSEARCH_USE_OPENMP=1 -DUSEARCH_USE_SIMSIMD=1
|
|
307
|
+
cmake --build ./build_artifacts --config Release -j
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
Then, on Windows, copy the library to the CSharp project and run the tests:
|
|
311
|
+
|
|
312
|
+
```sh
|
|
313
|
+
mkdir -p ".\csharp\lib\runtimes\win-x64\native"
|
|
314
|
+
cp ".\build_artifacts\libusearch_c.dll" ".\csharp\lib\runtimes\win-x64\native"
|
|
315
|
+
cd csharp
|
|
316
|
+
dotnet test -c Debug --logger "console;verbosity=detailed"
|
|
317
|
+
dotnet test -c Release
|
|
318
|
+
```
|
|
319
|
+
|
|
294
320
|
## Wolfram
|
|
295
321
|
|
|
296
322
|
```sh
|
package/Cargo.toml
CHANGED
package/README.md
CHANGED
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.9.
|
|
1
|
+
2.9.1
|
package/c/lib.cpp
CHANGED
|
@@ -106,7 +106,7 @@ extern "C" {
|
|
|
106
106
|
|
|
107
107
|
USEARCH_EXPORT usearch_index_t usearch_init(usearch_init_options_t* options, usearch_error_t* error) {
|
|
108
108
|
|
|
109
|
-
assert(options && error);
|
|
109
|
+
assert(options && error && "Missing arguments");
|
|
110
110
|
|
|
111
111
|
index_dense_config_t config(options->connectivity, options->expansion_add, options->expansion_search);
|
|
112
112
|
config.multi = options->multi;
|
|
@@ -132,13 +132,13 @@ USEARCH_EXPORT void usearch_free(usearch_index_t index, usearch_error_t*) {
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
USEARCH_EXPORT size_t usearch_serialized_length(usearch_index_t index, usearch_error_t*) {
|
|
135
|
-
assert(index);
|
|
135
|
+
assert(index && "Missing arguments");
|
|
136
136
|
return reinterpret_cast<index_dense_t*>(index)->serialized_length();
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
USEARCH_EXPORT void usearch_save(usearch_index_t index, char const* path, usearch_error_t* error) {
|
|
140
140
|
|
|
141
|
-
assert(index && path && error);
|
|
141
|
+
assert(index && path && error && "Missing arguments");
|
|
142
142
|
serialization_result_t result = reinterpret_cast<index_dense_t*>(index)->save(path);
|
|
143
143
|
if (!result)
|
|
144
144
|
*error = result.error.release();
|
|
@@ -146,7 +146,7 @@ USEARCH_EXPORT void usearch_save(usearch_index_t index, char const* path, usearc
|
|
|
146
146
|
|
|
147
147
|
USEARCH_EXPORT void usearch_load(usearch_index_t index, char const* path, usearch_error_t* error) {
|
|
148
148
|
|
|
149
|
-
assert(index && path && error);
|
|
149
|
+
assert(index && path && error && "Missing arguments");
|
|
150
150
|
serialization_result_t result = reinterpret_cast<index_dense_t*>(index)->load(path);
|
|
151
151
|
if (!result)
|
|
152
152
|
*error = result.error.release();
|
|
@@ -154,7 +154,7 @@ USEARCH_EXPORT void usearch_load(usearch_index_t index, char const* path, usearc
|
|
|
154
154
|
|
|
155
155
|
USEARCH_EXPORT void usearch_view(usearch_index_t index, char const* path, usearch_error_t* error) {
|
|
156
156
|
|
|
157
|
-
assert(index && path && error);
|
|
157
|
+
assert(index && path && error && "Missing arguments");
|
|
158
158
|
serialization_result_t result = reinterpret_cast<index_dense_t*>(index)->view(path);
|
|
159
159
|
if (!result)
|
|
160
160
|
*error = result.error.release();
|
|
@@ -162,7 +162,7 @@ USEARCH_EXPORT void usearch_view(usearch_index_t index, char const* path, usearc
|
|
|
162
162
|
|
|
163
163
|
USEARCH_EXPORT void usearch_metadata(char const* path, usearch_init_options_t* options, usearch_error_t* error) {
|
|
164
164
|
|
|
165
|
-
assert(path && options && error);
|
|
165
|
+
assert(path && options && error && "Missing arguments");
|
|
166
166
|
index_dense_metadata_result_t result = index_dense_metadata_from_path(path);
|
|
167
167
|
if (!result)
|
|
168
168
|
*error = result.error.release();
|
|
@@ -180,7 +180,7 @@ USEARCH_EXPORT void usearch_metadata(char const* path, usearch_init_options_t* o
|
|
|
180
180
|
|
|
181
181
|
USEARCH_EXPORT void usearch_save_buffer(usearch_index_t index, void* buffer, size_t length, usearch_error_t* error) {
|
|
182
182
|
|
|
183
|
-
assert(index && buffer && length && error);
|
|
183
|
+
assert(index && buffer && length && error && "Missing arguments");
|
|
184
184
|
memory_mapped_file_t memory_map((byte_t*)buffer, length);
|
|
185
185
|
serialization_result_t result = reinterpret_cast<index_dense_t*>(index)->save(std::move(memory_map));
|
|
186
186
|
if (!result)
|
|
@@ -190,7 +190,7 @@ USEARCH_EXPORT void usearch_save_buffer(usearch_index_t index, void* buffer, siz
|
|
|
190
190
|
USEARCH_EXPORT void usearch_load_buffer(usearch_index_t index, void const* buffer, size_t length,
|
|
191
191
|
usearch_error_t* error) {
|
|
192
192
|
|
|
193
|
-
assert(index && buffer && length && error);
|
|
193
|
+
assert(index && buffer && length && error && "Missing arguments");
|
|
194
194
|
memory_mapped_file_t memory_map((byte_t*)buffer, length);
|
|
195
195
|
serialization_result_t result = reinterpret_cast<index_dense_t*>(index)->load(std::move(memory_map));
|
|
196
196
|
if (!result)
|
|
@@ -200,7 +200,7 @@ USEARCH_EXPORT void usearch_load_buffer(usearch_index_t index, void const* buffe
|
|
|
200
200
|
USEARCH_EXPORT void usearch_view_buffer(usearch_index_t index, void const* buffer, size_t length,
|
|
201
201
|
usearch_error_t* error) {
|
|
202
202
|
|
|
203
|
-
assert(index && buffer && length && error);
|
|
203
|
+
assert(index && buffer && length && error && "Missing arguments");
|
|
204
204
|
memory_mapped_file_t memory_map((byte_t*)buffer, length);
|
|
205
205
|
serialization_result_t result = reinterpret_cast<index_dense_t*>(index)->view(std::move(memory_map));
|
|
206
206
|
if (!result)
|
|
@@ -210,7 +210,7 @@ USEARCH_EXPORT void usearch_view_buffer(usearch_index_t index, void const* buffe
|
|
|
210
210
|
USEARCH_EXPORT void usearch_metadata_buffer(void const* buffer, size_t length, usearch_init_options_t* options,
|
|
211
211
|
usearch_error_t* error) {
|
|
212
212
|
|
|
213
|
-
assert(buffer && length && options && error);
|
|
213
|
+
assert(buffer && length && options && error && "Missing arguments");
|
|
214
214
|
index_dense_metadata_result_t result =
|
|
215
215
|
index_dense_metadata_from_buffer(memory_mapped_file_t((byte_t*)(buffer), length));
|
|
216
216
|
if (!result)
|
|
@@ -244,7 +244,7 @@ USEARCH_EXPORT size_t usearch_connectivity(usearch_index_t index, usearch_error_
|
|
|
244
244
|
}
|
|
245
245
|
|
|
246
246
|
USEARCH_EXPORT void usearch_reserve(usearch_index_t index, size_t capacity, usearch_error_t* error) {
|
|
247
|
-
assert(index && error);
|
|
247
|
+
assert(index && error && "Missing arguments");
|
|
248
248
|
if (!reinterpret_cast<index_dense_t*>(index)->reserve(capacity))
|
|
249
249
|
*error = "Out of memory!";
|
|
250
250
|
}
|
|
@@ -253,19 +253,19 @@ USEARCH_EXPORT void usearch_add(
|
|
|
253
253
|
usearch_index_t index, usearch_key_t key, void const* vector, usearch_scalar_kind_t kind, //
|
|
254
254
|
usearch_error_t* error) {
|
|
255
255
|
|
|
256
|
-
assert(index && vector && error);
|
|
256
|
+
assert(index && vector && error && "Missing arguments");
|
|
257
257
|
add_result_t result = add_(reinterpret_cast<index_dense_t*>(index), key, vector, scalar_kind_to_cpp(kind));
|
|
258
258
|
if (!result)
|
|
259
259
|
*error = result.error.release();
|
|
260
260
|
}
|
|
261
261
|
|
|
262
262
|
USEARCH_EXPORT bool usearch_contains(usearch_index_t index, usearch_key_t key, usearch_error_t*) {
|
|
263
|
-
assert(index);
|
|
263
|
+
assert(index && "Missing arguments");
|
|
264
264
|
return reinterpret_cast<index_dense_t*>(index)->contains(key);
|
|
265
265
|
}
|
|
266
266
|
|
|
267
267
|
USEARCH_EXPORT size_t usearch_count(usearch_index_t index, usearch_key_t key, usearch_error_t*) {
|
|
268
|
-
assert(index);
|
|
268
|
+
assert(index && "Missing arguments");
|
|
269
269
|
return reinterpret_cast<index_dense_t*>(index)->count(key);
|
|
270
270
|
}
|
|
271
271
|
|
|
@@ -273,7 +273,7 @@ USEARCH_EXPORT size_t usearch_search(
|
|
|
273
273
|
usearch_index_t index, void const* vector, usearch_scalar_kind_t kind, size_t results_limit, //
|
|
274
274
|
usearch_key_t* found_keys, usearch_distance_t* found_distances, usearch_error_t* error) {
|
|
275
275
|
|
|
276
|
-
assert(index && vector && error);
|
|
276
|
+
assert(index && vector && error && "Missing arguments");
|
|
277
277
|
search_result_t result =
|
|
278
278
|
search_(reinterpret_cast<index_dense_t*>(index), vector, scalar_kind_to_cpp(kind), results_limit);
|
|
279
279
|
if (!result) {
|
|
@@ -294,7 +294,7 @@ USEARCH_EXPORT size_t usearch_get( //
|
|
|
294
294
|
|
|
295
295
|
USEARCH_EXPORT size_t usearch_remove(usearch_index_t index, usearch_key_t key, usearch_error_t* error) {
|
|
296
296
|
|
|
297
|
-
assert(index && error);
|
|
297
|
+
assert(index && error && "Missing arguments");
|
|
298
298
|
labeling_result_t result = reinterpret_cast<index_dense_t*>(index)->remove(key);
|
|
299
299
|
if (!result)
|
|
300
300
|
*error = result.error.release();
|
|
@@ -304,7 +304,7 @@ USEARCH_EXPORT size_t usearch_remove(usearch_index_t index, usearch_key_t key, u
|
|
|
304
304
|
USEARCH_EXPORT size_t usearch_rename( //
|
|
305
305
|
usearch_index_t index, usearch_key_t from, usearch_key_t to, usearch_error_t* error) {
|
|
306
306
|
|
|
307
|
-
assert(index && error);
|
|
307
|
+
assert(index && error && "Missing arguments");
|
|
308
308
|
labeling_result_t result = reinterpret_cast<index_dense_t*>(index)->rename(from, to);
|
|
309
309
|
if (!result)
|
|
310
310
|
*error = result.error.release();
|
|
@@ -330,6 +330,8 @@ USEARCH_EXPORT void usearch_exact_search( //
|
|
|
330
330
|
usearch_distance_t* distances, size_t distances_stride, //
|
|
331
331
|
usearch_error_t* error) {
|
|
332
332
|
|
|
333
|
+
assert(dataset && queries && keys && distances && error && "Missing arguments");
|
|
334
|
+
|
|
333
335
|
metric_punned_t metric(dimensions, metric_kind_to_cpp(metric_kind), scalar_kind_to_cpp(scalar_kind));
|
|
334
336
|
executor_default_t executor(threads);
|
|
335
337
|
static exact_search_t search;
|
package/c/test.c
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#include <errno.h>
|
|
2
|
-
#include <stdio.h>
|
|
2
|
+
#include <stdio.h> // `remove`
|
|
3
3
|
#include <stdlib.h>
|
|
4
4
|
#include <sys/stat.h>
|
|
5
5
|
|
|
@@ -236,7 +236,13 @@ void test_save_load(size_t const collection_size, size_t const dimensions) {
|
|
|
236
236
|
|
|
237
237
|
usearch_error_t error = NULL;
|
|
238
238
|
usearch_init_options_t opts = create_options(dimensions);
|
|
239
|
-
|
|
239
|
+
usearch_init_options_t weird_ops = opts;
|
|
240
|
+
weird_ops.connectivity = 11;
|
|
241
|
+
weird_ops.expansion_add = 15;
|
|
242
|
+
weird_ops.expansion_search = 19;
|
|
243
|
+
weird_ops.metric_kind = usearch_metric_pearson_k;
|
|
244
|
+
weird_ops.quantization = usearch_scalar_f64_k;
|
|
245
|
+
usearch_index_t index = usearch_init(&weird_ops, &error);
|
|
240
246
|
usearch_reserve(index, collection_size, &error);
|
|
241
247
|
|
|
242
248
|
// Add vectors
|
|
@@ -248,23 +254,32 @@ void test_save_load(size_t const collection_size, size_t const dimensions) {
|
|
|
248
254
|
}
|
|
249
255
|
|
|
250
256
|
// Save and free the index
|
|
251
|
-
usearch_save(index, "
|
|
257
|
+
usearch_save(index, "tmp.usearch", &error);
|
|
252
258
|
ASSERT(!error, error);
|
|
253
259
|
usearch_free(index, &error);
|
|
254
260
|
ASSERT(!error, error);
|
|
255
261
|
|
|
262
|
+
// Reset the options
|
|
263
|
+
opts.connectivity = 0;
|
|
264
|
+
opts.dimensions = 0;
|
|
265
|
+
opts.expansion_add = 0;
|
|
266
|
+
opts.expansion_search = 0;
|
|
267
|
+
opts.metric = NULL;
|
|
268
|
+
opts.quantization = usearch_scalar_unknown_k;
|
|
269
|
+
opts.metric_kind = usearch_metric_unknown_k;
|
|
270
|
+
|
|
256
271
|
// Reinit
|
|
257
272
|
index = usearch_init(&opts, &error);
|
|
258
273
|
ASSERT(!error, error);
|
|
259
274
|
ASSERT(usearch_size(index, &error) == 0, error);
|
|
260
275
|
|
|
261
276
|
// Load
|
|
262
|
-
usearch_load(index, "
|
|
277
|
+
usearch_load(index, "tmp.usearch", &error);
|
|
263
278
|
ASSERT(!error, error);
|
|
264
279
|
ASSERT(usearch_size(index, &error) == collection_size, error);
|
|
265
280
|
ASSERT(usearch_capacity(index, &error) == collection_size, error);
|
|
266
281
|
ASSERT(usearch_dimensions(index, &error) == dimensions, error);
|
|
267
|
-
ASSERT(usearch_connectivity(index, &error) ==
|
|
282
|
+
ASSERT(usearch_connectivity(index, &error) == weird_ops.connectivity, error);
|
|
268
283
|
|
|
269
284
|
// Check vectors in the index
|
|
270
285
|
for (size_t i = 0; i < collection_size; ++i) {
|
|
@@ -272,8 +287,27 @@ void test_save_load(size_t const collection_size, size_t const dimensions) {
|
|
|
272
287
|
ASSERT(usearch_contains(index, key, &error), error);
|
|
273
288
|
}
|
|
274
289
|
|
|
290
|
+
// Create result buffers
|
|
291
|
+
usearch_key_t* keys = (usearch_key_t*)malloc(collection_size * sizeof(usearch_key_t));
|
|
292
|
+
float* distances = (float*)malloc(collection_size * sizeof(float));
|
|
293
|
+
ASSERT(keys && distances, "Failed to allocate memory");
|
|
294
|
+
|
|
295
|
+
// Find the vectors
|
|
296
|
+
for (size_t i = 0; i < collection_size; i++) {
|
|
297
|
+
size_t found_count = usearch_search(index, data + i * dimensions, usearch_scalar_f32_k, collection_size, keys,
|
|
298
|
+
distances, &error);
|
|
299
|
+
ASSERT(!error, error);
|
|
300
|
+
ASSERT(found_count >= 1 && found_count <= collection_size, "Vector is missing");
|
|
301
|
+
}
|
|
302
|
+
|
|
275
303
|
free(data);
|
|
304
|
+
free(keys);
|
|
305
|
+
free(distances);
|
|
276
306
|
usearch_free(index, &error);
|
|
307
|
+
|
|
308
|
+
// Remove the file from disk
|
|
309
|
+
remove("tmp.usearch");
|
|
310
|
+
|
|
277
311
|
printf("Test: Save/Load - PASSED\n");
|
|
278
312
|
}
|
|
279
313
|
|
|
@@ -300,7 +334,7 @@ void test_view(size_t const collection_size, size_t const dimensions) {
|
|
|
300
334
|
}
|
|
301
335
|
|
|
302
336
|
// Save and free the index
|
|
303
|
-
usearch_save(index, "
|
|
337
|
+
usearch_save(index, "tmp.usearch", &error);
|
|
304
338
|
ASSERT(!error, error);
|
|
305
339
|
usearch_free(index, &error);
|
|
306
340
|
ASSERT(!error, error);
|
|
@@ -310,7 +344,7 @@ void test_view(size_t const collection_size, size_t const dimensions) {
|
|
|
310
344
|
ASSERT(!error, error);
|
|
311
345
|
|
|
312
346
|
// View
|
|
313
|
-
usearch_view(index, "
|
|
347
|
+
usearch_view(index, "tmp.usearch", &error);
|
|
314
348
|
ASSERT(!error, error);
|
|
315
349
|
|
|
316
350
|
free(data);
|
package/c/usearch.h
CHANGED
|
@@ -39,25 +39,25 @@ USEARCH_EXPORT typedef usearch_distance_t (*usearch_metric_t)(void const*, void
|
|
|
39
39
|
*/
|
|
40
40
|
USEARCH_EXPORT typedef enum usearch_metric_kind_t {
|
|
41
41
|
usearch_metric_unknown_k = 0,
|
|
42
|
-
usearch_metric_cos_k,
|
|
43
|
-
usearch_metric_ip_k,
|
|
44
|
-
usearch_metric_l2sq_k,
|
|
45
|
-
usearch_metric_haversine_k,
|
|
46
|
-
usearch_metric_divergence_k,
|
|
47
|
-
usearch_metric_pearson_k,
|
|
48
|
-
usearch_metric_jaccard_k,
|
|
49
|
-
usearch_metric_hamming_k,
|
|
50
|
-
usearch_metric_tanimoto_k,
|
|
51
|
-
usearch_metric_sorensen_k,
|
|
42
|
+
usearch_metric_cos_k = 1,
|
|
43
|
+
usearch_metric_ip_k = 2,
|
|
44
|
+
usearch_metric_l2sq_k = 3,
|
|
45
|
+
usearch_metric_haversine_k = 4,
|
|
46
|
+
usearch_metric_divergence_k = 5,
|
|
47
|
+
usearch_metric_pearson_k = 6,
|
|
48
|
+
usearch_metric_jaccard_k = 7,
|
|
49
|
+
usearch_metric_hamming_k = 8,
|
|
50
|
+
usearch_metric_tanimoto_k = 9,
|
|
51
|
+
usearch_metric_sorensen_k = 10,
|
|
52
52
|
} usearch_metric_kind_t;
|
|
53
53
|
|
|
54
54
|
USEARCH_EXPORT typedef enum usearch_scalar_kind_t {
|
|
55
55
|
usearch_scalar_unknown_k = 0,
|
|
56
|
-
usearch_scalar_f32_k,
|
|
57
|
-
usearch_scalar_f64_k,
|
|
58
|
-
usearch_scalar_f16_k,
|
|
59
|
-
usearch_scalar_i8_k,
|
|
60
|
-
usearch_scalar_b1_k,
|
|
56
|
+
usearch_scalar_f32_k = 1,
|
|
57
|
+
usearch_scalar_f64_k = 2,
|
|
58
|
+
usearch_scalar_f16_k = 3,
|
|
59
|
+
usearch_scalar_i8_k = 4,
|
|
60
|
+
usearch_scalar_b1_k = 5,
|
|
61
61
|
} usearch_scalar_kind_t;
|
|
62
62
|
|
|
63
63
|
USEARCH_EXPORT typedef struct usearch_init_options_t {
|
package/conanfile.py
CHANGED
|
@@ -7,7 +7,7 @@ required_conan_version = ">=1.53.0"
|
|
|
7
7
|
class USearchConan(ConanFile):
|
|
8
8
|
|
|
9
9
|
name = "usearch"
|
|
10
|
-
version = '2.9.
|
|
10
|
+
version = '2.9.1'
|
|
11
11
|
license = "Apache-2.0"
|
|
12
12
|
description = "Smaller & Faster Single-File Vector Search Engine from Unum"
|
|
13
13
|
homepage = "https://github.com/unum-cloud/usearch"
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
#define USEARCH_VERSION_MAJOR 2
|
|
13
13
|
#define USEARCH_VERSION_MINOR 9
|
|
14
|
-
#define USEARCH_VERSION_PATCH
|
|
14
|
+
#define USEARCH_VERSION_PATCH 1
|
|
15
15
|
|
|
16
16
|
// Inferring C++ version
|
|
17
17
|
// https://stackoverflow.com/a/61552074
|
|
@@ -2543,8 +2543,8 @@ class index_gt {
|
|
|
2543
2543
|
if (!next.reserve(expansion))
|
|
2544
2544
|
return result.failed("Out of memory!");
|
|
2545
2545
|
|
|
2546
|
-
result.cluster.member =
|
|
2547
|
-
|
|
2546
|
+
result.cluster.member = at(search_for_one_(query, metric, prefetch, entry_slot_, max_level_,
|
|
2547
|
+
static_cast<level_t>(level - 1), context));
|
|
2548
2548
|
result.cluster.distance = context.measure(query, result.cluster.member, metric);
|
|
2549
2549
|
|
|
2550
2550
|
// Normalize stats
|
|
@@ -3422,7 +3422,7 @@ class index_gt {
|
|
|
3422
3422
|
distance_t radius = context.measure(query, citerator_at(start_slot), metric);
|
|
3423
3423
|
next.insert_reserved({-radius, static_cast<compressed_slot_t>(start_slot)});
|
|
3424
3424
|
top.insert_reserved({radius, static_cast<compressed_slot_t>(start_slot)});
|
|
3425
|
-
visits.set(start_slot);
|
|
3425
|
+
visits.set(static_cast<compressed_slot_t>(start_slot));
|
|
3426
3426
|
|
|
3427
3427
|
while (!next.empty()) {
|
|
3428
3428
|
|
|
@@ -3496,7 +3496,7 @@ class index_gt {
|
|
|
3496
3496
|
distance_t radius = context.measure(query, citerator_at(start_slot), metric);
|
|
3497
3497
|
next.insert_reserved({-radius, static_cast<compressed_slot_t>(start_slot)});
|
|
3498
3498
|
top.insert_reserved({radius, static_cast<compressed_slot_t>(start_slot)});
|
|
3499
|
-
visits.set(start_slot);
|
|
3499
|
+
visits.set(static_cast<compressed_slot_t>(start_slot));
|
|
3500
3500
|
|
|
3501
3501
|
while (!next.empty()) {
|
|
3502
3502
|
|
|
@@ -199,7 +199,7 @@ inline index_dense_metadata_result_t index_dense_metadata_from_path(char const*
|
|
|
199
199
|
|
|
200
200
|
// Check if it starts with 32-bit
|
|
201
201
|
if (offset_if_u32 + sizeof(index_dense_head_buffer_t) < file_size) {
|
|
202
|
-
if (std::fseek(file.get(), offset_if_u32, SEEK_SET) != 0)
|
|
202
|
+
if (std::fseek(file.get(), static_cast<long>(offset_if_u32), SEEK_SET) != 0)
|
|
203
203
|
return result.failed(std::strerror(errno));
|
|
204
204
|
read = std::fread(result.head_buffer, sizeof(index_dense_head_buffer_t), 1, file.get());
|
|
205
205
|
if (!read)
|
|
@@ -213,7 +213,7 @@ inline index_dense_metadata_result_t index_dense_metadata_from_path(char const*
|
|
|
213
213
|
|
|
214
214
|
// Check if it starts with 64-bit
|
|
215
215
|
if (offset_if_u64 + sizeof(index_dense_head_buffer_t) < file_size) {
|
|
216
|
-
if (std::fseek(file.get(), offset_if_u64, SEEK_SET) != 0)
|
|
216
|
+
if (std::fseek(file.get(), static_cast<long>(offset_if_u64), SEEK_SET) != 0)
|
|
217
217
|
return result.failed(std::strerror(errno));
|
|
218
218
|
read = std::fread(result.head_buffer, sizeof(index_dense_head_buffer_t), 1, file.get());
|
|
219
219
|
if (!read)
|
|
@@ -929,8 +929,10 @@ class index_dense_gt {
|
|
|
929
929
|
if (head.kind_compressed_slot != unum::usearch::scalar_kind<compressed_slot_t>())
|
|
930
930
|
return result.failed("Slot type doesn't match, consider rebuilding");
|
|
931
931
|
|
|
932
|
-
metric_ = metric_t(head.dimensions, head.kind_metric, head.kind_scalar);
|
|
933
932
|
config_.multi = head.multi;
|
|
933
|
+
metric_ = metric_t(head.dimensions, head.kind_metric, head.kind_scalar);
|
|
934
|
+
cast_buffer_.resize(available_threads_.size() * metric_.bytes_per_vector());
|
|
935
|
+
casts_ = make_casts_(head.kind_scalar);
|
|
934
936
|
}
|
|
935
937
|
|
|
936
938
|
// Pull the actual proximity graph
|
|
@@ -1013,8 +1015,10 @@ class index_dense_gt {
|
|
|
1013
1015
|
if (head.kind_compressed_slot != unum::usearch::scalar_kind<compressed_slot_t>())
|
|
1014
1016
|
return result.failed("Slot type doesn't match, consider rebuilding");
|
|
1015
1017
|
|
|
1016
|
-
metric_ = metric_t(head.dimensions, head.kind_metric, head.kind_scalar);
|
|
1017
1018
|
config_.multi = head.multi;
|
|
1019
|
+
metric_ = metric_t(head.dimensions, head.kind_metric, head.kind_scalar);
|
|
1020
|
+
cast_buffer_.resize(available_threads_.size() * metric_.bytes_per_vector());
|
|
1021
|
+
casts_ = make_casts_(head.kind_scalar);
|
|
1018
1022
|
offset += sizeof(buffer);
|
|
1019
1023
|
}
|
|
1020
1024
|
|
|
@@ -1006,10 +1006,11 @@ template <typename scalar_at = float, typename result_at = scalar_at> struct met
|
|
|
1006
1006
|
#elif defined(USEARCH_DEFINED_GCC)
|
|
1007
1007
|
#pragma GCC ivdep
|
|
1008
1008
|
#endif
|
|
1009
|
-
for (std::size_t i = 0; i != dim; ++i)
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1009
|
+
for (std::size_t i = 0; i != dim; ++i) {
|
|
1010
|
+
result_t ai = static_cast<result_t>(a[i]);
|
|
1011
|
+
result_t bi = static_cast<result_t>(b[i]);
|
|
1012
|
+
ab += ai * bi, a2 += square(ai), b2 += square(bi);
|
|
1013
|
+
}
|
|
1013
1014
|
|
|
1014
1015
|
result_t result_if_zero[2][2];
|
|
1015
1016
|
result_if_zero[0][0] = 1 - ab / (std::sqrt(a2) * std::sqrt(b2));
|
|
@@ -1036,8 +1037,11 @@ template <typename scalar_at = float, typename result_at = scalar_at> struct met
|
|
|
1036
1037
|
#elif defined(USEARCH_DEFINED_GCC)
|
|
1037
1038
|
#pragma GCC ivdep
|
|
1038
1039
|
#endif
|
|
1039
|
-
for (std::size_t i = 0; i != dim; ++i)
|
|
1040
|
-
|
|
1040
|
+
for (std::size_t i = 0; i != dim; ++i) {
|
|
1041
|
+
result_t ai = static_cast<result_t>(a[i]);
|
|
1042
|
+
result_t bi = static_cast<result_t>(b[i]);
|
|
1043
|
+
ab_deltas_sq += square(ai - bi);
|
|
1044
|
+
}
|
|
1041
1045
|
return ab_deltas_sq;
|
|
1042
1046
|
}
|
|
1043
1047
|
};
|
|
@@ -1095,9 +1099,10 @@ template <typename scalar_at = std::uint64_t, typename result_at = float> struct
|
|
|
1095
1099
|
#elif defined(USEARCH_DEFINED_GCC)
|
|
1096
1100
|
#pragma GCC ivdep
|
|
1097
1101
|
#endif
|
|
1098
|
-
for (std::size_t i = 0; i != words; ++i)
|
|
1099
|
-
and_count += std::bitset<bits_per_word_k>(a[i] & b[i]).count()
|
|
1100
|
-
|
|
1102
|
+
for (std::size_t i = 0; i != words; ++i) {
|
|
1103
|
+
and_count += std::bitset<bits_per_word_k>(a[i] & b[i]).count();
|
|
1104
|
+
or_count += std::bitset<bits_per_word_k>(a[i] | b[i]).count();
|
|
1105
|
+
}
|
|
1101
1106
|
return 1 - result_t(and_count) / or_count;
|
|
1102
1107
|
}
|
|
1103
1108
|
};
|
|
@@ -1126,9 +1131,10 @@ template <typename scalar_at = std::uint64_t, typename result_at = float> struct
|
|
|
1126
1131
|
#elif defined(USEARCH_DEFINED_GCC)
|
|
1127
1132
|
#pragma GCC ivdep
|
|
1128
1133
|
#endif
|
|
1129
|
-
for (std::size_t i = 0; i != words; ++i)
|
|
1130
|
-
and_count += std::bitset<bits_per_word_k>(a[i] & b[i]).count()
|
|
1131
|
-
|
|
1134
|
+
for (std::size_t i = 0; i != words; ++i) {
|
|
1135
|
+
and_count += std::bitset<bits_per_word_k>(a[i] & b[i]).count();
|
|
1136
|
+
any_count += std::bitset<bits_per_word_k>(a[i]).count() + std::bitset<bits_per_word_k>(b[i]).count();
|
|
1137
|
+
}
|
|
1132
1138
|
return 1 - 2 * result_t(and_count) / any_count;
|
|
1133
1139
|
}
|
|
1134
1140
|
};
|
|
@@ -1176,11 +1182,13 @@ template <typename scalar_at = float, typename result_at = float> struct metric_
|
|
|
1176
1182
|
#pragma GCC ivdep
|
|
1177
1183
|
#endif
|
|
1178
1184
|
for (std::size_t i = 0; i != dim; ++i) {
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1185
|
+
result_t ai = static_cast<result_t>(a[i]);
|
|
1186
|
+
result_t bi = static_cast<result_t>(b[i]);
|
|
1187
|
+
a_sum += ai;
|
|
1188
|
+
b_sum += bi;
|
|
1189
|
+
ab_sum += ai * bi;
|
|
1190
|
+
a_sq_sum += ai * ai;
|
|
1191
|
+
b_sq_sum += bi * bi;
|
|
1184
1192
|
}
|
|
1185
1193
|
result_t denom = std::sqrt((dim * a_sq_sum - a_sum * a_sum) * (dim * b_sq_sum - b_sum * b_sum));
|
|
1186
1194
|
result_t corr = (dim * ab_sum - a_sum * b_sum) / denom;
|
|
@@ -1197,7 +1205,7 @@ template <typename scalar_at = float, typename result_at = float> struct metric_
|
|
|
1197
1205
|
|
|
1198
1206
|
inline result_t operator()(scalar_t const* p, scalar_t const* q, std::size_t dim) const noexcept {
|
|
1199
1207
|
result_t kld_pm{}, kld_qm{};
|
|
1200
|
-
|
|
1208
|
+
result_t epsilon = std::numeric_limits<result_t>::epsilon();
|
|
1201
1209
|
#if USEARCH_USE_OPENMP
|
|
1202
1210
|
#pragma omp simd reduction(+ : kld_pm, kld_qm)
|
|
1203
1211
|
#elif defined(USEARCH_DEFINED_CLANG)
|
|
@@ -1206,9 +1214,11 @@ template <typename scalar_at = float, typename result_at = float> struct metric_
|
|
|
1206
1214
|
#pragma GCC ivdep
|
|
1207
1215
|
#endif
|
|
1208
1216
|
for (std::size_t i = 0; i != dim; ++i) {
|
|
1209
|
-
result_t
|
|
1210
|
-
|
|
1211
|
-
|
|
1217
|
+
result_t pi = static_cast<result_t>(p[i]);
|
|
1218
|
+
result_t qi = static_cast<result_t>(q[i]);
|
|
1219
|
+
result_t mi = (pi + qi) / 2 + epsilon;
|
|
1220
|
+
kld_pm += pi * std::log((pi + epsilon) / mi);
|
|
1221
|
+
kld_qm += qi * std::log((qi + epsilon) / mi);
|
|
1212
1222
|
}
|
|
1213
1223
|
return (kld_pm + kld_qm) / 2;
|
|
1214
1224
|
}
|
|
@@ -1253,7 +1263,7 @@ struct l2sq_i8_t {
|
|
|
1253
1263
|
#endif
|
|
1254
1264
|
for (std::size_t i = 0; i != dim; i++)
|
|
1255
1265
|
ab_deltas_sq += square(std::int16_t(a[i]) - std::int16_t(b[i]));
|
|
1256
|
-
return ab_deltas_sq;
|
|
1266
|
+
return static_cast<result_t>(ab_deltas_sq);
|
|
1257
1267
|
}
|
|
1258
1268
|
};
|
|
1259
1269
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "usearch",
|
|
3
|
-
"version": "2.9.
|
|
3
|
+
"version": "2.9.1",
|
|
4
4
|
"description": "Smaller & Faster Single-File Vector Search Engine from Unum",
|
|
5
5
|
"author": "Ash Vardanian (https://ashvardanian.com/)",
|
|
6
6
|
"license": "Apache 2.0",
|
|
@@ -34,7 +34,8 @@
|
|
|
34
34
|
"exports": {
|
|
35
35
|
".": {
|
|
36
36
|
"types": "./javascript/types/usearch.d.ts",
|
|
37
|
-
"require": "./javascript/usearch.js"
|
|
37
|
+
"require": "./javascript/usearch.js",
|
|
38
|
+
"import": "./javascript/usearch.js"
|
|
38
39
|
},
|
|
39
40
|
"./package.json": "./package.json"
|
|
40
41
|
},
|