usearch 2.10.2 → 2.10.5

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 (112) hide show
  1. package/README.md +1 -1
  2. package/binding.gyp +101 -0
  3. package/c/CMakeLists.txt +27 -0
  4. package/c/README.md +34 -0
  5. package/c/lib.cpp +362 -0
  6. package/c/test.c +382 -0
  7. package/c/usearch.h +356 -0
  8. package/cmake/clipp.cmake +7 -0
  9. package/cmake/config.cmake.in +15 -0
  10. package/cmake/emscripten.cmake +8 -0
  11. package/cmake/jemalloc.cmake +62 -0
  12. package/cmake/pkg-config.pc.in +4 -0
  13. package/cmake/usearchConfigVersion.cmake.in +20 -0
  14. package/cpp/CMakeLists.txt +14 -0
  15. package/cpp/README.md +161 -0
  16. package/cpp/bench.cpp +616 -0
  17. package/cpp/test.cpp +324 -0
  18. package/fp16/CMakeLists.txt +176 -0
  19. package/fp16/LICENSE +11 -0
  20. package/fp16/README.md +20 -0
  21. package/fp16/bench/alt-element.cc +89 -0
  22. package/fp16/bench/from-alt-array.cc +175 -0
  23. package/fp16/bench/from-ieee-array.cc +399 -0
  24. package/fp16/bench/ieee-element.cc +272 -0
  25. package/fp16/bench/to-alt-array.cc +91 -0
  26. package/fp16/bench/to-ieee-array.cc +303 -0
  27. package/fp16/cmake/DownloadGoogleBenchmark.cmake +15 -0
  28. package/fp16/cmake/DownloadGoogleTest.cmake +15 -0
  29. package/fp16/cmake/DownloadPSimd.cmake +15 -0
  30. package/fp16/configure.py +65 -0
  31. package/fp16/confu.yaml +8 -0
  32. package/fp16/include/fp16/__init__.py +0 -0
  33. package/fp16/include/fp16/avx.py +50 -0
  34. package/fp16/include/fp16/avx2.py +53 -0
  35. package/fp16/include/fp16/bitcasts.h +92 -0
  36. package/fp16/include/fp16/fp16.h +451 -0
  37. package/fp16/include/fp16/psimd.h +131 -0
  38. package/fp16/include/fp16.h +11 -0
  39. package/fp16/jni/Android.mk +6 -0
  40. package/fp16/jni/Application.mk +4 -0
  41. package/fp16/test/alt-from-fp32-value.cc +498 -0
  42. package/fp16/test/alt-to-fp32-bits.cc +263 -0
  43. package/fp16/test/alt-to-fp32-psimd.cc +145 -0
  44. package/fp16/test/alt-to-fp32-value.cc +348 -0
  45. package/fp16/test/alt-to-fp32x2-psimd.cc +245 -0
  46. package/fp16/test/bitcasts.cc +56 -0
  47. package/fp16/test/ieee-from-fp32-value.cc +523 -0
  48. package/fp16/test/ieee-to-fp32-bits.cc +333 -0
  49. package/fp16/test/ieee-to-fp32-psimd.cc +312 -0
  50. package/fp16/test/ieee-to-fp32-value.cc +420 -0
  51. package/fp16/test/ieee-to-fp32x2-psimd.cc +541 -0
  52. package/fp16/test/peachpy/alt-xmm-to-fp32-xmm-avx.cc +96 -0
  53. package/fp16/test/peachpy/alt-xmm-to-fp32-ymm-avx2.cc +96 -0
  54. package/fp16/test/peachpy/stubs.py +38 -0
  55. package/fp16/test/tables.cc +530 -0
  56. package/fp16/test/tables.h +13 -0
  57. package/fp16/third-party/THHalf.h +92 -0
  58. package/fp16/third-party/eigen-half.h +170 -0
  59. package/fp16/third-party/float16-compressor.h +80 -0
  60. package/fp16/third-party/half.hpp +2916 -0
  61. package/fp16/third-party/npy-halffloat.h +328 -0
  62. package/include/usearch/index.hpp +3838 -0
  63. package/include/usearch/index_dense.hpp +2004 -0
  64. package/include/usearch/index_plugins.hpp +2255 -0
  65. package/javascript/dist-package-cjs.json +3 -0
  66. package/javascript/dist-package-esm.json +3 -0
  67. package/javascript/lib.cpp +350 -0
  68. package/javascript/node-gyp-build.d.ts +1 -0
  69. package/javascript/tsconfig-base.json +25 -0
  70. package/javascript/tsconfig-cjs.json +8 -0
  71. package/javascript/tsconfig-esm.json +8 -0
  72. package/javascript/usearch.test.js +84 -0
  73. package/javascript/usearch.ts +640 -0
  74. package/package.json +10 -3
  75. package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
  76. package/prebuilds/linux-arm64/usearch.node +0 -0
  77. package/prebuilds/linux-x64/usearch.node +0 -0
  78. package/prebuilds/win32-ia32/usearch.node +0 -0
  79. package/prebuilds/win32-x64/usearch.node +0 -0
  80. package/simsimd/.releaserc +87 -0
  81. package/simsimd/CONTRIBUTING.md +114 -0
  82. package/simsimd/Cargo.lock +709 -0
  83. package/simsimd/Cargo.toml +44 -0
  84. package/simsimd/LICENSE +201 -0
  85. package/simsimd/README.md +708 -0
  86. package/simsimd/binding.gyp +36 -0
  87. package/simsimd/build.rs +51 -0
  88. package/simsimd/c/lib.c +110 -0
  89. package/simsimd/include/simsimd/binary.h +258 -0
  90. package/simsimd/include/simsimd/dot.h +1237 -0
  91. package/simsimd/include/simsimd/geospatial.h +37 -0
  92. package/simsimd/include/simsimd/probability.h +563 -0
  93. package/simsimd/include/simsimd/simsimd.h +1129 -0
  94. package/simsimd/include/simsimd/spatial.h +1019 -0
  95. package/simsimd/include/simsimd/types.h +309 -0
  96. package/simsimd/javascript/bench.js +127 -0
  97. package/simsimd/javascript/dist-package-cjs.json +3 -0
  98. package/simsimd/javascript/dist-package-esm.json +3 -0
  99. package/simsimd/javascript/fallback.ts +203 -0
  100. package/simsimd/javascript/lib.c +107 -0
  101. package/simsimd/javascript/node-gyp-build.d.ts +1 -0
  102. package/simsimd/javascript/simsimd.ts +135 -0
  103. package/simsimd/javascript/test.mjs +179 -0
  104. package/simsimd/javascript/tsconfig-base.json +37 -0
  105. package/simsimd/javascript/tsconfig-cjs.json +8 -0
  106. package/simsimd/javascript/tsconfig-esm.json +8 -0
  107. package/simsimd/package-lock.json +1709 -0
  108. package/simsimd/package.json +61 -0
  109. package/simsimd/rust/benches/cosine.rs +27 -0
  110. package/simsimd/rust/benches/native.rs +30 -0
  111. package/simsimd/rust/benches/sqeuclidean.rs +27 -0
  112. package/simsimd/rust/lib.rs +778 -0
package/c/test.c ADDED
@@ -0,0 +1,382 @@
1
+ #include <errno.h>
2
+ #include <stdio.h> // `remove`
3
+ #include <stdlib.h>
4
+ #include <sys/stat.h>
5
+
6
+ #include "usearch.h"
7
+
8
+ #define ASSERT(must_be_true, message) \
9
+ if (!(must_be_true)) { \
10
+ printf("Assert: %s\n", message); \
11
+ exit(-1); \
12
+ }
13
+
14
+ /**
15
+ * @brief Creates and initializes vectors with random float values.
16
+ *
17
+ * @param count The number of vectors.
18
+ * @param dimensions The number of dimensions per vector.
19
+ * @return A pointer to the first element of the vectors, that must be @b free-ed afterwards.
20
+ */
21
+ float* create_vectors(size_t const count, size_t const dimensions) {
22
+ float* data = (float*)malloc(count * dimensions * sizeof(float));
23
+ ASSERT(data, "Failed to allocate memory");
24
+ for (size_t index = 0; index < count * dimensions; ++index)
25
+ data[index] = (float)rand() / (float)RAND_MAX;
26
+ return data;
27
+ }
28
+
29
+ usearch_init_options_t create_options(size_t const dimensions) {
30
+ usearch_init_options_t opts;
31
+ opts.connectivity = 3; // 32 in faiss
32
+ opts.dimensions = dimensions;
33
+ opts.expansion_add = 40; // 40 in faiss
34
+ opts.expansion_search = 16; // 10 in faiss
35
+ opts.metric_kind = usearch_metric_ip_k;
36
+ opts.metric = NULL;
37
+ opts.quantization = usearch_scalar_f32_k;
38
+ opts.multi = false;
39
+ return opts;
40
+ }
41
+
42
+ /**
43
+ * This test is designed to verify the initialization of the index with specific dimensions and ensures that the
44
+ * associated properties are set correctly. It initializes the index twice, checking for errors at each step, and
45
+ * performs a reserve operation to pre-allocate space in the index, verifying the correct settings of size, capacity,
46
+ * dimensions, and connectivity after each operation.
47
+ */
48
+ void test_init(size_t const collection_size, size_t const dimensions) {
49
+ printf("Test: Index Initialization... %zu vectors, %zu dimensions \n", collection_size, dimensions);
50
+
51
+ // Init index
52
+ usearch_error_t error = NULL;
53
+ usearch_init_options_t opts = create_options(dimensions);
54
+ usearch_index_t index = usearch_init(&opts, &error);
55
+ ASSERT(!error, error);
56
+ usearch_free(index, &error);
57
+ ASSERT(!error, error);
58
+
59
+ // Init second time
60
+ index = usearch_init(&opts, &error);
61
+ ASSERT(!error, error);
62
+
63
+ ASSERT(usearch_size(index, &error) == 0, error);
64
+ ASSERT(usearch_capacity(index, &error) == 0, error);
65
+ ASSERT(usearch_dimensions(index, &error) == dimensions, error);
66
+ ASSERT(usearch_connectivity(index, &error) == opts.connectivity, error);
67
+
68
+ // Reserve
69
+ usearch_reserve(index, collection_size, &error);
70
+ ASSERT(!error, error);
71
+ ASSERT(usearch_size(index, &error) == 0, error);
72
+ ASSERT(usearch_capacity(index, &error) == collection_size, error);
73
+ ASSERT(usearch_dimensions(index, &error) == dimensions, error);
74
+ ASSERT(usearch_connectivity(index, &error) == opts.connectivity, error);
75
+
76
+ usearch_free(index, &error);
77
+ ASSERT(!error, error);
78
+
79
+ printf("Test: Index Initialization - PASSED\n");
80
+ }
81
+
82
+ /**
83
+ * This test validates the addition of vectors to the index. It initializes the index and reserves space for vectors.
84
+ * It then iteratively adds vectors to the index and checks if the index contains the added vectors by verifying the
85
+ * size, capacity, and presence of each vector in the index.
86
+ */
87
+ void test_add_vector(size_t const collection_size, size_t const dimensions) {
88
+ printf("Test: Add Vector... %zu vectors, %zu dimensions \n", collection_size, dimensions);
89
+
90
+ usearch_error_t error = NULL;
91
+ usearch_init_options_t opts = create_options(dimensions);
92
+ usearch_index_t index = usearch_init(&opts, &error);
93
+ usearch_reserve(index, collection_size, &error);
94
+
95
+ // Add vectors
96
+ float* data = create_vectors(collection_size, dimensions);
97
+ for (size_t i = 0; i < collection_size; ++i) {
98
+ usearch_key_t key = i;
99
+ usearch_add(index, key, data + i * dimensions, usearch_scalar_f32_k, &error);
100
+ ASSERT(!error, error);
101
+ }
102
+
103
+ ASSERT(usearch_size(index, &error) == collection_size, error);
104
+ ASSERT(usearch_capacity(index, &error) == collection_size, error);
105
+
106
+ // Check vectors in the index
107
+ for (size_t i = 0; i < collection_size; ++i) {
108
+ usearch_key_t key = i;
109
+ ASSERT(usearch_contains(index, key, &error), error);
110
+ }
111
+ ASSERT(!usearch_contains(index, -1, &error), error); // Non existing key
112
+
113
+ free(data);
114
+ usearch_free(index, &error);
115
+ printf("Test: Add Vector - PASSED\n");
116
+ }
117
+
118
+ /**
119
+ * This test ensures that vectors added to the index can be correctly found. It initializes the index, reserves space,
120
+ * and adds vectors. It then performs a search query for each added vector to ensure that the vectors are correctly
121
+ * found in the index, validating the count of found vectors.
122
+ */
123
+ void test_find_vector(size_t const collection_size, size_t const dimensions) {
124
+ printf("Test: Find Vector... %zu vectors, %zu dimensions \n", collection_size, dimensions);
125
+
126
+ usearch_error_t error = NULL;
127
+ usearch_init_options_t opts = create_options(dimensions);
128
+ usearch_index_t index = usearch_init(&opts, &error);
129
+ usearch_reserve(index, collection_size, &error);
130
+
131
+ // Create result buffers
132
+ usearch_key_t* keys = (usearch_key_t*)malloc(collection_size * sizeof(usearch_key_t));
133
+ float* distances = (float*)malloc(collection_size * sizeof(float));
134
+ ASSERT(keys && distances, "Failed to allocate memory");
135
+
136
+ // Add vectors
137
+ float* data = create_vectors(collection_size, dimensions);
138
+ for (size_t i = 0; i < collection_size; ++i) {
139
+ usearch_key_t key = i;
140
+ usearch_add(index, key, data + i * dimensions, usearch_scalar_f32_k, &error);
141
+ ASSERT(!error, error);
142
+ }
143
+
144
+ // Find the vectors
145
+ for (size_t i = 0; i < collection_size; i++) {
146
+ size_t found_count = usearch_search(index, data + i * dimensions, usearch_scalar_f32_k, collection_size, keys,
147
+ distances, &error);
148
+ ASSERT(!error, error);
149
+ ASSERT(found_count >= 1 && found_count <= collection_size, "Vector is missing");
150
+ }
151
+
152
+ free(data);
153
+ free(keys);
154
+ free(distances);
155
+ usearch_free(index, &error);
156
+ printf("Test: Find Vector - PASSED\n");
157
+ }
158
+
159
+ /**
160
+ * This test checks the ability of the index to handle multiple vectors associated with the same key. It initializes
161
+ * the index with the multi-option enabled, reserves space, and adds multiple vectors with the same key. The test then
162
+ * retrieves vectors associated with the key from the index and checks the count of retrieved vectors.
163
+ */
164
+ void test_get_vector(size_t const collection_size, size_t const dimensions) {
165
+ printf("Test: Get Vector... %zu vectors, %zu dimensions \n", collection_size, dimensions);
166
+
167
+ usearch_error_t error = NULL;
168
+ usearch_init_options_t opts = create_options(dimensions);
169
+ opts.multi = true;
170
+ usearch_index_t index = usearch_init(&opts, &error);
171
+ usearch_reserve(index, collection_size, &error);
172
+
173
+ // Create result buffers
174
+ float* vectors = (float*)malloc(collection_size * dimensions * sizeof(float));
175
+ ASSERT(vectors, "Failed to allocate memory");
176
+
177
+ // Add multiple vectors with SAME key
178
+ usearch_key_t const key = 1;
179
+ float* data = create_vectors(collection_size, dimensions);
180
+ for (size_t i = 0; i < collection_size; i++) {
181
+ usearch_add(index, key, data + i * dimensions, usearch_scalar_f32_k, &error);
182
+ ASSERT(!error, error);
183
+ }
184
+
185
+ // Retrieve vectors from index
186
+ size_t found_count = usearch_get(index, key, collection_size, vectors, usearch_scalar_f32_k, &error);
187
+ ASSERT(found_count == collection_size, "Vector is missing");
188
+
189
+ free(vectors);
190
+ free(data);
191
+ usearch_free(index, &error);
192
+
193
+ printf("Test: Get Vector - PASSED\n");
194
+ }
195
+
196
+ /**
197
+ * This test ensures that vectors can be successfully removed from the index. It initializes the index, reserves space,
198
+ * and adds vectors. It then iteratively removes each vector from the index and checks for errors. However, note that
199
+ * the assert in this test expects an error, indicating that the remove functionality is not currently supported.
200
+ */
201
+ void test_remove_vector(size_t const collection_size, size_t const dimensions) {
202
+ printf("Test: Remove Vector... %zu vectors, %zu dimensions \n", collection_size, dimensions);
203
+
204
+ usearch_error_t error = NULL;
205
+ usearch_init_options_t opts = create_options(dimensions);
206
+ usearch_index_t index = usearch_init(&opts, &error);
207
+ usearch_reserve(index, collection_size, &error);
208
+
209
+ // Add vectors
210
+ float* data = create_vectors(collection_size, dimensions);
211
+ for (size_t i = 0; i < collection_size; ++i) {
212
+ usearch_key_t key = i;
213
+ usearch_add(index, key, data + i * dimensions, usearch_scalar_f32_k, &error);
214
+ ASSERT(!error, error);
215
+ }
216
+
217
+ // Remove the vectors
218
+ for (size_t i = 0; i < collection_size; i++) {
219
+ usearch_key_t key = i;
220
+ usearch_remove(index, key, &error);
221
+ ASSERT(!error, "Currently, Remove is not supported");
222
+ }
223
+
224
+ free(data);
225
+ usearch_free(index, &error);
226
+ printf("Test: Remove Vector - PASSED\n");
227
+ }
228
+
229
+ /**
230
+ * This test validates the save and load functionality of the index. It initializes the index, reserves space, and adds
231
+ * vectors. The index is then saved to a file and freed. A new index is initialized, and the previously saved index is
232
+ * loaded into it. The test then validates the loaded index properties and ensures that it contains all the vectors
233
+ * from the saved index.
234
+ */
235
+ void test_save_load(size_t const collection_size, size_t const dimensions) {
236
+ printf("Test: Save/Load... %zu vectors, %zu dimensions \n", collection_size, dimensions);
237
+ float* data = create_vectors(collection_size, dimensions);
238
+
239
+ usearch_error_t error = NULL;
240
+ usearch_init_options_t opts = create_options(dimensions);
241
+ usearch_init_options_t weird_ops = opts;
242
+ weird_ops.connectivity = 11;
243
+ weird_ops.expansion_add = 15;
244
+ weird_ops.expansion_search = 19;
245
+ weird_ops.metric_kind = usearch_metric_pearson_k;
246
+ weird_ops.quantization = usearch_scalar_f64_k;
247
+
248
+ {
249
+
250
+ usearch_index_t index = usearch_init(&weird_ops, &error);
251
+ usearch_reserve(index, collection_size, &error);
252
+
253
+ // Add vectors
254
+ for (size_t i = 0; i < collection_size; ++i) {
255
+ usearch_key_t key = i;
256
+ usearch_add(index, key, data + i * dimensions, usearch_scalar_f32_k, &error);
257
+ ASSERT(!error, error);
258
+ }
259
+
260
+ // Save and free the index
261
+ usearch_save(index, "tmp.usearch", &error);
262
+ ASSERT(!error, error);
263
+ usearch_free(index, &error);
264
+ ASSERT(!error, error);
265
+ }
266
+
267
+ // Reset the options
268
+ opts.connectivity = 0;
269
+ opts.dimensions = 0;
270
+ opts.expansion_add = 0;
271
+ opts.expansion_search = 0;
272
+ opts.metric = NULL;
273
+ opts.quantization = usearch_scalar_unknown_k;
274
+ opts.metric_kind = usearch_metric_unknown_k;
275
+
276
+ // Reinit
277
+ {
278
+
279
+ usearch_index_t index = usearch_init(&opts, &error);
280
+ ASSERT(!error, error);
281
+ ASSERT(usearch_size(index, &error) == 0, error);
282
+
283
+ // Load
284
+ usearch_load(index, "tmp.usearch", &error);
285
+ ASSERT(!error, error);
286
+ ASSERT(usearch_size(index, &error) == collection_size, error);
287
+ ASSERT(usearch_capacity(index, &error) == collection_size, error);
288
+ ASSERT(usearch_dimensions(index, &error) == dimensions, error);
289
+ ASSERT(usearch_connectivity(index, &error) == weird_ops.connectivity, error);
290
+
291
+ // Check vectors in the index
292
+ for (size_t i = 0; i < collection_size; ++i) {
293
+ usearch_key_t key = i;
294
+ ASSERT(usearch_contains(index, key, &error), error);
295
+ }
296
+
297
+ // Create result buffers
298
+ usearch_key_t* keys = (usearch_key_t*)malloc(collection_size * sizeof(usearch_key_t));
299
+ float* distances = (float*)malloc(collection_size * sizeof(float));
300
+ ASSERT(keys && distances, "Failed to allocate memory");
301
+
302
+ // Find the vectors
303
+ for (size_t i = 0; i < collection_size; i++) {
304
+ size_t found_count = usearch_search(index, data + i * dimensions, usearch_scalar_f32_k, collection_size,
305
+ keys, distances, &error);
306
+ ASSERT(!error, error);
307
+ ASSERT(found_count >= 1 && found_count <= collection_size, "Vector is missing");
308
+ }
309
+
310
+ free(keys);
311
+ free(distances);
312
+ usearch_free(index, &error);
313
+ }
314
+
315
+ free(data);
316
+
317
+ // Remove the file from disk
318
+ remove("tmp.usearch");
319
+ printf("Test: Save/Load - PASSED\n");
320
+ }
321
+
322
+ /**
323
+ * This test is designed to validate the view functionality of the index. It initializes the index, reserves space, and
324
+ * adds vectors. The index is then saved to a file and freed. A new index is initialized and a view is created from the
325
+ * saved index file. The test is mainly focused on ensuring that no errors occur during these operations, but it does
326
+ * not verify the properties or contents of the viewed index.
327
+ */
328
+ void test_view(size_t const collection_size, size_t const dimensions) {
329
+ printf("Test: View... %zu vectors, %zu dimensions \n", collection_size, dimensions);
330
+
331
+ usearch_error_t error = NULL;
332
+ usearch_init_options_t opts = create_options(dimensions);
333
+ usearch_index_t index = usearch_init(&opts, &error);
334
+ usearch_reserve(index, collection_size, &error);
335
+
336
+ // Add vectors
337
+ float* data = create_vectors(collection_size, dimensions);
338
+ for (size_t i = 0; i < collection_size; ++i) {
339
+ usearch_key_t key = i;
340
+ usearch_add(index, key, data + i * dimensions, usearch_scalar_f32_k, &error);
341
+ ASSERT(!error, error);
342
+ }
343
+
344
+ // Save and free the index
345
+ usearch_save(index, "tmp.usearch", &error);
346
+ ASSERT(!error, error);
347
+ usearch_free(index, &error);
348
+ ASSERT(!error, error);
349
+
350
+ // Reinit
351
+ index = usearch_init(&opts, &error);
352
+ ASSERT(!error, error);
353
+
354
+ // View
355
+ usearch_view(index, "tmp.usearch", &error);
356
+ ASSERT(!error, error);
357
+
358
+ free(data);
359
+ usearch_free(index, &error);
360
+ printf("Test: View - PASSED\n");
361
+ }
362
+
363
+ int main(int argc, char const* argv[]) {
364
+
365
+ size_t collection_sizes[] = {11, 512};
366
+ size_t dimensions[] = {83, 2}; // Not all distance functions make sense for 1 dimensional data
367
+ for (size_t index = 0; index < sizeof(collection_sizes) / sizeof(collection_sizes[0]); ++index) {
368
+ for (size_t jdx = 0; jdx < sizeof(dimensions) / sizeof(dimensions[0]); ++jdx) {
369
+ test_init(collection_sizes[index], dimensions[jdx]);
370
+ test_add_vector(collection_sizes[index], dimensions[jdx]);
371
+ test_find_vector(collection_sizes[index], dimensions[jdx]);
372
+ test_get_vector(collection_sizes[index], dimensions[jdx]);
373
+ test_remove_vector(collection_sizes[index], dimensions[jdx]);
374
+ test_save_load(collection_sizes[index], dimensions[jdx]);
375
+ test_view(collection_sizes[index], dimensions[jdx]);
376
+ }
377
+ }
378
+
379
+ (void)argc;
380
+ (void)argv;
381
+ return 0;
382
+ }