usearch 2.8.3 → 2.8.5

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 (43) hide show
  1. package/.github/workflows/release.yml +4 -2
  2. package/.vscode/settings.json +179 -179
  3. package/CITATION.cff +1 -1
  4. package/CONTRIBUTING.md +268 -6
  5. package/Cargo.toml +1 -1
  6. package/README.md +64 -59
  7. package/build.gradle +7 -9
  8. package/conanfile.py +1 -1
  9. package/cpp/README.md +89 -21
  10. package/csharp/DEV_SETUP.md +1 -1
  11. package/csharp/nuget/nuget-package.props +1 -1
  12. package/docs/{compilation.rst → contributing.rst} +2 -2
  13. package/docs/index.rst +1 -1
  14. package/include/usearch/index.hpp +1 -1
  15. package/include/usearch/index_dense.hpp +11 -7
  16. package/java/cloud/unum/usearch/Index.java +119 -53
  17. package/package.json +1 -1
  18. package/python/README.md +1 -1
  19. package/simsimd/CMakeLists.txt +1 -1
  20. package/simsimd/README.md +7 -1
  21. package/simsimd/include/simsimd/probability.h +24 -24
  22. package/simsimd/include/simsimd/types.h +8 -0
  23. package/simsimd/javascript/{test.js → test/simsimd.test.js} +15 -15
  24. package/simsimd/package.json +4 -8
  25. package/simsimd/setup.py +3 -0
  26. package/wasmer.toml +1 -1
  27. package/docs/compilation.md +0 -215
  28. package/simsimd/.clang-format +0 -10
  29. package/simsimd/.github/workflows/prerelease.yml +0 -89
  30. package/simsimd/.github/workflows/release.yml +0 -141
  31. package/simsimd/.github/workflows/update_version.sh +0 -5
  32. package/simsimd/.vscode/launch.json +0 -53
  33. package/simsimd/.vscode/settings.json +0 -114
  34. package/simsimd/.vscode/tasks.json +0 -23
  35. package/simsimd/go.mod +0 -3
  36. package/simsimd/golang/bench_test.go +0 -40
  37. package/simsimd/golang/simsimd.go +0 -47
  38. package/simsimd/golang/unit_test.go +0 -40
  39. package/simsimd/pyproject.toml +0 -42
  40. package/simsimd/python/bench.ipynb +0 -187
  41. package/simsimd/python/bench.py +0 -268
  42. package/simsimd/python/lib.c +0 -492
  43. package/simsimd/python/test.py +0 -195
@@ -1,17 +1,17 @@
1
1
  package cloud.unum.usearch;
2
2
 
3
- import java.io.File;
4
- import java.io.InputStream;
5
- import java.nio.file.Files;
6
- import java.nio.file.StandardCopyOption;
7
-
8
3
  /**
9
4
  * Java bindings for Unum USearch.
10
5
  * <p>
11
- * Provides interface to interact with USearch library and perform various operations related to indexing and searching.
6
+ * Provides interface to interact with USearch library and perform various
7
+ * operations related to indexing and searching.
12
8
  *
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>
9
+ * @see <a href=
10
+ * "https://nachtimwald.com/2017/06/06/wrapping-a-c-library-in-java/">Wrapping
11
+ * a C library in Java</a>
12
+ * @see <a href=
13
+ * "https://www3.ntu.edu.sg/home/ehchua/programming/java/javanativeinterface.html">Java
14
+ * Native Interface tutorial</a>
15
15
  */
16
16
  public class Index {
17
17
 
@@ -20,33 +20,34 @@ public class Index {
20
20
  /**
21
21
  * Creates a new instance of Index with specified parameters.
22
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
23
+ * @param metric the metric type for distance calculation between
24
+ * vectors
25
+ * @param quantization the scalar type for quantization of vector data
26
+ * @param dimensions the number of dimensions in the vectors
27
+ * @param capacity the initial capacity of the index
28
+ * @param connectivity the connectivity parameter that limits
29
+ * connections-per-node in graph
30
+ * @param expansion_add the expansion factor used for index construction when
31
+ * adding vectors
32
+ * @param expansion_search the expansion factor used for index construction
33
+ * during search operations
30
34
  */
31
35
  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(
36
+ String metric,
37
+ String quantization,
38
+ long dimensions,
39
+ long capacity,
40
+ long connectivity,
41
+ long expansion_add,
42
+ long expansion_search) {
43
+ c_ptr = c_create(
42
44
  metric,
43
45
  quantization,
44
46
  dimensions,
45
47
  capacity,
46
48
  connectivity,
47
49
  expansion_add,
48
- expansion_search
49
- );
50
+ expansion_search);
50
51
  }
51
52
 
52
53
  /**
@@ -97,8 +98,8 @@ public class Index {
97
98
  /**
98
99
  * Adds a vector with a specified key to the index.
99
100
  *
100
- * @param key the key associated with the vector
101
- * @param vector the vector data
101
+ * @param key the key associated with the vector
102
+ * @param vector the vector data
102
103
  */
103
104
  public void add(int key, float vector[]) {
104
105
  c_add(c_ptr, key, vector);
@@ -107,9 +108,9 @@ public class Index {
107
108
  /**
108
109
  * Searches for closest vectors to the specified query vector.
109
110
  *
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
111
+ * @param vector the query vector data
112
+ * @param count the number of nearest neighbors to search
113
+ * @return an array of keys of the nearest neighbors
113
114
  */
114
115
  public int[] search(float vector[], long count) {
115
116
  return c_search(c_ptr, vector, count);
@@ -146,7 +147,8 @@ public class Index {
146
147
  * Removes the vector associated with the given key from the index.
147
148
  *
148
149
  * @param key the key of the vector to be removed.
149
- * @return {@code true} if the vector was successfully removed, {@code false} otherwise.
150
+ * @return {@code true} if the vector was successfully removed, {@code false}
151
+ * otherwise.
150
152
  */
151
153
  public boolean remove(int key) {
152
154
  return c_remove(c_ptr, key);
@@ -156,13 +158,21 @@ public class Index {
156
158
  * Renames the vector to map to a different key.
157
159
  *
158
160
  * @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
+ * @param to the new key for the vector.
162
+ * @return {@code true} if the vector was successfully renamed, {@code false}
163
+ * otherwise.
161
164
  */
162
165
  public boolean rename(int from, int to) {
163
166
  return c_rename(c_ptr, from, to);
164
167
  }
165
168
 
169
+ /**
170
+ * Configuration class for building an Index instance.
171
+ * <p>
172
+ * This class provides a builder pattern to set various configurations for an
173
+ * Index. Once all configurations
174
+ * are set, calling {@link #build()} will produce an instance of {@link Index}.
175
+ */
166
176
  public static class Config {
167
177
 
168
178
  private String _metric = "ip";
@@ -173,50 +183,102 @@ public class Index {
173
183
  private long _expansion_add = 0;
174
184
  private long _expansion_search = 0;
175
185
 
176
- public Config() {}
186
+ /**
187
+ * Default constructor for the Config class.
188
+ */
189
+ public Config() {
190
+ }
177
191
 
192
+ /**
193
+ * Constructs an Index instance based on the current configuration settings.
194
+ *
195
+ * @return a newly constructed Index instance.
196
+ */
178
197
  public Index build() {
179
198
  return new Index(
180
- _metric,
181
- _quantization,
182
- _dimensions,
183
- _capacity,
184
- _connectivity,
185
- _expansion_add,
186
- _expansion_search
187
- );
199
+ _metric,
200
+ _quantization,
201
+ _dimensions,
202
+ _capacity,
203
+ _connectivity,
204
+ _expansion_add,
205
+ _expansion_search);
188
206
  }
189
207
 
208
+ /**
209
+ * Sets the metric for distance calculation between vectors.
210
+ *
211
+ * @param _metric the metric type
212
+ * @return this configuration instance
213
+ */
190
214
  public Config metric(String _metric) {
191
215
  this._metric = _metric;
192
216
  return this;
193
217
  }
194
218
 
219
+ /**
220
+ * Sets the scalar type for quantization of vector data.
221
+ *
222
+ * @param _quantization the quantization type
223
+ * @return this configuration instance
224
+ */
195
225
  public Config quantization(String _quantization) {
196
226
  this._quantization = _quantization;
197
227
  return this;
198
228
  }
199
229
 
230
+ /**
231
+ * Sets the number of dimensions in the vectors.
232
+ *
233
+ * @param _dimensions the number of dimensions
234
+ * @return this configuration instance
235
+ */
200
236
  public Config dimensions(long _dimensions) {
201
237
  this._dimensions = _dimensions;
202
238
  return this;
203
239
  }
204
240
 
241
+ /**
242
+ * Sets the initial capacity of the index.
243
+ *
244
+ * @param _capacity the index capacity
245
+ * @return this configuration instance
246
+ */
205
247
  public Config capacity(long _capacity) {
206
248
  this._capacity = _capacity;
207
249
  return this;
208
250
  }
209
251
 
252
+ /**
253
+ * Sets the connectivity parameter that limits connections-per-node in the
254
+ * graph.
255
+ *
256
+ * @param _connectivity the connectivity value
257
+ * @return this configuration instance
258
+ */
210
259
  public Config connectivity(long _connectivity) {
211
260
  this._connectivity = _connectivity;
212
261
  return this;
213
262
  }
214
263
 
264
+ /**
265
+ * Sets the expansion factor used for index construction when adding vectors.
266
+ *
267
+ * @param _expansion_add the expansion factor for adding vectors
268
+ * @return this configuration instance
269
+ */
215
270
  public Config expansion_add(long _expansion_add) {
216
271
  this._expansion_add = _expansion_add;
217
272
  return this;
218
273
  }
219
274
 
275
+ /**
276
+ * Sets the expansion factor used for index construction during search
277
+ * operations.
278
+ *
279
+ * @param _expansion_search the expansion factor for search
280
+ * @return this configuration instance
281
+ */
220
282
  public Config expansion_search(long _expansion_search) {
221
283
  this._expansion_search = _expansion_search;
222
284
  return this;
@@ -227,21 +289,25 @@ public class Index {
227
289
  System.loadLibrary("usearch");
228
290
  }
229
291
 
292
+ /**
293
+ * A simple main method to test the Index functionalities.
294
+ *
295
+ * @param args command line arguments (not used in this case)
296
+ */
230
297
  public static void main(String[] args) {
231
298
  Index index = new Index.Config().metric("cos").dimensions(100).build();
232
299
  index.size();
233
300
  System.out.println("Java tests passed!");
234
301
  }
235
302
 
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
- );
303
+ private static native long c_create(
304
+ String metric,
305
+ String quantization,
306
+ long dimensions,
307
+ long capacity,
308
+ long connectivity,
309
+ long expansion_add,
310
+ long expansion_search);
245
311
 
246
312
  private static native void c_destroy(long ptr);
247
313
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "usearch",
3
- "version": "2.8.3",
3
+ "version": "2.8.5",
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.5"
4
4
  description="Smaller & Faster Single-File Vector Search Engine from Unum"
5
5
  license="Apache-2.0"
6
6
  readme="README.md"