usearch 2.8.9 → 2.8.12

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.
@@ -127,7 +127,7 @@ jobs:
127
127
  wget https://apt.llvm.org/llvm.sh
128
128
  chmod +x llvm.sh
129
129
  sudo ./llvm.sh 16
130
- cmake -B build_artifacts -DCMAKE_BUILD_TYPE=RelWithDebInfo -DUSEARCH_BUILD_TEST_CPP=1 -DUSEARCH_BUILD_TEST_C=1 -DUSEARCH_BUILD_LIB_C=1 -DDUSEARCH_USE_OPENMP=0 -DUSEARCH_USE_SIMSIMD=1 -DUSEARCH_USE_JEMALLOC=1
130
+ cmake -B build_artifacts -DCMAKE_BUILD_TYPE=RelWithDebInfo -DUSEARCH_BUILD_TEST_CPP=1 -DUSEARCH_BUILD_TEST_C=1 -DUSEARCH_BUILD_LIB_C=1 -DUSEARCH_USE_OPENMP=0 -DUSEARCH_USE_SIMSIMD=1 -DUSEARCH_USE_JEMALLOC=1
131
131
  cmake --build build_artifacts --config RelWithDebInfo
132
132
  - name: Test C++
133
133
  run: ./build_artifacts/test_cpp
@@ -432,6 +432,7 @@ jobs:
432
432
  npm install
433
433
  npm ci
434
434
  npm test
435
+ npm run typegen
435
436
 
436
437
  - name: Publish
437
438
  uses: JS-DevTools/npm-publish@v2
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.8.9
8
+ version: 2.8.12
9
9
  doi: 10.5281/zenodo.7949416
10
10
  date-released: 2023-10-22
11
11
  url: "https://github.com/unum-cloud/usearch"
package/CONTRIBUTING.md CHANGED
@@ -232,21 +232,30 @@ Afterwards, in a new terminal:
232
232
 
233
233
  ```sh
234
234
  gradle clean build
235
- java -cp . -Djava.library.path="$(pwd)/build/libs/usearch/shared" java/cloud/unum/usearch/Index.java
235
+ gradle test
236
+ ```
237
+
238
+ Alternatively, to run the `Index.main`:
239
+
240
+ ```sh
241
+ java -cp "$(pwd)/build/classes/java/main" -Djava.library.path="$(pwd)/build/libs/usearch/shared" java/cloud/unum/usearch/Index.java
236
242
  ```
237
243
 
238
244
  Or step by-step:
239
245
 
240
246
  ```sh
241
- cs java/unum/cloud/usearch
242
- javac -h . Index.java
247
+ cd java/cloud/unum/usearch
248
+ javac -h . Index.java NativeUtils.java
249
+
250
+ # Ensure JAVA_HOME system environment variable has been set
251
+ # e.g. export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
243
252
 
244
253
  # Ubuntu:
245
- g++ -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux cloud_unum_usearch_Index.cpp -o cloud_unum_usearch_Index.o
246
- g++ -shared -fPIC -o libusearch_c.so cloud_unum_usearch_Index.o -lc
254
+ g++ -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux -I../../../../include cloud_unum_usearch_Index.cpp -o cloud_unum_usearch_Index.o
255
+ g++ -shared -fPIC -o libusearch.so cloud_unum_usearch_Index.o -lc
247
256
 
248
257
  # Windows
249
- g++ -c -I%JAVA_HOME%\include -I%JAVA_HOME%\include\win32 cloud_unum_usearch_Index.cpp -o cloud_unum_usearch_Index.o
258
+ g++ -c -I%JAVA_HOME%\include -I%JAVA_HOME%\include\win32 cloud_unum_usearch_Index.cpp -I..\..\..\..\include -o cloud_unum_usearch_Index.o
250
259
  g++ -shared -o USearchJNI.dll cloud_unum_usearch_Index.o -Wl,--add-stdcall-alias
251
260
 
252
261
  # MacOS
@@ -256,9 +265,11 @@ g++ -std=c++11 -c -fPIC \
256
265
  -I../../../../simsimd/include \
257
266
  -I${JAVA_HOME}/include -I${JAVA_HOME}/include/darwin cloud_unum_usearch_Index.cpp -o cloud_unum_usearch_Index.o
258
267
  g++ -dynamiclib -o libusearch.dylib cloud_unum_usearch_Index.o -lc
268
+
259
269
  # Run linking to that directory
260
- java -cp . -Djava.library.path="$(pwd)/java/cloud/unum/usearch/" Index.java
261
- java -cp . -Djava.library.path="$(pwd)/java" cloud.unum.usearch.Index
270
+ cd ../../../..
271
+ cp cloud/unum/usearch/libusearch.* .
272
+ java -cp . -Djava.library.path="$(pwd)" cloud.unum.usearch.Index
262
273
  ```
263
274
 
264
275
  ## Wolfram
package/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "usearch"
3
- version = "2.8.9"
3
+ version = "2.8.12"
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
@@ -50,6 +50,7 @@ Linux • MacOS • Windows • iOS • WebAssembly
50
50
  - ✅ [20x faster than][faster-than-faiss] [FAISS][faiss] implementation of [HNSW algorithm][hnsw-algorithm].
51
51
  - ✅ Simple and extensible [single C++11 header][usearch-header] implementation.
52
52
  - ✅ Compatible with a dozen programming languages out of the box.
53
+ - ✅ [Trusted](#integrations) by some of the most loved Datalakes and Databases, like [ClickHouse][clickhouse-docs].
53
54
  - ✅ [SIMD][simd]-optimized and [user-defined metrics](#user-defined-functions) with JIT compilation.
54
55
  - ✅ Hardware-agnostic `f16` & `i8` - [half-precision & quarter-precision support](#memory-efficiency-downcasting-and-quantization).
55
56
  - ✅ [View large indexes from disk](#serving-index-from-disk) without loading into RAM.
@@ -67,6 +68,17 @@ Linux • MacOS • Windows • iOS • WebAssembly
67
68
  [hnsw-algorithm]: https://arxiv.org/abs/1603.09320
68
69
  [simd]: https://en.wikipedia.org/wiki/Single_instruction,_multiple_data
69
70
  [faster-than-faiss]: https://www.unum.cloud/blog/2023-11-07-scaling-vector-search-with-intel
71
+ [clickhouse-docs]: https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/annindexes#usearch
72
+
73
+ __Technical Insights__ and related articles:
74
+
75
+ - [Uses Horner's method for polynomial approximations, beating GCC 12 by 119x](https://ashvardanian.com/posts/gcc-12-vs-avx512fp16/).
76
+ - [Uses Arm SVE and x86 AVX-512's masked loads to eliminate tail `for`-loops](https://ashvardanian.com/posts/simsimd-faster-scipy/#tails-of-the-past-the-significance-of-masked-loads).
77
+ - [Uses AVX-512 FP16 for half-precision operations, that few compilers vectorize](https://ashvardanian.com/posts/simsimd-faster-scipy/#the-challenge-of-f16).
78
+ - [Substitutes LibC's `sqrt` calls with bithacks using Jan Kadlec's constant](https://ashvardanian.com/posts/simsimd-faster-scipy/#bonus-section-bypassing-sqrt-and-libc-dependencies).
79
+ - [For every language implements a custom separate binding](https://ashvardanian.com/posts/porting-cpp-library-to-ten-languages/).
80
+ - [For Python avoids slow PyBind11, and even `PyArg_ParseTuple` for speed](https://ashvardanian.com/posts/pybind11-cpython-tutorial/).
81
+ - [For JavaScript uses typed arrays and NAPI for zero-copy calls](https://ashvardanian.com/posts/javascript-ai-vector-search/).
70
82
 
71
83
  ## Comparison with FAISS
72
84
 
@@ -132,34 +144,6 @@ index = Index(
132
144
  )
133
145
  ```
134
146
 
135
- ## User-Defined Functions
136
-
137
- While most vector search packages concentrate on just a few metrics - "Inner Product distance" and "Euclidean distance," USearch extends this list to include any user-defined metrics.
138
- This flexibility allows you to customize your search for various applications, from computing geospatial coordinates with the rare [Haversine][haversine] distance to creating custom metrics for composite embeddings from multiple AI models.
139
-
140
- ![USearch: Vector Search Approaches](https://github.com/unum-cloud/usearch/blob/main/assets/usearch-approaches-white.png?raw=true)
141
-
142
- Unlike older approaches indexing high-dimensional spaces, like KD-Trees and Locality Sensitive Hashing, HNSW doesn't require vectors to be identical in length.
143
- They only have to be comparable.
144
- So you can apply it in [obscure][obscure] applications, like searching for similar sets or fuzzy text matching, using [GZip][gzip-similarity] as a distance function.
145
-
146
- > Read more about [JIT and UDF in USearch Python SDK](https://unum-cloud.github.io/usearch/python#user-defined-metrics-and-jit-in-python).
147
-
148
- [haversine]: https://ashvardanian.com/posts/abusing-vector-search#geo-spatial-indexing
149
- [obscure]: https://ashvardanian.com/posts/abusing-vector-search
150
- [gzip-similarity]: https://twitter.com/LukeGessler/status/1679211291292889100?s=20
151
-
152
- ## Memory Efficiency, Downcasting, and Quantization
153
-
154
- Training a quantization model and dimension-reduction is a common approach to accelerate vector search.
155
- Those, however, are only sometimes reliable, can significantly affect the statistical properties of your data, and require regular adjustments if your distribution shifts.
156
-
157
- ![USearch uint40_t support](https://github.com/unum-cloud/usearch/blob/main/assets/usearch-neighbor-types.png?raw=true)
158
-
159
- Instead, we have focused on high-precision arithmetic over low-precision downcasted vectors.
160
- The same index, and `add` and `search` operations will automatically down-cast or up-cast between `f32_t`, `f16_t`, `f64_t`, and `i8_t` representations, even if the hardware doesn't natively support it.
161
- Continuing the topic of memory efficiency, we provide a `uint40_t` to allow collection with over 4B+ vectors without allocating 8 bytes for every neighbor reference in the proximity graph.
162
-
163
147
  ## Serialization & Serving `Index` from Disk
164
148
 
165
149
  USearch supports multiple forms of serialization:
@@ -275,16 +259,56 @@ pairs: dict = men.join(women, max_proposals=0, exact=False)
275
259
 
276
260
  > Read more in the post: [Combinatorial Stable Marriages for Semantic Search 💍](https://ashvardanian.com/posts/searching-stable-marriages)
277
261
 
262
+ ## User-Defined Functions
263
+
264
+ While most vector search packages concentrate on just a few metrics - "Inner Product distance" and "Euclidean distance," USearch extends this list to include any user-defined metrics.
265
+ This flexibility allows you to customize your search for various applications, from computing geospatial coordinates with the rare [Haversine][haversine] distance to creating custom metrics for composite embeddings from multiple AI models.
266
+
267
+ ![USearch: Vector Search Approaches](https://github.com/unum-cloud/usearch/blob/main/assets/usearch-approaches-white.png?raw=true)
268
+
269
+ Unlike older approaches indexing high-dimensional spaces, like KD-Trees and Locality Sensitive Hashing, HNSW doesn't require vectors to be identical in length.
270
+ They only have to be comparable.
271
+ So you can apply it in [obscure][obscure] applications, like searching for similar sets or fuzzy text matching, using [GZip][gzip-similarity] as a distance function.
272
+
273
+ > Read more about [JIT and UDF in USearch Python SDK](https://unum-cloud.github.io/usearch/python#user-defined-metrics-and-jit-in-python).
274
+
275
+ [haversine]: https://ashvardanian.com/posts/abusing-vector-search#geo-spatial-indexing
276
+ [obscure]: https://ashvardanian.com/posts/abusing-vector-search
277
+ [gzip-similarity]: https://twitter.com/LukeGessler/status/1679211291292889100?s=20
278
+
279
+ ## Memory Efficiency, Downcasting, and Quantization
280
+
281
+ Training a quantization model and dimension-reduction is a common approach to accelerate vector search.
282
+ Those, however, are only sometimes reliable, can significantly affect the statistical properties of your data, and require regular adjustments if your distribution shifts.
283
+ Instead, we have focused on high-precision arithmetic over low-precision downcasted vectors.
284
+ The same index, and `add` and `search` operations will automatically down-cast or up-cast between `f64_t`, `f32_t`, `f16_t`, `i8_t`, and single-bit representations.
285
+ You can use the following command to check, if hardware acceleration is enabled:
286
+
287
+ ```sh
288
+ $ python -c 'from usearch.index import Index; print(Index(ndim=768, metric="cos", dtype="f16").hardware_acceleration)'
289
+ > avx512+f16
290
+ $ python -c 'from usearch.index import Index; print(Index(ndim=166, metric="tanimoto").hardware_acceleration)'
291
+ > avx512+popcnt
292
+ ```
293
+
294
+ Using smaller numeric types will save you RAM needed to store the vectors, but you can also compress the neighbors lists forming our proximity graphs.
295
+ By default, 32-bit `uint32_t` is used to enumerate those, which is not enough if you need to address over 4 Billion entries.
296
+ For such cases we provide a custom `uint40_t` type, that will still be 37.5% more space-efficient than the commonly used 8-byte integers, and will scale up to 1 Trillion entries.
297
+
298
+ ![USearch uint40_t support](https://github.com/unum-cloud/usearch/blob/main/assets/usearch-neighbor-types.png?raw=true)
299
+
278
300
  ## Functionality
279
301
 
280
302
  By now, the core functionality is supported across all bindings.
281
303
  Broader functionality is ported per request.
304
+ In some cases, like Batch operations, feature parity is meaningless, as the host language has full multi-threading capabilities and the USearch index structure is concurrent by design, so the users can implement batching/scheduling/load-balancing in the most optimal way for their applications.
282
305
 
283
306
  | | C++ 11 | Python 3 | C 99 | Java | JavaScript | Rust | GoLang | Swift |
284
307
  | :---------------------- | :----: | :------: | :---: | :---: | :--------: | :---: | :----: | :---: |
285
- | Add, search | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
308
+ | Add, search, remove | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
286
309
  | Save, load, view | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
287
310
  | User-defined metrics | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
311
+ | Batch operations | ❌ | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ |
288
312
  | Joins | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
289
313
  | Variable-length vectors | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
290
314
  | 4B+ capacities | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
@@ -400,7 +424,7 @@ doi = {10.5281/zenodo.7949416},
400
424
  author = {Vardanian, Ash},
401
425
  title = {{USearch by Unum Cloud}},
402
426
  url = {https://github.com/unum-cloud/usearch},
403
- version = {2.8.9},
427
+ version = {2.8.12},
404
428
  year = {2023},
405
429
  month = oct,
406
430
  }
package/VERSION CHANGED
@@ -1 +1 @@
1
- 2.8.9
1
+ 2.8.12
package/build.gradle CHANGED
@@ -23,6 +23,11 @@ sourceSets {
23
23
  srcDir "java/"
24
24
  exclude "test/"
25
25
  }
26
+ // Ensure native libraries are included in the main source set
27
+ resources {
28
+ srcDirs "$buildDir/libs"
29
+ include "usearch/**"
30
+ }
26
31
  }
27
32
  test {
28
33
  java {
@@ -98,15 +103,25 @@ test {
98
103
 
99
104
  // Rearrange test classpath, add compiled JAR instead of main classes
100
105
  classpath = project.sourceSets.test.output + configurations.testRuntimeClasspath + files(jar.archiveFile)
106
+
107
+ // Enable detailed test logging
108
+ testLogging {
109
+ // Ensure that we get output from all tests, not just failing ones
110
+ showStandardStreams = true
111
+ exceptionFormat = 'full' // Can be 'short', 'full', or 'summary'
112
+
113
+ // More detailed test result logging
114
+ events "passed", "skipped", "failed"
115
+ }
101
116
  }
102
117
 
103
118
  jar {
104
119
  dependsOn("usearchSharedLibrary")
105
- into("usearch") {
106
- from("$buildDir/libs/usearch/shared/libusearch.dylib")
107
- from("$buildDir/libs/usearch/shared/libusearch.dll")
108
- from("$buildDir/libs/usearch/shared/libusearch.so")
120
+ from("$buildDir/libs/usearch/shared") {
121
+ include "libusearch.so", "libusearch.dylib", "libusearch.dll"
122
+ into "usearch"
109
123
  }
124
+ from sourceSets.main.output
110
125
  }
111
126
 
112
127
  signing {
@@ -180,4 +195,10 @@ publishing {
180
195
  }
181
196
  }
182
197
  }
183
- }
198
+ }
199
+
200
+ // Ensure that the native library is built before the Java code
201
+ compileJava.dependsOn tasks.withType(SharedLibraryBinarySpec)
202
+ tasks.named("processResources").configure {
203
+ dependsOn tasks.named("linkUsearchSharedLibrary")
204
+ }
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.8.9'
10
+ version = '2.8.12'
11
11
  license = "Apache-2.0"
12
12
  description = "Smaller & Faster Single-File Vector Search Engine from Unum"
13
13
  homepage = "https://github.com/unum-cloud/usearch"
@@ -11,7 +11,7 @@
11
11
 
12
12
  #define USEARCH_VERSION_MAJOR 2
13
13
  #define USEARCH_VERSION_MINOR 8
14
- #define USEARCH_VERSION_PATCH 9
14
+ #define USEARCH_VERSION_PATCH 12
15
15
 
16
16
  // Inferring C++ version
17
17
  // https://stackoverflow.com/a/61552074
@@ -108,13 +108,10 @@ struct index_dense_config_t : public index_config_t {
108
108
 
109
109
  index_dense_config_t(index_config_t base) noexcept : index_config_t(base) {}
110
110
 
111
- index_dense_config_t( //
112
- std::size_t connectivity = default_connectivity(), //
113
- std::size_t expansion_add = default_expansion_add(),
114
- std::size_t expansion_search = default_expansion_search()) noexcept
115
- : index_config_t(connectivity), //
116
- expansion_add(expansion_add ? expansion_add : default_expansion_add()),
117
- expansion_search(expansion_search ? expansion_search : default_expansion_search()) {}
111
+ index_dense_config_t(std::size_t c = default_connectivity(), std::size_t ea = default_expansion_add(),
112
+ std::size_t es = default_expansion_search()) noexcept
113
+ : index_config_t(c), expansion_add(ea ? ea : default_expansion_add()),
114
+ expansion_search(es ? es : default_expansion_search()) {}
118
115
  };
119
116
 
120
117
  struct index_dense_clustering_config_t {
@@ -1343,11 +1343,13 @@ class metric_punned_t {
1343
1343
  scalar_kind_(scalar_kind) {
1344
1344
 
1345
1345
  #if USEARCH_USE_SIMSIMD
1346
- if (configure_with_simsimd())
1347
- return;
1346
+ if (!configure_with_simsimd())
1347
+ configure_with_auto_vectorized();
1348
1348
  #endif
1349
-
1350
1349
  configure_with_auto_vectorized();
1350
+
1351
+ if (scalar_kind == scalar_kind_t::b1x8_k)
1352
+ raw_arg3_ = raw_arg4_ = divide_round_up<CHAR_BIT>(dimensions_);
1351
1353
  }
1352
1354
 
1353
1355
  inline metric_punned_t( //
@@ -1402,6 +1404,7 @@ class metric_punned_t {
1402
1404
  case metric_kind_t::cos_k: kind = simsimd_metric_cos_k; break;
1403
1405
  case metric_kind_t::l2sq_k: kind = simsimd_metric_l2sq_k; break;
1404
1406
  case metric_kind_t::hamming_k: kind = simsimd_metric_hamming_k; break;
1407
+ case metric_kind_t::tanimoto_k: kind = simsimd_metric_jaccard_k; break;
1405
1408
  case metric_kind_t::jaccard_k: kind = simsimd_metric_jaccard_k; break;
1406
1409
  default: break;
1407
1410
  }
@@ -1498,18 +1501,9 @@ class metric_punned_t {
1498
1501
  break;
1499
1502
  }
1500
1503
  case metric_kind_t::jaccard_k: // Equivalent to Tanimoto
1501
- case metric_kind_t::tanimoto_k:
1502
- raw_ptr_ = (punned_ptr_t)&equidimensional_<metric_tanimoto_gt<b1x8_t>>,
1503
- raw_arg3_ = raw_arg4_ = divide_round_up<CHAR_BIT>(dimensions_), scalar_kind_ = scalar_kind_t::b1x8_k;
1504
- break;
1505
- case metric_kind_t::hamming_k:
1506
- raw_ptr_ = (punned_ptr_t)&equidimensional_<metric_hamming_gt<b1x8_t>>,
1507
- raw_arg3_ = raw_arg4_ = divide_round_up<CHAR_BIT>(dimensions_), scalar_kind_ = scalar_kind_t::b1x8_k;
1508
- break;
1509
- case metric_kind_t::sorensen_k:
1510
- raw_ptr_ = (punned_ptr_t)&equidimensional_<metric_sorensen_gt<b1x8_t>>,
1511
- raw_arg3_ = raw_arg4_ = divide_round_up<CHAR_BIT>(dimensions_), scalar_kind_ = scalar_kind_t::b1x8_k;
1512
- break;
1504
+ case metric_kind_t::tanimoto_k: raw_ptr_ = (punned_ptr_t)&equidimensional_<metric_tanimoto_gt<b1x8_t>>; break;
1505
+ case metric_kind_t::hamming_k: raw_ptr_ = (punned_ptr_t)&equidimensional_<metric_hamming_gt<b1x8_t>>; break;
1506
+ case metric_kind_t::sorensen_k: raw_ptr_ = (punned_ptr_t)&equidimensional_<metric_sorensen_gt<b1x8_t>>; break;
1513
1507
  default: return;
1514
1508
  }
1515
1509
  }
@@ -0,0 +1,237 @@
1
+ export class Index {
2
+ /**
3
+ * Constructs a new index.
4
+ *
5
+ * @param {(number | {dimensions: number, metric: MetricKind = MetricKind.Cos, quantization: ScalarKind = ScalarKind.F32, connectivity: number = 0, expansion_add: number = 0, expansion_search: number = 0, multi: boolean = false})} dimensionsOrConfigs
6
+ * @param {MetricKind} [metric=MetricKind.Cos] - Optional, default is 'cos'.
7
+ * @param {ScalarKind} [quantization=ScalarKind.F32] - Optional, default is 'f32'.
8
+ * @param {number} [connectivity=0] - Optional, default is 0.
9
+ * @param {number} [expansion_add=0] - Optional, default is 0.
10
+ * @param {number} [expansion_search=0] - Optional, default is 0.
11
+ * @param {boolean} [multi=false] - Optional, default is false.
12
+ * @throws Will throw an error if any of the parameters are of incorrect type or invalid value.
13
+ */
14
+ constructor(dimensionsOrConfigs: number | {
15
+ dimensions: number;
16
+ metric: MetricKind;
17
+ quantization: ScalarKind;
18
+ connectivity: number;
19
+ expansion_add: number;
20
+ expansion_search: number;
21
+ multi: boolean;
22
+ }, metric?: MetricKind, quantization?: ScalarKind, connectivity?: number, expansion_add?: number, expansion_search?: number, multi?: boolean);
23
+ _compiledIndex: any;
24
+ /**
25
+ * Add vectors to the index.
26
+ *
27
+ * This method accepts vectors and their corresponding keys for indexing.
28
+ * Each key should correspond to a vector. If a single key is provided,
29
+ * it is broadcasted to match the number of provided vectors.
30
+ *
31
+ * Vectors should be provided as a flat typed array representing a matrix
32
+ * where each row is a vector to be indexed. The matrix should have a size
33
+ * of n * d, where n is the number of vectors, and d is the dimensionality
34
+ * of the vectors.
35
+ *
36
+ * Keys should be provided as a BigInt or an array-like object of BigInts
37
+ * representing the unique identifier for each vector.
38
+ *
39
+ * @param {bigint|bigint[]|BigUint64Array} keys - Input identifiers for every vector.
40
+ * If a single key is provided, it is associated with all provided vectors.
41
+ * @param {Float32Array|Float64Array|Int8Array} vectors - Input matrix representing vectors,
42
+ * matrix of size n * d, where n is the number of vectors, and d is their dimensionality.
43
+ * @throws Will throw an error if the length of keys doesn't match the number of vectors
44
+ * or if it's not a single key.
45
+ */
46
+ add(keys: bigint | bigint[] | BigUint64Array, vectors: Float32Array | Float64Array | Int8Array): void;
47
+ /**
48
+ * Perform a k-nearest neighbor search on the index.
49
+ *
50
+ * This method accepts a matrix of query vectors and returns the closest vectors
51
+ * from the index for each query. The method returns an object containing the keys,
52
+ * distances, and counts of the matches found.
53
+ *
54
+ * Vectors should be provided as a flat typed array representing a matrix where
55
+ * each row is a vector. The matrix should be of size n * d, where n is the
56
+ * number of query vectors, and d is their dimensionality.
57
+ *
58
+ * The parameter `k` specifies the number of nearest neighbors to return for each
59
+ * query vector. If there are not enough results for a query, the result array is
60
+ * padded with -1s.
61
+ *
62
+ * @param {Float32Array|Float64Array|Int8Array|Array<Array<number>>} vectors - Input matrix representing query vectors, can be a TypedArray or an array of arrays.
63
+ * @param {number} k - The number of nearest neighbors to search for each query vector.
64
+ * @return {Matches|BatchMatches} - Search results for one or more queries, containing keys, distances, and counts of the matches found.
65
+ * @throws Will throw an error if `k` is not a positive integer or if the size of the vectors is not a multiple of dimensions.
66
+ * @throws Will throw an error if `vectors` is not a valid input type (TypedArray or an array of arrays) or if its flattened size is not a multiple of dimensions.
67
+ */
68
+ search(vectors: Float32Array | Float64Array | Int8Array | Array<Array<number>>, k: number): Matches | BatchMatches;
69
+ /**
70
+ * Verifies the presence of one or more keys in the index.
71
+ *
72
+ * This method accepts one or multiple keys as input and returns a boolean or
73
+ * an array of booleans indicating whether each key is present in the index.
74
+ *
75
+ * @param {bigint|bigint[]|BigUint64Array} keys - The identifier(s) of the vector(s) to be checked for presence in the index.
76
+ * @return {boolean|boolean[]} - Returns true if a single key is contained in the index, false otherwise. Returns an array of booleans corresponding to the presence of each key in the index when multiple keys are provided.
77
+ * @throws Will throw an error if keys are not integers.
78
+ */
79
+ contains(keys: bigint | bigint[] | BigUint64Array): boolean | boolean[];
80
+ /**
81
+ * Counts the number of times keys shows up in the index.
82
+ *
83
+ * @param {bigint|bigint[]|BigUint64Array} keys - The identifier(s) of the vector(s) to be enumerated.
84
+ * @return {number|number[]} - Returns the number of vectors found when a single key is provided. Returns an array of big integers corresponding to the number of vectors found for each key when multiple keys are provided.
85
+ * @throws Will throw an error if keys are not integers.
86
+ */
87
+ count(keys: bigint | bigint[] | BigUint64Array): number | number[];
88
+ /**
89
+ * Removes one or multiple vectors from the index.
90
+ *
91
+ * This method accepts one or multiple keys as input and removes the corresponding vectors from the index.
92
+ * It returns the number of vectors actually removed for each key provided.
93
+ *
94
+ * @param {bigint|bigint[]|BigUint64Array} keys - The identifier(s) of the vector(s) to be removed.
95
+ * @return {number|number[]} - Returns the number of vectors deleted when a single key is provided. Returns an array of big integers corresponding to the number of vectors deleted for each key when multiple keys are provided.
96
+ * @throws Will throw an error if keys are not integers.
97
+ */
98
+ remove(keys: bigint | bigint[] | BigUint64Array): number | number[];
99
+ /**
100
+ * Returns the dimensionality of vectors.
101
+ * @return {number} The dimensionality of vectors.
102
+ */
103
+ dimensions(): number;
104
+ /**
105
+ * Returns connectivity.
106
+ * @return {number} The connectivity of index.
107
+ */
108
+ connectivity(): number;
109
+ /**
110
+ * Returns the number of vectors currently indexed.
111
+ * @return {number} The number of vectors currently indexed.
112
+ */
113
+ size(): number;
114
+ /**
115
+ * Returns index capacity.
116
+ * @return {number} The capacity of index.
117
+ */
118
+ capacity(): number;
119
+ /**
120
+ * Write index to a file.
121
+ * @param {string} path File path to write.
122
+ * @throws Will throw an error if `path` is not a string.
123
+ */
124
+ save(path: string): void;
125
+ /**
126
+ * Load index from a file.
127
+ * @param {string} path File path to read.
128
+ * @throws Will throw an error if `path` is not a string.
129
+ */
130
+ load(path: string): void;
131
+ /**
132
+ * View index from a file, without loading into RAM.
133
+ * @param {string} path File path to read.
134
+ * @throws Will throw an error if `path` is not a string.
135
+ */
136
+ view(path: string): void;
137
+ }
138
+ /**
139
+ * *
140
+ */
141
+ export type MetricKind = string;
142
+ export namespace MetricKind {
143
+ let Unknown: string;
144
+ let Cos: string;
145
+ let IP: string;
146
+ let L2sq: string;
147
+ let Haversine: string;
148
+ let Divergence: string;
149
+ let Pearson: string;
150
+ let Jaccard: string;
151
+ let Hamming: string;
152
+ let Tanimoto: string;
153
+ let Sorensen: string;
154
+ }
155
+ /**
156
+ * *
157
+ */
158
+ export type ScalarKind = string;
159
+ export namespace ScalarKind {
160
+ let Unknown_1: string;
161
+ export { Unknown_1 as Unknown };
162
+ export let F32: string;
163
+ export let F64: string;
164
+ export let F16: string;
165
+ export let I8: string;
166
+ export let B1: string;
167
+ }
168
+ /**
169
+ * Represents a set of search results.
170
+ */
171
+ export class Matches {
172
+ /**
173
+ * Constructs a Matches object.
174
+ *
175
+ * @param {BigUint64Array} keys - The keys of the nearest neighbors found.
176
+ * @param {Float32Array} distances - The distances of the nearest neighbors found.
177
+ */
178
+ constructor(keys: BigUint64Array, distances: Float32Array);
179
+ keys: BigUint64Array;
180
+ distances: Float32Array;
181
+ }
182
+ /**
183
+ * Represents a set of batched search results.
184
+ */
185
+ export class BatchMatches {
186
+ /**
187
+ * Constructs a BatchMatches object.
188
+ *
189
+ * @param {BigUint64Array} keys - The keys of the nearest neighbors found in the batch.
190
+ * @param {Float32Array} distances - The distances of the nearest neighbors found in the batch.
191
+ * @param {BigUint64Array} counts - The number of neighbors found for each query in the batch.
192
+ * @param {bigint} k - The limit for search results per query in the batch.
193
+ */
194
+ constructor(keys: BigUint64Array, distances: Float32Array, counts: BigUint64Array, k: bigint);
195
+ keys: BigUint64Array;
196
+ distances: Float32Array;
197
+ counts: BigUint64Array;
198
+ k: bigint;
199
+ /**
200
+ * Retrieves a Matches object at the specified index in the batch.
201
+ *
202
+ * @param {number} i - The index at which to retrieve the Matches object.
203
+ * @returns {Matches} - A Matches object representing the search results at the specified index in the batch.
204
+ */
205
+ get(i: number): Matches;
206
+ }
207
+ /**
208
+ * Performs an exact search on the given dataset to find the best matching vectors for each query.
209
+ *
210
+ * @param {Float32Array|Float64Array|Int8Array|Array<Array<number>>} dataset - The dataset containing vectors to be searched. It can be a TypedArray or an array of arrays.
211
+ * @param {Float32Array|Float64Array|Int8Array|Array<Array<number>>} queries - The queries containing vectors to search for in the dataset. It can be a TypedArray or an array of arrays.
212
+ * @param {number} dimensions - The dimensionality of the vectors in both the dataset and the queries. It defines the number of elements in each vector.
213
+ * @param {number} count - The number of nearest neighbors to return for each query. If the dataset contains fewer vectors than the specified count, the result will contain only the available vectors.
214
+ * @param {MetricKind} metric - The distance metric to be used for the search.
215
+ * @return {Matches|BatchMatches} - Returns a `Matches` or `BatchMatches` object containing the results of the search.
216
+ * @throws Will throw an error if `dimensions` and `count` are not positive integers.
217
+ * @throws Will throw an error if `metric` is not a valid MetricKind.
218
+ * @throws Will throw an error if `dataset` and `queries` are not valid input types (TypedArray or an array of arrays).
219
+ * @throws Will throw an error if the sizes of the flattened `dataset` and `queries` are not multiples of `dimensions`.
220
+ * @throws Will throw an error if `count` is greater than the number of vectors in the `dataset`.
221
+ *
222
+ * @example
223
+ * const dataset = [[1.0, 2.0], [3.0, 4.0]]; // Two vectors: [1.0, 2.0] and [3.0, 4.0]
224
+ * const queries = [[1.5, 2.5]]; // One vector: [1.5, 2.5]
225
+ * const dimensions = 2; // The number of elements in each vector.
226
+ * const count = 1; // The number of nearest neighbors to return for each query.
227
+ * const metric = MetricKind.IP; // Using the Inner Product distance metric.
228
+ *
229
+ * const result = exactSearch(dataset, queries, dimensions, count, metric);
230
+ * // result might be:
231
+ * // {
232
+ * // keys: BigUint64Array [ 1n ],
233
+ * // distances: Float32Array [ some_value ],
234
+ * // }
235
+ */
236
+ export function exactSearch(dataset: Float32Array | Float64Array | Int8Array | Array<Array<number>>, queries: Float32Array | Float64Array | Int8Array | Array<Array<number>>, dimensions: number, count: number, metric: MetricKind): Matches | BatchMatches;
237
+ //# sourceMappingURL=usearch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usearch.d.ts","sourceRoot":"","sources":["../usearch.js"],"names":[],"mappings":"AAsIA;IAEI;;;;;;;;;;;OAWG;IACH;oBATkC,MAAM;gBAAU,UAAU;sBAAiC,UAAU;sBAAiC,MAAM;uBAAqB,MAAM;0BAAwB,MAAM;eAAa,OAAO;gBAChN,UAAU,iBACV,UAAU,iBACV,MAAM,kBACN,MAAM,qBACN,MAAM,UACN,OAAO,EAgCjB;IADG,oBAAwI;IAG5I;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,UAPW,MAAM,GAAC,MAAM,EAAE,GAAC,cAAc,WAE9B,YAAY,GAAC,YAAY,GAAC,SAAS,QAoB7C;IAED;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,gBANW,YAAY,GAAC,YAAY,GAAC,SAAS,GAAC,MAAM,MAAM,MAAM,CAAC,CAAC,KACxD,MAAM,GACL,OAAO,GAAC,YAAY,CAqB/B;IAED;;;;;;;;;OASG;IACH,eAJW,MAAM,GAAC,MAAM,EAAE,GAAC,cAAc,GAC7B,OAAO,GAAC,OAAO,EAAE,CAU5B;IAED;;;;;;OAMG;IACH,YAJW,MAAM,GAAC,MAAM,EAAE,GAAC,cAAc,GAC7B,MAAM,GAAC,MAAM,EAAE,CAU1B;IAED;;;;;;;;;OASG;IACH,aAJW,MAAM,GAAC,MAAM,EAAE,GAAC,cAAc,GAC7B,MAAM,GAAC,MAAM,EAAE,CAU1B;IAED;;;OAGG;IACH,cAFY,MAAM,CAEsC;IAExD;;;OAGG;IACH,gBAFY,MAAM,CAE0C;IAE5D;;;OAGG;IACH,QAFY,MAAM,CAE0B;IAE5C;;;OAGG;IACH,YAFY,MAAM,CAEkC;IAEpD;;;;OAIG;IACH,WAHW,MAAM,QAMhB;IAED;;;;OAIG;IACH,WAHW,MAAM,QAMhB;IAED;;;;OAIG;IACH,WAHW,MAAM,QAMhB;CACJ;;;;yBAzWS,MAAM;;;;;;;;;;;;;;;;;yBAmBN,MAAM;;;;;;;;;;AAYhB;;GAEG;AACH;IACI;;;;;OAKG;IACH,kBAHW,cAAc,aACd,YAAY,EAKtB;IAFG,qBAAgB;IAChB,wBAA0B;CAEjC;AAED;;GAEG;AACH;IACI;;;;;;;OAOG;IACH,kBALW,cAAc,aACd,YAAY,UACZ,cAAc,KACd,MAAM,EAOhB;IAJG,qBAAgB;IAChB,wBAA0B;IAC1B,uBAAoB;IACpB,UAAU;IAGd;;;;;OAKG;IACH,OAHW,MAAM,GACJ,OAAO,CAQnB;CACJ;AA4RD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,qCA1BW,YAAY,GAAC,YAAY,GAAC,SAAS,GAAC,MAAM,MAAM,MAAM,CAAC,CAAC,WACxD,YAAY,GAAC,YAAY,GAAC,SAAS,GAAC,MAAM,MAAM,MAAM,CAAC,CAAC,cACxD,MAAM,SACN,MAAM,UACN,UAAU,GACT,OAAO,GAAC,YAAY,CA0D/B"}
@@ -137,7 +137,7 @@ class Index {
137
137
  /**
138
138
  * Constructs a new index.
139
139
  *
140
- * @param {number} dimensionsOrConfigs
140
+ * @param {(number | {dimensions: number, metric: MetricKind = MetricKind.Cos, quantization: ScalarKind = ScalarKind.F32, connectivity: number = 0, expansion_add: number = 0, expansion_search: number = 0, multi: boolean = false})} dimensionsOrConfigs
141
141
  * @param {MetricKind} [metric=MetricKind.Cos] - Optional, default is 'cos'.
142
142
  * @param {ScalarKind} [quantization=ScalarKind.F32] - Optional, default is 'f32'.
143
143
  * @param {number} [connectivity=0] - Optional, default is 0.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "usearch",
3
- "version": "2.8.9",
3
+ "version": "2.8.12",
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",
@@ -25,9 +25,24 @@
25
25
  },
26
26
  "scripts": {
27
27
  "test": "node --test ./javascript/usearch.test.js",
28
- "install": "node-gyp rebuild"
28
+ "install": "node-gyp rebuild",
29
+ "typegen": "npx tsc"
29
30
  },
30
31
  "devDependencies": {
31
32
  "typescript": "^5.1.6"
32
- }
33
+ },
34
+ "exports": {
35
+ ".": {
36
+ "types": "./javascript/types/usearch.d.ts",
37
+ "require": "./javascript/usearch.js"
38
+ },
39
+ "./package.json": "./package.json"
40
+ },
41
+ "typesVersions": {
42
+ "*": {
43
+ "*": [
44
+ "./javascript/types/usearch.d.ts"
45
+ ]
46
+ }
47
+ }
33
48
  }
package/pyproject.toml CHANGED
@@ -9,7 +9,7 @@ xfail_strict = true
9
9
  filterwarnings = ["error"]
10
10
 
11
11
  # Avoid running tests, as everything is happening in a super slow container
12
- # We have already run all the relavent Python tests in `prerelease.yml`
12
+ # We have already run all the relavent Python tests in `prerelease.yml`
13
13
  # test-requires = ["pytest", "numpy"]
14
14
  # test-command = "pytest {project}/python/scripts"
15
15
  [tool.cibuildwheel]
package/setup.py CHANGED
@@ -14,18 +14,8 @@ def get_bool_env(name: str, preference: bool) -> bool:
14
14
  return os.environ.get(name, "1" if preference else "0") == "1"
15
15
 
16
16
 
17
- def get_bool_env_w_name(name: str, preference: bool) -> bool:
18
- return name, get_bool_env(name, preference)
19
-
20
-
21
- def get_is_gcc():
22
- try:
23
- compiler_version = subprocess.check_output(
24
- ["c++", "--version"], universal_newlines=True
25
- )
26
- return "gcc" in compiler_version.lower()
27
- except Exception:
28
- return False
17
+ def get_bool_env_w_name(name: str, preference: bool) -> tuple:
18
+ return name, "1" if get_bool_env(name, preference) else "0"
29
19
 
30
20
 
31
21
  # Check the environment variables
@@ -33,9 +23,23 @@ is_linux: bool = sys.platform == "linux"
33
23
  is_macos: bool = sys.platform == "darwin"
34
24
  is_windows: bool = sys.platform == "win32"
35
25
 
26
+
27
+ is_gcc = False
28
+ if is_linux:
29
+ cxx = os.environ.get("CXX")
30
+ if cxx:
31
+ try:
32
+ command = "where" if os.name == "nt" else "which"
33
+ full_path = subprocess.check_output([command, cxx], text=True).strip()
34
+ compiler_name = os.path.basename(full_path)
35
+ is_gcc = ("g++" in compiler_name) and ("clang++" not in compiler_name)
36
+ except subprocess.CalledProcessError:
37
+ pass
38
+
39
+
36
40
  prefer_simsimd: bool = is_linux or is_macos
37
41
  prefer_fp16lib: bool = True
38
- prefer_openmp: bool = is_linux and get_is_gcc()
42
+ prefer_openmp: bool = is_linux and is_gcc
39
43
 
40
44
  use_simsimd: bool = get_bool_env("USEARCH_USE_SIMSIMD", prefer_simsimd)
41
45
  use_fp16lib: bool = get_bool_env("USEARCH_USE_FP16LIB", prefer_fp16lib)
@@ -123,6 +127,8 @@ if is_windows:
123
127
  ]
124
128
  )
125
129
 
130
+ print("macros_args", macros_args)
131
+
126
132
  ext_modules = [
127
133
  Pybind11Extension(
128
134
  "usearch.compiled",
package/simsimd/README.md CHANGED
@@ -24,6 +24,15 @@ SimSIMD leverages SIMD intrinsics, capabilities that only select compilers effec
24
24
  [scipy]: https://docs.scipy.org/doc/scipy/reference/spatial.distance.html#module-scipy.spatial.distance
25
25
  [numpy]: https://numpy.org/doc/stable/reference/generated/numpy.inner.html
26
26
 
27
+ __Technical Insights__ and related articles:
28
+
29
+ - [Uses Horner's method for polynomial approximations, beating GCC 12 by 119x](https://ashvardanian.com/posts/gcc-12-vs-avx512fp16/).
30
+ - [Uses Arm SVE and x86 AVX-512's masked loads to eliminate tail `for`-loops](https://ashvardanian.com/posts/simsimd-faster-scipy/#tails-of-the-past-the-significance-of-masked-loads).
31
+ - [Uses AVX-512 FP16 for half-precision operations, that few compilers vectorize](https://ashvardanian.com/posts/simsimd-faster-scipy/#the-challenge-of-f16).
32
+ - [Substitutes LibC's `sqrt` calls with bithacks using Jan Kadlec's constant](https://ashvardanian.com/posts/simsimd-faster-scipy/#bonus-section-bypassing-sqrt-and-libc-dependencies).
33
+ - [For Python avoids slow PyBind11, SWIG, and even `PyArg_ParseTuple` for speed](https://ashvardanian.com/posts/pybind11-cpython-tutorial/).
34
+ - [For JavaScript uses typed arrays and NAPI for zero-copy calls](https://ashvardanian.com/posts/javascript-ai-vector-search/).
35
+
27
36
  ## Benchmarks
28
37
 
29
38
  ### Apple M2 Pro
@@ -48,14 +57,6 @@ On the Intel Sapphire Rapids platform, SimSIMD was benchmarked against auto-vect
48
57
  | Inner Product | 3.81 M/s | _192.02 k/s_ | _5.99 M/s_ | __31 x__ |
49
58
  | Jensen Shannon | 1.18 M/s | _18.13 k/s_ | _2.14 M/s_ | __118 x__ |
50
59
 
51
- __Technical Insights__:
52
-
53
- - [Uses Arm SVE and x86 AVX-512's masked loads to eliminate tail `for`-loops](https://ashvardanian.com/posts/simsimd-faster-scipy/#tails-of-the-past-the-significance-of-masked-loads).
54
- - [Uses AVX-512 FP16 for half-precision operations, that few compilers vectorize](https://ashvardanian.com/posts/simsimd-faster-scipy/#the-challenge-of-f16).
55
- - [Substitutes LibC's `sqrt` calls with bithacks using Jan Kadlec's constant](https://ashvardanian.com/posts/simsimd-faster-scipy/#bonus-section-bypassing-sqrt-and-libc-dependencies).
56
- - Avoids slow PyBind11 and SWIG, directly using the CPython C API.
57
- - Avoids slow `PyArg_ParseTuple` and manually unpacks argument tuples.
58
-
59
60
  __Broader Benchmarking Results__:
60
61
 
61
62
  - [Apple M2 Pro](https://ashvardanian.com/posts/simsimd-faster-scipy/#appendix-1-performance-on-apple-m2-pro).
@@ -17,8 +17,9 @@
17
17
  * x86 intrinsics: https://www.intel.com/content/www/us/en/docs/intrinsics-guide/
18
18
  * Arm intrinsics: https://developer.arm.com/architectures/instruction-sets/intrinsics/
19
19
  */
20
+ #ifndef SIMSIMD_BINARY_H
21
+ #define SIMSIMD_BINARY_H
20
22
 
21
- #pragma once
22
23
  #include "types.h"
23
24
 
24
25
  #ifdef __cplusplus
@@ -195,4 +196,6 @@ simsimd_avx512_b8_jaccard_cycle:
195
196
 
196
197
  #ifdef __cplusplus
197
198
  }
198
- #endif
199
+ #endif
200
+
201
+ #endif
@@ -18,8 +18,9 @@
18
18
  * x86 intrinsics: https://www.intel.com/content/www/us/en/docs/intrinsics-guide/
19
19
  * Arm intrinsics: https://developer.arm.com/architectures/instruction-sets/intrinsics/
20
20
  */
21
+ #ifndef SIMSIMD_PROBABILITY_H
22
+ #define SIMSIMD_PROBABILITY_H
21
23
 
22
- #pragma once
23
24
  #include "types.h"
24
25
 
25
26
  #define SIMSIMD_MAKE_KL(name, input_type, accumulator_type, converter, epsilon) \
@@ -539,4 +540,6 @@ simsimd_avx512_f16_js_cycle:
539
540
 
540
541
  #ifdef __cplusplus
541
542
  }
542
- #endif
543
+ #endif
544
+
545
+ #endif
@@ -11,7 +11,9 @@
11
11
  * Detecting target CPU features at compile time: https://stackoverflow.com/a/28939692/2766161
12
12
  */
13
13
 
14
- #pragma once
14
+ #ifndef SIMSIMD_SIMSIMD_H
15
+ #define SIMSIMD_SIMSIMD_H
16
+
15
17
  #include "binary.h" // Hamming, Jaccard
16
18
  #include "probability.h" // Kullback-Leibler, Jensen–Shannon
17
19
  #include "spatial.h" // L2, Inner Product, Cosine
@@ -423,3 +425,5 @@ inline static simsimd_metric_punned_t simsimd_metric_punned( //
423
425
  #ifdef __cplusplus
424
426
  }
425
427
  #endif
428
+
429
+ #endif
@@ -20,8 +20,9 @@
20
20
  * x86 intrinsics: https://www.intel.com/content/www/us/en/docs/intrinsics-guide/
21
21
  * Arm intrinsics: https://developer.arm.com/architectures/instruction-sets/intrinsics/
22
22
  */
23
+ #ifndef SIMSIMD_SPATIAL_H
24
+ #define SIMSIMD_SPATIAL_H
23
25
 
24
- #pragma once
25
26
  #include "types.h"
26
27
 
27
28
  #define SIMSIMD_MAKE_L2SQ(name, input_type, accumulator_type, converter) \
@@ -1000,4 +1001,6 @@ simsimd_avx512_i8_ip(simsimd_i8_t const* a, simsimd_i8_t const* b, simsimd_size_
1000
1001
 
1001
1002
  #ifdef __cplusplus
1002
1003
  }
1004
+ #endif
1005
+
1003
1006
  #endif
@@ -1,67 +1,59 @@
1
- #pragma once
1
+ #ifndef SIMSIMD_TYPES_H
2
+ #define SIMSIMD_TYPES_H
2
3
 
3
4
  // Compiling for Arm: SIMSIMD_TARGET_ARM
5
+ #if !defined(SIMSIMD_TARGET_ARM)
4
6
  #if defined(__aarch64__) || defined(_M_ARM64)
5
7
  #define SIMSIMD_TARGET_ARM 1
8
+ #else
9
+ #define SIMSIMD_TARGET_ARM 0
10
+ #endif // defined(__aarch64__) || defined(_M_ARM64)
11
+ #endif // !defined(SIMSIMD_TARGET_ARM)
12
+
13
+ // Compiling for x86: SIMSIMD_TARGET_X86
14
+ #if !defined(SIMSIMD_TARGET_X86)
15
+ #if defined(__x86_64__) || defined(_M_X64)
16
+ #define SIMSIMD_TARGET_X86 1
17
+ #else
18
+ #define SIMSIMD_TARGET_X86 0
19
+ #endif // defined(__x86_64__) || defined(_M_X64)
20
+ #endif // !defined(SIMSIMD_TARGET_X86)
6
21
 
7
22
  // Compiling for Arm: SIMSIMD_TARGET_ARM_NEON
8
- #if !defined(SIMSIMD_TARGET_ARM_NEON)
23
+ #if !defined(SIMSIMD_TARGET_ARM_NEON) || !SIMSIMD_TARGET_ARM
9
24
  #if defined(__ARM_NEON)
10
- #define SIMSIMD_TARGET_ARM_NEON 1
25
+ #define SIMSIMD_TARGET_ARM_NEON SIMSIMD_TARGET_ARM
11
26
  #else
12
27
  #define SIMSIMD_TARGET_ARM_NEON 0
13
- #endif
14
- #endif
28
+ #endif // defined(__ARM_NEON)
29
+ #endif // !defined(SIMSIMD_TARGET_ARM_NEON)
15
30
 
16
31
  // Compiling for Arm: SIMSIMD_TARGET_ARM_SVE
17
- #if !defined(SIMSIMD_TARGET_ARM_SVE)
32
+ #if !defined(SIMSIMD_TARGET_ARM_SVE) || !SIMSIMD_TARGET_ARM
18
33
  #if defined(__ARM_FEATURE_SVE)
19
- #define SIMSIMD_TARGET_ARM_SVE 1
34
+ #define SIMSIMD_TARGET_ARM_SVE SIMSIMD_TARGET_ARM
20
35
  #else
21
36
  #define SIMSIMD_TARGET_ARM_SVE 0
22
- #endif
23
- #endif
24
-
25
- #undef SIMSIMD_TARGET_X86
26
- #undef SIMSIMD_TARGET_X86_AVX2
27
- #undef SIMSIMD_TARGET_X86_AVX512
28
- #define SIMSIMD_TARGET_X86 0
29
- #define SIMSIMD_TARGET_X86_AVX2 0
30
- #define SIMSIMD_TARGET_X86_AVX512 0
31
-
32
- // Compiling for x86: SIMSIMD_TARGET_X86
33
- #elif defined(__x86_64__) || defined(_M_X64)
34
- #define SIMSIMD_TARGET_X86 1
37
+ #endif // defined(__ARM_FEATURE_SVE)
38
+ #endif // !defined(SIMSIMD_TARGET_ARM_SVE)
35
39
 
36
40
  // Compiling for x86: SIMSIMD_TARGET_X86_AVX2
37
- #if !defined(SIMSIMD_TARGET_X86_AVX2)
41
+ #if !defined(SIMSIMD_TARGET_X86_AVX2) || !SIMSIMD_TARGET_X86
38
42
  #if defined(__AVX2__)
39
43
  #define SIMSIMD_TARGET_X86_AVX2 1
40
44
  #else
41
45
  #define SIMSIMD_TARGET_X86_AVX2 0
42
- #endif
43
- #endif
46
+ #endif // defined(__AVX2__)
47
+ #endif // !defined(SIMSIMD_TARGET_X86_AVX2)
44
48
 
45
49
  // Compiling for x86: SIMSIMD_TARGET_X86_AVX512
46
- #if !defined(SIMSIMD_TARGET_X86_AVX512)
47
- #if defined(__AVX512F__) || defined(__AVX512VPOPCNTDQ__)
50
+ #if !defined(SIMSIMD_TARGET_X86_AVX512) || !SIMSIMD_TARGET_X86
51
+ #if defined(__AVX512F__) && defined(__AVX512FP16__) && defined(__AVX512VNNI__) && defined(__AVX512VPOPCNTDQ__)
48
52
  #define SIMSIMD_TARGET_X86_AVX512 1
49
53
  #else
50
54
  #define SIMSIMD_TARGET_X86_AVX512 0
51
- #endif
52
- #endif
53
-
54
- #undef SIMSIMD_TARGET_ARM
55
- #undef SIMSIMD_TARGET_ARM_NEON
56
- #undef SIMSIMD_TARGET_ARM_SVE
57
- #define SIMSIMD_TARGET_ARM 0
58
- #define SIMSIMD_TARGET_ARM_NEON 0
59
- #define SIMSIMD_TARGET_ARM_SVE 0
60
-
61
- // Compiling for unknown hardware architecture
62
- #else
63
- #error Unknown hardware architecture!
64
- #endif
55
+ #endif // defined(__AVX512F__) && defined(__AVX512FP16__) && defined(__AVX512VNNI__) && defined(__AVX512VPOPCNTDQ__)
56
+ #endif // !defined(SIMSIMD_TARGET_X86_AVX512)
65
57
 
66
58
  #ifdef _MSC_VER
67
59
  #include <intrin.h>
@@ -206,4 +198,6 @@ inline static float simsimd_uncompress_f16(unsigned short x) {
206
198
 
207
199
  #ifdef __cplusplus
208
200
  } // extern "C"
209
- #endif
201
+ #endif
202
+
203
+ #endif
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "simsimd",
3
- "version": "3.5.4",
3
+ "version": "3.5.5",
4
4
  "description": "Vector Similarity Functions 3x-200x Faster than SciPy and NumPy",
5
5
  "author": "Ash Vardanian",
6
6
  "license": "Apache 2.0",
package/tsconfig.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ // Change this to match your project
3
+ "include": ["javascript/usearch.js"],
4
+ "compilerOptions": {
5
+ // Tells TypeScript to read JS files, as
6
+ // normally they are ignored as source files
7
+ "allowJs": true,
8
+ // Generate d.ts files
9
+ "declaration": true,
10
+ // This compiler run should
11
+ // only output d.ts files
12
+ "emitDeclarationOnly": true,
13
+ // Types should go into this directory.
14
+ // Removing this would place the .d.ts files
15
+ // next to the .js files
16
+ "outDir": "javascript/types",
17
+ // go to js file when using IDE functions like
18
+ // "Go to Definition" in VSCode
19
+ "declarationMap": true
20
+ }
21
+ }
package/wasmer.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name="unum/usearch"
3
- version="2.8.9"
3
+ version="2.8.12"
4
4
  description="Smaller & Faster Single-File Vector Search Engine from Unum"
5
5
  license="Apache-2.0"
6
6
  readme="README.md"