usearch 2.6.0 → 2.7.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/. npmignore +14 -0
- package/.cmake-format.py +19 -0
- package/.github/workflows/Dockerfile.libs +2 -2
- package/.github/workflows/prerelease.yml +85 -64
- package/.github/workflows/release.yml +24 -15
- package/.gitignore +1 -1
- package/.vscode/launch.json +47 -14
- package/.vscode/settings.json +7 -0
- package/.vscode/tasks.json +44 -8
- package/CITATION.cff +1 -1
- package/CMakeLists.txt +218 -67
- package/Cargo.toml +1 -1
- package/README.md +1 -1
- package/binding.gyp +3 -2
- package/build.gradle +19 -10
- package/c/CMakeLists.txt +21 -48
- package/c/README.md +5 -5
- package/c/lib.cpp +52 -7
- package/c/test.c +137 -94
- package/c/usearch.h +42 -0
- package/cmake/clipp.cmake +0 -1
- package/cmake/jemalloc.cmake +21 -37
- package/conanfile.py +1 -1
- package/cpp/CMakeLists.txt +14 -123
- package/cpp/README.md +26 -22
- package/cpp/bench.cpp +0 -12
- package/cpp/test.cpp +29 -1
- package/csharp/nuget/nuget-package.props +1 -1
- package/docs/compilation.md +23 -16
- package/docs/conf.py +1 -1
- package/golang/README.md +52 -51
- package/golang/lib.go +1 -1
- package/golang/lib_test.go +4 -1
- package/include/usearch/index.hpp +2 -2
- package/include/usearch/index_plugins.hpp +345 -160
- package/javascript/lib.cpp +204 -250
- package/javascript/usearch.js +440 -2
- package/javascript/usearch.test.js +37 -0
- package/package.json +10 -5
- package/python/lib.cpp +95 -224
- package/python/scripts/bench_exact.py +2 -2
- package/python/scripts/test_jit.py +2 -13
- package/python/scripts/test_sparse.py +1 -1
- package/python/scripts/test_tooling.py +15 -5
- package/rust/lib.cpp +7 -4
- package/rust/lib.hpp +2 -0
- package/rust/lib.rs +128 -8
- package/setup.py +14 -4
- package/wasm/CMakeLists.txt +4 -12
- package/wasm/lib.cpp +1 -1
- package/wasmer.toml +1 -1
- package/javascript/docs.js +0 -111
- package/javascript/test.js +0 -32
- package/javascript/usearch.d.ts +0 -110
- package/tsconfig.json +0 -8
package/c/test.c
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#include <stdio.h>
|
|
2
1
|
#include <errno.h>
|
|
3
2
|
#include <stdio.h>
|
|
4
3
|
#include <stdlib.h>
|
|
@@ -6,24 +5,30 @@
|
|
|
6
5
|
|
|
7
6
|
#include "usearch.h"
|
|
8
7
|
|
|
9
|
-
#define ASSERT(must_be_true, message)
|
|
10
|
-
if (!(must_be_true)) {
|
|
11
|
-
printf("Assert: %s\n", message);
|
|
12
|
-
exit(-1);
|
|
8
|
+
#define ASSERT(must_be_true, message) \
|
|
9
|
+
if (!(must_be_true)) { \
|
|
10
|
+
printf("Assert: %s\n", message); \
|
|
11
|
+
exit(-1); \
|
|
13
12
|
}
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
|
|
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) {
|
|
17
22
|
float* data = (float*)malloc(count * dimensions * sizeof(float));
|
|
18
23
|
ASSERT(data, "Failed to allocate memory");
|
|
19
|
-
for (size_t
|
|
20
|
-
data[
|
|
24
|
+
for (size_t index = 0; index < count * dimensions; ++index)
|
|
25
|
+
data[index] = (float)rand() / (float)RAND_MAX;
|
|
21
26
|
return data;
|
|
22
27
|
}
|
|
23
28
|
|
|
24
|
-
usearch_init_options_t create_options(size_t dimensions) {
|
|
29
|
+
usearch_init_options_t create_options(size_t const dimensions) {
|
|
25
30
|
usearch_init_options_t opts;
|
|
26
|
-
opts.connectivity =
|
|
31
|
+
opts.connectivity = 3; // 32 in faiss
|
|
27
32
|
opts.dimensions = dimensions;
|
|
28
33
|
opts.expansion_add = 40; // 40 in faiss
|
|
29
34
|
opts.expansion_search = 16; // 10 in faiss
|
|
@@ -33,265 +38,303 @@ usearch_init_options_t create_options(size_t dimensions) {
|
|
|
33
38
|
return opts;
|
|
34
39
|
}
|
|
35
40
|
|
|
36
|
-
|
|
41
|
+
/**
|
|
42
|
+
* This test is designed to verify the initialization of the index with specific dimensions and ensures that the
|
|
43
|
+
* associated properties are set correctly. It initializes the index twice, checking for errors at each step, and
|
|
44
|
+
* performs a reserve operation to pre-allocate space in the index, verifying the correct settings of size, capacity,
|
|
45
|
+
* dimensions, and connectivity after each operation.
|
|
46
|
+
*/
|
|
47
|
+
void test_init(size_t const collection_size, size_t const dimensions) {
|
|
37
48
|
printf("Test: Index Initialization...\n");
|
|
38
49
|
|
|
39
50
|
// Init index
|
|
40
51
|
usearch_error_t error = NULL;
|
|
41
52
|
usearch_init_options_t opts = create_options(dimensions);
|
|
42
|
-
usearch_index_t
|
|
53
|
+
usearch_index_t index = usearch_init(&opts, &error);
|
|
43
54
|
ASSERT(!error, error);
|
|
44
|
-
usearch_free(
|
|
55
|
+
usearch_free(index, &error);
|
|
45
56
|
ASSERT(!error, error);
|
|
46
57
|
|
|
47
58
|
// Init second time
|
|
48
|
-
|
|
59
|
+
index = usearch_init(&opts, &error);
|
|
49
60
|
ASSERT(!error, error);
|
|
50
61
|
|
|
51
|
-
ASSERT(usearch_size(
|
|
52
|
-
ASSERT(usearch_capacity(
|
|
53
|
-
ASSERT(usearch_dimensions(
|
|
54
|
-
ASSERT(usearch_connectivity(
|
|
62
|
+
ASSERT(usearch_size(index, &error) == 0, error);
|
|
63
|
+
ASSERT(usearch_capacity(index, &error) == 0, error);
|
|
64
|
+
ASSERT(usearch_dimensions(index, &error) == dimensions, error);
|
|
65
|
+
ASSERT(usearch_connectivity(index, &error) == opts.connectivity, error);
|
|
55
66
|
|
|
56
67
|
// Reserve
|
|
57
|
-
usearch_reserve(
|
|
68
|
+
usearch_reserve(index, collection_size, &error);
|
|
58
69
|
ASSERT(!error, error);
|
|
59
|
-
ASSERT(usearch_size(
|
|
60
|
-
ASSERT(usearch_capacity(
|
|
61
|
-
ASSERT(usearch_dimensions(
|
|
62
|
-
ASSERT(usearch_connectivity(
|
|
70
|
+
ASSERT(usearch_size(index, &error) == 0, error);
|
|
71
|
+
ASSERT(usearch_capacity(index, &error) == collection_size, error);
|
|
72
|
+
ASSERT(usearch_dimensions(index, &error) == dimensions, error);
|
|
73
|
+
ASSERT(usearch_connectivity(index, &error) == opts.connectivity, error);
|
|
63
74
|
|
|
64
|
-
usearch_free(
|
|
75
|
+
usearch_free(index, &error);
|
|
65
76
|
ASSERT(!error, error);
|
|
66
77
|
|
|
67
78
|
printf("Test: Index Initialization - PASSED\n");
|
|
68
79
|
}
|
|
69
80
|
|
|
70
|
-
|
|
81
|
+
/**
|
|
82
|
+
* This test validates the addition of vectors to the index. It initializes the index and reserves space for vectors.
|
|
83
|
+
* It then iteratively adds vectors to the index and checks if the index contains the added vectors by verifying the
|
|
84
|
+
* size, capacity, and presence of each vector in the index.
|
|
85
|
+
*/
|
|
86
|
+
void test_add_vector(size_t const collection_size, size_t const dimensions) {
|
|
71
87
|
printf("Test: Add Vector...\n");
|
|
72
88
|
|
|
73
89
|
usearch_error_t error = NULL;
|
|
74
90
|
usearch_init_options_t opts = create_options(dimensions);
|
|
75
|
-
usearch_index_t
|
|
76
|
-
usearch_reserve(
|
|
91
|
+
usearch_index_t index = usearch_init(&opts, &error);
|
|
92
|
+
usearch_reserve(index, collection_size, &error);
|
|
77
93
|
|
|
78
94
|
// Add vectors
|
|
79
95
|
float* data = create_vectors(collection_size, dimensions);
|
|
80
96
|
for (size_t i = 0; i < collection_size; ++i) {
|
|
81
97
|
usearch_key_t key = i;
|
|
82
|
-
usearch_add(
|
|
98
|
+
usearch_add(index, key, data + i * dimensions, usearch_scalar_f32_k, &error);
|
|
83
99
|
ASSERT(!error, error);
|
|
84
100
|
}
|
|
85
101
|
|
|
86
|
-
ASSERT(usearch_size(
|
|
87
|
-
ASSERT(usearch_capacity(
|
|
102
|
+
ASSERT(usearch_size(index, &error) == collection_size, error);
|
|
103
|
+
ASSERT(usearch_capacity(index, &error) == collection_size, error);
|
|
88
104
|
|
|
89
105
|
// Check vectors in the index
|
|
90
106
|
for (size_t i = 0; i < collection_size; ++i) {
|
|
91
107
|
usearch_key_t key = i;
|
|
92
|
-
ASSERT(usearch_contains(
|
|
108
|
+
ASSERT(usearch_contains(index, key, &error), error);
|
|
93
109
|
}
|
|
94
|
-
ASSERT(!usearch_contains(
|
|
110
|
+
ASSERT(!usearch_contains(index, -1, &error), error); // Non existing key
|
|
95
111
|
|
|
96
112
|
free(data);
|
|
97
|
-
usearch_free(
|
|
113
|
+
usearch_free(index, &error);
|
|
98
114
|
printf("Test: Add Vector - PASSED\n");
|
|
99
115
|
}
|
|
100
116
|
|
|
101
|
-
|
|
117
|
+
/**
|
|
118
|
+
* This test ensures that vectors added to the index can be correctly found. It initializes the index, reserves space,
|
|
119
|
+
* and adds vectors. It then performs a search query for each added vector to ensure that the vectors are correctly
|
|
120
|
+
* found in the index, validating the count of found vectors.
|
|
121
|
+
*/
|
|
122
|
+
void test_find_vector(size_t const collection_size, size_t const dimensions) {
|
|
102
123
|
printf("Test: Find Vector...\n");
|
|
103
124
|
|
|
104
125
|
usearch_error_t error = NULL;
|
|
105
126
|
usearch_init_options_t opts = create_options(dimensions);
|
|
106
|
-
usearch_index_t
|
|
107
|
-
usearch_reserve(
|
|
127
|
+
usearch_index_t index = usearch_init(&opts, &error);
|
|
128
|
+
usearch_reserve(index, collection_size, &error);
|
|
108
129
|
|
|
109
130
|
// Create result buffers
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
float* distances = (float*)malloc(results_count * sizeof(float));
|
|
131
|
+
usearch_key_t* keys = (usearch_key_t*)malloc(collection_size * sizeof(usearch_key_t));
|
|
132
|
+
float* distances = (float*)malloc(collection_size * sizeof(float));
|
|
113
133
|
ASSERT(keys && distances, "Failed to allocate memory");
|
|
114
134
|
|
|
115
135
|
// Add vectors
|
|
116
136
|
float* data = create_vectors(collection_size, dimensions);
|
|
117
137
|
for (size_t i = 0; i < collection_size; ++i) {
|
|
118
138
|
usearch_key_t key = i;
|
|
119
|
-
usearch_add(
|
|
139
|
+
usearch_add(index, key, data + i * dimensions, usearch_scalar_f32_k, &error);
|
|
120
140
|
ASSERT(!error, error);
|
|
121
141
|
}
|
|
122
142
|
|
|
123
143
|
// Find the vectors
|
|
124
144
|
for (size_t i = 0; i < collection_size; i++) {
|
|
125
|
-
|
|
126
|
-
|
|
145
|
+
size_t found_count = usearch_search(index, data + i * dimensions, usearch_scalar_f32_k, collection_size, keys,
|
|
146
|
+
distances, &error);
|
|
127
147
|
ASSERT(!error, error);
|
|
128
|
-
ASSERT(found_count
|
|
148
|
+
ASSERT(found_count >= 1 && found_count <= collection_size, "Vector is missing");
|
|
129
149
|
}
|
|
130
150
|
|
|
131
151
|
free(data);
|
|
132
152
|
free(keys);
|
|
133
153
|
free(distances);
|
|
134
|
-
usearch_free(
|
|
154
|
+
usearch_free(index, &error);
|
|
135
155
|
printf("Test: Find Vector - PASSED\n");
|
|
136
156
|
}
|
|
137
157
|
|
|
138
|
-
|
|
158
|
+
/**
|
|
159
|
+
* This test checks the ability of the index to handle multiple vectors associated with the same key. It initializes
|
|
160
|
+
* the index with the multi-option enabled, reserves space, and adds multiple vectors with the same key. The test then
|
|
161
|
+
* retrieves vectors associated with the key from the index and checks the count of retrieved vectors.
|
|
162
|
+
*/
|
|
163
|
+
void test_get_vector(size_t const collection_size, size_t const dimensions) {
|
|
139
164
|
printf("Test: Get Vector...\n");
|
|
140
165
|
|
|
141
166
|
usearch_error_t error = NULL;
|
|
142
167
|
usearch_init_options_t opts = create_options(dimensions);
|
|
143
168
|
opts.multi = true;
|
|
144
|
-
usearch_index_t
|
|
145
|
-
usearch_reserve(
|
|
169
|
+
usearch_index_t index = usearch_init(&opts, &error);
|
|
170
|
+
usearch_reserve(index, collection_size, &error);
|
|
146
171
|
|
|
147
172
|
// Create result buffers
|
|
148
|
-
|
|
149
|
-
float* vectors = (float*)malloc(results_count * dimensions * sizeof(float));
|
|
173
|
+
float* vectors = (float*)malloc(collection_size * dimensions * sizeof(float));
|
|
150
174
|
ASSERT(vectors, "Failed to allocate memory");
|
|
151
175
|
|
|
152
176
|
// Add multiple vectors with SAME key
|
|
153
177
|
usearch_key_t const key = 1;
|
|
154
178
|
float* data = create_vectors(collection_size, dimensions);
|
|
155
179
|
for (size_t i = 0; i < collection_size; i++) {
|
|
156
|
-
usearch_add(
|
|
180
|
+
usearch_add(index, key, data + i * dimensions, usearch_scalar_f32_k, &error);
|
|
157
181
|
ASSERT(!error, error);
|
|
158
182
|
}
|
|
159
183
|
|
|
160
184
|
// Retrieve vectors from index
|
|
161
|
-
size_t
|
|
162
|
-
ASSERT(
|
|
185
|
+
size_t found_count = usearch_get(index, key, collection_size, vectors, usearch_scalar_f32_k, &error);
|
|
186
|
+
ASSERT(found_count == collection_size, "Vector is missing");
|
|
163
187
|
|
|
164
188
|
free(vectors);
|
|
165
189
|
free(data);
|
|
166
|
-
usearch_free(
|
|
190
|
+
usearch_free(index, &error);
|
|
167
191
|
|
|
168
192
|
printf("Test: Get Vector - PASSED\n");
|
|
169
193
|
}
|
|
170
194
|
|
|
171
|
-
|
|
195
|
+
/**
|
|
196
|
+
* This test ensures that vectors can be successfully removed from the index. It initializes the index, reserves space,
|
|
197
|
+
* and adds vectors. It then iteratively removes each vector from the index and checks for errors. However, note that
|
|
198
|
+
* the assert in this test expects an error, indicating that the remove functionality is not currently supported.
|
|
199
|
+
*/
|
|
200
|
+
void test_remove_vector(size_t const collection_size, size_t const dimensions) {
|
|
172
201
|
printf("Test: Remove Vector...\n");
|
|
173
202
|
|
|
174
203
|
usearch_error_t error = NULL;
|
|
175
204
|
usearch_init_options_t opts = create_options(dimensions);
|
|
176
|
-
usearch_index_t
|
|
177
|
-
usearch_reserve(
|
|
205
|
+
usearch_index_t index = usearch_init(&opts, &error);
|
|
206
|
+
usearch_reserve(index, collection_size, &error);
|
|
178
207
|
|
|
179
208
|
// Add vectors
|
|
180
209
|
float* data = create_vectors(collection_size, dimensions);
|
|
181
210
|
for (size_t i = 0; i < collection_size; ++i) {
|
|
182
211
|
usearch_key_t key = i;
|
|
183
|
-
usearch_add(
|
|
212
|
+
usearch_add(index, key, data + i * dimensions, usearch_scalar_f32_k, &error);
|
|
184
213
|
ASSERT(!error, error);
|
|
185
214
|
}
|
|
186
215
|
|
|
187
216
|
// Remove the vectors
|
|
188
217
|
for (size_t i = 0; i < collection_size; i++) {
|
|
189
218
|
usearch_key_t key = i;
|
|
190
|
-
usearch_remove(
|
|
219
|
+
usearch_remove(index, key, &error);
|
|
191
220
|
ASSERT(!error, "Currently, Remove is not supported");
|
|
192
221
|
}
|
|
193
222
|
|
|
194
223
|
free(data);
|
|
195
|
-
usearch_free(
|
|
224
|
+
usearch_free(index, &error);
|
|
196
225
|
printf("Test: Remove Vector - PASSED\n");
|
|
197
226
|
}
|
|
198
227
|
|
|
199
|
-
|
|
228
|
+
/**
|
|
229
|
+
* This test validates the save and load functionality of the index. It initializes the index, reserves space, and adds
|
|
230
|
+
* vectors. The index is then saved to a file and freed. A new index is initialized, and the previously saved index is
|
|
231
|
+
* loaded into it. The test then validates the loaded index properties and ensures that it contains all the vectors
|
|
232
|
+
* from the saved index.
|
|
233
|
+
*/
|
|
234
|
+
void test_save_load(size_t const collection_size, size_t const dimensions) {
|
|
200
235
|
printf("Test: Save/Load...\n");
|
|
201
236
|
|
|
202
237
|
usearch_error_t error = NULL;
|
|
203
238
|
usearch_init_options_t opts = create_options(dimensions);
|
|
204
|
-
usearch_index_t
|
|
205
|
-
usearch_reserve(
|
|
239
|
+
usearch_index_t index = usearch_init(&opts, &error);
|
|
240
|
+
usearch_reserve(index, collection_size, &error);
|
|
206
241
|
|
|
207
242
|
// Add vectors
|
|
208
243
|
float* data = create_vectors(collection_size, dimensions);
|
|
209
244
|
for (size_t i = 0; i < collection_size; ++i) {
|
|
210
245
|
usearch_key_t key = i;
|
|
211
|
-
usearch_add(
|
|
246
|
+
usearch_add(index, key, data + i * dimensions, usearch_scalar_f32_k, &error);
|
|
212
247
|
ASSERT(!error, error);
|
|
213
248
|
}
|
|
214
249
|
|
|
215
250
|
// Save and free the index
|
|
216
|
-
usearch_save(
|
|
251
|
+
usearch_save(index, "usearch_index.bin", &error);
|
|
217
252
|
ASSERT(!error, error);
|
|
218
|
-
usearch_free(
|
|
253
|
+
usearch_free(index, &error);
|
|
219
254
|
ASSERT(!error, error);
|
|
220
255
|
|
|
221
256
|
// Reinit
|
|
222
|
-
|
|
257
|
+
index = usearch_init(&opts, &error);
|
|
223
258
|
ASSERT(!error, error);
|
|
224
|
-
ASSERT(usearch_size(
|
|
259
|
+
ASSERT(usearch_size(index, &error) == 0, error);
|
|
225
260
|
|
|
226
261
|
// Load
|
|
227
|
-
usearch_load(
|
|
262
|
+
usearch_load(index, "usearch_index.bin", &error);
|
|
228
263
|
ASSERT(!error, error);
|
|
229
|
-
ASSERT(usearch_size(
|
|
230
|
-
ASSERT(usearch_capacity(
|
|
231
|
-
ASSERT(usearch_dimensions(
|
|
232
|
-
ASSERT(usearch_connectivity(
|
|
264
|
+
ASSERT(usearch_size(index, &error) == collection_size, error);
|
|
265
|
+
ASSERT(usearch_capacity(index, &error) == collection_size, error);
|
|
266
|
+
ASSERT(usearch_dimensions(index, &error) == dimensions, error);
|
|
267
|
+
ASSERT(usearch_connectivity(index, &error) == opts.connectivity, error);
|
|
233
268
|
|
|
234
269
|
// Check vectors in the index
|
|
235
270
|
for (size_t i = 0; i < collection_size; ++i) {
|
|
236
271
|
usearch_key_t key = i;
|
|
237
|
-
ASSERT(usearch_contains(
|
|
272
|
+
ASSERT(usearch_contains(index, key, &error), error);
|
|
238
273
|
}
|
|
239
274
|
|
|
240
275
|
free(data);
|
|
241
|
-
usearch_free(
|
|
276
|
+
usearch_free(index, &error);
|
|
242
277
|
printf("Test: Save/Load - PASSED\n");
|
|
243
278
|
}
|
|
244
279
|
|
|
245
|
-
|
|
280
|
+
/**
|
|
281
|
+
* This test is designed to validate the view functionality of the index. It initializes the index, reserves space, and
|
|
282
|
+
* adds vectors. The index is then saved to a file and freed. A new index is initialized and a view is created from the
|
|
283
|
+
* saved index file. The test is mainly focused on ensuring that no errors occur during these operations, but it does
|
|
284
|
+
* not verify the properties or contents of the viewed index.
|
|
285
|
+
*/
|
|
286
|
+
void test_view(size_t const collection_size, size_t const dimensions) {
|
|
246
287
|
printf("Test: View...\n");
|
|
247
288
|
|
|
248
289
|
usearch_error_t error = NULL;
|
|
249
290
|
usearch_init_options_t opts = create_options(dimensions);
|
|
250
|
-
usearch_index_t
|
|
251
|
-
usearch_reserve(
|
|
291
|
+
usearch_index_t index = usearch_init(&opts, &error);
|
|
292
|
+
usearch_reserve(index, collection_size, &error);
|
|
252
293
|
|
|
253
294
|
// Add vectors
|
|
254
295
|
float* data = create_vectors(collection_size, dimensions);
|
|
255
296
|
for (size_t i = 0; i < collection_size; ++i) {
|
|
256
297
|
usearch_key_t key = i;
|
|
257
|
-
usearch_add(
|
|
298
|
+
usearch_add(index, key, data + i * dimensions, usearch_scalar_f32_k, &error);
|
|
258
299
|
ASSERT(!error, error);
|
|
259
300
|
}
|
|
260
301
|
|
|
261
302
|
// Save and free the index
|
|
262
|
-
usearch_save(
|
|
303
|
+
usearch_save(index, "usearch_index.bin", &error);
|
|
263
304
|
ASSERT(!error, error);
|
|
264
|
-
usearch_free(
|
|
305
|
+
usearch_free(index, &error);
|
|
265
306
|
ASSERT(!error, error);
|
|
266
307
|
|
|
267
308
|
// Reinit
|
|
268
|
-
|
|
309
|
+
index = usearch_init(&opts, &error);
|
|
269
310
|
ASSERT(!error, error);
|
|
270
311
|
|
|
271
312
|
// View
|
|
272
|
-
usearch_view(
|
|
313
|
+
usearch_view(index, "usearch_index.bin", &error);
|
|
273
314
|
ASSERT(!error, error);
|
|
274
315
|
|
|
275
316
|
free(data);
|
|
276
|
-
usearch_free(
|
|
317
|
+
usearch_free(index, &error);
|
|
277
318
|
printf("Test: View - PASSED\n");
|
|
278
319
|
}
|
|
279
320
|
|
|
280
|
-
int main() {
|
|
321
|
+
int main(int argc, char const* argv[]) {
|
|
281
322
|
|
|
282
323
|
size_t collection_sizes[] = {11, 512};
|
|
283
324
|
size_t dimensions[] = {83, 1};
|
|
284
|
-
for (size_t
|
|
325
|
+
for (size_t index = 0; index < sizeof(collection_sizes) / sizeof(collection_sizes[0]); ++index) {
|
|
285
326
|
for (size_t jdx = 0; jdx < sizeof(dimensions) / sizeof(dimensions[0]); ++jdx) {
|
|
286
|
-
test_init(collection_sizes[
|
|
287
|
-
test_add_vector(collection_sizes[
|
|
288
|
-
test_find_vector(collection_sizes[
|
|
289
|
-
test_get_vector(collection_sizes[
|
|
290
|
-
test_remove_vector(collection_sizes[
|
|
291
|
-
test_save_load(collection_sizes[
|
|
292
|
-
test_view(collection_sizes[
|
|
327
|
+
test_init(collection_sizes[index], dimensions[jdx]);
|
|
328
|
+
test_add_vector(collection_sizes[index], dimensions[jdx]);
|
|
329
|
+
test_find_vector(collection_sizes[index], dimensions[jdx]);
|
|
330
|
+
test_get_vector(collection_sizes[index], dimensions[jdx]);
|
|
331
|
+
test_remove_vector(collection_sizes[index], dimensions[jdx]);
|
|
332
|
+
test_save_load(collection_sizes[index], dimensions[jdx]);
|
|
333
|
+
test_view(collection_sizes[index], dimensions[jdx]);
|
|
293
334
|
}
|
|
294
335
|
}
|
|
295
336
|
|
|
337
|
+
(void)argc;
|
|
338
|
+
(void)argv;
|
|
296
339
|
return 0;
|
|
297
|
-
}
|
|
340
|
+
}
|
package/c/usearch.h
CHANGED
|
@@ -241,6 +241,48 @@ USEARCH_EXPORT size_t usearch_remove(usearch_index_t, usearch_key_t key, usearch
|
|
|
241
241
|
*/
|
|
242
242
|
USEARCH_EXPORT size_t usearch_rename(usearch_index_t, usearch_key_t from, usearch_key_t to, usearch_error_t* error);
|
|
243
243
|
|
|
244
|
+
/**
|
|
245
|
+
* @brief Computes the distance between two equi-dimensional vectors.
|
|
246
|
+
* @param[in] vector_first The first vector for comparison.
|
|
247
|
+
* @param[in] vector_second The second vector for comparison.
|
|
248
|
+
* @param[in] scalar_kind The scalar type used in the vectors.
|
|
249
|
+
* @param[in] dimensions The number of dimensions in each vector.
|
|
250
|
+
* @param[in] metric_kind The metric kind used for distance calculation between vectors.
|
|
251
|
+
* @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
|
|
252
|
+
* @return Distance between given vectors.
|
|
253
|
+
*/
|
|
254
|
+
USEARCH_EXPORT usearch_distance_t usearch_distance( //
|
|
255
|
+
void const* vector_first, void const* vector_second, //
|
|
256
|
+
usearch_scalar_kind_t scalar_kind, size_t dimensions, //
|
|
257
|
+
usearch_metric_kind_t metric_kind, usearch_error_t* error);
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* @brief Multi-threaded exact nearest neighbors search for equi-dimensional vectors.
|
|
261
|
+
* @param[in] dataset Pointer to the first scalar of the dataset matrix.
|
|
262
|
+
* @param[in] queries Pointer to the first scalar of the queries matrix.
|
|
263
|
+
* @param[in] dataset_size Number of vectors in the `dataset`.
|
|
264
|
+
* @param[in] queries_size Number of vectors in the `queries` set.
|
|
265
|
+
* @param[in] dataset_stride Number of bytes between starts of consecutive vectors in `dataset`.
|
|
266
|
+
* @param[in] queries_stride Number of bytes between starts of consecutive vectors in `queries`.
|
|
267
|
+
* @param[in] scalar_kind The scalar type used in the vectors.
|
|
268
|
+
* @param[in] dimensions The number of dimensions in each vector.
|
|
269
|
+
* @param[in] metric_kind The metric kind used for distance calculation between vectors.
|
|
270
|
+
* @param[in] count Upper bound on the number of neighbors to search, the "k" in "kANN".
|
|
271
|
+
* @param[in] threads Upper bound for the number of CPU threads to use.
|
|
272
|
+
* @param[out] keys Output buffer for up to `count` nearest neighbors keys.
|
|
273
|
+
* @param[out] distances Output buffer for up to `count` distances to nearest neighbors.
|
|
274
|
+
* @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
|
|
275
|
+
* @return Number of found matches.
|
|
276
|
+
*/
|
|
277
|
+
USEARCH_EXPORT void usearch_exact_search( //
|
|
278
|
+
void const* dataset, size_t dataset_size, size_t dataset_stride, //
|
|
279
|
+
void const* queries, size_t queries_size, size_t queries_stride, //
|
|
280
|
+
usearch_scalar_kind_t scalar_kind, size_t dimensions, //
|
|
281
|
+
usearch_metric_kind_t metric_kind, size_t count, size_t threads, //
|
|
282
|
+
usearch_key_t* keys, size_t keys_stride, //
|
|
283
|
+
usearch_distance_t* distances, size_t distances_stride, //
|
|
284
|
+
usearch_error_t* error);
|
|
285
|
+
|
|
244
286
|
#ifdef __cplusplus
|
|
245
287
|
}
|
|
246
288
|
#endif
|
package/cmake/clipp.cmake
CHANGED
package/cmake/jemalloc.cmake
CHANGED
|
@@ -1,44 +1,35 @@
|
|
|
1
|
-
|
|
2
1
|
include(ExternalProject)
|
|
3
2
|
set(JEMALLOC_DISABLE_TLS)
|
|
4
3
|
|
|
5
|
-
if(${USTORE_BUILD_SDK_PYTHON})
|
|
4
|
+
if (${USTORE_BUILD_SDK_PYTHON})
|
|
6
5
|
set(JEMALLOC_DISABLE_TLS --disable-initial-exec-tls)
|
|
7
|
-
endif()
|
|
6
|
+
endif ()
|
|
8
7
|
|
|
9
|
-
if(${USTORE_REBUILD_JEMALLOC})
|
|
8
|
+
if (${USTORE_REBUILD_JEMALLOC})
|
|
10
9
|
set(JEMALLOC_PREFIX_DIR ${CMAKE_BINARY_DIR}/_deps/jemalloc)
|
|
11
10
|
set(JEMALLOC_SRC_DIR ${JEMALLOC_PREFIX_DIR}/src/jemalloc)
|
|
12
11
|
set(JEMALLOC_INSTALL_DIR ${JEMALLOC_PREFIX_DIR}/install)
|
|
13
12
|
set(JEMALLOC_DEPENDENCY jemalloc)
|
|
14
13
|
|
|
15
|
-
ExternalProject_Add(
|
|
14
|
+
ExternalProject_Add(
|
|
15
|
+
jemalloc
|
|
16
16
|
GIT_REPOSITORY https://github.com/jemalloc/jemalloc.git
|
|
17
17
|
GIT_TAG 5.3.0
|
|
18
18
|
PREFIX ${JEMALLOC_PREFIX_DIR}
|
|
19
|
-
CONFIGURE_COMMAND
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
BUILD_COMMAND echo Building jemalloc && cd ${JEMALLOC_SRC_DIR}
|
|
24
|
-
&& make install_lib_static install_include
|
|
19
|
+
CONFIGURE_COMMAND
|
|
20
|
+
echo Configuring jemalloc && cd ${JEMALLOC_SRC_DIR} && ./autogen.sh && ./configure
|
|
21
|
+
--prefix=${JEMALLOC_INSTALL_DIR} --enable-prof ${JEMALLOC_DISABLE_TLS} # --with-jemalloc-prefix=je_
|
|
22
|
+
BUILD_COMMAND echo Building jemalloc && cd ${JEMALLOC_SRC_DIR} && make install_lib_static install_include
|
|
25
23
|
INSTALL_COMMAND ""
|
|
26
24
|
UPDATE_COMMAND ""
|
|
27
25
|
)
|
|
28
26
|
|
|
29
|
-
# Create libjemalloc and libjemalloc_pic targets to be used as
|
|
30
|
-
# dependencies
|
|
27
|
+
# Create libjemalloc and libjemalloc_pic targets to be used as dependencies
|
|
31
28
|
add_library(libjemalloc STATIC IMPORTED GLOBAL)
|
|
32
29
|
add_library(libjemalloc_pic STATIC IMPORTED GLOBAL)
|
|
33
30
|
|
|
34
|
-
set_property(TARGET libjemalloc
|
|
35
|
-
|
|
36
|
-
${JEMALLOC_INSTALL_DIR}/lib/libjemalloc.a
|
|
37
|
-
)
|
|
38
|
-
set_property(TARGET libjemalloc_pic
|
|
39
|
-
PROPERTY IMPORTED_LOCATION
|
|
40
|
-
${JEMALLOC_INSTALL_DIR}/lib/libjemalloc_pic.a
|
|
41
|
-
)
|
|
31
|
+
set_property(TARGET libjemalloc PROPERTY IMPORTED_LOCATION ${JEMALLOC_INSTALL_DIR}/lib/libjemalloc.a)
|
|
32
|
+
set_property(TARGET libjemalloc_pic PROPERTY IMPORTED_LOCATION ${JEMALLOC_INSTALL_DIR}/lib/libjemalloc_pic.a)
|
|
42
33
|
|
|
43
34
|
link_libraries(-Wl,--no-as-needed)
|
|
44
35
|
link_libraries(dl ${libjemalloc_pic})
|
|
@@ -49,30 +40,23 @@ if(${USTORE_REBUILD_JEMALLOC})
|
|
|
49
40
|
|
|
50
41
|
include_directories(${JEMALLOC_SOURCE_DIR}/include)
|
|
51
42
|
|
|
52
|
-
else()
|
|
53
|
-
find_path(JEMALLOC_ROOT_DIR
|
|
54
|
-
NAMES include/jemalloc/jemalloc.h
|
|
55
|
-
)
|
|
43
|
+
else ()
|
|
44
|
+
find_path(JEMALLOC_ROOT_DIR NAMES include/jemalloc/jemalloc.h)
|
|
56
45
|
|
|
57
|
-
find_library(
|
|
46
|
+
find_library(
|
|
47
|
+
JEMALLOC_LIBRARIES
|
|
58
48
|
NAMES jemalloc
|
|
59
49
|
HINTS ${JEMALLOC_ROOT_DIR}/lib
|
|
60
50
|
)
|
|
61
51
|
|
|
62
|
-
find_path(
|
|
52
|
+
find_path(
|
|
53
|
+
JEMALLOC_INCLUDE_DIR
|
|
63
54
|
NAMES jemalloc/jemalloc.h
|
|
64
55
|
HINTS ${JEMALLOC_ROOT_DIR}/include
|
|
65
56
|
)
|
|
66
57
|
|
|
67
58
|
include(FindPackageHandleStandardArgs)
|
|
68
|
-
find_package_handle_standard_args(JeMalloc DEFAULT_MSG
|
|
69
|
-
JEMALLOC_LIBRARIES
|
|
70
|
-
JEMALLOC_INCLUDE_DIR
|
|
71
|
-
)
|
|
59
|
+
find_package_handle_standard_args(JeMalloc DEFAULT_MSG JEMALLOC_LIBRARIES JEMALLOC_INCLUDE_DIR)
|
|
72
60
|
|
|
73
|
-
mark_as_advanced(
|
|
74
|
-
|
|
75
|
-
JEMALLOC_LIBRARIES
|
|
76
|
-
JEMALLOC_INCLUDE_DIR
|
|
77
|
-
)
|
|
78
|
-
endif()
|
|
61
|
+
mark_as_advanced(JEMALLOC_ROOT_DIR JEMALLOC_LIBRARIES JEMALLOC_INCLUDE_DIR)
|
|
62
|
+
endif ()
|
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.
|
|
10
|
+
version = '2.7.0'
|
|
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"
|