usearch 2.7.7 → 2.8.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 (53) hide show
  1. package/.dockerignore +93 -0
  2. package/.github/workflows/Dockerfile.libs +6 -2
  3. package/.github/workflows/prerelease.yml +242 -245
  4. package/.github/workflows/release.yml +390 -356
  5. package/.gitignore +1 -0
  6. package/.vscode/settings.json +3 -1
  7. package/CITATION.cff +1 -1
  8. package/CMakeLists.txt +35 -5
  9. package/Cargo.toml +1 -1
  10. package/README.md +1 -1
  11. package/build.gradle +6 -0
  12. package/c/README.md +3 -3
  13. package/c/lib.cpp +75 -11
  14. package/c/usearch.h +22 -1
  15. package/conanfile.py +1 -1
  16. package/cpp/README.md +2 -1
  17. package/cpp/bench.cpp +3 -0
  18. package/cpp/test.cpp +12 -12
  19. package/csharp/nuget/nuget-package.props +1 -1
  20. package/docs/compilation.md +5 -13
  21. package/golang/lib.go +4 -1
  22. package/include/usearch/index.hpp +31 -30
  23. package/include/usearch/index_dense.hpp +49 -48
  24. package/include/usearch/index_plugins.hpp +70 -8
  25. package/java/cloud/unum/usearch/Index.java +118 -26
  26. package/java/cloud/unum/usearch/cloud_unum_usearch_Index.cpp +8 -8
  27. package/javascript/usearch.js +1 -0
  28. package/objc/USearchObjective.mm +4 -1
  29. package/objc/include/USearchObjective.h +1 -0
  30. package/package.json +1 -1
  31. package/python/lib.cpp +3 -2
  32. package/python/scripts/bench.ipynb +24 -2
  33. package/python/usearch/index.py +8 -3
  34. package/rust/lib.cpp +14 -12
  35. package/rust/lib.hpp +13 -13
  36. package/rust/lib.rs +46 -0
  37. package/setup.py +15 -3
  38. package/simsimd/.github/workflows/prerelease.yml +7 -8
  39. package/simsimd/.github/workflows/release.yml +18 -20
  40. package/simsimd/README.md +13 -8
  41. package/simsimd/binding.gyp +1 -1
  42. package/simsimd/cpp/bench.cxx +17 -3
  43. package/simsimd/include/simsimd/binary.h +1 -3
  44. package/simsimd/include/simsimd/probability.h +234 -361
  45. package/simsimd/include/simsimd/simsimd.h +95 -65
  46. package/simsimd/include/simsimd/spatial.h +0 -3
  47. package/simsimd/include/simsimd/types.h +12 -7
  48. package/simsimd/javascript/test.js +23 -5
  49. package/simsimd/package.json +2 -2
  50. package/wasmer.toml +1 -1
  51. package/wolfram/lib.cpp +1 -1
  52. package/csharp/eng/build_lib.sh +0 -65
  53. package/csharp/eng/clean.sh +0 -12
package/.gitignore CHANGED
@@ -16,6 +16,7 @@ bin
16
16
  build
17
17
  build_release
18
18
  build_debug
19
+ build_artifacts
19
20
  _deps
20
21
  CMakeCache.txt
21
22
  CMakeFiles
@@ -102,7 +102,9 @@
102
102
  "__verbose_abort": "cpp",
103
103
  "shared_mutex": "cpp",
104
104
  "ranges": "cpp",
105
- "span": "cpp"
105
+ "span": "cpp",
106
+ "format": "cpp",
107
+ "charconv": "cpp"
106
108
  },
107
109
  "cSpell.words": [
108
110
  "allclose",
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.7.7
8
+ version: 2.8.0
9
9
  doi: 10.5281/zenodo.7949416
10
10
  date-released: 2023-10-22
11
11
  url: "https://github.com/unum-cloud/usearch"
package/CMakeLists.txt CHANGED
@@ -260,13 +260,43 @@ function (setup_target TARGET_NAME)
260
260
  endif ()
261
261
 
262
262
  target_include_directories(${TARGET_NAME} PRIVATE ${USEARCH_HEADER_INCLUDES})
263
- set_target_properties(${TARGET_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR})
264
- set_target_properties(${TARGET_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR})
265
- set_target_properties(${TARGET_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
266
- set_target_properties(${TARGET_NAME} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
267
- set_target_properties(${TARGET_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
268
263
  set_target_properties(${TARGET_NAME} PROPERTIES CXX_STANDARD 17)
269
264
 
265
+ # On Windows, when using multi-configuration CMake builds, the paths will be nested, resulting in
266
+ # "build_debug\Debug" on Windows instead of "build_debug". That's why we override all the configs to use the same
267
+ # output directory.
268
+ set_target_properties(
269
+ ${TARGET_NAME}
270
+ PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
271
+ ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
272
+ LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
273
+ )
274
+ set_target_properties(
275
+ ${TARGET_NAME}
276
+ PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}"
277
+ ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}"
278
+ LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}"
279
+ )
280
+ set_target_properties(
281
+ ${TARGET_NAME}
282
+ PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}"
283
+ ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}"
284
+ LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}"
285
+ )
286
+ set_target_properties(
287
+ ${TARGET_NAME}
288
+ PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_BINARY_DIR}"
289
+ ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_BINARY_DIR}"
290
+ LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_BINARY_DIR}"
291
+ )
292
+
293
+ # On Linux and MacOS our primary shared libraries for C are called `libusearch_c.so` and `libusearch_c.dylib`, while
294
+ # on Windows the "lib" prefix might be missing by default, so let's ensure it's always there
295
+ get_target_property(TARGET_TYPE ${TARGET_NAME} TYPE)
296
+ if (TARGET_TYPE STREQUAL "SHARED_LIBRARY" OR TARGET_TYPE STREQUAL "STATIC_LIBRARY")
297
+ set_target_properties(${TARGET_NAME} PROPERTIES PREFIX "lib")
298
+ endif ()
299
+
270
300
  # Core compilation settings affecting "index.hpp"
271
301
  target_compile_definitions(${TARGET_NAME} PRIVATE $<$<NOT:$<BOOL:${USEARCH_USE_OPENMP}>>:USEARCH_USE_OPENMP=0>)
272
302
 
package/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "usearch"
3
- version = "2.7.7"
3
+ version = "2.8.0"
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
@@ -392,7 +392,7 @@ doi = {10.5281/zenodo.7949416},
392
392
  author = {Vardanian, Ash},
393
393
  title = {{USearch by Unum Cloud}},
394
394
  url = {https://github.com/unum-cloud/usearch},
395
- version = {2.7.7},
395
+ version = {2.8.0},
396
396
  year = {2023},
397
397
  month = oct,
398
398
  }
package/build.gradle CHANGED
@@ -36,6 +36,11 @@ task sourcesJar(type: Jar, dependsOn: classes) {
36
36
  from sourceSets.main.allSource
37
37
  }
38
38
 
39
+ task javadocJar(type: Jar, dependsOn: javadoc) {
40
+ archiveClassifier.set('javadoc')
41
+ from javadoc.destinationDir
42
+ }
43
+
39
44
  dependencies {
40
45
  testImplementation('junit:junit:4.13.2')
41
46
  }
@@ -117,6 +122,7 @@ publishing {
117
122
  from components.java
118
123
 
119
124
  artifact sourcesJar
125
+ artifact javadocJar
120
126
 
121
127
  if (project.hasProperty('signArtifacts') && signArtifacts.toBoolean()) {
122
128
  signing {
package/c/README.md CHANGED
@@ -6,9 +6,9 @@ The simplest form to integrate is to copy the contents of `usearch/c/` into your
6
6
  To build the library `libusearch_static_c` and `libusearch_c`, pass enable the `USEARCH_BUILD_LIB_C` CMake option:
7
7
 
8
8
  ```bash
9
- cmake -B ./build -DUSEARCH_BUILD_LIB_C=1 -DUSEARCH_BUILD_TEST_C=1 -DUSEARCH_BUILD_TEST_CPP=0 -DUSEARCH_BUILD_BENCH_CPP=0
10
- make -C ./build
11
- ./build/test_c
9
+ cmake -DCMAKE_BUILD_TYPE=Release -DUSEARCH_BUILD_LIB_C=1 -DUSEARCH_BUILD_TEST_C=1 -DUSEARCH_BUILD_TEST_CPP=0 -DUSEARCH_BUILD_BENCH_CPP=0 -B ./build_release
10
+ cmake --build ./build_release --config Release
11
+ ./build_release/test_c
12
12
  ```
13
13
 
14
14
  ## Quickstart
package/c/lib.cpp CHANGED
@@ -13,16 +13,16 @@ using add_result_t = typename index_dense_t::add_result_t;
13
13
  using search_result_t = typename index_dense_t::search_result_t;
14
14
  using labeling_result_t = typename index_dense_t::labeling_result_t;
15
15
 
16
- static_assert(std::is_same<usearch_key_t, index_dense_t::key_t>::value, "Type mismatch between C and C++");
16
+ static_assert(std::is_same<usearch_key_t, index_dense_t::vector_key_t>::value, "Type mismatch between C and C++");
17
17
  static_assert(std::is_same<usearch_distance_t, index_dense_t::distance_t>::value, "Type mismatch between C and C++");
18
18
 
19
- // helper functions that are not part of the C ABI
20
- metric_kind_t to_native_metric(usearch_metric_kind_t kind) {
19
+ metric_kind_t metric_kind_to_cpp(usearch_metric_kind_t kind) {
21
20
  switch (kind) {
22
21
  case usearch_metric_ip_k: return metric_kind_t::ip_k;
23
22
  case usearch_metric_l2sq_k: return metric_kind_t::l2sq_k;
24
23
  case usearch_metric_cos_k: return metric_kind_t::cos_k;
25
24
  case usearch_metric_haversine_k: return metric_kind_t::haversine_k;
25
+ case usearch_metric_divergence_k: return metric_kind_t::divergence_k;
26
26
  case usearch_metric_pearson_k: return metric_kind_t::pearson_k;
27
27
  case usearch_metric_jaccard_k: return metric_kind_t::jaccard_k;
28
28
  case usearch_metric_hamming_k: return metric_kind_t::hamming_k;
@@ -32,7 +32,22 @@ metric_kind_t to_native_metric(usearch_metric_kind_t kind) {
32
32
  }
33
33
  }
34
34
 
35
- scalar_kind_t to_native_scalar(usearch_scalar_kind_t kind) {
35
+ usearch_metric_kind_t metric_kind_to_c(metric_kind_t kind) {
36
+ switch (kind) {
37
+ case metric_kind_t::ip_k: return usearch_metric_ip_k;
38
+ case metric_kind_t::l2sq_k: return usearch_metric_l2sq_k;
39
+ case metric_kind_t::cos_k: return usearch_metric_cos_k;
40
+ case metric_kind_t::haversine_k: return usearch_metric_haversine_k;
41
+ case metric_kind_t::divergence_k: return usearch_metric_divergence_k;
42
+ case metric_kind_t::pearson_k: return usearch_metric_pearson_k;
43
+ case metric_kind_t::jaccard_k: return usearch_metric_jaccard_k;
44
+ case metric_kind_t::hamming_k: return usearch_metric_hamming_k;
45
+ case metric_kind_t::tanimoto_k: return usearch_metric_tanimoto_k;
46
+ case metric_kind_t::sorensen_k: return usearch_metric_sorensen_k;
47
+ default: return usearch_metric_unknown_k;
48
+ }
49
+ }
50
+ scalar_kind_t scalar_kind_to_cpp(usearch_scalar_kind_t kind) {
36
51
  switch (kind) {
37
52
  case usearch_scalar_f32_k: return scalar_kind_t::f32_k;
38
53
  case usearch_scalar_f64_k: return scalar_kind_t::f64_k;
@@ -43,6 +58,17 @@ scalar_kind_t to_native_scalar(usearch_scalar_kind_t kind) {
43
58
  }
44
59
  }
45
60
 
61
+ usearch_scalar_kind_t scalar_kind_to_c(scalar_kind_t kind) {
62
+ switch (kind) {
63
+ case scalar_kind_t::f32_k: return usearch_scalar_f32_k;
64
+ case scalar_kind_t::f64_k: return usearch_scalar_f64_k;
65
+ case scalar_kind_t::f16_k: return usearch_scalar_f16_k;
66
+ case scalar_kind_t::i8_k: return usearch_scalar_i8_k;
67
+ case scalar_kind_t::b1x8_k: return usearch_scalar_b1_k;
68
+ default: return usearch_scalar_unknown_k;
69
+ }
70
+ }
71
+
46
72
  add_result_t add_(index_dense_t* index, usearch_key_t key, void const* vector, scalar_kind_t kind) {
47
73
  switch (kind) {
48
74
  case scalar_kind_t::f32_k: return index->add(key, (f32_t const*)vector);
@@ -84,8 +110,8 @@ USEARCH_EXPORT usearch_index_t usearch_init(usearch_init_options_t* options, use
84
110
 
85
111
  index_dense_config_t config(options->connectivity, options->expansion_add, options->expansion_search);
86
112
  config.multi = options->multi;
87
- metric_kind_t metric_kind = to_native_metric(options->metric_kind);
88
- scalar_kind_t scalar_kind = to_native_scalar(options->quantization);
113
+ metric_kind_t metric_kind = metric_kind_to_cpp(options->metric_kind);
114
+ scalar_kind_t scalar_kind = scalar_kind_to_cpp(options->quantization);
89
115
 
90
116
  metric_punned_t metric = //
91
117
  !options->metric ? metric_punned_t(options->dimensions, metric_kind, scalar_kind)
@@ -134,6 +160,24 @@ USEARCH_EXPORT void usearch_view(usearch_index_t index, char const* path, usearc
134
160
  *error = result.error.release();
135
161
  }
136
162
 
163
+ USEARCH_EXPORT void usearch_metadata(char const* path, usearch_init_options_t* options, usearch_error_t* error) {
164
+
165
+ assert(path && options && error);
166
+ index_dense_metadata_result_t result = index_dense_metadata_from_path(path);
167
+ if (!result)
168
+ *error = result.error.release();
169
+
170
+ options->metric_kind = metric_kind_to_c(result.head.kind_metric);
171
+ options->quantization = scalar_kind_to_c(result.head.kind_scalar);
172
+ options->dimensions = result.head.dimensions;
173
+ options->multi = result.head.multi;
174
+
175
+ options->connectivity = 0;
176
+ options->expansion_add = 0;
177
+ options->expansion_search = 0;
178
+ options->metric = NULL;
179
+ }
180
+
137
181
  USEARCH_EXPORT void usearch_save_buffer(usearch_index_t index, void* buffer, size_t length, usearch_error_t* error) {
138
182
 
139
183
  assert(index && buffer && length && error);
@@ -163,6 +207,26 @@ USEARCH_EXPORT void usearch_view_buffer(usearch_index_t index, void const* buffe
163
207
  *error = result.error.release();
164
208
  }
165
209
 
210
+ USEARCH_EXPORT void usearch_metadata_buffer(void const* buffer, size_t length, usearch_init_options_t* options,
211
+ usearch_error_t* error) {
212
+
213
+ assert(buffer && length && options && error);
214
+ index_dense_metadata_result_t result =
215
+ index_dense_metadata_from_buffer(memory_mapped_file_t((byte_t*)(buffer), length));
216
+ if (!result)
217
+ *error = result.error.release();
218
+
219
+ options->metric_kind = metric_kind_to_c(result.head.kind_metric);
220
+ options->quantization = scalar_kind_to_c(result.head.kind_scalar);
221
+ options->dimensions = result.head.dimensions;
222
+ options->multi = result.head.multi;
223
+
224
+ options->connectivity = 0;
225
+ options->expansion_add = 0;
226
+ options->expansion_search = 0;
227
+ options->metric = NULL;
228
+ }
229
+
166
230
  USEARCH_EXPORT size_t usearch_size(usearch_index_t index, usearch_error_t*) { //
167
231
  return reinterpret_cast<index_dense_t*>(index)->size();
168
232
  }
@@ -190,7 +254,7 @@ USEARCH_EXPORT void usearch_add(
190
254
  usearch_error_t* error) {
191
255
 
192
256
  assert(index && vector && error);
193
- add_result_t result = add_(reinterpret_cast<index_dense_t*>(index), key, vector, to_native_scalar(kind));
257
+ add_result_t result = add_(reinterpret_cast<index_dense_t*>(index), key, vector, scalar_kind_to_cpp(kind));
194
258
  if (!result)
195
259
  *error = result.error.release();
196
260
  }
@@ -211,7 +275,7 @@ USEARCH_EXPORT size_t usearch_search(
211
275
 
212
276
  assert(index && vector && error);
213
277
  search_result_t result =
214
- search_(reinterpret_cast<index_dense_t*>(index), vector, to_native_scalar(kind), results_limit);
278
+ search_(reinterpret_cast<index_dense_t*>(index), vector, scalar_kind_to_cpp(kind), results_limit);
215
279
  if (!result) {
216
280
  *error = result.error.release();
217
281
  return 0;
@@ -225,7 +289,7 @@ USEARCH_EXPORT size_t usearch_get( //
225
289
  void* vectors, usearch_scalar_kind_t kind, usearch_error_t*) {
226
290
 
227
291
  assert(index && vectors);
228
- return get_(reinterpret_cast<index_dense_t*>(index), key, count, vectors, to_native_scalar(kind));
292
+ return get_(reinterpret_cast<index_dense_t*>(index), key, count, vectors, scalar_kind_to_cpp(kind));
229
293
  }
230
294
 
231
295
  USEARCH_EXPORT size_t usearch_remove(usearch_index_t index, usearch_key_t key, usearch_error_t* error) {
@@ -253,7 +317,7 @@ USEARCH_EXPORT usearch_distance_t usearch_distance( //
253
317
  usearch_metric_kind_t metric_kind, usearch_error_t* error) {
254
318
 
255
319
  (void)error;
256
- metric_punned_t metric(dimensions, to_native_metric(metric_kind), to_native_scalar(scalar_kind));
320
+ metric_punned_t metric(dimensions, metric_kind_to_cpp(metric_kind), scalar_kind_to_cpp(scalar_kind));
257
321
  return metric((byte_t const*)vector_first, (byte_t const*)vector_second);
258
322
  }
259
323
 
@@ -266,7 +330,7 @@ USEARCH_EXPORT void usearch_exact_search( //
266
330
  usearch_distance_t* distances, size_t distances_stride, //
267
331
  usearch_error_t* error) {
268
332
 
269
- metric_punned_t metric(dimensions, to_native_metric(metric_kind), to_native_scalar(scalar_kind));
333
+ metric_punned_t metric(dimensions, metric_kind_to_cpp(metric_kind), scalar_kind_to_cpp(scalar_kind));
270
334
  executor_default_t executor(threads);
271
335
  static exact_search_t search;
272
336
  exact_search_results_t result = search( //
package/c/usearch.h CHANGED
@@ -14,7 +14,8 @@ extern "C" {
14
14
  #endif
15
15
 
16
16
  #include <stdbool.h> // `bool`
17
- #include <stdint.h> // `size_t`
17
+ #include <stddef.h> // `size_t`
18
+ #include <stdint.h> // `uint64_t`
18
19
 
19
20
  USEARCH_EXPORT typedef void* usearch_index_t;
20
21
  USEARCH_EXPORT typedef uint64_t usearch_key_t;
@@ -42,6 +43,7 @@ USEARCH_EXPORT typedef enum usearch_metric_kind_t {
42
43
  usearch_metric_ip_k,
43
44
  usearch_metric_l2sq_k,
44
45
  usearch_metric_haversine_k,
46
+ usearch_metric_divergence_k,
45
47
  usearch_metric_pearson_k,
46
48
  usearch_metric_jaccard_k,
47
49
  usearch_metric_hamming_k,
@@ -136,6 +138,15 @@ USEARCH_EXPORT void usearch_load(usearch_index_t, char const* path, usearch_erro
136
138
  */
137
139
  USEARCH_EXPORT void usearch_view(usearch_index_t, char const* path, usearch_error_t* error);
138
140
 
141
+ /**
142
+ * @brief Loads index metadata from a file.
143
+ * @param[in] path The file path from where the index will be loaded.
144
+ * @param[out] options Pointer to the `usearch_init_options_t` structure to be populated.
145
+ * @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
146
+ * @return A handle to the initialized USearch index, or `NULL` on failure.
147
+ */
148
+ USEARCH_EXPORT void usearch_metadata(char const* path, usearch_init_options_t* options, usearch_error_t* error);
149
+
139
150
  /**
140
151
  * @brief Saves the index to an in-memory buffer.
141
152
  * @param[in] buffer The in-memory continuous buffer where the index will be saved.
@@ -157,6 +168,16 @@ USEARCH_EXPORT void usearch_load_buffer(usearch_index_t, void const* buffer, siz
157
168
  */
158
169
  USEARCH_EXPORT void usearch_view_buffer(usearch_index_t, void const* buffer, size_t length, usearch_error_t* error);
159
170
 
171
+ /**
172
+ * @brief Loads index metadata from an in-memory buffer.
173
+ * @param[in] path The file path from where the index will be loaded.
174
+ * @param[out] options Pointer to the `usearch_init_options_t` structure to be populated.
175
+ * @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
176
+ * @return A handle to the initialized USearch index, or `NULL` on failure.
177
+ */
178
+ USEARCH_EXPORT void usearch_metadata_buffer(void const* buffer, size_t length, usearch_init_options_t* options,
179
+ usearch_error_t* error);
180
+
160
181
  USEARCH_EXPORT size_t usearch_size(usearch_index_t, usearch_error_t* error);
161
182
  USEARCH_EXPORT size_t usearch_capacity(usearch_index_t, usearch_error_t* error);
162
183
  USEARCH_EXPORT size_t usearch_dimensions(usearch_index_t, usearch_error_t* error);
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.7.7'
10
+ version = '2.8.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"
package/cpp/README.md CHANGED
@@ -21,7 +21,7 @@ using namespace unum::usearch;
21
21
  metric_punned_t metric(256, metric_kind_t::l2sq_k, scalar_kind_t::f32_k);
22
22
 
23
23
  // If you plan to store more than 4 Billion entries - use `index_dense_big_t`.
24
- // Or directly instantiate the template variant you need - `index_dense_gt<key_t, internal_id_t>`.
24
+ // Or directly instantiate the template variant you need - `index_dense_gt<vector_key_t, internal_id_t>`.
25
25
  index_dense_t index = index_dense_t::make(metric);
26
26
  float vec[3] = {0.1, 0.3, 0.2};
27
27
 
@@ -76,6 +76,7 @@ The following distances are pre-packaged:
76
76
  - `metric_sorensen_gt<scalar_t>` for "Dice-Sorensen" coefficient for bit-strings.
77
77
  - `metric_pearson_gt<scalar_t>` for "Pearson" correlation between probability distributions.
78
78
  - `metric_haversine_gt<scalar_t>` for "Haversine" or "Great Circle" distance between coordinates used in GIS applications.
79
+ - `metric_divergence_gt<scalar_t>` for the "Jensen Shannon" similarity between probability distributions.
79
80
 
80
81
  ## Multi-Threading
81
82
 
package/cpp/bench.cpp CHANGED
@@ -447,6 +447,7 @@ struct args_t {
447
447
  bool metric_l2 = false;
448
448
  bool metric_cos = false;
449
449
  bool metric_haversine = false;
450
+ bool metric_divergence = false;
450
451
  bool metric_hamming = false;
451
452
  bool metric_tanimoto = false;
452
453
  bool metric_sorensen = false;
@@ -458,6 +459,8 @@ struct args_t {
458
459
  return metric_kind_t::cos_k;
459
460
  if (metric_haversine)
460
461
  return metric_kind_t::haversine_k;
462
+ if (metric_divergence)
463
+ return metric_kind_t::divergence_k;
461
464
  if (metric_hamming)
462
465
  return metric_kind_t::hamming_k;
463
466
  if (metric_tanimoto)
package/cpp/test.cpp CHANGED
@@ -25,15 +25,15 @@ void test_cosine(index_at& index, std::vector<std::vector<scalar_at>> const& vec
25
25
 
26
26
  using scalar_t = scalar_at;
27
27
  using index_t = index_at;
28
- using key_t = typename index_t::key_t;
28
+ using vector_key_t = typename index_t::vector_key_t;
29
29
  using distance_t = typename index_t::distance_t;
30
30
 
31
31
  // Generate some keys starting from end,
32
32
  // for three vectors from the dataset
33
- key_t const key_max = default_free_value<key_t>() - 1;
34
- key_t const key_first = key_max - 0;
35
- key_t const key_second = key_max - 1;
36
- key_t const key_third = key_max - 2;
33
+ vector_key_t const key_max = default_free_value<vector_key_t>() - 1;
34
+ vector_key_t const key_first = key_max - 0;
35
+ vector_key_t const key_second = key_max - 1;
36
+ vector_key_t const key_third = key_max - 2;
37
37
  scalar_t const* vector_first = vectors[0].data();
38
38
  scalar_t const* vector_second = vectors[1].data();
39
39
  scalar_t const* vector_third = vectors[2].data();
@@ -50,7 +50,7 @@ void test_cosine(index_at& index, std::vector<std::vector<scalar_at>> const& vec
50
50
  index.add(key_first, vector_first, args...);
51
51
 
52
52
  // Default approximate search
53
- key_t matched_keys[10] = {0};
53
+ vector_key_t matched_keys[10] = {0};
54
54
  distance_t matched_distances[10] = {0};
55
55
  std::size_t matched_count = index.search(vector_first, 5, args...).dump_to(matched_keys, matched_distances);
56
56
 
@@ -69,7 +69,7 @@ void test_cosine(index_at& index, std::vector<std::vector<scalar_at>> const& vec
69
69
  // Validate scans
70
70
  std::size_t count = 0;
71
71
  for (auto member : index) {
72
- key_t id = member.key;
72
+ vector_key_t id = member.key;
73
73
  expect(id <= key_first && id >= key_third);
74
74
  count++;
75
75
  }
@@ -159,10 +159,10 @@ template <typename scalar_at, typename key_at, typename slot_at> //
159
159
  void test_cosine(std::size_t collection_size, std::size_t dimensions) {
160
160
 
161
161
  using scalar_t = scalar_at;
162
- using key_t = key_at;
162
+ using vector_key_t = key_at;
163
163
  using slot_t = slot_at;
164
164
 
165
- using index_typed_t = index_gt<float, key_t, slot_t>;
165
+ using index_typed_t = index_gt<float, vector_key_t, slot_t>;
166
166
  using member_cref_t = typename index_typed_t::member_cref_t;
167
167
  using member_citerator_t = typename index_typed_t::member_citerator_t;
168
168
 
@@ -205,7 +205,7 @@ void test_cosine(std::size_t collection_size, std::size_t dimensions) {
205
205
  for (bool multi : {false, true}) {
206
206
  for (std::size_t connectivity : {3, 13, 50}) {
207
207
  std::printf("- punned with connectivity %zu \n", connectivity);
208
- using index_t = index_dense_gt<key_t, slot_t>;
208
+ using index_t = index_dense_gt<vector_key_t, slot_t>;
209
209
  metric_punned_t metric(dimensions, metric_kind_t::cos_k, scalar_kind<scalar_at>());
210
210
  index_dense_config_t config(connectivity);
211
211
  config.multi = multi;
@@ -217,10 +217,10 @@ void test_cosine(std::size_t collection_size, std::size_t dimensions) {
217
217
 
218
218
  template <typename key_at, typename slot_at> void test_tanimoto(std::size_t dimensions, std::size_t connectivity) {
219
219
 
220
- using key_t = key_at;
220
+ using vector_key_t = key_at;
221
221
  using slot_t = slot_at;
222
222
 
223
- using index_punned_t = index_dense_gt<key_t, slot_t>;
223
+ using index_punned_t = index_dense_gt<vector_key_t, slot_t>;
224
224
  std::size_t words = divide_round_up<CHAR_BIT>(dimensions);
225
225
  metric_punned_t metric(words, metric_kind_t::tanimoto_k, scalar_kind_t::b1x8_k);
226
226
  index_config_t config(connectivity);
@@ -1,7 +1,7 @@
1
1
  <?xml version="1.0" encoding="utf-8"?>
2
2
  <Project>
3
3
  <PropertyGroup>
4
- <Version Condition="'$(Version)' == ''">2.7.7</Version>
4
+ <Version Condition="'$(Version)' == ''">2.8.0</Version>
5
5
 
6
6
  <Authors>Unum</Authors>
7
7
  <Company>Unum</Company>
@@ -23,6 +23,7 @@ cmake -B ./build_release \
23
23
  -DUSEARCH_BUILD_BENCH_CPP=1 \
24
24
  -DUSEARCH_BUILD_LIB_C=1 \
25
25
  -DUSEARCH_BUILD_TEST_C=1 \
26
+ -DUSEARCH_USE_NATIVE_F16=1 \
26
27
  && \
27
28
  make -C ./build_release -j
28
29
  ```
@@ -157,18 +158,6 @@ swift test -v
157
158
  There are a few ways to compile the C 99 USearch SDK.
158
159
  Using the Makefile, specifying the targets you need:
159
160
 
160
- ```sh
161
- make -C ./c libusearch_c.so
162
- ```
163
-
164
- With options:
165
-
166
- ```sh
167
- make USEARCH_USE_OPENMP=1 USEARCH_USE_SIMSIMD=1 -C ./c libusearch_c.so
168
- ```
169
-
170
- Using CMake:
171
-
172
161
  ```sh
173
162
  cmake -B ./build_release -DUSEARCH_BUILD_LIB_C=1 -DUSEARCH_BUILD_TEST_C=1 -DUSEARCH_USE_OPENMP=1 -DUSEARCH_USE_SIMSIMD=1
174
163
  cmake --build ./build_release --config Release -j
@@ -183,7 +172,10 @@ GoLang bindings are based on C.
183
172
  So one should first compile the C library, link it with GoLang, and only then run tests.
184
173
 
185
174
  ```sh
186
- make -C ./c libusearch_c.so && mv ./c/libusearch_c.so ./golang/ && cp ./c/usearch.h ./golang/
175
+ cmake -B ./build_release -DUSEARCH_BUILD_LIB_C=1 -DUSEARCH_BUILD_TEST_C=1 -DUSEARCH_USE_OPENMP=1 -DUSEARCH_USE_SIMSIMD=1
176
+ cmake --build ./build_release --config Release -j
177
+ mv ./c/libusearch_c.so ./golang/
178
+ cp ./c/usearch.h ./golang/
187
179
  cd golang && go test -v ; cd ..
188
180
  ```
189
181
 
package/golang/lib.go CHANGED
@@ -6,7 +6,7 @@ import (
6
6
  )
7
7
 
8
8
  /*
9
- #cgo LDFLAGS: -L. -lusearch_c
9
+ #cgo LDFLAGS: -L. -L/usr/local/lib -lusearch_c
10
10
  #include "usearch.h"
11
11
  #include <stdlib.h>
12
12
  */
@@ -21,6 +21,7 @@ const (
21
21
  Cosine
22
22
  L2sq
23
23
  Haversine
24
+ Divergence
24
25
  Pearson
25
26
  Hamming
26
27
  Tanimoto
@@ -37,6 +38,8 @@ func (m Metric) String() string {
37
38
  return "cos"
38
39
  case Haversine:
39
40
  return "haversine"
41
+ case Divergence:
42
+ return "divergence"
40
43
  case Pearson:
41
44
  return "pearson"
42
45
  case Hamming: