usearch 2.7.6 → 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 +4 -1
  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 +91 -24
  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 +6 -6
  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
@@ -44,10 +44,22 @@
44
44
  // Propagate the `f16` settings
45
45
  #define SIMSIMD_NATIVE_F16 USEARCH_USE_NATIVE_F16
46
46
  #if defined(USEARCH_DEFINED_LINUX)
47
+ #define SIMSIMD_TARGET_X86_AVX512 1
48
+ #define SIMSIMD_TARGET_ARM_SVE 1
49
+ #define SIMSIMD_TARGET_X86_AVX2 1
50
+ #define SIMSIMD_TARGET_ARM_NEON 1
47
51
  #include <simsimd/simsimd.h>
48
52
  #elif defined(USEARCH_DEFINED_APPLE)
49
53
  #define SIMSIMD_TARGET_X86_AVX512 0
50
54
  #define SIMSIMD_TARGET_ARM_SVE 0
55
+ #define SIMSIMD_TARGET_X86_AVX2 1
56
+ #define SIMSIMD_TARGET_ARM_NEON 1
57
+ #include <simsimd/simsimd.h>
58
+ #else
59
+ #define SIMSIMD_TARGET_X86_AVX512 0
60
+ #define SIMSIMD_TARGET_ARM_SVE 0
61
+ #define SIMSIMD_TARGET_X86_AVX2 0
62
+ #define SIMSIMD_TARGET_ARM_NEON 0
51
63
  #include <simsimd/simsimd.h>
52
64
  #endif
53
65
  #endif
@@ -100,6 +112,7 @@ enum class metric_kind_t : std::uint8_t {
100
112
  // Custom:
101
113
  pearson_k = 'p',
102
114
  haversine_k = 'h',
115
+ divergence_k = 'd',
103
116
 
104
117
  // Sets:
105
118
  jaccard_k = 'j',
@@ -186,20 +199,6 @@ inline bool str_equals(char const* begin, std::size_t len, char const* other_beg
186
199
  return len == other_len && std::strncmp(begin, other_begin, len) == 0;
187
200
  }
188
201
 
189
- inline char const* isa_name(simsimd_capability_t isa_kind) noexcept {
190
- switch (isa_kind) {
191
- case simsimd_cap_serial_k: return "serial";
192
- case simsimd_cap_arm_neon_k: return "neon";
193
- case simsimd_cap_arm_sve_k: return "sve";
194
- case simsimd_cap_x86_avx2_k: return "avx2";
195
- case simsimd_cap_x86_avx512_k: return "avx512";
196
- case simsimd_cap_x86_avx2fp16_k: return "avx2+f16";
197
- case simsimd_cap_x86_avx512fp16_k: return "avx512+f16";
198
- case simsimd_cap_x86_avx512vpopcntdq_k: return "avx512+popcnt";
199
- default: return "unknown";
200
- }
201
- }
202
-
203
202
  inline std::size_t bits_per_scalar(scalar_kind_t scalar_kind) noexcept {
204
203
  switch (scalar_kind) {
205
204
  case scalar_kind_t::f64_k: return 64;
@@ -241,6 +240,7 @@ inline char const* metric_kind_name(metric_kind_t metric) noexcept {
241
240
  case metric_kind_t::l2sq_k: return "l2sq";
242
241
  case metric_kind_t::pearson_k: return "pearson";
243
242
  case metric_kind_t::haversine_k: return "haversine";
243
+ case metric_kind_t::divergence_k: return "divergence";
244
244
  case metric_kind_t::jaccard_k: return "jaccard";
245
245
  case metric_kind_t::hamming_k: return "hamming";
246
246
  case metric_kind_t::tanimoto_k: return "tanimoto";
@@ -277,6 +277,8 @@ inline expected_gt<metric_kind_t> metric_from_name(char const* name, std::size_t
277
277
  parsed.result = metric_kind_t::cos_k;
278
278
  } else if (str_equals(name, len, "haversine")) {
279
279
  parsed.result = metric_kind_t::haversine_k;
280
+ } else if (str_equals(name, len, "divergence")) {
281
+ parsed.result = metric_kind_t::divergence_k;
280
282
  } else if (str_equals(name, len, "pearson")) {
281
283
  parsed.result = metric_kind_t::pearson_k;
282
284
  } else if (str_equals(name, len, "hamming")) {
@@ -286,8 +288,8 @@ inline expected_gt<metric_kind_t> metric_from_name(char const* name, std::size_t
286
288
  } else if (str_equals(name, len, "sorensen")) {
287
289
  parsed.result = metric_kind_t::sorensen_k;
288
290
  } else
289
- parsed.failed(
290
- "Unknown distance, choose: l2sq, ip, cos, haversine, jaccard, pearson, hamming, tanimoto, sorensen");
291
+ parsed.failed("Unknown distance, choose: l2sq, ip, cos, haversine, divergence, jaccard, pearson, hamming, "
292
+ "tanimoto, sorensen");
291
293
  return parsed;
292
294
  }
293
295
 
@@ -570,7 +572,9 @@ class aligned_allocator_gt {
570
572
  using size_type = std::size_t;
571
573
  using pointer = element_at*;
572
574
  using const_pointer = element_at const*;
573
- template <typename other_element_at> struct rebind { using other = aligned_allocator_gt<other_element_at>; };
575
+ template <typename other_element_at> struct rebind {
576
+ using other = aligned_allocator_gt<other_element_at>;
577
+ };
574
578
 
575
579
  constexpr std::size_t alignment() const { return alignment_ak; }
576
580
 
@@ -1180,6 +1184,32 @@ template <typename scalar_at = float, typename result_at = float> struct metric_
1180
1184
  }
1181
1185
  };
1182
1186
 
1187
+ /**
1188
+ * @brief Measures Jensen-Shannon Divergence between two probability distributions.
1189
+ */
1190
+ template <typename scalar_at = float, typename result_at = float> struct metric_divergence_gt {
1191
+ using scalar_t = scalar_at;
1192
+ using result_t = result_at;
1193
+
1194
+ inline result_t operator()(scalar_t const* p, scalar_t const* q, std::size_t dim) const noexcept {
1195
+ result_t kld_pm{}, kld_qm{};
1196
+ scalar_t epsilon = std::numeric_limits<scalar_t>::epsilon();
1197
+ #if USEARCH_USE_OPENMP
1198
+ #pragma omp simd reduction(+ : kld_pm, kld_qm)
1199
+ #elif defined(USEARCH_DEFINED_CLANG)
1200
+ #pragma clang loop vectorize(enable)
1201
+ #elif defined(USEARCH_DEFINED_GCC)
1202
+ #pragma GCC ivdep
1203
+ #endif
1204
+ for (std::size_t i = 0; i != dim; ++i) {
1205
+ result_t mi = result_t(p[i] + q[i]) / 2 + epsilon;
1206
+ kld_pm += p[i] * std::log((p[i] + epsilon) / mi);
1207
+ kld_qm += q[i] * std::log((q[i] + epsilon) / mi);
1208
+ }
1209
+ return (kld_pm + kld_qm) / 2;
1210
+ }
1211
+ };
1212
+
1183
1213
  struct cos_i8_t {
1184
1214
  using scalar_t = i8_t;
1185
1215
  using result_t = f32_t;
@@ -1283,7 +1313,10 @@ class metric_punned_t {
1283
1313
  std::size_t dimensions_ = 0;
1284
1314
  metric_kind_t metric_kind_ = metric_kind_t::unknown_k;
1285
1315
  scalar_kind_t scalar_kind_ = scalar_kind_t::unknown_k;
1316
+
1317
+ #if USEARCH_USE_SIMSIMD
1286
1318
  simsimd_capability_t isa_kind_ = simsimd_cap_serial_k;
1319
+ #endif
1287
1320
 
1288
1321
  public:
1289
1322
  /**
@@ -1303,7 +1336,7 @@ class metric_punned_t {
1303
1336
  metric_kind_t metric_kind = metric_kind_t::l2sq_k, //
1304
1337
  scalar_kind_t scalar_kind = scalar_kind_t::f32_k) noexcept
1305
1338
  : raw_arg3_(dimensions), raw_arg4_(dimensions), dimensions_(dimensions), metric_kind_(metric_kind),
1306
- scalar_kind_(scalar_kind), isa_kind_(simsimd_cap_serial_k) {
1339
+ scalar_kind_(scalar_kind) {
1307
1340
 
1308
1341
  #if USEARCH_USE_SIMSIMD
1309
1342
  if (configure_with_simsimd())
@@ -1328,7 +1361,23 @@ class metric_punned_t {
1328
1361
  inline std::size_t dimensions() const noexcept { return dimensions_; }
1329
1362
  inline metric_kind_t metric_kind() const noexcept { return metric_kind_; }
1330
1363
  inline scalar_kind_t scalar_kind() const noexcept { return scalar_kind_; }
1331
- inline simsimd_capability_t isa_kind() const noexcept { return isa_kind_; }
1364
+
1365
+ inline char const* isa_name() const noexcept {
1366
+ #if USEARCH_USE_SIMSIMD
1367
+ switch (isa_kind_) {
1368
+ case simsimd_cap_serial_k: return "serial";
1369
+ case simsimd_cap_arm_neon_k: return "neon";
1370
+ case simsimd_cap_arm_sve_k: return "sve";
1371
+ case simsimd_cap_x86_avx2_k: return "avx2";
1372
+ case simsimd_cap_x86_avx512_k: return "avx512";
1373
+ case simsimd_cap_x86_avx2fp16_k: return "avx2+f16";
1374
+ case simsimd_cap_x86_avx512fp16_k: return "avx512+f16";
1375
+ case simsimd_cap_x86_avx512vpopcntdq_k: return "avx512+popcnt";
1376
+ default: return "unknown";
1377
+ }
1378
+ #endif
1379
+ return "serial";
1380
+ }
1332
1381
 
1333
1382
  inline std::size_t bytes_per_vector() const noexcept {
1334
1383
  return divide_round_up<CHAR_BIT>(dimensions_ * bits_per_scalar(scalar_kind_));
@@ -1339,8 +1388,8 @@ class metric_punned_t {
1339
1388
  }
1340
1389
 
1341
1390
  private:
1342
- bool configure_with_simsimd() noexcept {
1343
1391
  #if USEARCH_USE_SIMSIMD
1392
+ bool configure_with_simsimd(simsimd_capability_t simd_caps) noexcept {
1344
1393
  simsimd_metric_kind_t kind = simsimd_metric_unknown_k;
1345
1394
  simsimd_datatype_t datatype = simsimd_datatype_unknown_k;
1346
1395
  simsimd_capability_t allowed = simsimd_cap_any_k;
@@ -1350,6 +1399,7 @@ class metric_punned_t {
1350
1399
  case metric_kind_t::l2sq_k: kind = simsimd_metric_l2sq_k; break;
1351
1400
  case metric_kind_t::hamming_k: kind = simsimd_metric_hamming_k; break;
1352
1401
  case metric_kind_t::jaccard_k: kind = simsimd_metric_jaccard_k; break;
1402
+ default: break;
1353
1403
  }
1354
1404
  switch (scalar_kind_) {
1355
1405
  case scalar_kind_t::f32_k: datatype = simsimd_datatype_f32_k; break;
@@ -1357,20 +1407,25 @@ class metric_punned_t {
1357
1407
  case scalar_kind_t::f16_k: datatype = simsimd_datatype_f16_k; break;
1358
1408
  case scalar_kind_t::i8_k: datatype = simsimd_datatype_i8_k; break;
1359
1409
  case scalar_kind_t::b1x8_k: datatype = simsimd_datatype_b8_k; break;
1410
+ default: break;
1360
1411
  }
1361
1412
  simsimd_metric_punned_t simd_metric = NULL;
1362
1413
  simsimd_capability_t simd_kind = simsimd_cap_any_k;
1363
- simsimd_find_metric_punned(kind, datatype, simsimd_capabilities(), allowed, &simd_metric, &simd_kind);
1414
+ simsimd_find_metric_punned(kind, datatype, simd_caps, allowed, &simd_metric, &simd_kind);
1364
1415
  if (simd_metric == nullptr)
1365
1416
  return false;
1366
1417
 
1367
1418
  raw_ptr_ = (punned_ptr_t)simd_metric;
1368
1419
  isa_kind_ = simd_kind;
1369
1420
  return true;
1421
+ }
1422
+ bool configure_with_simsimd() noexcept {
1423
+ static simsimd_capability_t static_capabilities = simsimd_capabilities();
1424
+ return configure_with_simsimd(static_capabilities);
1425
+ }
1370
1426
  #else
1371
- return false;
1427
+ bool configure_with_simsimd() noexcept { return false; }
1372
1428
  #endif
1373
- }
1374
1429
 
1375
1430
  void configure_with_auto_vectorized() noexcept {
1376
1431
  switch (metric_kind_) {
@@ -1427,6 +1482,17 @@ class metric_punned_t {
1427
1482
  }
1428
1483
  break;
1429
1484
  }
1485
+ case metric_kind_t::divergence_k: {
1486
+ switch (scalar_kind_) {
1487
+ case scalar_kind_t::f16_k:
1488
+ raw_ptr_ = (punned_ptr_t)&equidimensional_<metric_divergence_gt<f16_t, f32_t>>;
1489
+ break;
1490
+ case scalar_kind_t::f32_k: raw_ptr_ = (punned_ptr_t)&equidimensional_<metric_divergence_gt<f32_t>>; break;
1491
+ case scalar_kind_t::f64_k: raw_ptr_ = (punned_ptr_t)&equidimensional_<metric_divergence_gt<f64_t>>; break;
1492
+ default: raw_ptr_ = nullptr; break;
1493
+ }
1494
+ break;
1495
+ }
1430
1496
  case metric_kind_t::jaccard_k: // Equivalent to Tanimoto
1431
1497
  case metric_kind_t::tanimoto_k:
1432
1498
  raw_ptr_ = (punned_ptr_t)&equidimensional_<metric_tanimoto_gt<b1x8_t>>,
@@ -2113,7 +2179,8 @@ class flat_hash_multi_set_gt {
2113
2179
  slot_ref_t slot = slot_ref(slot_index);
2114
2180
  if ((~slot.header.populated & slot.mask) | (slot.header.deleted & slot.mask)) {
2115
2181
  // Found an empty or deleted slot
2116
- populated_slots_ += populate_slot(slot, element);
2182
+ populate_slot(slot, element);
2183
+ ++populated_slots_;
2117
2184
  return true;
2118
2185
  }
2119
2186
  // Move to the next slot
@@ -1,83 +1,170 @@
1
1
  package cloud.unum.usearch;
2
2
 
3
3
  import java.io.File;
4
+ import java.io.InputStream;
4
5
  import java.nio.file.Files;
5
6
  import java.nio.file.StandardCopyOption;
6
- import java.io.InputStream;
7
7
 
8
8
  /**
9
- * @brief Java bindings for Unum USearch.
10
- *
11
- * @see Tutorials:
12
- * https://nachtimwald.com/2017/06/06/wrapping-a-c-library-in-java/
13
- * https://www3.ntu.edu.sg/home/ehchua/programming/java/javanativeinterface.html
9
+ * Java bindings for Unum USearch.
10
+ * <p>
11
+ * Provides interface to interact with USearch library and perform various operations related to indexing and searching.
12
+ *
13
+ * @see <a href="https://nachtimwald.com/2017/06/06/wrapping-a-c-library-in-java/">Wrapping a C library in Java</a>
14
+ * @see <a href="https://www3.ntu.edu.sg/home/ehchua/programming/java/javanativeinterface.html">Java Native Interface tutorial</a>
14
15
  */
15
16
  public class Index {
16
17
 
17
18
  private long c_ptr = 0;
18
19
 
19
- public Index(String metric, String quantization, //
20
- long dimensions, long capacity, long connectivity, //
21
- long expansion_add, long expansion_search) {
22
- c_ptr = c_create(
20
+ /**
21
+ * Creates a new instance of Index with specified parameters.
22
+ *
23
+ * @param metric the metric type for distance calculation between vectors
24
+ * @param quantization the scalar type for quantization of vector data
25
+ * @param dimensions the number of dimensions in the vectors
26
+ * @param capacity the initial capacity of the index
27
+ * @param connectivity the connectivity parameter that limits connections-per-node in graph
28
+ * @param expansion_add the expansion factor used for index construction when adding vectors
29
+ * @param expansion_search the expansion factor used for index construction during search operations
30
+ */
31
+ public Index(
32
+ String metric,
33
+ String quantization, //
34
+ long dimensions,
35
+ long capacity,
36
+ long connectivity, //
37
+ long expansion_add,
38
+ long expansion_search
39
+ ) {
40
+ c_ptr =
41
+ c_create(
23
42
  metric,
24
43
  quantization,
25
44
  dimensions,
26
45
  capacity,
27
46
  connectivity,
28
47
  expansion_add,
29
- expansion_search);
48
+ expansion_search
49
+ );
30
50
  }
31
51
 
52
+ /**
53
+ * Retrieves the current size of the index.
54
+ *
55
+ * @return the number of vectors currently indexed.
56
+ */
32
57
  public long size() {
33
58
  return c_size(c_ptr);
34
59
  }
35
60
 
61
+ /**
62
+ * Retrieves the connectivity parameter of the index.
63
+ *
64
+ * @return the connectivity parameter that limits connections-per-node in graph.
65
+ */
36
66
  public long connectivity() {
37
67
  return c_connectivity(c_ptr);
38
68
  }
39
69
 
70
+ /**
71
+ * Retrieves the number of dimensions of the vectors in the index.
72
+ *
73
+ * @return the number of dimensions in the vectors.
74
+ */
40
75
  public long dimensions() {
41
76
  return c_dimensions(c_ptr);
42
77
  }
43
78
 
79
+ /**
80
+ * Retrieves the current capacity of the index.
81
+ *
82
+ * @return the total capacity including current size.
83
+ */
44
84
  public long capacity() {
45
85
  return c_capacity(c_ptr);
46
86
  }
47
87
 
88
+ /**
89
+ * Reserves memory for a specified number of incoming vectors.
90
+ *
91
+ * @param capacity the desired total capacity including current size.
92
+ */
48
93
  public void reserve(long capacity) {
49
94
  c_reserve(c_ptr, capacity);
50
95
  }
51
96
 
97
+ /**
98
+ * Adds a vector with a specified key to the index.
99
+ *
100
+ * @param key the key associated with the vector
101
+ * @param vector the vector data
102
+ */
52
103
  public void add(int key, float vector[]) {
53
104
  c_add(c_ptr, key, vector);
54
105
  }
55
106
 
107
+ /**
108
+ * Searches for closest vectors to the specified query vector.
109
+ *
110
+ * @param vector the query vector data
111
+ * @param count the number of nearest neighbors to search
112
+ * @return an array of keys of the nearest neighbors
113
+ */
56
114
  public int[] search(float vector[], long count) {
57
115
  return c_search(c_ptr, vector, count);
58
116
  }
59
117
 
118
+ /**
119
+ * Saves the index to a file.
120
+ *
121
+ * @param path the file path where the index will be saved.
122
+ */
60
123
  public void save(String path) {
61
124
  c_save(c_ptr, path);
62
125
  }
63
126
 
127
+ /**
128
+ * Loads the index from a file.
129
+ *
130
+ * @param path the file path from where the index will be loaded.
131
+ */
64
132
  public void load(String path) {
65
133
  c_load(c_ptr, path);
66
134
  }
67
135
 
136
+ /**
137
+ * Creates a view of the index from a file without copying it into memory.
138
+ *
139
+ * @param path the file path from where the view will be created.
140
+ */
68
141
  public void view(String path) {
69
142
  c_view(c_ptr, path);
70
143
  }
71
144
 
145
+ /**
146
+ * Removes the vector associated with the given key from the index.
147
+ *
148
+ * @param key the key of the vector to be removed.
149
+ * @return {@code true} if the vector was successfully removed, {@code false} otherwise.
150
+ */
72
151
  public boolean remove(int key) {
73
152
  return c_remove(c_ptr, key);
74
153
  }
75
-
154
+
155
+ /**
156
+ * Renames the vector to map to a different key.
157
+ *
158
+ * @param from the key of the vector to be renamed.
159
+ * @param to the new key for the vector.
160
+ * @return {@code true} if the vector was successfully renamed, {@code false} otherwise.
161
+ */
76
162
  public boolean rename(int from, int to) {
77
163
  return c_rename(c_ptr, from, to);
78
164
  }
79
165
 
80
166
  public static class Config {
167
+
81
168
  private String _metric = "ip";
82
169
  private String _quantization = "f32";
83
170
  private long _dimensions = 0;
@@ -86,18 +173,18 @@ public class Index {
86
173
  private long _expansion_add = 0;
87
174
  private long _expansion_search = 0;
88
175
 
89
- public Config() {
90
- }
176
+ public Config() {}
91
177
 
92
178
  public Index build() {
93
179
  return new Index(
94
- _metric,
95
- _quantization,
96
- _dimensions,
97
- _capacity,
98
- _connectivity,
99
- _expansion_add,
100
- _expansion_search);
180
+ _metric,
181
+ _quantization,
182
+ _dimensions,
183
+ _capacity,
184
+ _connectivity,
185
+ _expansion_add,
186
+ _expansion_search
187
+ );
101
188
  }
102
189
 
103
190
  public Config metric(String _metric) {
@@ -146,10 +233,15 @@ public class Index {
146
233
  System.out.println("Java tests passed!");
147
234
  }
148
235
 
149
- private static native long c_create(//
150
- String metric, String quantization, //
151
- long dimensions, long capacity, long connectivity, //
152
- long expansion_add, long expansion_search);
236
+ private static native long c_create( //
237
+ String metric,
238
+ String quantization, //
239
+ long dimensions,
240
+ long capacity,
241
+ long connectivity, //
242
+ long expansion_add,
243
+ long expansion_search
244
+ );
153
245
 
154
246
  private static native void c_destroy(long ptr);
155
247
 
@@ -176,4 +268,4 @@ public class Index {
176
268
  private static native boolean c_remove(long ptr, int key);
177
269
 
178
270
  private static native boolean c_rename(long ptr, int from, int to);
179
- }
271
+ }
@@ -124,10 +124,10 @@ JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1add( //
124
124
  jsize vector_dims = (*env).GetArrayLength(vector);
125
125
  float_span_t vector_span = float_span_t{vector_data, static_cast<std::size_t>(vector_dims)};
126
126
 
127
- using key_t = typename index_dense_t::key_t;
127
+ using vector_key_t = typename index_dense_t::vector_key_t;
128
128
  using add_result_t = typename index_dense_t::add_result_t;
129
129
 
130
- add_result_t result = reinterpret_cast<index_dense_t*>(c_ptr)->add(static_cast<key_t>(key), vector_span);
130
+ add_result_t result = reinterpret_cast<index_dense_t*>(c_ptr)->add(static_cast<vector_key_t>(key), vector_span);
131
131
  if (!result) {
132
132
  jclass jc = (*env).FindClass("java/lang/Error");
133
133
  if (jc)
@@ -152,13 +152,13 @@ JNIEXPORT jintArray JNICALL Java_cloud_unum_usearch_Index_c_1search( //
152
152
  jsize vector_dims = (*env).GetArrayLength(vector);
153
153
  float_span_t vector_span = float_span_t{vector_data, static_cast<std::size_t>(vector_dims)};
154
154
 
155
- using key_t = typename index_dense_t::key_t;
155
+ using vector_key_t = typename index_dense_t::vector_key_t;
156
156
  using search_result_t = typename index_dense_t::search_result_t;
157
157
 
158
158
  search_result_t result =
159
159
  reinterpret_cast<index_dense_t*>(c_ptr)->search(vector_span, static_cast<std::size_t>(wanted));
160
160
  if (result) {
161
- std::size_t found = result.dump_to(reinterpret_cast<key_t*>(matches_data), NULL);
161
+ std::size_t found = result.dump_to(reinterpret_cast<vector_key_t*>(matches_data), NULL);
162
162
  (*env).SetIntArrayRegion(matches, 0, found, matches_data);
163
163
  } else {
164
164
  jclass jc = (*env).FindClass("java/lang/Error");
@@ -172,9 +172,9 @@ JNIEXPORT jintArray JNICALL Java_cloud_unum_usearch_Index_c_1search( //
172
172
  }
173
173
 
174
174
  JNIEXPORT bool JNICALL Java_cloud_unum_usearch_Index_c_1remove(JNIEnv* env, jclass, jlong c_ptr, jlong key) {
175
- using key_t = typename index_dense_t::key_t;
175
+ using vector_key_t = typename index_dense_t::vector_key_t;
176
176
  using labeling_result_t = typename index_dense_t::labeling_result_t;
177
- labeling_result_t result = reinterpret_cast<index_dense_t*>(c_ptr)->remove(static_cast<key_t>(key));
177
+ labeling_result_t result = reinterpret_cast<index_dense_t*>(c_ptr)->remove(static_cast<vector_key_t>(key));
178
178
  if (!result) {
179
179
  jclass jc = (*env).FindClass("java/lang/Error");
180
180
  if (jc)
@@ -184,10 +184,10 @@ JNIEXPORT bool JNICALL Java_cloud_unum_usearch_Index_c_1remove(JNIEnv* env, jcla
184
184
  }
185
185
 
186
186
  JNIEXPORT bool JNICALL Java_cloud_unum_usearch_Index_c_1rename(JNIEnv* env, jclass, jlong c_ptr, jlong from, jlong to) {
187
- using key_t = typename index_dense_t::key_t;
187
+ using vector_key_t = typename index_dense_t::vector_key_t;
188
188
  using labeling_result_t = typename index_dense_t::labeling_result_t;
189
189
  labeling_result_t result =
190
- reinterpret_cast<index_dense_t*>(c_ptr)->rename(static_cast<key_t>(from), static_cast<key_t>(to));
190
+ reinterpret_cast<index_dense_t*>(c_ptr)->rename(static_cast<vector_key_t>(from), static_cast<vector_key_t>(to));
191
191
  if (!result) {
192
192
  jclass jc = (*env).FindClass("java/lang/Error");
193
193
  if (jc)
@@ -11,6 +11,7 @@ const MetricKind = {
11
11
  IP: 'ip',
12
12
  L2sq: 'l2sq',
13
13
  Haversine: 'haversine',
14
+ Divergence: 'divergence',
14
15
  Pearson: 'pearson',
15
16
  Jaccard: 'jaccard',
16
17
  Hamming: 'hamming',
@@ -14,7 +14,7 @@ using labeling_result_t = typename index_dense_t::labeling_result_t;
14
14
  using search_result_t = typename index_dense_t::search_result_t;
15
15
  using shared_index_dense_t = std::shared_ptr<index_dense_t>;
16
16
 
17
- static_assert(std::is_same<USearchKey, index_dense_t::key_t>::value, "Type mismatch between Objective-C and C++");
17
+ static_assert(std::is_same<USearchKey, index_dense_t::vector_key_t>::value, "Type mismatch between Objective-C and C++");
18
18
 
19
19
  metric_kind_t to_native_metric(USearchMetric m) {
20
20
  switch (m) {
@@ -33,6 +33,9 @@ metric_kind_t to_native_metric(USearchMetric m) {
33
33
  case USearchMetricHaversine:
34
34
  return metric_kind_t::haversine_k;
35
35
 
36
+ case USearchMetricDivergence:
37
+ return metric_kind_t::divergence_k;
38
+
36
39
  case USearchMetricJaccard:
37
40
  return metric_kind_t::jaccard_k;
38
41
 
@@ -19,6 +19,7 @@ typedef NS_ENUM(NSUInteger, USearchMetric) {
19
19
  USearchMetricL2sq,
20
20
  USearchMetricPearson,
21
21
  USearchMetricHaversine,
22
+ USearchMetricDivergence,
22
23
  USearchMetricJaccard,
23
24
  USearchMetricHamming,
24
25
  USearchMetricTanimoto,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "usearch",
3
- "version": "2.7.6",
3
+ "version": "2.8.0",
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",
package/python/lib.cpp CHANGED
@@ -38,7 +38,7 @@ using py_shape_t = py::array::ShapeContainer;
38
38
  using metric_t = metric_punned_t;
39
39
  using distance_t = distance_punned_t;
40
40
 
41
- using dense_key_t = typename index_dense_t::key_t;
41
+ using dense_key_t = typename index_dense_t::vector_key_t;
42
42
  using dense_add_result_t = typename index_dense_t::add_result_t;
43
43
  using dense_search_result_t = typename index_dense_t::search_result_t;
44
44
  using dense_labeling_result_t = typename index_dense_t::labeling_result_t;
@@ -48,7 +48,7 @@ using dense_clustering_result_t = typename index_dense_t::clustering_result_t;
48
48
  using progress_func_t = std::function<bool(std::size_t /*processed*/, std::size_t /*total*/)>;
49
49
 
50
50
  struct progress_t {
51
- inline progress_t(nullptr_t = nullptr) : func_(&dummy_progress) {}
51
+ inline progress_t(std::nullptr_t = nullptr) : func_(&dummy_progress) {}
52
52
  inline progress_t(progress_func_t const& func) : func_(func ? func : &dummy_progress) {}
53
53
  inline bool operator()(std::size_t processed, std::size_t total) const noexcept { return func_(processed, total); }
54
54
 
@@ -864,6 +864,7 @@ PYBIND11_MODULE(compiled, m) {
864
864
  .value("L2sq", metric_kind_t::l2sq_k)
865
865
 
866
866
  .value("Haversine", metric_kind_t::haversine_k)
867
+ .value("Divergence", metric_kind_t::divergence_k)
867
868
  .value("Pearson", metric_kind_t::pearson_k)
868
869
  .value("Jaccard", metric_kind_t::jaccard_k)
869
870
  .value("Hamming", metric_kind_t::hamming_k)
@@ -918,7 +919,7 @@ PYBIND11_MODULE(compiled, m) {
918
919
  m.def(
919
920
  "hardware_acceleration",
920
921
  [](scalar_kind_t scalar_kind, std::size_t dimensions, metric_kind_t metric_kind) -> py::str {
921
- return isa_name(metric_t(dimensions, metric_kind, scalar_kind).isa_kind());
922
+ return metric_t(dimensions, metric_kind, scalar_kind).isa_name();
922
923
  },
923
924
  py::kw_only(), //
924
925
  py::arg("dtype") = scalar_kind_t::f32_k, //
@@ -1087,9 +1088,8 @@ PYBIND11_MODULE(compiled, m) {
1087
1088
  py::arg("metric_pointer") = 0 //
1088
1089
  );
1089
1090
 
1090
- i.def_property_readonly("hardware_acceleration", [](dense_index_py_t const& index) -> py::str {
1091
- return isa_name(index.metric().isa_kind());
1092
- });
1091
+ i.def_property_readonly("hardware_acceleration",
1092
+ [](dense_index_py_t const& index) -> py::str { return index.metric().isa_name(); });
1093
1093
 
1094
1094
  i.def("contains_one", &dense_index_py_t::contains);
1095
1095
  i.def("count_one", &dense_index_py_t::count);
@@ -11,7 +11,7 @@
11
11
  },
12
12
  {
13
13
  "cell_type": "code",
14
- "execution_count": null,
14
+ "execution_count": 1,
15
15
  "metadata": {},
16
16
  "outputs": [],
17
17
  "source": [
@@ -19,6 +19,28 @@
19
19
  "import plotly.graph_objects as go"
20
20
  ]
21
21
  },
22
+ {
23
+ "cell_type": "code",
24
+ "execution_count": 6,
25
+ "metadata": {},
26
+ "outputs": [
27
+ {
28
+ "data": {
29
+ "text/plain": [
30
+ "('auto', 'auto', 'auto')"
31
+ ]
32
+ },
33
+ "execution_count": 6,
34
+ "metadata": {},
35
+ "output_type": "execute_result"
36
+ }
37
+ ],
38
+ "source": [
39
+ "from usearch.index import Index\n",
40
+ "\n",
41
+ "Index(ndim=256, metric=\"cos\", dtype=\"f32\").hardware_acceleration, Index(ndim=256, metric=\"cos\", dtype=\"f16\").hardware_acceleration, Index(ndim=256, metric=\"cos\", dtype=\"i8\").hardware_acceleration"
42
+ ]
43
+ },
22
44
  {
23
45
  "cell_type": "code",
24
46
  "execution_count": null,
@@ -162,7 +184,7 @@
162
184
  "name": "python",
163
185
  "nbconvert_exporter": "python",
164
186
  "pygments_lexer": "ipython3",
165
- "version": "3.10.11"
187
+ "version": "3.11.5"
166
188
  },
167
189
  "orig_nbformat": 4
168
190
  },