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 CHANGED
@@ -5,7 +5,7 @@ authors:
5
5
  given-names: "Ash"
6
6
  orcid: "https://orcid.org/0000-0002-4882-1815"
7
7
  title: "USearch by Unum Cloud"
8
- version: 2.9.0
8
+ version: 2.9.1
9
9
  doi: 10.5281/zenodo.7949416
10
10
  date-released: 2023-10-22
11
11
  url: "https://github.com/unum-cloud/usearch"
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
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "usearch"
3
- version = "2.9.0"
3
+ version = "2.9.1"
4
4
  authors = ["Ash Vardanian <1983160+ashvardanian@users.noreply.github.com>"]
5
5
  description = "Smaller & Faster Single-File Vector Search Engine from Unum"
6
6
  edition = "2021"
package/README.md CHANGED
@@ -434,7 +434,7 @@ doi = {10.5281/zenodo.7949416},
434
434
  author = {Vardanian, Ash},
435
435
  title = {{USearch by Unum Cloud}},
436
436
  url = {https://github.com/unum-cloud/usearch},
437
- version = {2.9.0},
437
+ version = {2.9.1},
438
438
  year = {2023},
439
439
  month = oct,
440
440
  }
package/VERSION CHANGED
@@ -1 +1 @@
1
- 2.9.0
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
- usearch_index_t index = usearch_init(&opts, &error);
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, "usearch_index.bin", &error);
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, "usearch_index.bin", &error);
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) == opts.connectivity, 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, "usearch_index.bin", &error);
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, "usearch_index.bin", &error);
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.0'
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 0
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
- at(search_for_one_(query, metric, prefetch, entry_slot_, max_level_, level - 1, context));
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
- ab += result_t(a[i]) * result_t(b[i]), //
1011
- a2 += square<result_t>(a[i]), //
1012
- b2 += square<result_t>(b[i]);
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
- ab_deltas_sq += square(result_t(a[i]) - result_t(b[i]));
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
- or_count += std::bitset<bits_per_word_k>(a[i] | b[i]).count();
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
- any_count += std::bitset<bits_per_word_k>(a[i]).count() + std::bitset<bits_per_word_k>(b[i]).count();
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
- a_sum += result_t(a[i]);
1180
- b_sum += result_t(b[i]);
1181
- ab_sum += result_t(a[i]) * result_t(b[i]);
1182
- a_sq_sum += result_t(a[i]) * result_t(a[i]);
1183
- b_sq_sum += result_t(b[i]) * result_t(b[i]);
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
- scalar_t epsilon = std::numeric_limits<scalar_t>::epsilon();
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 mi = result_t(p[i] + q[i]) / 2 + epsilon;
1210
- kld_pm += p[i] * std::log((p[i] + epsilon) / mi);
1211
- kld_qm += q[i] * std::log((q[i] + epsilon) / mi);
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.0",
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
  },
package/wasmer.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name="unum/usearch"
3
- version="2.9.0"
3
+ version="2.9.1"
4
4
  description="Smaller & Faster Single-File Vector Search Engine from Unum"
5
5
  license="Apache-2.0"
6
6
  readme="README.md"