usearch 2.8.3 → 2.8.4

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 (40) hide show
  1. package/.vscode/settings.json +1 -0
  2. package/CITATION.cff +1 -1
  3. package/CONTRIBUTING.md +258 -6
  4. package/Cargo.toml +1 -1
  5. package/README.md +57 -53
  6. package/conanfile.py +1 -1
  7. package/cpp/README.md +89 -21
  8. package/csharp/DEV_SETUP.md +1 -1
  9. package/csharp/nuget/nuget-package.props +1 -1
  10. package/docs/{compilation.rst → contributing.rst} +2 -2
  11. package/docs/index.rst +1 -1
  12. package/include/usearch/index.hpp +1 -1
  13. package/include/usearch/index_dense.hpp +11 -7
  14. package/package.json +1 -1
  15. package/python/README.md +1 -1
  16. package/simsimd/CMakeLists.txt +1 -1
  17. package/simsimd/README.md +7 -1
  18. package/simsimd/include/simsimd/probability.h +24 -24
  19. package/simsimd/include/simsimd/types.h +8 -0
  20. package/simsimd/javascript/{test.js → test/simsimd.test.js} +15 -15
  21. package/simsimd/package.json +4 -8
  22. package/simsimd/setup.py +3 -0
  23. package/wasmer.toml +1 -1
  24. package/docs/compilation.md +0 -215
  25. package/simsimd/.clang-format +0 -10
  26. package/simsimd/.github/workflows/prerelease.yml +0 -89
  27. package/simsimd/.github/workflows/release.yml +0 -141
  28. package/simsimd/.github/workflows/update_version.sh +0 -5
  29. package/simsimd/.vscode/launch.json +0 -53
  30. package/simsimd/.vscode/settings.json +0 -114
  31. package/simsimd/.vscode/tasks.json +0 -23
  32. package/simsimd/go.mod +0 -3
  33. package/simsimd/golang/bench_test.go +0 -40
  34. package/simsimd/golang/simsimd.go +0 -47
  35. package/simsimd/golang/unit_test.go +0 -40
  36. package/simsimd/pyproject.toml +0 -42
  37. package/simsimd/python/bench.ipynb +0 -187
  38. package/simsimd/python/bench.py +0 -268
  39. package/simsimd/python/lib.c +0 -492
  40. package/simsimd/python/test.py +0 -195
@@ -11,7 +11,7 @@ To obtain all libraries, download the artifacts generated by the GitHub workflow
11
11
 
12
12
  To get a library for your current platform (Linux or Macos), execute: `./eng/build_lib.sh`.
13
13
 
14
- For more details, refer to the [compilation guide](https://github.com/unum-cloud/usearch/blob/main/docs/compilation.md).
14
+ For more details, refer to the [compilation guide](https://github.com/unum-cloud/usearch/blob/main/CONTRIBUTING.md).
15
15
 
16
16
  # Build and Test
17
17
 
@@ -1,7 +1,7 @@
1
1
  <?xml version="1.0" encoding="utf-8"?>
2
2
  <Project>
3
3
  <PropertyGroup>
4
- <Version Condition="'$(Version)' == ''">2.8.3</Version>
4
+ <Version Condition="'$(Version)' == ''">2.8.4</Version>
5
5
 
6
6
  <Authors>Unum</Authors>
7
7
  <Company>Unum</Company>
@@ -1,5 +1,5 @@
1
1
  ========================
2
- Compilation
2
+ Contributing
3
3
  ========================
4
4
 
5
- .. mdinclude:: compilation.md
5
+ .. mdinclude:: ../CONTRIBUTING.md
package/docs/index.rst CHANGED
@@ -22,7 +22,7 @@ Overview
22
22
  :hidden:
23
23
  :caption: �
24
24
 
25
- compilation
25
+ contributing
26
26
  benchmarks
27
27
  format
28
28
 
@@ -11,7 +11,7 @@
11
11
 
12
12
  #define USEARCH_VERSION_MAJOR 2
13
13
  #define USEARCH_VERSION_MINOR 8
14
- #define USEARCH_VERSION_PATCH 3
14
+ #define USEARCH_VERSION_PATCH 4
15
15
 
16
16
  // Inferring C++ version
17
17
  // https://stackoverflow.com/a/61552074
@@ -323,7 +323,7 @@ class index_dense_gt {
323
323
  /// @brief Schema: input buffer, bytes in input buffer, output buffer.
324
324
  using cast_t = std::function<bool(byte_t const*, std::size_t, byte_t*)>;
325
325
  /// @brief Punned index.
326
- using index_t = index_gt< //
326
+ using index_t = index_gt< //
327
327
  distance_t, vector_key_t, compressed_slot_t, //
328
328
  dynamic_allocator_t, tape_allocator_t>;
329
329
  using index_allocator_t = aligned_allocator_gt<index_t, 64>;
@@ -1512,10 +1512,14 @@ class index_dense_gt {
1512
1512
  * @brief Implements clustering, classifying the given objects (vectors of member keys)
1513
1513
  * into a given number of clusters.
1514
1514
  *
1515
- * @param[in] queries_begin Iterator targeting the fiest query.
1516
- * @param[in] queries_end
1515
+ * @param[in] queries_begin Iterator pointing to the first query.
1516
+ * @param[in] queries_end Iterator pointing to the last query.
1517
1517
  * @param[in] executor Thread-pool to execute the job in parallel.
1518
1518
  * @param[in] progress Callback to report the execution progress.
1519
+ * @param[in] config Configuration parameters for clustering.
1520
+ *
1521
+ * @param[out] cluster_keys Pointer to the array where the cluster keys will be exported.
1522
+ * @param[out] cluster_distances Pointer to the array where the distances to those centroids will be exported.
1519
1523
  */
1520
1524
  template < //
1521
1525
  typename queries_iterator_at, //
@@ -1526,7 +1530,7 @@ class index_dense_gt {
1526
1530
  queries_iterator_at queries_begin, //
1527
1531
  queries_iterator_at queries_end, //
1528
1532
  index_dense_clustering_config_t config, //
1529
- vector_key_t* cluster_keys, //
1533
+ vector_key_t* cluster_keys, //
1530
1534
  distance_t* cluster_distances, //
1531
1535
  executor_at&& executor = executor_at{}, //
1532
1536
  progress_at&& progress = progress_at{}) {
@@ -1715,7 +1719,7 @@ class index_dense_gt {
1715
1719
  }
1716
1720
 
1717
1721
  template <typename scalar_at>
1718
- add_result_t add_( //
1722
+ add_result_t add_( //
1719
1723
  vector_key_t key, scalar_at const* vector, //
1720
1724
  std::size_t thread, bool force_vector_copy, cast_t const& cast) {
1721
1725
 
@@ -1811,8 +1815,8 @@ class index_dense_gt {
1811
1815
  }
1812
1816
 
1813
1817
  template <typename scalar_at>
1814
- aggregated_distances_t distance_between_( //
1815
- vector_key_t key, scalar_at const* vector, //
1818
+ aggregated_distances_t distance_between_( //
1819
+ vector_key_t key, scalar_at const* vector, //
1816
1820
  std::size_t thread, cast_t const& cast) const {
1817
1821
 
1818
1822
  // Cast the vector, if needed for compatibility with `metric_`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "usearch",
3
- "version": "2.8.3",
3
+ "version": "2.8.4",
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/README.md CHANGED
@@ -10,7 +10,7 @@ pip install usearch
10
10
 
11
11
  ```python
12
12
  import numpy as np
13
- from usearch.index import Index
13
+ from usearch.index import Index, Matches
14
14
 
15
15
  index = Index(
16
16
  ndim=3, # Define the number of dimensions in input vectors
@@ -48,7 +48,7 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "^(Apple)?Clang$")
48
48
  endif()
49
49
  add_compile_options(-pedantic -ferror-limit=1)
50
50
  elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
51
- add_compile_options(-march=native -pedantic -fmax-errors=1)
51
+ add_compile_options(-march=native -pedantic -fmax-errors=1 -Wno-tautological-constant-compare)
52
52
  elseif(CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM")
53
53
  add_compile_options(-w -ferror-limit=1)
54
54
  endif()
package/simsimd/README.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # SimSIMD 📏
2
2
 
3
+ <div>
4
+ <a href="https://pypi.org/project/simsimd/"> <img alt="PyPI - Downloads" src="https://img.shields.io/pypi/dm/simsimd?label=pypi%20downloads"> </a>
5
+ <a href="https://www.npmjs.com/package/simsimd"> <img alt="npm" src="https://img.shields.io/npm/dy/simsimd?label=npm%20dowloads"> </a>
6
+ <img alt="GitHub code size in bytes" src="https://img.shields.io/github/languages/code-size/ashvardanian/simsimd">
7
+ </div>
8
+
3
9
  ## Efficient Alternative to [`scipy.spatial.distance`][scipy] and [`numpy.inner`][numpy]
4
10
 
5
11
  SimSIMD leverages SIMD intrinsics, capabilities that only select compilers effectively utilize. This framework supports conventional AVX2 instructions on x86, NEON on Arm, as well as __rare__ AVX-512 FP16 instructions on x86 and Scalable Vector Extensions (SVE) on Arm. Designed specifically for Machine Learning contexts, it's optimized for handling high-dimensional vector embeddings.
@@ -189,7 +195,7 @@ __To test and benchmark JavaScript bindings__:
189
195
  ```sh
190
196
  npm install --dev
191
197
  npm test
192
- npm bench
198
+ npm run bench
193
199
  ```
194
200
 
195
201
  __To test and benchmark GoLang bindings__:
@@ -52,17 +52,17 @@
52
52
  extern "C" {
53
53
  #endif
54
54
 
55
- SIMSIMD_MAKE_KL(serial, f32, f32, SIMSIMD_IDENTIFY, 1e-6) // simsimd_serial_f32_kl
56
- SIMSIMD_MAKE_JS(serial, f32, f32, SIMSIMD_IDENTIFY, 1e-6) // simsimd_serial_f32_js
55
+ SIMSIMD_MAKE_KL(serial, f32, f32, SIMSIMD_IDENTIFY, SIMSIMD_F32_DIVISION_EPSILON) // simsimd_serial_f32_kl
56
+ SIMSIMD_MAKE_JS(serial, f32, f32, SIMSIMD_IDENTIFY, SIMSIMD_F32_DIVISION_EPSILON) // simsimd_serial_f32_js
57
57
 
58
- SIMSIMD_MAKE_KL(serial, f16, f32, SIMSIMD_UNCOMPRESS_F16, 1e-3) // simsimd_serial_f16_kl
59
- SIMSIMD_MAKE_JS(serial, f16, f32, SIMSIMD_UNCOMPRESS_F16, 1e-3) // simsimd_serial_f16_js
58
+ SIMSIMD_MAKE_KL(serial, f16, f32, SIMSIMD_UNCOMPRESS_F16, SIMSIMD_F32_DIVISION_EPSILON) // simsimd_serial_f16_kl
59
+ SIMSIMD_MAKE_JS(serial, f16, f32, SIMSIMD_UNCOMPRESS_F16, SIMSIMD_F32_DIVISION_EPSILON) // simsimd_serial_f16_js
60
60
 
61
- SIMSIMD_MAKE_KL(accurate, f32, f64, SIMSIMD_IDENTIFY, 1e-6) // simsimd_accurate_f32_kl
62
- SIMSIMD_MAKE_JS(accurate, f32, f64, SIMSIMD_IDENTIFY, 1e-6) // simsimd_accurate_f32_js
61
+ SIMSIMD_MAKE_KL(accurate, f32, f64, SIMSIMD_IDENTIFY, SIMSIMD_F32_DIVISION_EPSILON) // simsimd_accurate_f32_kl
62
+ SIMSIMD_MAKE_JS(accurate, f32, f64, SIMSIMD_IDENTIFY, SIMSIMD_F32_DIVISION_EPSILON) // simsimd_accurate_f32_js
63
63
 
64
- SIMSIMD_MAKE_KL(accurate, f16, f64, SIMSIMD_UNCOMPRESS_F16, 1e-6) // simsimd_accurate_f16_kl
65
- SIMSIMD_MAKE_JS(accurate, f16, f64, SIMSIMD_UNCOMPRESS_F16, 1e-6) // simsimd_accurate_f16_js
64
+ SIMSIMD_MAKE_KL(accurate, f16, f64, SIMSIMD_UNCOMPRESS_F16, SIMSIMD_F32_DIVISION_EPSILON) // simsimd_accurate_f16_kl
65
+ SIMSIMD_MAKE_JS(accurate, f16, f64, SIMSIMD_UNCOMPRESS_F16, SIMSIMD_F32_DIVISION_EPSILON) // simsimd_accurate_f16_js
66
66
 
67
67
  #if SIMSIMD_TARGET_ARM
68
68
  #if SIMSIMD_TARGET_ARM_NEON
@@ -108,7 +108,7 @@ __attribute__((target("+simd"))) //
108
108
  inline static simsimd_f32_t
109
109
  simsimd_neon_f32_kl(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n) {
110
110
  float32x4_t sum_vec = vdupq_n_f32(0);
111
- simsimd_f32_t epsilon = 1e-6;
111
+ simsimd_f32_t epsilon = SIMSIMD_F32_DIVISION_EPSILON;
112
112
  float32x4_t epsilon_vec = vdupq_n_f32(epsilon);
113
113
  simsimd_size_t i = 0;
114
114
  for (; i + 4 <= n; i += 4) {
@@ -129,7 +129,7 @@ simsimd_neon_f32_kl(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size
129
129
  __attribute__((target("+simd"))) inline static simsimd_f32_t
130
130
  simsimd_neon_f32_js(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n) {
131
131
  float32x4_t sum_vec = vdupq_n_f32(0);
132
- simsimd_f32_t epsilon = 1e-6;
132
+ simsimd_f32_t epsilon = SIMSIMD_F32_DIVISION_EPSILON;
133
133
  float32x4_t epsilon_vec = vdupq_n_f32(epsilon);
134
134
  simsimd_size_t i = 0;
135
135
  for (; i + 4 <= n; i += 4) {
@@ -147,11 +147,11 @@ simsimd_neon_f32_js(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size
147
147
  simsimd_f32_t log2_normalizer = 0.693147181f;
148
148
  simsimd_f32_t sum = vaddvq_f32(sum_vec) * log2_normalizer;
149
149
  for (; i < n; ++i) {
150
- simsimd_f32_t mi = a[i] + b[i];
150
+ simsimd_f32_t mi = 0.5f * (a[i] + b[i]);
151
151
  sum += a[i] * SIMSIMD_LOG((a[i] + epsilon) / (mi + epsilon));
152
152
  sum += b[i] * SIMSIMD_LOG((b[i] + epsilon) / (mi + epsilon));
153
153
  }
154
- return sum * 0.5f;
154
+ return sum;
155
155
  }
156
156
 
157
157
  /*
@@ -168,7 +168,7 @@ __attribute__((target("+simd+fp16"))) //
168
168
  inline static simsimd_f32_t
169
169
  simsimd_neon_f16_kl(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n) {
170
170
  float32x4_t sum_vec = vdupq_n_f32(0);
171
- simsimd_f32_t epsilon = 1e-3;
171
+ simsimd_f32_t epsilon = SIMSIMD_F32_DIVISION_EPSILON;
172
172
  float32x4_t epsilon_vec = vdupq_n_f32(epsilon);
173
173
  simsimd_size_t i = 0;
174
174
  for (; i + 4 <= n; i += 4) {
@@ -191,7 +191,7 @@ __attribute__((target("+simd+fp16"))) //
191
191
  inline static simsimd_f32_t
192
192
  simsimd_neon_f16_js(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n) {
193
193
  float32x4_t sum_vec = vdupq_n_f32(0);
194
- simsimd_f32_t epsilon = 1e-3;
194
+ simsimd_f32_t epsilon = SIMSIMD_F32_DIVISION_EPSILON;
195
195
  float32x4_t epsilon_vec = vdupq_n_f32(epsilon);
196
196
  simsimd_size_t i = 0;
197
197
  for (; i + 4 <= n; i += 4) {
@@ -211,11 +211,11 @@ simsimd_neon_f16_js(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size
211
211
  for (; i < n; ++i) {
212
212
  simsimd_f32_t ai = SIMSIMD_UNCOMPRESS_F16(a[i]);
213
213
  simsimd_f32_t bi = SIMSIMD_UNCOMPRESS_F16(b[i]);
214
- simsimd_f32_t mi = ai + bi;
214
+ simsimd_f32_t mi = 0.5f * (ai + bi);
215
215
  sum += ai * SIMSIMD_LOG((ai + epsilon) / (mi + epsilon));
216
216
  sum += bi * SIMSIMD_LOG((bi + epsilon) / (mi + epsilon));
217
217
  }
218
- return sum / 2;
218
+ return sum;
219
219
  }
220
220
 
221
221
  #endif // SIMSIMD_TARGET_ARM_NEON
@@ -268,7 +268,7 @@ __attribute__((target("avx2,f16c,fma"))) //
268
268
  inline static simsimd_f32_t
269
269
  simsimd_avx2_f16_kl(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n) {
270
270
  __m256 sum_vec = _mm256_set1_ps(0);
271
- simsimd_f32_t epsilon = 1e-5;
271
+ simsimd_f32_t epsilon = SIMSIMD_F32_DIVISION_EPSILON;
272
272
  __m256 epsilon_vec = _mm256_set1_ps(epsilon);
273
273
  simsimd_size_t i = 0;
274
274
  for (; i + 8 <= n; i += 8) {
@@ -300,7 +300,7 @@ __attribute__((target("avx2,f16c,fma"))) //
300
300
  inline static simsimd_f32_t
301
301
  simsimd_avx2_f16_js(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n) {
302
302
  __m256 sum_vec = _mm256_set1_ps(0);
303
- simsimd_f32_t epsilon = 1e-5;
303
+ simsimd_f32_t epsilon = SIMSIMD_F32_DIVISION_EPSILON;
304
304
  __m256 epsilon_vec = _mm256_set1_ps(epsilon);
305
305
  simsimd_size_t i = 0;
306
306
  for (; i + 8 <= n; i += 8) {
@@ -374,7 +374,7 @@ __attribute__((target("avx512f,avx512vl,bmi2"))) //
374
374
  inline static simsimd_f32_t
375
375
  simsimd_avx512_f32_kl(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n) {
376
376
  __m512 sum_vec = _mm512_set1_ps(0);
377
- simsimd_f32_t epsilon = 1e-6;
377
+ simsimd_f32_t epsilon = SIMSIMD_F32_DIVISION_EPSILON;
378
378
  __m512 epsilon_vec = _mm512_set1_ps(epsilon);
379
379
  __m512 a_vec, b_vec;
380
380
 
@@ -405,7 +405,7 @@ inline static simsimd_f32_t
405
405
  simsimd_avx512_f32_js(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n) {
406
406
  __m512 sum_a_vec = _mm512_set1_ps(0);
407
407
  __m512 sum_b_vec = _mm512_set1_ps(0);
408
- simsimd_f32_t epsilon = 1e-6;
408
+ simsimd_f32_t epsilon = SIMSIMD_F32_DIVISION_EPSILON;
409
409
  __m512 epsilon_vec = _mm512_set1_ps(epsilon);
410
410
  __m512 a_vec, b_vec;
411
411
 
@@ -425,8 +425,8 @@ simsimd_avx512_f32_js_cycle:
425
425
  __mmask16 nonzero_mask_b = _mm512_cmp_ps_mask(b_vec, epsilon_vec, _CMP_GE_OQ);
426
426
  __mmask16 nonzero_mask = nonzero_mask_a & nonzero_mask_b;
427
427
  __m512 m_recip_approx = _mm512_rcp14_ps(m_vec);
428
- __m512 ratio_a_vec = _mm512_mul_ps(a_vec, m_recip_approx);
429
- __m512 ratio_b_vec = _mm512_mul_ps(b_vec, m_recip_approx);
428
+ __m512 ratio_a_vec = _mm512_div_ps(a_vec, m_vec);
429
+ __m512 ratio_b_vec = _mm512_div_ps(b_vec, m_vec);
430
430
  __m512 log_ratio_a_vec = simsimd_avx512_f32_log2(ratio_a_vec);
431
431
  __m512 log_ratio_b_vec = simsimd_avx512_f32_log2(ratio_b_vec);
432
432
  sum_a_vec = _mm512_maskz_fmadd_ps(nonzero_mask, a_vec, log_ratio_a_vec, sum_a_vec);
@@ -472,7 +472,7 @@ __attribute__((target("avx512f,avx512vl,avx512fp16,bmi2"))) //
472
472
  inline static simsimd_f32_t
473
473
  simsimd_avx512_f16_kl(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n) {
474
474
  __m512h sum_vec = _mm512_set1_ph((_Float16)0);
475
- __m512h epsilon_vec = _mm512_set1_ph((_Float16)1e-6f);
475
+ __m512h epsilon_vec = _mm512_set1_ph((_Float16)SIMSIMD_F16_DIVISION_EPSILON);
476
476
  __m512h a_vec, b_vec;
477
477
 
478
478
  simsimd_avx512_f16_kl_cycle:
@@ -502,7 +502,7 @@ inline static simsimd_f32_t
502
502
  simsimd_avx512_f16_js(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n) {
503
503
  __m512h sum_a_vec = _mm512_set1_ph((_Float16)0);
504
504
  __m512h sum_b_vec = _mm512_set1_ph((_Float16)0);
505
- __m512h epsilon_vec = _mm512_set1_ph((_Float16)1e-6f);
505
+ __m512h epsilon_vec = _mm512_set1_ph((_Float16)SIMSIMD_F16_DIVISION_EPSILON);
506
506
  __m512h a_vec, b_vec;
507
507
 
508
508
  simsimd_avx512_f16_js_cycle:
@@ -91,6 +91,14 @@
91
91
  #define SIMSIMD_LOG(x) (logf(x))
92
92
  #endif
93
93
 
94
+ #ifndef SIMSIMD_F32_DIVISION_EPSILON
95
+ #define SIMSIMD_F32_DIVISION_EPSILON 1e-7
96
+ #endif
97
+
98
+ #ifndef SIMSIMD_F16_DIVISION_EPSILON
99
+ #define SIMSIMD_F16_DIVISION_EPSILON 1e-3
100
+ #endif
101
+
94
102
  #ifdef __cplusplus
95
103
  extern "C" {
96
104
  #endif
@@ -4,12 +4,6 @@ import assert from 'node:assert';
4
4
 
5
5
  const simsimd = bindings('simsimd');
6
6
 
7
- const f32Array1 = new Float32Array([1.0, 2.0, 3.0]);
8
- const f32Array2 = new Float32Array([4.0, 5.0, 6.0]);
9
-
10
- const u8Array1 = new Uint8Array([1, 2, 3]);
11
- const u8Array2 = new Uint8Array([4, 5, 6]);
12
-
13
7
  function assertAlmostEqual(actual, expected, tolerance = 1e-6) {
14
8
  const lowerBound = expected - tolerance;
15
9
  const upperBound = expected + tolerance;
@@ -17,20 +11,26 @@ function assertAlmostEqual(actual, expected, tolerance = 1e-6) {
17
11
  }
18
12
 
19
13
  test('Distance from itself', () => {
20
- assertAlmostEqual(simsimd.sqeuclidean(f32Array1, f32Array1), 0.0, 0.01);
21
- assertAlmostEqual(simsimd.cosine(f32Array1, f32Array1), 0.0, 0.01);
22
14
 
23
- // Inner-product distance on non-nroamalized vectors would yield:
24
- // 1 - 1 - 4 - 9 = -13
25
- assertAlmostEqual(simsimd.inner(f32Array1, f32Array1), -13.0, 0.01);
15
+ const f32s = new Float32Array([1.0, 2.0, 3.0]);
16
+ assertAlmostEqual(simsimd.sqeuclidean(f32s, f32s), 0.0, 0.01);
17
+ assertAlmostEqual(simsimd.cosine(f32s, f32s), 0.0, 0.01);
26
18
 
27
- assertAlmostEqual(simsimd.kullbackleibler(f32Array1, f32Array1), 0.0, 0.01);
28
- assertAlmostEqual(simsimd.jensenshannon(f32Array1, f32Array1), 0.0, 0.01);
19
+ const f32sNormalized = new Float32Array([1.0 / Math.sqrt(14), 2.0 / Math.sqrt(14), 3.0 / Math.sqrt(14)]);
20
+ assertAlmostEqual(simsimd.inner(f32sNormalized, f32sNormalized), 0.0, 0.01);
29
21
 
30
- assertAlmostEqual(simsimd.hamming(u8Array1, u8Array1), 0.0, 0.01);
31
- assertAlmostEqual(simsimd.jaccard(u8Array1, u8Array1), 0.0, 0.01);
22
+ const f32sDistribution = new Float32Array([1.0 / 6, 2.0 / 6, 3.0 / 6]);
23
+ assertAlmostEqual(simsimd.kullbackleibler(f32sDistribution, f32sDistribution), 0.0, 0.01);
24
+ assertAlmostEqual(simsimd.jensenshannon(f32sDistribution, f32sDistribution), 0.0, 0.01);
25
+
26
+ const u8s = new Uint8Array([1, 2, 3]);
27
+ assertAlmostEqual(simsimd.hamming(u8s, u8s), 0.0, 0.01);
28
+ assertAlmostEqual(simsimd.jaccard(u8s, u8s), 0.0, 0.01);
32
29
  });
33
30
 
31
+ const f32Array1 = new Float32Array([1.0, 2.0, 3.0]);
32
+ const f32Array2 = new Float32Array([4.0, 5.0, 6.0]);
33
+
34
34
  test('Squared Euclidean Distance', () => {
35
35
  const result = simsimd.sqeuclidean(f32Array1, f32Array2);
36
36
  assertAlmostEqual(result, 27.0, 0.01);
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "simsimd",
3
- "version": "3.3.0",
3
+ "version": "3.5.3",
4
4
  "description": "Vector Similarity Functions 3x-200x Faster than SciPy and NumPy",
5
5
  "author": "Ash Vardanian",
6
6
  "license": "Apache 2.0",
7
7
  "main": "javascript/simsimd.js",
8
8
  "type": "module",
9
- "repository": {
10
- "type": "git",
11
- "url": "https://github.com/ashvardanian/simsimd.git"
9
+ "scripts": {
10
+ "test": "node --test ./javascript/test",
11
+ "bench": "node ./javascript/bench.js"
12
12
  },
13
13
  "gypfile": true,
14
14
  "engines": {
@@ -19,10 +19,6 @@
19
19
  "bindings": "~1.2.1",
20
20
  "node-addon-api": "^3.0.0"
21
21
  },
22
- "scripts": {
23
- "test": "node --test ./javascript/test.js",
24
- "bench": "node ./javascript/bench.js"
25
- },
26
22
  "devDependencies": {
27
23
  "benchmark": "^2.1.4",
28
24
  "mathjs": "^11.11.2",
package/simsimd/setup.py CHANGED
@@ -27,6 +27,9 @@ if sys.platform == "linux":
27
27
  compile_args.append("-fopenmp")
28
28
  link_args.append("-lgomp")
29
29
 
30
+ # Add vectorized `logf` implementation from the `glibc`
31
+ link_args.append("-lm")
32
+
30
33
  if sys.platform == "darwin":
31
34
  compile_args.append("-std=c11")
32
35
  compile_args.append("-O3")
package/wasmer.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name="unum/usearch"
3
- version="2.8.3"
3
+ version="2.8.4"
4
4
  description="Smaller & Faster Single-File Vector Search Engine from Unum"
5
5
  license="Apache-2.0"
6
6
  readme="README.md"
@@ -1,215 +0,0 @@
1
- # Compiling USearch
2
-
3
- This document describes the workflow for advanced USearch users and enthusiasts willing to contribute to the project.
4
- Before building the first time, please pull submodules.
5
-
6
- ```sh
7
- git submodule update --init --recursive
8
- ```
9
-
10
- ## C++11
11
-
12
- Linux:
13
-
14
- ```sh
15
- sudo apt-get update
16
- sudo apt-get install cmake build-essential libjemalloc-dev
17
- cmake -B ./build_release \
18
- -DCMAKE_BUILD_TYPE=Release \
19
- -DUSEARCH_USE_OPENMP=1 \
20
- -DUSEARCH_USE_SIMSIMD=1 \
21
- -DUSEARCH_USE_JEMALLOC=1 \
22
- -DUSEARCH_BUILD_TEST_CPP=1 \
23
- -DUSEARCH_BUILD_BENCH_CPP=1 \
24
- -DUSEARCH_BUILD_LIB_C=1 \
25
- -DUSEARCH_BUILD_TEST_C=1 \
26
- -DUSEARCH_USE_NATIVE_F16=1 \
27
- && \
28
- make -C ./build_release -j
29
- ```
30
-
31
- MacOS:
32
-
33
- ```sh
34
- brew install libomp llvm
35
- cmake -B ./build_release \
36
- -DCMAKE_C_COMPILER="/opt/homebrew/opt/llvm/bin/clang" \
37
- -DCMAKE_CXX_COMPILER="/opt/homebrew/opt/llvm/bin/clang++" \
38
- -DUSEARCH_USE_OPENMP=1 \
39
- -DUSEARCH_USE_SIMSIMD=1 \
40
- -DUSEARCH_BUILD_BENCH_CPP=1 \
41
- -DUSEARCH_BUILD_TEST_CPP=1 \
42
- && \
43
- make -C ./build_release -j
44
- ```
45
-
46
- Linting:
47
-
48
- ```sh
49
- cppcheck --enable=all --force --suppress=cstyleCast --suppress=unusedFunction \
50
- include/usearch/index.hpp \
51
- include/index_dense.hpp \
52
- include/index_plugins.hpp
53
- ```
54
-
55
- Testing:
56
-
57
- ```sh
58
- cmake -DUSEARCH_BUILD_TEST_CPP=1 -B ./build_debug
59
- cmake --build ./build_debug --config Debug
60
- ./build_debug/test_cpp
61
- ```
62
-
63
- ## Python 3
64
-
65
- Use PyTest to validate the build.
66
- The `-s` option will disable capturing the logs.
67
- The `-x` option will exit after first failure to simplify debugging.
68
-
69
- ```sh
70
- pip install -e . && pytest python/scripts/ -s -x
71
- ```
72
-
73
- Linting:
74
-
75
- ```sh
76
- pip install ruff
77
- ruff --format=github --select=E9,F63,F7,F82 --target-version=py37 python
78
- ```
79
-
80
- Testing wheel builds locally:
81
-
82
- ```sh
83
- pip install cibuildwheel
84
- cibuildwheel --platform linux
85
- ```
86
-
87
- ## JavaScript
88
-
89
- Node.JS:
90
-
91
- ```sh
92
- npm install && node --test ./javascript/usearch.test.js
93
- npm publish
94
- ```
95
-
96
- WebAssembly:
97
-
98
- ```sh
99
- emcmake cmake -B ./build -DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS} -s TOTAL_MEMORY=64MB" && emmake make -C ./build
100
- node ./build/usearch.test.js
101
- ```
102
-
103
- If you don't yet have `emcmake` installed:
104
-
105
- ```sh
106
- git clone https://github.com/emscripten-core/emsdk.git && ./emsdk/emsdk install latest && ./emsdk/emsdk activate latest && source ./emsdk/emsdk_env.sh
107
- ```
108
-
109
- ## Rust
110
-
111
- ```sh
112
- cargo test -p usearch
113
- cargo publish
114
- ```
115
-
116
- ## Java
117
-
118
- ```sh
119
- gradle clean build
120
- java -cp . -Djava.library.path="$(pwd)/build/libs/usearch/shared" java/cloud/unum/usearch/Index.java
121
- ```
122
-
123
- Or step by-step:
124
-
125
- ```sh
126
- cs java/unum/cloud/usearch
127
- javac -h . Index.java
128
-
129
- # Ubuntu:
130
- g++ -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux cloud_unum_usearch_Index.cpp -o cloud_unum_usearch_Index.o
131
- g++ -shared -fPIC -o libusearch_c.so cloud_unum_usearch_Index.o -lc
132
-
133
- # Windows
134
- g++ -c -I%JAVA_HOME%\include -I%JAVA_HOME%\include\win32 cloud_unum_usearch_Index.cpp -o cloud_unum_usearch_Index.o
135
- g++ -shared -o USearchJNI.dll cloud_unum_usearch_Index.o -Wl,--add-stdcall-alias
136
-
137
- # MacOS
138
- g++ -std=c++11 -c -fPIC \
139
- -I../../../../include \
140
- -I../../../../fp16/include \
141
- -I../../../../simsimd/include \
142
- -I${JAVA_HOME}/include -I${JAVA_HOME}/include/darwin cloud_unum_usearch_Index.cpp -o cloud_unum_usearch_Index.o
143
- g++ -dynamiclib -o libusearch.dylib cloud_unum_usearch_Index.o -lc
144
- # Run linking to that directory
145
- java -cp . -Djava.library.path="$(pwd)/java/cloud/unum/usearch/" Index.java
146
- java -cp . -Djava.library.path="$(pwd)/java" cloud.unum.usearch.Index
147
- ```
148
-
149
- ## Objective-C and Swift
150
-
151
- ```sh
152
- swift build
153
- swift test -v
154
- ```
155
-
156
- ## C 99
157
-
158
- There are a few ways to compile the C 99 USearch SDK.
159
- Using the Makefile, specifying the targets you need:
160
-
161
- ```sh
162
- cmake -B ./build_release -DUSEARCH_BUILD_LIB_C=1 -DUSEARCH_BUILD_TEST_C=1 -DUSEARCH_USE_OPENMP=1 -DUSEARCH_USE_SIMSIMD=1
163
- cmake --build ./build_release --config Release -j
164
- ./build_release/test_c
165
- # On Windows:
166
- .\build_release\test_c.exe
167
- ```
168
-
169
- ## GoLang
170
-
171
- GoLang bindings are based on C.
172
- So one should first compile the C library, link it with GoLang, and only then run tests.
173
-
174
- ```sh
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/
179
- cd golang && go test -v ; cd ..
180
- ```
181
-
182
- ## Wolfram
183
-
184
- ```sh
185
- brew install --cask wolfram-engine
186
- ```
187
-
188
- ## Docker
189
-
190
- ```sh
191
- docker build -t unum/usearch . && docker run unum/usearch
192
- ```
193
-
194
- For multi-architecture builds and publications:
195
-
196
- ```sh
197
- version=$(cat VERSION)
198
- docker buildx create --use &&
199
- docker login &&
200
- docker buildx build \
201
- --platform "linux/amd64,linux/arm64" \
202
- --build-arg version=$version \
203
- --file Dockerfile \
204
- --tag unum/usearch:$version \
205
- --tag unum/usearch:latest \
206
- --push .
207
- ```
208
-
209
- ## Sub-Modules
210
-
211
- Extending metrics in SimSIMD:
212
-
213
- ```sh
214
- git push --set-upstream https://github.com/ashvardanian/simsimd.git HEAD:main
215
- ```
@@ -1,10 +0,0 @@
1
- Language: Cpp
2
- BasedOnStyle: LLVM
3
- IndentWidth: 4
4
- TabWidth: 4
5
- NamespaceIndentation: None
6
- ColumnLimit: 120
7
- ReflowComments: true
8
- UseTab: Never
9
- PointerAlignment: Left
10
- AllowShortCaseLabelsOnASingleLine: true