usearch 1.2.2 → 2.0.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 (42) hide show
  1. package/.github/workflows/prerelease.yml +71 -0
  2. package/.github/workflows/release.yml +77 -2
  3. package/.github/workflows/update_version.sh +1 -0
  4. package/.gitignore +11 -1
  5. package/.vscode/settings.json +5 -1
  6. package/CMakeLists.txt +1 -0
  7. package/Cargo.toml +1 -1
  8. package/README.md +31 -18
  9. package/c/lib.cpp +38 -4
  10. package/c/test.c +117 -114
  11. package/c/usearch.h +28 -1
  12. package/conanfile.py +1 -1
  13. package/cpp/test.cpp +2 -2
  14. package/csharp/.editorconfig +361 -0
  15. package/csharp/Cloud.Unum.USearch.sln +34 -0
  16. package/csharp/DEV_SETUP.md +51 -0
  17. package/csharp/Directory.Build.props +29 -0
  18. package/csharp/README.md +77 -0
  19. package/csharp/build_and_test.cmd +31 -0
  20. package/csharp/build_and_test.sh +30 -0
  21. package/csharp/eng/build_lib.sh +65 -0
  22. package/csharp/eng/clean.sh +12 -0
  23. package/csharp/nuget/NUGET.md +11 -0
  24. package/csharp/nuget/nuget-package.props +33 -0
  25. package/csharp/pack.sh +56 -0
  26. package/csharp/src/Cloud.Unum.USearch.Tests/Cloud.Unum.USearch.Tests.csproj +39 -0
  27. package/csharp/src/Cloud.Unum.USearch.Tests/InitTests.cs +306 -0
  28. package/csharp/src/Cloud.Unum.USearch.Tests/Usings.cs +1 -0
  29. package/docs/benchmarks.md +6 -6
  30. package/docs/compilation.md +1 -1
  31. package/include/usearch/index.hpp +172 -52
  32. package/include/usearch/index_dense.hpp +201 -64
  33. package/include/usearch/index_plugins.hpp +90 -69
  34. package/package.json +2 -2
  35. package/python/lib.cpp +99 -37
  36. package/python/scripts/test_index.py +38 -10
  37. package/python/usearch/index.py +87 -37
  38. package/rust/README.md +2 -2
  39. package/rust/lib.cpp +42 -19
  40. package/rust/lib.hpp +14 -0
  41. package/rust/lib.rs +85 -43
  42. package/wasmer.toml +1 -1
package/c/test.c CHANGED
@@ -13,46 +13,18 @@
13
13
  }
14
14
 
15
15
 
16
- void parse_vectors_from_file(char const* file_path, size_t* count, size_t* dimension, float** data) {
17
-
18
- // Open the file
19
- struct stat st = {};
20
- ASSERT(stat(file_path, &st) == 0, "Failed to get metadata of the file");
21
- FILE* file = fopen(file_path, "rb");
22
- ASSERT(file, "Failed to open the file");
23
-
24
- // Read vectors dimension and calculate count
25
- int dim = 0;
26
- size_t read = fread(&dim, sizeof(int), 1, file);
27
- ASSERT(read == 1, "Failed to read from the file");
28
- ASSERT(st.st_size % ((dim + 1) * sizeof(float)) == 0, "File does not contain a whole number of vectors");
29
- *dimension = (size_t)dim;
30
- *count = st.st_size / ((dim + 1) * sizeof(float));
31
-
32
- // Allocate memory for the vectors' data
33
- *data = (float*)malloc(*count * *dimension * sizeof(float));
34
- ASSERT(*data, "Failed to allocate memory");
35
-
36
- // Read the data
37
- for (size_t i = 0; i < *count; ++i) {
38
- read = fread(*data + i * *dimension, sizeof(float), *dimension, file);
39
- ASSERT(read == *dimension, "Failed to read from the file");
40
- if (i == *count - 1)
41
- break;
42
-
43
- // Skip
44
- float skip;
45
- read = fread(&skip, sizeof(float), 1, file);
46
- ASSERT(read == 1, "Failed to read from the file");
47
- }
48
-
49
- fclose(file);
16
+ float* create_vectors(size_t count, size_t dimensions) {
17
+ float* data = (float*)malloc(count * dimensions * sizeof(float));
18
+ ASSERT(data, "Failed to allocate memory");
19
+ for (size_t idx = 0; idx < count * dimensions; ++idx)
20
+ data[idx] = (float)rand() / (float)RAND_MAX;
21
+ return data;
50
22
  }
51
23
 
52
- usearch_init_options_t create_options(size_t vector_dimension) {
24
+ usearch_init_options_t create_options(size_t dimensions) {
53
25
  usearch_init_options_t opts;
54
26
  opts.connectivity = 2; // 32 in faiss
55
- opts.dimensions = vector_dimension;
27
+ opts.dimensions = dimensions;
56
28
  opts.expansion_add = 40; // 40 in faiss
57
29
  opts.expansion_search = 16; // 10 in faiss
58
30
  opts.metric_kind = usearch_metric_ip_k;
@@ -61,14 +33,13 @@ usearch_init_options_t create_options(size_t vector_dimension) {
61
33
  return opts;
62
34
  }
63
35
 
64
- void test_init(size_t vectors_count, size_t vector_dimension) {
36
+ void test_init(size_t collection_size, size_t dimensions) {
65
37
  printf("Test: Index Initialization...\n");
66
38
 
67
39
  // Init index
68
- usearch_index_t idx = NULL;
69
40
  usearch_error_t error = NULL;
70
- usearch_init_options_t opts = create_options(vector_dimension);
71
- idx = usearch_init(&opts, &error);
41
+ usearch_init_options_t opts = create_options(dimensions);
42
+ usearch_index_t idx = usearch_init(&opts, &error);
72
43
  ASSERT(!error, error);
73
44
  usearch_free(idx, &error);
74
45
  ASSERT(!error, error);
@@ -79,15 +50,15 @@ void test_init(size_t vectors_count, size_t vector_dimension) {
79
50
 
80
51
  ASSERT(usearch_size(idx, &error) == 0, error);
81
52
  ASSERT(usearch_capacity(idx, &error) == 0, error);
82
- ASSERT(usearch_dimensions(idx, &error) == vector_dimension, error);
53
+ ASSERT(usearch_dimensions(idx, &error) == dimensions, error);
83
54
  ASSERT(usearch_connectivity(idx, &error) == opts.connectivity, error);
84
55
 
85
56
  // Reserve
86
- usearch_reserve(idx, vectors_count, &error);
57
+ usearch_reserve(idx, collection_size, &error);
87
58
  ASSERT(!error, error);
88
59
  ASSERT(usearch_size(idx, &error) == 0, error);
89
- ASSERT(usearch_capacity(idx, &error) == vectors_count, error);
90
- ASSERT(usearch_dimensions(idx, &error) == vector_dimension, error);
60
+ ASSERT(usearch_capacity(idx, &error) == collection_size, error);
61
+ ASSERT(usearch_dimensions(idx, &error) == dimensions, error);
91
62
  ASSERT(usearch_connectivity(idx, &error) == opts.connectivity, error);
92
63
 
93
64
  usearch_free(idx, &error);
@@ -96,110 +67,148 @@ void test_init(size_t vectors_count, size_t vector_dimension) {
96
67
  printf("Test: Index Initialization - PASSED\n");
97
68
  }
98
69
 
99
- void test_add_vector(size_t vectors_count, size_t vector_dimension, float const* data) {
70
+ void test_add_vector(size_t collection_size, size_t dimensions) {
100
71
  printf("Test: Add Vector...\n");
101
72
 
102
- usearch_index_t idx = NULL;
103
73
  usearch_error_t error = NULL;
104
- usearch_init_options_t opts = create_options(vector_dimension);
105
- idx = usearch_init(&opts, &error);
106
- usearch_reserve(idx, vectors_count, &error);
74
+ usearch_init_options_t opts = create_options(dimensions);
75
+ usearch_index_t idx = usearch_init(&opts, &error);
76
+ usearch_reserve(idx, collection_size, &error);
107
77
 
108
78
  // Add vectors
109
- for (size_t i = 0; i < vectors_count; ++i) {
79
+ float* data = create_vectors(collection_size, dimensions);
80
+ for (size_t i = 0; i < collection_size; ++i) {
110
81
  usearch_key_t key = i;
111
- usearch_add(idx, key, data + i * vector_dimension, usearch_scalar_f32_k, &error);
82
+ usearch_add(idx, key, data + i * dimensions, usearch_scalar_f32_k, &error);
112
83
  ASSERT(!error, error);
113
84
  }
114
85
 
115
- ASSERT(usearch_size(idx, &error) == vectors_count, error);
116
- ASSERT(usearch_capacity(idx, &error) == vectors_count, error);
86
+ ASSERT(usearch_size(idx, &error) == collection_size, error);
87
+ ASSERT(usearch_capacity(idx, &error) == collection_size, error);
117
88
 
118
89
  // Check vectors in the index
119
- for (size_t i = 0; i < vectors_count; ++i) {
90
+ for (size_t i = 0; i < collection_size; ++i) {
120
91
  usearch_key_t key = i;
121
92
  ASSERT(usearch_contains(idx, key, &error), error);
122
93
  }
123
94
  ASSERT(!usearch_contains(idx, -1, &error), error); // Non existing key
124
95
 
96
+ free(data);
125
97
  usearch_free(idx, &error);
126
98
  printf("Test: Add Vector - PASSED\n");
127
99
  }
128
100
 
129
- void test_find_vector(size_t vectors_count, size_t vector_dimension, float const* data) {
101
+ void test_find_vector(size_t collection_size, size_t dimensions) {
130
102
  printf("Test: Find Vector...\n");
131
103
 
132
- usearch_index_t idx = NULL;
133
104
  usearch_error_t error = NULL;
134
- usearch_init_options_t opts = create_options(vector_dimension);
135
- idx = usearch_init(&opts, &error);
136
- usearch_reserve(idx, vectors_count, &error);
105
+ usearch_init_options_t opts = create_options(dimensions);
106
+ usearch_index_t idx = usearch_init(&opts, &error);
107
+ usearch_reserve(idx, collection_size, &error);
137
108
 
138
109
  // Create result buffers
139
- int results_count = 10;
110
+ int results_count = collection_size;
140
111
  usearch_key_t* keys = (usearch_key_t*)malloc(results_count * sizeof(usearch_key_t));
141
112
  float* distances = (float*)malloc(results_count * sizeof(float));
142
113
  ASSERT(keys && distances, "Failed to allocate memory");
143
114
 
144
115
  // Add vectors
145
- for (size_t i = 0; i < vectors_count; ++i) {
116
+ float* data = create_vectors(collection_size, dimensions);
117
+ for (size_t i = 0; i < collection_size; ++i) {
146
118
  usearch_key_t key = i;
147
- usearch_add(idx, key, data + i * vector_dimension, usearch_scalar_f32_k, &error);
119
+ usearch_add(idx, key, data + i * dimensions, usearch_scalar_f32_k, &error);
148
120
  ASSERT(!error, error);
149
121
  }
150
122
 
151
123
  // Find the vectors
152
- for (size_t i = 0; i < vectors_count; i++) {
153
- const void *query_vector = data + i * vector_dimension;
124
+ for (size_t i = 0; i < collection_size; i++) {
125
+ const void *query_vector = data + i * dimensions;
154
126
  size_t found_count = usearch_search(idx, query_vector, usearch_scalar_f32_k, results_count, keys, distances, &error);
155
127
  ASSERT(!error, error);
156
128
  ASSERT(found_count = results_count, "Vector is missing");
157
129
  }
158
130
 
131
+ free(data);
132
+ free(keys);
133
+ free(distances);
159
134
  usearch_free(idx, &error);
160
135
  printf("Test: Find Vector - PASSED\n");
161
136
  }
162
137
 
163
- void test_remove_vector(size_t vectors_count, size_t vector_dimension, float const* data) {
138
+ void test_get_vector(size_t collection_size, size_t dimensions) {
139
+ printf("Test: Get Vector...\n");
140
+
141
+ usearch_error_t error = NULL;
142
+ usearch_init_options_t opts = create_options(dimensions);
143
+ opts.multi = true;
144
+ usearch_index_t idx = usearch_init(&opts, &error);
145
+ usearch_reserve(idx, collection_size, &error);
146
+
147
+ // Create result buffers
148
+ int results_count = collection_size;
149
+ float* vectors = (float*)malloc(results_count * dimensions * sizeof(float));
150
+ ASSERT(vectors, "Failed to allocate memory");
151
+
152
+ // Add multiple vectors with SAME key
153
+ usearch_key_t const key = 1;
154
+ float* data = create_vectors(collection_size, dimensions);
155
+ for (size_t i = 0; i < collection_size; i++) {
156
+ usearch_add(idx, key, data + i * dimensions, usearch_scalar_f32_k, &error);
157
+ ASSERT(!error, error);
158
+ }
159
+
160
+ // Retrieve vectors from index
161
+ size_t count = usearch_get(idx, key, collection_size, vectors, usearch_scalar_f32_k, &error);
162
+ ASSERT(count == results_count, "Vector is missing");
163
+
164
+ free(vectors);
165
+ free(data);
166
+ usearch_free(idx, &error);
167
+
168
+ printf("Test: Get Vector - PASSED\n");
169
+ }
170
+
171
+ void test_remove_vector(size_t collection_size, size_t dimensions) {
164
172
  printf("Test: Remove Vector...\n");
165
173
 
166
- usearch_index_t idx = NULL;
167
174
  usearch_error_t error = NULL;
168
- usearch_init_options_t opts = create_options(vector_dimension);
169
- idx = usearch_init(&opts, &error);
170
- usearch_reserve(idx, vectors_count, &error);
175
+ usearch_init_options_t opts = create_options(dimensions);
176
+ usearch_index_t idx = usearch_init(&opts, &error);
177
+ usearch_reserve(idx, collection_size, &error);
171
178
 
172
179
  // Add vectors
173
- for (size_t i = 0; i < vectors_count; ++i) {
180
+ float* data = create_vectors(collection_size, dimensions);
181
+ for (size_t i = 0; i < collection_size; ++i) {
174
182
  usearch_key_t key = i;
175
- usearch_add(idx, key, data + i * vector_dimension, usearch_scalar_f32_k, &error);
183
+ usearch_add(idx, key, data + i * dimensions, usearch_scalar_f32_k, &error);
176
184
  ASSERT(!error, error);
177
185
  }
178
186
 
179
187
  // Remove the vectors
180
- for (size_t i = 0; i < vectors_count; i++) {
188
+ for (size_t i = 0; i < collection_size; i++) {
181
189
  usearch_key_t key = i;
182
190
  usearch_remove(idx, key, &error);
183
- ASSERT(error, "Currently, Remove is not supported");
191
+ ASSERT(!error, "Currently, Remove is not supported");
184
192
  }
185
193
 
194
+ free(data);
186
195
  usearch_free(idx, &error);
187
196
  printf("Test: Remove Vector - PASSED\n");
188
197
  }
189
198
 
190
- void test_save_load(size_t vectors_count, size_t vector_dimension, float const* data) {
199
+ void test_save_load(size_t collection_size, size_t dimensions) {
191
200
  printf("Test: Save/Load...\n");
192
201
 
193
- usearch_index_t idx = NULL;
194
202
  usearch_error_t error = NULL;
195
- usearch_init_options_t opts = create_options(vector_dimension);
196
- idx = usearch_init(&opts, &error);
197
- usearch_reserve(idx, vectors_count, &error);
203
+ usearch_init_options_t opts = create_options(dimensions);
204
+ usearch_index_t idx = usearch_init(&opts, &error);
205
+ usearch_reserve(idx, collection_size, &error);
198
206
 
199
207
  // Add vectors
200
- for (size_t i = 0; i < vectors_count; ++i) {
208
+ float* data = create_vectors(collection_size, dimensions);
209
+ for (size_t i = 0; i < collection_size; ++i) {
201
210
  usearch_key_t key = i;
202
- usearch_add(idx, key, data + i * vector_dimension, usearch_scalar_f32_k, &error);
211
+ usearch_add(idx, key, data + i * dimensions, usearch_scalar_f32_k, &error);
203
212
  ASSERT(!error, error);
204
213
  }
205
214
 
@@ -217,34 +226,35 @@ void test_save_load(size_t vectors_count, size_t vector_dimension, float const*
217
226
  // Load
218
227
  usearch_load(idx, "usearch_index.bin", &error);
219
228
  ASSERT(!error, error);
220
- ASSERT(usearch_size(idx, &error) == vectors_count, error);
221
- ASSERT(usearch_capacity(idx, &error) == vectors_count, error);
222
- ASSERT(usearch_dimensions(idx, &error) == vector_dimension, error);
229
+ ASSERT(usearch_size(idx, &error) == collection_size, error);
230
+ ASSERT(usearch_capacity(idx, &error) == collection_size, error);
231
+ ASSERT(usearch_dimensions(idx, &error) == dimensions, error);
223
232
  ASSERT(usearch_connectivity(idx, &error) == opts.connectivity, error);
224
233
 
225
234
  // Check vectors in the index
226
- for (size_t i = 0; i < vectors_count; ++i) {
235
+ for (size_t i = 0; i < collection_size; ++i) {
227
236
  usearch_key_t key = i;
228
237
  ASSERT(usearch_contains(idx, key, &error), error);
229
238
  }
230
239
 
240
+ free(data);
231
241
  usearch_free(idx, &error);
232
242
  printf("Test: Save/Load - PASSED\n");
233
243
  }
234
244
 
235
- void test_view(size_t vectors_count, size_t vector_dimension, float const* data) {
245
+ void test_view(size_t collection_size, size_t dimensions) {
236
246
  printf("Test: View...\n");
237
247
 
238
- usearch_index_t idx = NULL;
239
248
  usearch_error_t error = NULL;
240
- usearch_init_options_t opts = create_options(vector_dimension);
241
- idx = usearch_init(&opts, &error);
242
- usearch_reserve(idx, vectors_count, &error);
249
+ usearch_init_options_t opts = create_options(dimensions);
250
+ usearch_index_t idx = usearch_init(&opts, &error);
251
+ usearch_reserve(idx, collection_size, &error);
243
252
 
244
253
  // Add vectors
245
- for (size_t i = 0; i < vectors_count; ++i) {
254
+ float* data = create_vectors(collection_size, dimensions);
255
+ for (size_t i = 0; i < collection_size; ++i) {
246
256
  usearch_key_t key = i;
247
- usearch_add(idx, key, data + i * vector_dimension, usearch_scalar_f32_k, &error);
257
+ usearch_add(idx, key, data + i * dimensions, usearch_scalar_f32_k, &error);
248
258
  ASSERT(!error, error);
249
259
  }
250
260
 
@@ -262,33 +272,26 @@ void test_view(size_t vectors_count, size_t vector_dimension, float const* data)
262
272
  usearch_view(idx, "usearch_index.bin", &error);
263
273
  ASSERT(!error, error);
264
274
 
275
+ free(data);
265
276
  usearch_free(idx, &error);
266
277
  printf("Test: View - PASSED\n");
267
278
  }
268
279
 
269
- int main(int argc, char* argv[]) {
270
- // Resolve file path
271
- char const* filename = "sample.fvecs";
272
- if (argc == 2)
273
- filename = argv[1];
274
-
275
- // Read data from the file
276
- float* data = NULL;
277
- size_t vectors_count = 0;
278
- size_t vector_dimension = 0;
279
- parse_vectors_from_file(filename, &vectors_count, &vector_dimension, &data);
280
- vectors_count = vectors_count > 100000 ? 100000 : vectors_count; // Just limit vectors
281
-
282
- // Test
283
- test_init(vectors_count, vector_dimension);
284
- test_add_vector(vectors_count, vector_dimension, data);
285
- test_find_vector(vectors_count, vector_dimension, data);
286
- test_remove_vector(vectors_count, vector_dimension, data);
287
- test_save_load(vectors_count, vector_dimension, data);
288
- test_view(vectors_count, vector_dimension, data);
289
-
290
- // Free vectors' buffer
291
- free(data);
280
+ int main() {
281
+
282
+ size_t collection_sizes[] = {11, 512};
283
+ size_t dimensions[] = {83, 1};
284
+ for (size_t idx = 0; idx < sizeof(collection_sizes) / sizeof(collection_sizes[0]); ++idx) {
285
+ for (size_t jdx = 0; jdx < sizeof(dimensions) / sizeof(dimensions[0]); ++jdx) {
286
+ test_init(collection_sizes[idx], dimensions[jdx]);
287
+ test_add_vector(collection_sizes[idx], dimensions[jdx]);
288
+ test_find_vector(collection_sizes[idx], dimensions[jdx]);
289
+ test_get_vector(collection_sizes[idx], dimensions[jdx]);
290
+ test_remove_vector(collection_sizes[idx], dimensions[jdx]);
291
+ test_save_load(collection_sizes[idx], dimensions[jdx]);
292
+ test_view(collection_sizes[idx], dimensions[jdx]);
293
+ }
294
+ }
292
295
 
293
296
  return 0;
294
297
  }
package/c/usearch.h CHANGED
@@ -109,6 +109,12 @@ USEARCH_EXPORT usearch_index_t usearch_init(usearch_init_options_t* options, use
109
109
  */
110
110
  USEARCH_EXPORT void usearch_free(usearch_index_t, usearch_error_t* error);
111
111
 
112
+ /**
113
+ * @brief Reports expected file size after serialization.
114
+ * @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
115
+ */
116
+ USEARCH_EXPORT size_t usearch_serialized_length(usearch_index_t, usearch_error_t* error);
117
+
112
118
  /**
113
119
  * @brief Saves the index to a file.
114
120
  * @param[in] path The file path where the index will be saved.
@@ -124,12 +130,33 @@ USEARCH_EXPORT void usearch_save(usearch_index_t, char const* path, usearch_erro
124
130
  USEARCH_EXPORT void usearch_load(usearch_index_t, char const* path, usearch_error_t* error);
125
131
 
126
132
  /**
127
- * @brief Creates a view of the index from a file without loading it into memory.
133
+ * @brief Creates a view of the index from a file without copying it into memory.
128
134
  * @param[in] path The file path from where the view will be created.
129
135
  * @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
130
136
  */
131
137
  USEARCH_EXPORT void usearch_view(usearch_index_t, char const* path, usearch_error_t* error);
132
138
 
139
+ /**
140
+ * @brief Saves the index to an in-memory buffer.
141
+ * @param[in] buffer The in-memory continuous buffer where the index will be saved.
142
+ * @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
143
+ */
144
+ USEARCH_EXPORT void usearch_save_buffer(usearch_index_t, void* buffer, size_t length, usearch_error_t* error);
145
+
146
+ /**
147
+ * @brief Loads the index from an in-memory buffer.
148
+ * @param[in] buffer The in-memory continuous buffer from where the index will be loaded.
149
+ * @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
150
+ */
151
+ USEARCH_EXPORT void usearch_load_buffer(usearch_index_t, void const* buffer, size_t length, usearch_error_t* error);
152
+
153
+ /**
154
+ * @brief Creates a view of the index from an in-memory buffer without copying it into memory.
155
+ * @param[in] buffer The in-memory continuous buffer from where the view will be created.
156
+ * @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
157
+ */
158
+ USEARCH_EXPORT void usearch_view_buffer(usearch_index_t, void const* buffer, size_t length, usearch_error_t* error);
159
+
133
160
  USEARCH_EXPORT size_t usearch_size(usearch_index_t, usearch_error_t* error);
134
161
  USEARCH_EXPORT size_t usearch_capacity(usearch_index_t, usearch_error_t* error);
135
162
  USEARCH_EXPORT size_t usearch_dimensions(usearch_index_t, usearch_error_t* error);
package/conanfile.py CHANGED
@@ -4,7 +4,7 @@ from conans import ConanFile
4
4
  class USearchConan(ConanFile):
5
5
 
6
6
  name = 'USearch'
7
- version = '1.2.2'
7
+ version = '2.0.0'
8
8
  license = 'Apache 2.0'
9
9
  url = 'https://github.com/unum-cloud/usearch'
10
10
  description = 'Smaller & Faster Single-File Vector Search Engine from Unum'
package/cpp/test.cpp CHANGED
@@ -118,7 +118,7 @@ void test_cosine(index_at& index, std::vector<std::vector<scalar_at>> const& vec
118
118
  }
119
119
 
120
120
  // Search again over mapped index
121
- // file_head_result_t head = index_dense_metadata("tmp.usearch");
121
+ // file_head_result_t head = index_dense_metadata_from_path("tmp.usearch");
122
122
  // expect(head.size == 3);
123
123
  index.view("tmp.usearch");
124
124
  matched_count = index.search(vector_first, 5, args...).dump_to(matched_keys, matched_distances);
@@ -140,7 +140,7 @@ void test_cosine(index_at& index, std::vector<std::vector<scalar_at>> const& vec
140
140
 
141
141
  // Check metadata
142
142
  if constexpr (punned_ak) {
143
- index_dense_metadata_result_t meta = index_dense_metadata("tmp.usearch");
143
+ index_dense_metadata_result_t meta = index_dense_metadata_from_path("tmp.usearch");
144
144
  expect(bool(meta));
145
145
  }
146
146
  }