usearch 2.8.7 → 2.8.9

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 (113) hide show
  1. package/CITATION.cff +1 -1
  2. package/CMakeLists.txt +3 -3
  3. package/CONTRIBUTING.md +26 -3
  4. package/Cargo.toml +1 -1
  5. package/Dockerfile +16 -0
  6. package/README.md +41 -38
  7. package/VERSION +1 -0
  8. package/binding.gyp +57 -8
  9. package/conanfile.py +1 -1
  10. package/include/usearch/index.hpp +1 -1
  11. package/include/usearch/index_plugins.hpp +28 -24
  12. package/javascript/README.md +64 -12
  13. package/javascript/lib.cpp +11 -3
  14. package/javascript/usearch.js +4 -2
  15. package/javascript/usearch.test.js +15 -0
  16. package/package.json +1 -2
  17. package/setup.py +76 -15
  18. package/simsimd/README.md +14 -13
  19. package/simsimd/include/simsimd/probability.h +2 -2
  20. package/simsimd/package.json +1 -1
  21. package/wasmer.toml +1 -1
  22. package/. npmignore +0 -14
  23. package/.gitignore +0 -95
  24. package/.vscode/launch.json +0 -181
  25. package/.vscode/settings.json +0 -180
  26. package/.vscode/tasks.json +0 -71
  27. package/Package.swift +0 -41
  28. package/csharp/.editorconfig +0 -361
  29. package/csharp/Cloud.Unum.USearch.sln +0 -34
  30. package/csharp/DEV_SETUP.md +0 -51
  31. package/csharp/Directory.Build.props +0 -29
  32. package/csharp/README.md +0 -74
  33. package/csharp/build_and_test.cmd +0 -31
  34. package/csharp/build_and_test.sh +0 -30
  35. package/csharp/nuget/nuget-package.props +0 -33
  36. package/csharp/pack.sh +0 -56
  37. package/csharp/src/Cloud.Unum.USearch.Tests/Cloud.Unum.USearch.Tests.csproj +0 -39
  38. package/csharp/src/Cloud.Unum.USearch.Tests/USearchIndexTests.cs +0 -1013
  39. package/csharp/src/Cloud.Unum.USearch.Tests/Usings.cs +0 -1
  40. package/docs/_static/custom.css +0 -26
  41. package/docs/_static/custom.js +0 -7
  42. package/docs/benchmarks.md +0 -245
  43. package/docs/benchmarks.rst +0 -5
  44. package/docs/c/index.rst +0 -11
  45. package/docs/c/reference.rst +0 -7
  46. package/docs/conf.dox +0 -2668
  47. package/docs/conf.py +0 -53
  48. package/docs/contributing.rst +0 -5
  49. package/docs/cpp/index.rst +0 -11
  50. package/docs/cpp/reference.rst +0 -17
  51. package/docs/csharp/index.rst +0 -6
  52. package/docs/format.md +0 -86
  53. package/docs/format.rst +0 -5
  54. package/docs/golang/index.rst +0 -6
  55. package/docs/index.rst +0 -33
  56. package/docs/java/index.rst +0 -11
  57. package/docs/java/reference.rst +0 -7
  58. package/docs/javascript/index.rst +0 -11
  59. package/docs/javascript/reference.rst +0 -12
  60. package/docs/python/index.rst +0 -11
  61. package/docs/python/reference.rst +0 -42
  62. package/docs/rust/index.rst +0 -6
  63. package/docs/swift/index.rst +0 -6
  64. package/docs/wolfram/index.rst +0 -6
  65. package/golang/README.md +0 -95
  66. package/golang/go.mod +0 -3
  67. package/golang/lib.go +0 -379
  68. package/golang/lib_test.go +0 -108
  69. package/java/README.md +0 -22
  70. package/java/cloud/unum/usearch/Index.java +0 -337
  71. package/java/cloud/unum/usearch/cloud_unum_usearch_Index.cpp +0 -197
  72. package/java/cloud/unum/usearch/cloud_unum_usearch_Index.h +0 -125
  73. package/java/test/IndexTest.java +0 -30
  74. package/objc/USearchObjective.mm +0 -299
  75. package/objc/include/USearchObjective.h +0 -154
  76. package/python/README.md +0 -292
  77. package/python/lib.cpp +0 -1216
  78. package/python/scripts/bench.ipynb +0 -193
  79. package/python/scripts/bench.py +0 -137
  80. package/python/scripts/bench_exact.py +0 -44
  81. package/python/scripts/cluster.ipynb +0 -160
  82. package/python/scripts/index_faiss.py +0 -100
  83. package/python/scripts/join.py +0 -155
  84. package/python/scripts/test_index.py +0 -247
  85. package/python/scripts/test_jit.py +0 -231
  86. package/python/scripts/test_sparse.py +0 -32
  87. package/python/scripts/test_tooling.py +0 -133
  88. package/python/usearch/__init__.py +0 -0
  89. package/python/usearch/client.py +0 -124
  90. package/python/usearch/eval.py +0 -470
  91. package/python/usearch/index.py +0 -1401
  92. package/python/usearch/io.py +0 -113
  93. package/python/usearch/numba.py +0 -121
  94. package/python/usearch/server.py +0 -137
  95. package/rust/README.md +0 -66
  96. package/rust/lib.cpp +0 -136
  97. package/rust/lib.hpp +0 -69
  98. package/rust/lib.rs +0 -610
  99. package/simsimd/CMakeLists.txt +0 -67
  100. package/simsimd/cpp/bench.cxx +0 -206
  101. package/simsimd/package-ci.json +0 -10
  102. package/simsimd/setup.py +0 -86
  103. package/swift/Index+Sugar.swift +0 -153
  104. package/swift/README.md +0 -48
  105. package/swift/Test.swift +0 -37
  106. package/swift/USearch.swift +0 -8
  107. package/wasm/CMakeLists.txt +0 -7
  108. package/wasm/README.md +0 -13
  109. package/wasm/lib.cpp +0 -5
  110. package/wolfram/CMakeLists.txt +0 -18
  111. package/wolfram/README.md +0 -13
  112. package/wolfram/lib.cpp +0 -160
  113. package/wolfram/test.wls +0 -27
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.7
8
+ version: 2.8.9
9
9
  doi: 10.5281/zenodo.7949416
10
10
  date-released: 2023-10-22
11
11
  url: "https://github.com/unum-cloud/usearch"
package/CMakeLists.txt CHANGED
@@ -19,7 +19,7 @@ option(USEARCH_INSTALL "Install CMake targets" OFF)
19
19
  option(USEARCH_USE_OPENMP "Use OpenMP for a thread pool" OFF)
20
20
  option(USEARCH_USE_SIMSIMD "Use SimSIMD hardware-accelerated metrics" OFF)
21
21
  option(USEARCH_USE_JEMALLOC "Use JeMalloc for faster memory allocations" OFF)
22
- option(USEARCH_USE_NATIVE_F16 "Use native half-precision types" OFF)
22
+ option(USEARCH_USE_FP16LIB "Use software emulation for half-precision types" ON)
23
23
 
24
24
  option(USEARCH_BUILD_TEST_CPP "Compile a native unit test in C++" ${USEARCH_IS_MAIN_PROJECT})
25
25
  option(USEARCH_BUILD_BENCH_CPP "Compile a native benchmark in C++" ${USEARCH_IS_MAIN_PROJECT})
@@ -69,7 +69,7 @@ target_compile_definitions(
69
69
 
70
70
  # Supplementary compilation settings affecting "index_plugins.hpp"
71
71
  target_compile_definitions(
72
- ${USEARCH_TARGET_NAME} INTERFACE $<$<NOT:$<BOOL:${USEARCH_USE_NATIVE_F16}>>:USEARCH_USE_NATIVE_F16=0>
72
+ ${USEARCH_TARGET_NAME} INTERFACE $<$<NOT:$<BOOL:${USEARCH_USE_FP16LIB}>>:USEARCH_USE_FP16LIB=1>
73
73
  )
74
74
 
75
75
  target_compile_definitions(
@@ -302,7 +302,7 @@ function (setup_target TARGET_NAME)
302
302
 
303
303
  # Supplementary compilation settings affecting "index_plugins.hpp"
304
304
  target_compile_definitions(
305
- ${TARGET_NAME} PRIVATE $<$<NOT:$<BOOL:${USEARCH_USE_NATIVE_F16}>>:USEARCH_USE_NATIVE_F16=0>
305
+ ${TARGET_NAME} PRIVATE $<$<NOT:$<BOOL:${USEARCH_USE_FP16LIB}>>:USEARCH_USE_FP16LIB=1>
306
306
  )
307
307
 
308
308
  target_compile_definitions(${TARGET_NAME} PRIVATE $<$<NOT:$<BOOL:${USEARCH_USE_SIMSIMD}>>:USEARCH_USE_SIMSIMD=0>)
package/CONTRIBUTING.md CHANGED
@@ -49,7 +49,7 @@ The CMakeLists.txt file has a number of options you can pass:
49
49
  - `USEARCH_USE_OPENMP` - use OpenMP for parallelism
50
50
  - `USEARCH_USE_SIMSIMD` - use SimSIMD for vectorization
51
51
  - `USEARCH_USE_JEMALLOC` - use Jemalloc for memory management
52
- - `USEARCH_USE_NATIVE_F16` - use native half-precision floating point
52
+ - `USEARCH_USE_FP16LIB` - use software emulation for half-precision floating point
53
53
 
54
54
  Putting all of this together on Ubuntu and compiling the "release" version using the GCC 12 compiler:
55
55
 
@@ -58,7 +58,7 @@ cmake \
58
58
  -DCMAKE_BUILD_TYPE=Release \
59
59
  -DCMAKE_C_COMPILER=gcc-12 \
60
60
  -DCMAKE_CXX_COMPILER=g++-12 \
61
- -DUSEARCH_USE_NATIVE_F16=1 \
61
+ -DUSEARCH_USE_FP16LIB=1 \
62
62
  -DUSEARCH_USE_OPENMP=1 \
63
63
  -DUSEARCH_USE_SIMSIMD=1 \
64
64
  -DUSEARCH_USE_JEMALLOC=1 \
@@ -80,7 +80,7 @@ cmake \
80
80
  -DCMAKE_BUILD_TYPE=Release \
81
81
  -DCMAKE_C_COMPILER="/opt/homebrew/opt/llvm/bin/clang" \
82
82
  -DCMAKE_CXX_COMPILER="/opt/homebrew/opt/llvm/bin/clang++" \
83
- -DUSEARCH_USE_NATIVE_F16=1 \
83
+ -DUSEARCH_USE_FP16LIB=1 \
84
84
  -DUSEARCH_USE_OPENMP=1 \
85
85
  -DUSEARCH_USE_SIMSIMD=1 \
86
86
  -DUSEARCH_USE_JEMALLOC=1 \
@@ -144,6 +144,29 @@ node --test ./javascript/usearch.test.js
144
144
  npm publish
145
145
  ```
146
146
 
147
+ To compile for AWS Lambda you'd need to recompile the binding.
148
+ You can test the setup locally, overriding some of the compilation variables in Docker image:
149
+
150
+ ```Dockerfile
151
+ FROM public.ecr.aws/lambda/nodejs:18-x86_64
152
+ RUN npm init -y
153
+ RUN yum install tar git python3 cmake gcc-c++ -y && yum groupinstall "Development Tools" -y
154
+
155
+ # Assuming AWS Linux 2 uses old compilers:
156
+ ENV USEARCH_USE_FP16LIB 1
157
+ ENV DUSEARCH_USE_SIMSIMD 1
158
+ ENV SIMSIMD_TARGET_X86_AVX2 1
159
+ ENV SIMSIMD_TARGET_X86_AVX512 0
160
+ ENV SIMSIMD_TARGET_ARM_NEON 1
161
+ ENV SIMSIMD_TARGET_ARM_SVE 0
162
+
163
+ # For specific PR:
164
+ # RUN npm install --build-from-source unum-cloud/usearch#pull/302/head
165
+ # For specific version:
166
+ # RUN npm install --build-from-source usearch@2.8.8
167
+ RUN npm install --build-from-source usearch
168
+ ```
169
+
147
170
  To compile to WebAssembly make sure you have `emscripten` installed and run the following script:
148
171
 
149
172
  ```sh
package/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "usearch"
3
- version = "2.8.7"
3
+ version = "2.8.9"
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/Dockerfile ADDED
@@ -0,0 +1,16 @@
1
+ # syntax=docker/dockerfile:1
2
+
3
+ FROM ubuntu:23.04
4
+ ENV DEBIAN_FRONTEND=noninteractive
5
+
6
+ RUN apt-get update && \
7
+ apt-get install -y --no-install-recommends python3.11 python3-pip && \
8
+ apt-get clean && \
9
+ rm -rf /var/lib/apt/lists/*
10
+ RUN pip3 install --no-cache-dir --break-system-packages ucall usearch
11
+
12
+ WORKDIR /usearch
13
+ COPY python/usearch/server.py server.py
14
+
15
+ ENTRYPOINT ["python3", "./server.py"]
16
+ EXPOSE 8545
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  <h1 align="center">USearch</h1>
2
2
  <h3 align="center">
3
- Smaller & <a href="https://www.unum.cloud/blog/2023-11-11-scaling-vector-search">Faster</a> Single-File<br/>
3
+ Smaller & <a href="https://www.unum.cloud/blog/2023-11-07-scaling-vector-search-with-intel">Faster</a> Single-File<br/>
4
4
  Similarity Search Engine for <a href="https://github.com/ashvardanian/simsimd">Vectors</a> & 🔜 <a href="https://github.com/ashvardanian/stringzilla">Texts</a>
5
5
  </h3>
6
6
  <br/>
@@ -47,7 +47,7 @@ Linux • MacOS • Windows • iOS • WebAssembly
47
47
 
48
48
  ---
49
49
 
50
- - ✅ 10x faster than [FAISS][faiss] implementation of [HNSW algorithm][hnsw-algorithm].
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
53
  - ✅ [SIMD][simd]-optimized and [user-defined metrics](#user-defined-functions) with JIT compilation.
@@ -57,7 +57,7 @@ Linux • MacOS • Windows • iOS • WebAssembly
57
57
  - ✅ Variable dimensionality vectors for unique applications, including search over compressed data.
58
58
  - ✅ Binary Tanimoto and Sorensen coefficients for [Genomics and Chemistry applications](#usearch--rdkit--molecular-search).
59
59
  - ✅ Space-efficient point-clouds with `uint40_t`, accommodating 4B+ size.
60
- - ✅ Compatible with OpenMP and custom "executors", for fine-grained control over CPU utilization.
60
+ - ✅ Compatible with OpenMP and custom "executors" for fine-grained control over CPU utilization.
61
61
  - ✅ Near-real-time [clustering and sub-clustering](#clustering) for Tens or Millions of clusters.
62
62
  - ✅ [Semantic Search](#usearch--ai--multi-modal-semantic-search) and [Joins](#joins).
63
63
 
@@ -66,6 +66,7 @@ Linux • MacOS • Windows • iOS • WebAssembly
66
66
  [obscure-use-cases]: https://ashvardanian.com/posts/abusing-vector-search
67
67
  [hnsw-algorithm]: https://arxiv.org/abs/1603.09320
68
68
  [simd]: https://en.wikipedia.org/wiki/Single_instruction,_multiple_data
69
+ [faster-than-faiss]: https://www.unum.cloud/blog/2023-11-07-scaling-vector-search-with-intel
69
70
 
70
71
  ## Comparison with FAISS
71
72
 
@@ -73,22 +74,22 @@ FAISS is a widely recognized standard for high-performance vector search engines
73
74
  USearch and FAISS both employ the same HNSW algorithm, but they differ significantly in their design principles.
74
75
  USearch is compact and broadly compatible without sacrificing performance, primarily focusing on user-defined metrics and fewer dependencies.
75
76
 
76
- | | FAISS | USearch | Improvement |
77
- | :------------------------------------------- | ----------------------------: | -----------------------------: | -----------------------: |
78
- | Indexing time | | | |
79
- | 100 Million 96d `f32`, `f16`, `i8` vectors | 2.6 h, 2.6 h, 2.6 h | 0.3 h, 0.2 h, 0.2 h | __9.6x, 10.4x, 10.7x__ ⁰ |
80
- | 100 Million 1536d `f32`, `f16`, `i8` vectors | 5.0 h, 4.1 h, 3.8 h | 2.1 h, 1.1 h, 0.8 h | __2.3x 3.6x, 4.4x__ ⁰ |
81
- | | | | |
82
- | Codebase length | 84 K [SLOC][sloc] in `faiss/` | 3 K [SLOC][sloc] in `usearch/` | maintainable ¹ |
83
- | Supported metrics | 9 fixed metrics | any user-defined metrics | extendible ² |
84
- | Supported languages | C++, Python | 10 languages | portable ³ |
85
- | Supported ID types | 32-bit, 64-bit | 32-bit, 40-bit, 64-bit | efficient ⁴ |
86
- | Required dependencies | BLAS, OpenMP | - | light-weight ⁵ |
87
- | Bindings | SWIG | Native | low-latency ⁶ |
77
+ | | FAISS | USearch | Improvement |
78
+ | :------------------------------------------- | ----------------------------: | -----------------------------: | ---------------------: |
79
+ | Indexing time ⁰ | | | |
80
+ | 100 Million 96d `f32`, `f16`, `i8` vectors | 2.6 h, 2.6 h, 2.6 h | 0.3 h, 0.2 h, 0.2 h | __9.6x, 10.4x, 10.7x__ |
81
+ | 100 Million 1536d `f32`, `f16`, `i8` vectors | 5.0 h, 4.1 h, 3.8 h | 2.1 h, 1.1 h, 0.8 h | __2.3x 3.6x, 4.4x__ |
82
+ | | | | |
83
+ | Codebase length ¹ | 84 K [SLOC][sloc] in `faiss/` | 3 K [SLOC][sloc] in `usearch/` | maintainable |
84
+ | Supported metrics ² | 9 fixed metrics | any user-defined metrics | extendible |
85
+ | Supported languages ³ | C++, Python | 10 languages | portable |
86
+ | Supported ID types ⁴ | 32-bit, 64-bit | 32-bit, 40-bit, 64-bit | efficient |
87
+ | Required dependencies ⁵ | BLAS, OpenMP | - | light-weight |
88
+ | Bindings ⁶ | SWIG | Native | low-latency |
88
89
 
89
90
  [sloc]: https://en.wikipedia.org/wiki/Source_lines_of_code
90
91
 
91
- > ⁰ [Tested][intel-benchmarks] on Intel Sapphire Rapids, with the simplest inner-product distance, equivalent recall, and memory consumption, while also providing far superior search speed.
92
+ > ⁰ [Tested][intel-benchmarks] on Intel Sapphire Rapids, with the simplest inner-product distance, equivalent recall, and memory consumption while also providing far superior search speed.
92
93
  > ¹ A shorter codebase makes the project easier to maintain and audit.
93
94
  > ² User-defined metrics allow you to customize your search for various applications, from GIS to creating custom metrics for composite embeddings from multiple AI models or hybrid full-text and semantic search.
94
95
  > ³ With USearch, you can reuse the same preconstructed index in various programming languages.
@@ -96,12 +97,12 @@ USearch is compact and broadly compatible without sacrificing performance, prima
96
97
  > ⁵ Lack of obligatory dependencies makes USearch much more portable.
97
98
  > ⁶ Native bindings introduce lower call latencies than more straightforward approaches.
98
99
 
99
- [intel-benchmarks]: https://www.unum.cloud/blog/2023-11-11-scaling-vector-search
100
+ [intel-benchmarks]: https://www.unum.cloud/blog/2023-11-07-scaling-vector-search-with-intel
100
101
 
101
102
  Base functionality is identical to FAISS, and the interface must be familiar if you have ever investigated Approximate Nearest Neighbors search:
102
103
 
103
104
  ```py
104
- $ pip install usearch
105
+ $ pip install numpy usearch
105
106
 
106
107
  import numpy as np
107
108
  from usearch.index import Index
@@ -125,16 +126,16 @@ index = Index(
125
126
  ndim=3, # Define the number of dimensions in input vectors
126
127
  metric='cos', # Choose 'l2sq', 'haversine' or other metric, default = 'ip'
127
128
  dtype='f32', # Quantize to 'f16' or 'i8' if needed, default = 'f32'
128
- connectivity=16, # Optional: How frequent should the connections in the graph be
129
+ connectivity=16, # Optional: Limit number of neighbors per graph node
129
130
  expansion_add=128, # Optional: Control the recall of indexing
130
- expansion_search=64, # Optional: Control the quality of search
131
+ expansion_search=64, # Optional: Control the quality of the search
131
132
  )
132
133
  ```
133
134
 
134
135
  ## User-Defined Functions
135
136
 
136
- While most vector search packages concentrate on just a couple of metrics - "Inner Product distance" and "Euclidean distance," USearch extends this list to include any user-defined metrics.
137
- This flexibility allows you to customize your search for a myriad of applications, from computing geo-spatial coordinates with the rare [Haversine][haversine] distance to creating custom metrics for composite embeddings from multiple AI models.
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.
138
139
 
139
140
  ![USearch: Vector Search Approaches](https://github.com/unum-cloud/usearch/blob/main/assets/usearch-approaches-white.png?raw=true)
140
141
 
@@ -165,7 +166,7 @@ USearch supports multiple forms of serialization:
165
166
 
166
167
  - Into a __file__ defined with a path.
167
168
  - Into a __stream__ defined with a callback, serializing or reconstructing incrementally.
168
- - Into a __buffer__ of fixed length, or a memory-mapped file, that supports random access.
169
+ - Into a __buffer__ of fixed length or a memory-mapped file that supports random access.
169
170
 
170
171
  The latter allows you to serve indexes from external memory, enabling you to optimize your server choices for indexing speed and serving costs.
171
172
  This can result in __20x cost reduction__ on AWS and other public clouds.
@@ -198,7 +199,7 @@ one_in_many: Matches = search(vectors, vector, 50, MetricKind.L2sq, exact=True)
198
199
  many_in_many: BatchMatches = search(vectors, vectors, 50, MetricKind.L2sq, exact=True)
199
200
  ```
200
201
 
201
- By passing the `exact=True` argument, the system bypasses indexing altogether and performs a brute-force search through the entire dataset using SIMD-optimized similarity metrics from [SimSIMD](https://github.com/ashvardanian/simsimd).
202
+ If you pass the `exact=True` argument, the system bypasses indexing altogether and performs a brute-force search through the entire dataset using SIMD-optimized similarity metrics from [SimSIMD](https://github.com/ashvardanian/simsimd).
202
203
  When compared to FAISS's `IndexFlatL2` in Google Colab, __[USearch may offer up to a 20x performance improvement](https://github.com/unum-cloud/usearch/issues/176#issuecomment-1666650778)__:
203
204
 
204
205
  - `faiss.IndexFlatL2`: __55.3 ms__.
@@ -207,7 +208,7 @@ When compared to FAISS's `IndexFlatL2` in Google Colab, __[USearch may offer up
207
208
  ## `Indexes` for Multi-Index Lookups
208
209
 
209
210
  For larger workloads targeting billions or even trillions of vectors, parallel multi-index lookups become invaluable.
210
- These lookups prevent the need to construct a single, massive index, allowing users to query multiple smaller ones instead.
211
+ Instead of constructing one extensive index, you can build multiple smaller ones and view them together.
211
212
 
212
213
  ```py
213
214
  from usearch.index import Indexes
@@ -223,8 +224,8 @@ multi_index.search(...)
223
224
 
224
225
  ## Clustering
225
226
 
226
- Once the index is constructed, it can be used to cluster entries much faster.
227
- In essence, the `Index` itself can be seen as a clustering, and it allows iterative deepening.
227
+ Once the index is constructed, it can cluster entries much faster than using a separate clustering algorithm implementation.
228
+ Essentially, the `Index` itself can be seen as a clustering, allowing iterative deepening.
228
229
 
229
230
  ```py
230
231
  clustering = index.cluster(
@@ -236,7 +237,7 @@ clustering = index.cluster(
236
237
  # Get the clusters and their sizes
237
238
  centroid_keys, sizes = clustering.centroids_popularity
238
239
 
239
- # Use Matplotlib draw a histogram
240
+ # Use Matplotlib to draw a histogram
240
241
  clustering.plot_centroids_popularity()
241
242
 
242
243
  # Export a NetworkX graph of the clusters
@@ -245,24 +246,26 @@ g = clustering.network
245
246
  # Get members of a specific cluster
246
247
  first_members = clustering.members_of(centroid_keys[0])
247
248
 
248
- # Deepen into that cluster splitting it into more parts, all same arguments supported
249
+ # Deepen into that cluster, splitting it into more parts, all the same arguments supported
249
250
  sub_clustering = clustering.subcluster(min_count=..., max_count=...)
250
251
  ```
251
252
 
252
- Using Scikit-Learn, on a 1 Million point dataset, one may expect queries to take anywhere from minutes to hours, depending on the number of clusters you want to highlight. For 50'000 clusters the performance difference between USearch and conventional clustering methods may easily reach 100x.
253
+ The resulting clustering isn't identical to K-Means or other conventional approaches but serves the same purpose.
254
+ Alternatively, using Scikit-Learn on a 1 Million point dataset, one may expect queries to take anywhere from minutes to hours, depending on the number of clusters you want to highlight.
255
+ For 50'000 clusters, the performance difference between USearch and conventional clustering methods may easily reach 100x.
253
256
 
254
257
  ## Joins, One-to-One, One-to-Many, and Many-to-Many Mappings
255
258
 
256
- One of the big questions these days is how will AI change the world of databases and data management.
259
+ One of the big questions these days is how AI will change the world of databases and data management.
257
260
  Most databases are still struggling to implement high-quality fuzzy search, and the only kind of joins they know are deterministic.
258
- A `join` is different from searching for every entry, as it requires a one-to-one mapping, banning collisions among separate search results.
261
+ A `join` differs from searching for every entry, requiring a one-to-one mapping banning collisions among separate search results.
259
262
 
260
263
  | Exact Search | Fuzzy Search | Semantic Search ? |
261
264
  | :----------: | :----------: | :---------------: |
262
265
  | Exact Join | Fuzzy Join ? | Semantic Join ?? |
263
266
 
264
- Using USearch one can implement sub-quadratic complexity approximate, fuzzy, and semantic joins.
265
- This can come in handy in any fuzzy-matching tasks, common to Database Management Software.
267
+ Using USearch, one can implement sub-quadratic complexity approximate, fuzzy, and semantic joins.
268
+ This can be useful in any fuzzy-matching tasks common to Database Management Software.
266
269
 
267
270
  ```py
268
271
  men = Index(...)
@@ -270,7 +273,7 @@ women = Index(...)
270
273
  pairs: dict = men.join(women, max_proposals=0, exact=False)
271
274
  ```
272
275
 
273
- > Read more in post: [From Dating to Vector Search - "Stable Marriages" on a Planetary Scale 👩‍❤️‍👨](https://ashvardanian.com/posts/searching-stable-marriages)
276
+ > Read more in the post: [Combinatorial Stable Marriages for Semantic Search 💍](https://ashvardanian.com/posts/searching-stable-marriages)
274
277
 
275
278
  ## Functionality
276
279
 
@@ -345,7 +348,7 @@ We have pre-processed some commonly used datasets, cleaned the images, produced
345
348
  Comparing molecule graphs and searching for similar structures is expensive and slow.
346
349
  It can be seen as a special case of the NP-Complete Subgraph Isomorphism problem.
347
350
  Luckily, domain-specific approximate methods exist.
348
- The one commonly used in Chemistry, is to generate structures from [SMILES][smiles], and later hash them into binary fingerprints.
351
+ The one commonly used in Chemistry is to generate structures from [SMILES][smiles] and later hash them into binary fingerprints.
349
352
  The latter are searchable with binary similarity metrics, like the Tanimoto coefficient.
350
353
  Below is an example using the RDKit package.
351
354
 
@@ -379,7 +382,7 @@ matches = index.search(fingerprints, 10)
379
382
  With Objective-C and Swift iOS bindings, USearch can be easily used in mobile applications.
380
383
  The [SwiftVectorSearch](https://github.com/ashvardanian/SwiftVectorSearch) project illustrates how to build a dynamic, real-time search system on iOS.
381
384
  In this example, we use 2-dimensional vectors—encoded as latitude and longitude—to find the closest Points of Interest (POIs) on a map.
382
- The search is based on the Haversine distance metric, but can easily be extended to support high-dimensional vectors.
385
+ The search is based on the Haversine distance metric but can easily be extended to support high-dimensional vectors.
383
386
 
384
387
  ## Integrations
385
388
 
@@ -397,7 +400,7 @@ doi = {10.5281/zenodo.7949416},
397
400
  author = {Vardanian, Ash},
398
401
  title = {{USearch by Unum Cloud}},
399
402
  url = {https://github.com/unum-cloud/usearch},
400
- version = {2.8.7},
403
+ version = {2.8.9},
401
404
  year = {2023},
402
405
  month = oct,
403
406
  }
package/VERSION ADDED
@@ -0,0 +1 @@
1
+ 2.8.9
package/binding.gyp CHANGED
@@ -3,14 +3,6 @@
3
3
  {
4
4
  "target_name": "usearch",
5
5
  "sources": ["javascript/lib.cpp"],
6
- "include_dirs": [
7
- "<!@(node -p \"require('node-addon-api').include\")",
8
- "include",
9
- "fp16/include",
10
- "simsimd/include",
11
- ],
12
- "dependencies": ["<!(node -p \"require('node-addon-api').gyp\")"],
13
- "defines": ["USEARCH_USE_SIMSIMD=1", "USEARCH_USE_NATIVE_F16=0"],
14
6
  "cflags": [
15
7
  "-fexceptions",
16
8
  "-Wno-unknown-pragmas",
@@ -22,6 +14,13 @@
22
14
  "-Wno-maybe-uninitialized",
23
15
  "-std=c++17",
24
16
  ],
17
+ "include_dirs": [
18
+ "<!@(node -p \"require('node-addon-api').include\")",
19
+ "include",
20
+ "fp16/include",
21
+ "simsimd/include",
22
+ ],
23
+ "dependencies": ["<!(node -p \"require('node-addon-api').gyp\")"],
25
24
  "xcode_settings": {
26
25
  "GCC_ENABLE_CPP_EXCEPTIONS": "YES",
27
26
  "CLANG_CXX_LIBRARY": "libc++",
@@ -33,6 +32,56 @@
33
32
  "AdditionalOptions": ["-std:c++17"],
34
33
  }
35
34
  },
35
+ "conditions": [
36
+ [
37
+ 'OS=="linux"',
38
+ {
39
+ "cflags_cc": [
40
+ '<!(if [ "$USEARCH_USE_OPENMP" = "1" ]; then echo \'-fopenmp\'; fi)',
41
+ ],
42
+ "ldflags": [
43
+ '<!(if [ "$USEARCH_USE_OPENMP" = "1" ]; then echo \'-lgomp\'; fi)'
44
+ ],
45
+ "defines": [
46
+ "USEARCH_USE_OPENMP=<!(echo ${USEARCH_USE_OPENMP:-0})",
47
+ "USEARCH_USE_SIMSIMD=<!(echo ${USEARCH_USE_SIMSIMD:-1})",
48
+ "USEARCH_USE_FP16LIB=<!(echo ${USEARCH_USE_FP16LIB:-1})",
49
+ "SIMSIMD_TARGET_X86_AVX512=<!(echo ${SIMSIMD_TARGET_X86_AVX512:-1})",
50
+ "SIMSIMD_TARGET_ARM_SVE=<!(echo ${SIMSIMD_TARGET_ARM_SVE:-1})",
51
+ "SIMSIMD_TARGET_X86_AVX2=<!(echo ${SIMSIMD_TARGET_X86_AVX2:-1})",
52
+ "SIMSIMD_TARGET_ARM_NEON=<!(echo ${SIMSIMD_TARGET_ARM_NEON:-1})",
53
+ ],
54
+ },
55
+ ],
56
+ [
57
+ 'OS=="mac"',
58
+ {
59
+ "defines": [
60
+ "USEARCH_USE_OPENMP=<!(echo ${USEARCH_USE_OPENMP:-0})",
61
+ "USEARCH_USE_SIMSIMD=<!(echo ${USEARCH_USE_SIMSIMD:-0})",
62
+ "USEARCH_USE_FP16LIB=<!(echo ${USEARCH_USE_FP16LIB:-1})",
63
+ "SIMSIMD_TARGET_X86_AVX512=<!(echo ${SIMSIMD_TARGET_X86_AVX512:-0})",
64
+ "SIMSIMD_TARGET_ARM_SVE=<!(echo ${SIMSIMD_TARGET_ARM_SVE:-0})",
65
+ "SIMSIMD_TARGET_X86_AVX2=<!(echo ${SIMSIMD_TARGET_X86_AVX2:-1})",
66
+ "SIMSIMD_TARGET_ARM_NEON=<!(echo ${SIMSIMD_TARGET_ARM_NEON:-1})",
67
+ ],
68
+ },
69
+ ],
70
+ [
71
+ 'OS=="win"',
72
+ {
73
+ "defines": [
74
+ "USEARCH_USE_OPENMP=0",
75
+ "USEARCH_USE_SIMSIMD=0",
76
+ "USEARCH_USE_FP16LIB=1",
77
+ "SIMSIMD_TARGET_X86_AVX512=0",
78
+ "SIMSIMD_TARGET_ARM_SVE=0",
79
+ "SIMSIMD_TARGET_X86_AVX2=0",
80
+ "SIMSIMD_TARGET_ARM_NEON=0",
81
+ ],
82
+ },
83
+ ],
84
+ ],
36
85
  }
37
86
  ]
38
87
  }
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.7'
10
+ version = '2.8.9'
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 7
14
+ #define USEARCH_VERSION_PATCH 9
15
15
 
16
16
  // Inferring C++ version
17
17
  // https://stackoverflow.com/a/61552074
@@ -13,6 +13,10 @@
13
13
 
14
14
  #include <usearch/index.hpp> // `expected_gt` and macros
15
15
 
16
+ #if !defined(USEARCH_USE_OPENMP)
17
+ #define USEARCH_USE_OPENMP 0
18
+ #endif
19
+
16
20
  #if USEARCH_USE_OPENMP
17
21
  #include <omp.h> // `omp_get_num_threads()`
18
22
  #endif
@@ -21,18 +25,18 @@
21
25
  #include <sys/auxv.h> // `getauxval()`
22
26
  #endif
23
27
 
24
- #if !defined(USEARCH_USE_NATIVE_F16)
28
+ #if !defined(USEARCH_USE_FP16LIB)
25
29
  #if defined(__AVX512F__)
26
- #define USEARCH_USE_NATIVE_F16 1
30
+ #define USEARCH_USE_FP16LIB 0
27
31
  #elif defined(USEARCH_DEFINED_ARM)
28
32
  #include <arm_fp16.h> // `__fp16`
29
- #define USEARCH_USE_NATIVE_F16 1
33
+ #define USEARCH_USE_FP16LIB 0
30
34
  #else
31
- #define USEARCH_USE_NATIVE_F16 0
35
+ #define USEARCH_USE_FP16LIB 1
32
36
  #endif
33
37
  #endif
34
38
 
35
- #if !USEARCH_USE_NATIVE_F16
39
+ #if USEARCH_USE_FP16LIB
36
40
  #include <fp16/fp16.h>
37
41
  #endif
38
42
 
@@ -41,27 +45,27 @@
41
45
  #endif
42
46
 
43
47
  #if USEARCH_USE_SIMSIMD
48
+
44
49
  // Propagate the `f16` settings
45
- #define SIMSIMD_NATIVE_F16 USEARCH_USE_NATIVE_F16
46
- #if defined(USEARCH_DEFINED_LINUX)
50
+ #define SIMSIMD_NATIVE_F16 !USEARCH_USE_FP16LIB
51
+
52
+ #if !defined(SIMSIMD_TARGET_X86_AVX512) && defined(USEARCH_DEFINED_LINUX)
47
53
  #define SIMSIMD_TARGET_X86_AVX512 1
54
+ #endif
55
+
56
+ #if !defined(SIMSIMD_TARGET_ARM_SVE) && defined(USEARCH_DEFINED_LINUX)
48
57
  #define SIMSIMD_TARGET_ARM_SVE 1
58
+ #endif
59
+
60
+ #if !defined(SIMSIMD_TARGET_X86_AVX2) && (defined(USEARCH_DEFINED_LINUX) || defined(USEARCH_DEFINED_APPLE))
49
61
  #define SIMSIMD_TARGET_X86_AVX2 1
62
+ #endif
63
+
64
+ #if !defined(SIMSIMD_TARGET_ARM_NEON) && (defined(USEARCH_DEFINED_LINUX) || defined(USEARCH_DEFINED_APPLE))
50
65
  #define SIMSIMD_TARGET_ARM_NEON 1
51
- #include <simsimd/simsimd.h>
52
- #elif defined(USEARCH_DEFINED_APPLE)
53
- #define SIMSIMD_TARGET_X86_AVX512 0
54
- #define SIMSIMD_TARGET_ARM_SVE 0
55
- #define SIMSIMD_TARGET_X86_AVX2 1
56
- #define SIMSIMD_TARGET_ARM_NEON 1
57
- #include <simsimd/simsimd.h>
58
- #else
59
- #define SIMSIMD_TARGET_X86_AVX512 0
60
- #define SIMSIMD_TARGET_ARM_SVE 0
61
- #define SIMSIMD_TARGET_X86_AVX2 0
62
- #define SIMSIMD_TARGET_ARM_NEON 0
63
- #include <simsimd/simsimd.h>
64
66
  #endif
67
+
68
+ #include <simsimd/simsimd.h>
65
69
  #endif
66
70
 
67
71
  namespace unum {
@@ -77,7 +81,7 @@ struct uuid_t {
77
81
  class f16_bits_t;
78
82
  class i8_converted_t;
79
83
 
80
- #if USEARCH_USE_NATIVE_F16
84
+ #if !USEARCH_USE_FP16LIB
81
85
  #if defined(USEARCH_DEFINED_ARM)
82
86
  using f16_native_t = __fp16;
83
87
  #else
@@ -298,7 +302,7 @@ inline expected_gt<metric_kind_t> metric_from_name(char const* name) {
298
302
  }
299
303
 
300
304
  inline float f16_to_f32(std::uint16_t u16) noexcept {
301
- #if USEARCH_USE_NATIVE_F16
305
+ #if !USEARCH_USE_FP16LIB
302
306
  f16_native_t f16;
303
307
  std::memcpy(&f16, &u16, sizeof(std::uint16_t));
304
308
  return float(f16);
@@ -308,7 +312,7 @@ inline float f16_to_f32(std::uint16_t u16) noexcept {
308
312
  }
309
313
 
310
314
  inline std::uint16_t f32_to_f16(float f32) noexcept {
311
- #if USEARCH_USE_NATIVE_F16
315
+ #if !USEARCH_USE_FP16LIB
312
316
  f16_native_t f16 = f16_native_t(f32);
313
317
  std::uint16_t u16;
314
318
  std::memcpy(&u16, &f16, sizeof(std::uint16_t));
@@ -1415,7 +1419,7 @@ class metric_punned_t {
1415
1419
  if (simd_metric == nullptr)
1416
1420
  return false;
1417
1421
 
1418
- raw_ptr_ = (punned_ptr_t)simd_metric;
1422
+ std::memcpy(&raw_ptr_, &simd_metric, sizeof(simd_metric));
1419
1423
  isa_kind_ = simd_kind;
1420
1424
  return true;
1421
1425
  }