usearch 2.16.8 → 2.16.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.
- package/README.md +1 -1
- package/include/usearch/index.hpp +1 -1
- package/package.json +1 -1
- package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
- package/prebuilds/linux-arm64/usearch.node +0 -0
- package/prebuilds/linux-x64/usearch.node +0 -0
- package/simsimd/CONTRIBUTING.md +69 -12
- package/simsimd/Cargo.lock +1 -1
- package/simsimd/Cargo.toml +1 -1
- package/simsimd/README.md +253 -40
- package/simsimd/c/lib.c +114 -109
- package/simsimd/include/simsimd/binary.h +33 -17
- package/simsimd/include/simsimd/curved.h +867 -129
- package/simsimd/include/simsimd/dot.h +562 -569
- package/simsimd/include/simsimd/probability.h +14 -9
- package/simsimd/include/simsimd/simsimd.h +102 -46
- package/simsimd/include/simsimd/spatial.h +28 -18
- package/simsimd/include/simsimd/types.h +24 -0
- package/simsimd/javascript/fallback.ts +26 -15
- package/simsimd/javascript/simsimd.ts +1 -1
- package/simsimd/package-lock.json +10 -9
- package/simsimd/package.json +2 -2
- package/simsimd/rust/lib.rs +218 -5
- package/simsimd/scripts/bench.cxx +156 -97
- package/simsimd/scripts/test.c +14 -8
- package/simsimd/scripts/test.mjs +158 -145
- package/simsimd/scripts/test.py +71 -52
package/README.md
CHANGED
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/simsimd/CONTRIBUTING.md
CHANGED
|
@@ -6,6 +6,26 @@ To keep the quality of the code high, we have a set of [guidelines](https://gith
|
|
|
6
6
|
- [How to organize branches?](https://github.com/unum-cloud/awesome/blob/main/Workflow.md#branches)
|
|
7
7
|
- [How to style commits?](https://github.com/unum-cloud/awesome/blob/main/Workflow.md#commits)
|
|
8
8
|
|
|
9
|
+
## Navigating the Codebase
|
|
10
|
+
|
|
11
|
+
Primary kernels are implemented in header files under `include/simsimd/`:
|
|
12
|
+
|
|
13
|
+
- `dot.h` - dot products for real and complex vectors.
|
|
14
|
+
- `spatial.h` - spatial distances: L2, cosine distance.
|
|
15
|
+
- `binary.h` - binary distances: Hamming, Jaccard, etc.
|
|
16
|
+
- `probability.h` - probability metrics: KL-divergence, Jensen-Shannon, etc.
|
|
17
|
+
- `sparse.h` - sparse distances: weighted and normal set intersections.
|
|
18
|
+
- `curved.h` - bilinear forms for real and complex vectors, and Mahalanobis distance.
|
|
19
|
+
|
|
20
|
+
Bindings to other languages are in the respective directories:
|
|
21
|
+
|
|
22
|
+
- `python/lib.c` - Python bindings.
|
|
23
|
+
- `javascript/lib.c` - JavaScript bindings.
|
|
24
|
+
- `rust/lib.rs` - Rust bindings.
|
|
25
|
+
- `swift/SimSIMD.swift` - Swift bindings.
|
|
26
|
+
|
|
27
|
+
All tests, benchmarks, and examples are placed in the `scripts/` directory, if compatible with the toolchain of the implementation language.
|
|
28
|
+
|
|
9
29
|
## C and C++
|
|
10
30
|
|
|
11
31
|
To rerun experiments utilize the following command:
|
|
@@ -63,6 +83,15 @@ cmake -D CMAKE_BUILD_TYPE=Release \
|
|
|
63
83
|
cmake --build build_release --config Release
|
|
64
84
|
```
|
|
65
85
|
|
|
86
|
+
When benchmarking, make sure to disable multi-threading in the BLAS library, as it may interfere with the results:
|
|
87
|
+
|
|
88
|
+
```sh
|
|
89
|
+
export OPENBLAS_NUM_THREADS=1 # for OpenBLAS
|
|
90
|
+
export MKL_NUM_THREADS=1 # for Intel MKL
|
|
91
|
+
export VECLIB_MAXIMUM_THREADS=1 # for Apple Accelerate
|
|
92
|
+
export BLIS_NUM_THREADS=1 # for BLIS
|
|
93
|
+
```
|
|
94
|
+
|
|
66
95
|
## Python
|
|
67
96
|
|
|
68
97
|
Testing:
|
|
@@ -140,7 +169,6 @@ cibuildwheel --platform linux # works on any OS and builds all
|
|
|
140
169
|
cibuildwheel --platform linux --archs x86_64 # 64-bit x86, the most common on desktop and servers
|
|
141
170
|
cibuildwheel --platform linux --archs aarch64 # 64-bit Arm for mobile devices, Apple M-series, and AWS Graviton
|
|
142
171
|
cibuildwheel --platform linux --archs i686 # 32-bit Linux
|
|
143
|
-
cibuildwheel --platform linux --archs s390x # emulating big-endian IBM Z
|
|
144
172
|
cibuildwheel --platform macos # works only on MacOS
|
|
145
173
|
cibuildwheel --platform windows # works only on Windows
|
|
146
174
|
```
|
|
@@ -168,35 +196,65 @@ open target/criterion/report/index.html
|
|
|
168
196
|
|
|
169
197
|
## JavaScript
|
|
170
198
|
|
|
171
|
-
|
|
199
|
+
### NodeJS
|
|
200
|
+
|
|
201
|
+
If you don't have the environment configured, here are the [installation options](https://github.com/nvm-sh/nvm?tab=readme-ov-file#install--update-script) with different tools:
|
|
202
|
+
|
|
203
|
+
```sh
|
|
204
|
+
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash # Linux
|
|
205
|
+
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash # MacOS
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Install dependencies:
|
|
172
209
|
|
|
173
210
|
```sh
|
|
174
|
-
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
|
|
175
211
|
nvm install 20
|
|
212
|
+
npm install -g typescript # Install the TypeScript compiler globally
|
|
213
|
+
npm install --save-dev @types/node # Install the Node.js type definitions as a dev dependency
|
|
176
214
|
```
|
|
177
215
|
|
|
178
216
|
Testing and benchmarking:
|
|
179
217
|
|
|
180
218
|
```sh
|
|
181
|
-
npm
|
|
182
|
-
npm
|
|
183
|
-
npm
|
|
184
|
-
npm run bench
|
|
219
|
+
npm run build-js # Build the JavaScript code using TypeScript configurations
|
|
220
|
+
npm test # Run the test suite
|
|
221
|
+
npm run bench # Run the benchmark script
|
|
185
222
|
```
|
|
186
223
|
|
|
187
|
-
|
|
224
|
+
### Deno
|
|
225
|
+
|
|
226
|
+
If you don't have the environment configured, here are [installation options](https://docs.deno.com/runtime/getting_started/installation/) with different tools:
|
|
227
|
+
|
|
228
|
+
```sh
|
|
229
|
+
wget -qO- https://deno.land/x/install/install.sh | sh # Linux
|
|
230
|
+
curl -fsSL https://deno.land/install.sh | sh # MacOS
|
|
231
|
+
irm https://deno.land/install.ps1 | iex # Windows
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Testing:
|
|
188
235
|
|
|
189
236
|
```sh
|
|
190
237
|
deno test --allow-read
|
|
191
238
|
```
|
|
192
239
|
|
|
193
|
-
|
|
240
|
+
### Bun
|
|
241
|
+
|
|
242
|
+
If you don't have the environment configured, here are the [installation options](https://bun.sh/docs/installation) with different tools:
|
|
243
|
+
|
|
244
|
+
```sh
|
|
245
|
+
wget -qO- https://bun.sh/install | bash # for Linux
|
|
246
|
+
curl -fsSL https://bun.sh/install | bash # for macOS and WSL
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Testing:
|
|
194
250
|
|
|
195
251
|
```sh
|
|
196
|
-
|
|
197
|
-
bun test
|
|
252
|
+
bun install
|
|
253
|
+
bun test ./scripts/test.mjs
|
|
198
254
|
```
|
|
199
255
|
|
|
256
|
+
... wouldn't work for now.
|
|
257
|
+
|
|
200
258
|
## Swift
|
|
201
259
|
|
|
202
260
|
```sh
|
|
@@ -239,4 +297,3 @@ cd golang
|
|
|
239
297
|
go test # To test
|
|
240
298
|
go test -run=^$ -bench=. -benchmem # To benchmark
|
|
241
299
|
```
|
|
242
|
-
|
package/simsimd/Cargo.lock
CHANGED
package/simsimd/Cargo.toml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "simsimd"
|
|
3
3
|
description = "Portable mixed-precision BLAS-like vector math library for x86 and ARM"
|
|
4
|
-
version = "6.
|
|
4
|
+
version = "6.2.3"
|
|
5
5
|
edition = "2021"
|
|
6
6
|
license = "Apache-2.0"
|
|
7
7
|
authors = ["Ash Vardanian <1983160+ashvardanian@users.noreply.github.com>"]
|
package/simsimd/README.md
CHANGED
|
@@ -9,7 +9,7 @@ The rare few that support minimal mixed precision, run only on one platform, and
|
|
|
9
9
|
SimSIMD provides an alternative.
|
|
10
10
|
1️⃣ SimSIMD functions are practically as fast as `memcpy`.
|
|
11
11
|
2️⃣ Unlike BLAS, most kernels are designed for mixed-precision and bit-level operations.
|
|
12
|
-
3️⃣ SimSIMD [
|
|
12
|
+
3️⃣ SimSIMD often [ships more binaries than NumPy][compatibility] and has more backends than most BLAS implementations, and more high-level interfaces than most libraries.
|
|
13
13
|
|
|
14
14
|
[benchmarks]: https://ashvardanian.com/posts/simsimd-faster-scipy
|
|
15
15
|
[compatibility]: https://pypi.org/project/simsimd/#files
|
|
@@ -42,7 +42,7 @@ SimSIMD provides an alternative.
|
|
|
42
42
|
|
|
43
43
|
## Features
|
|
44
44
|
|
|
45
|
-
__SimSIMD__ (Arabic: "سيمسيم دي") is a mixed-precision math library of __over
|
|
45
|
+
__SimSIMD__ (Arabic: "سيمسيم دي") is a mixed-precision math library of __over 350 SIMD-optimized kernels__ extensively used in AI, Search, and DBMS workloads.
|
|
46
46
|
Named after the iconic ["Open Sesame"](https://en.wikipedia.org/wiki/Open_sesame) command that opened doors to treasure in _Ali Baba and the Forty Thieves_, SimSimd can help you 10x the cost-efficiency of your computational pipelines.
|
|
47
47
|
Implemented distance functions include:
|
|
48
48
|
|
|
@@ -92,17 +92,196 @@ You can learn more about the technical implementation details in the following b
|
|
|
92
92
|
|
|
93
93
|
## Benchmarks
|
|
94
94
|
|
|
95
|
-
|
|
96
|
-
|
|
95
|
+
<table style="width: 100%; text-align: center; table-layout: fixed;">
|
|
96
|
+
<colgroup>
|
|
97
|
+
<col style="width: 33%;">
|
|
98
|
+
<col style="width: 33%;">
|
|
99
|
+
<col style="width: 33%;">
|
|
100
|
+
</colgroup>
|
|
101
|
+
<tr>
|
|
102
|
+
<th align="center">NumPy</th>
|
|
103
|
+
<th align="center">C 99</th>
|
|
104
|
+
<th align="center">SimSIMD</th>
|
|
105
|
+
</tr>
|
|
106
|
+
<!-- Cosine distances with different precision levels -->
|
|
107
|
+
<tr>
|
|
108
|
+
<td colspan="4" align="center">cosine distances between 1536d vectors in <code>int8</code></td>
|
|
109
|
+
</tr>
|
|
110
|
+
<tr>
|
|
111
|
+
<td align="center"> <!-- scipy.spatial.distance.cosine -->
|
|
112
|
+
🚧 overflows<br/>
|
|
113
|
+
</td>
|
|
114
|
+
<td align="center"> <!-- serial -->
|
|
115
|
+
<span style="color:#ABABAB;">x86:</span> <b>10,548,600</b> ops/s<br/>
|
|
116
|
+
<span style="color:#ABABAB;">arm:</span> <b>11,379,300</b> ops/s
|
|
117
|
+
</td>
|
|
118
|
+
<td align="center"> <!-- simsimd -->
|
|
119
|
+
<span style="color:#ABABAB;">x86:</span> <b>16,151,800</b> ops/s<br/>
|
|
120
|
+
<span style="color:#ABABAB;">arm:</span> <b>13,524,000</b> ops/s
|
|
121
|
+
</td>
|
|
122
|
+
</tr>
|
|
123
|
+
<tr>
|
|
124
|
+
<td colspan="4" align="center">cosine distances between 1536d vectors in <code>bfloat16</code></td>
|
|
125
|
+
</tr>
|
|
126
|
+
<tr>
|
|
127
|
+
<td align="center"> <!-- scipy.spatial.distance.cosine -->
|
|
128
|
+
🚧 not supported<br/>
|
|
129
|
+
</td>
|
|
130
|
+
<td align="center"> <!-- serial -->
|
|
131
|
+
<span style="color:#ABABAB;">x86:</span> <b>119,835</b> ops/s<br/>
|
|
132
|
+
<span style="color:#ABABAB;">arm:</span> <b>403,909</b> ops/s
|
|
133
|
+
</td>
|
|
134
|
+
<td align="center"> <!-- simsimd -->
|
|
135
|
+
<span style="color:#ABABAB;">x86:</span> <b>9,738,540</b> ops/s<br/>
|
|
136
|
+
<span style="color:#ABABAB;">arm:</span> <b>4,881,900</b> ops/s
|
|
137
|
+
</td>
|
|
138
|
+
</tr>
|
|
139
|
+
<tr>
|
|
140
|
+
<td colspan="4" align="center">cosine distances between 1536d vectors in <code>float16</code></td>
|
|
141
|
+
</tr>
|
|
142
|
+
<tr>
|
|
143
|
+
<td align="center"> <!-- scipy.spatial.distance.cosine -->
|
|
144
|
+
<span style="color:#ABABAB;">x86:</span> <b>40,481</b> ops/s<br/>
|
|
145
|
+
<span style="color:#ABABAB;">arm:</span> <b>21,451</b> ops/s
|
|
146
|
+
</td>
|
|
147
|
+
<td align="center"> <!-- serial -->
|
|
148
|
+
<span style="color:#ABABAB;">x86:</span> <b>501,310</b> ops/s<br/>
|
|
149
|
+
<span style="color:#ABABAB;">arm:</span> <b>871,963</b> ops/s
|
|
150
|
+
</td>
|
|
151
|
+
<td align="center"> <!-- simsimd -->
|
|
152
|
+
<span style="color:#ABABAB;">x86:</span> <b>7,627,600</b> ops/s<br/>
|
|
153
|
+
<span style="color:#ABABAB;">arm:</span> <b>3,316,810</b> ops/s
|
|
154
|
+
</td>
|
|
155
|
+
</tr>
|
|
156
|
+
<tr>
|
|
157
|
+
<td colspan="4" align="center">cosine distances between 1536d vectors in <code>float32</code></td>
|
|
158
|
+
</tr>
|
|
159
|
+
<tr>
|
|
160
|
+
<td align="center"> <!-- scipy.spatial.distance.cosine -->
|
|
161
|
+
<span style="color:#ABABAB;">x86:</span> <b>253,902</b> ops/s<br/>
|
|
162
|
+
<span style="color:#ABABAB;">arm:</span> <b>46,394</b> ops/s
|
|
163
|
+
</td>
|
|
164
|
+
<td align="center"> <!-- serial -->
|
|
165
|
+
<span style="color:#ABABAB;">x86:</span> <b>882,484</b> ops/s<br/>
|
|
166
|
+
<span style="color:#ABABAB;">arm:</span> <b>399,661</b> ops/s
|
|
167
|
+
</td>
|
|
168
|
+
<td align="center"> <!-- simsimd -->
|
|
169
|
+
<span style="color:#ABABAB;">x86:</span> <b>8,202,910</b> ops/s<br/>
|
|
170
|
+
<span style="color:#ABABAB;">arm:</span> <b>3,400,620</b> ops/s
|
|
171
|
+
</td>
|
|
172
|
+
</tr>
|
|
173
|
+
<tr>
|
|
174
|
+
<td colspan="4" align="center">cosine distances between 1536d vectors in <code>float64</code></td>
|
|
175
|
+
</tr>
|
|
176
|
+
<tr>
|
|
177
|
+
<td align="center"> <!-- scipy.spatial.distance.cosine -->
|
|
178
|
+
<span style="color:#ABABAB;">x86:</span> <b>212,421</b> ops/s<br/>
|
|
179
|
+
<span style="color:#ABABAB;">arm:</span> <b>52,904</b> ops/s
|
|
180
|
+
</td>
|
|
181
|
+
<td align="center"> <!-- serial -->
|
|
182
|
+
<span style="color:#ABABAB;">x86:</span> <b>839,301</b> ops/s<br/>
|
|
183
|
+
<span style="color:#ABABAB;">arm:</span> <b>837,126</b> ops/s
|
|
184
|
+
</td>
|
|
185
|
+
<td align="center"> <!-- simsimd -->
|
|
186
|
+
<span style="color:#ABABAB;">x86:</span> <b>1,538,530</b> ops/s<br/>
|
|
187
|
+
<span style="color:#ABABAB;">arm:</span> <b>1,678,920</b> ops/s
|
|
188
|
+
</td>
|
|
189
|
+
</tr>
|
|
190
|
+
|
|
191
|
+
<!-- Euclidean distance with different precision level -->
|
|
192
|
+
<tr>
|
|
193
|
+
<td colspan="4" align="center">eculidean distance between 1536d vectors in <code>int8</code></td>
|
|
194
|
+
</tr>
|
|
195
|
+
<tr>
|
|
196
|
+
<td align="center"> <!-- scipy.spatial.distance.sqeuclidean -->
|
|
197
|
+
<span style="color:#ABABAB;">x86:</span> <b>252,113</b> ops/s<br/>
|
|
198
|
+
<span style="color:#ABABAB;">arm:</span> <b>177,443</b> ops/s
|
|
199
|
+
</td>
|
|
200
|
+
<td align="center"> <!-- serial -->
|
|
201
|
+
<span style="color:#ABABAB;">x86:</span> <b>6,690,110</b> ops/s<br/>
|
|
202
|
+
<span style="color:#ABABAB;">arm:</span> <b>4,114,160</b> ops/s
|
|
203
|
+
</td>
|
|
204
|
+
<td align="center"> <!-- simsimd -->
|
|
205
|
+
<span style="color:#ABABAB;">x86:</span> <b>18,989,000</b> ops/s<br/>
|
|
206
|
+
<span style="color:#ABABAB;">arm:</span> <b>18,878,200</b> ops/s
|
|
207
|
+
</td>
|
|
208
|
+
</tr>
|
|
209
|
+
<tr>
|
|
210
|
+
<td colspan="4" align="center">eculidean distance between 1536d vectors in <code>bfloat16</code></td>
|
|
211
|
+
</tr>
|
|
212
|
+
<tr>
|
|
213
|
+
<td align="center"> <!-- scipy.spatial.distance.sqeuclidean -->
|
|
214
|
+
🚧 not supported<br/>
|
|
215
|
+
</td>
|
|
216
|
+
<td align="center"> <!-- serial -->
|
|
217
|
+
<span style="color:#ABABAB;">x86:</span> <b>119,842</b> ops/s<br/>
|
|
218
|
+
<span style="color:#ABABAB;">arm:</span> <b>1,049,230</b> ops/s
|
|
219
|
+
</td>
|
|
220
|
+
<td align="center"> <!-- simsimd -->
|
|
221
|
+
<span style="color:#ABABAB;">x86:</span> <b>9,727,210</b> ops/s<br/>
|
|
222
|
+
<span style="color:#ABABAB;">arm:</span> <b>4,233,420</b> ops/s
|
|
223
|
+
</td>
|
|
224
|
+
</tr>
|
|
225
|
+
<tr>
|
|
226
|
+
<td colspan="4" align="center">eculidean distance between 1536d vectors in <code>float16</code></td>
|
|
227
|
+
</tr>
|
|
228
|
+
<tr>
|
|
229
|
+
<td align="center"> <!-- scipy.spatial.distance.sqeuclidean -->
|
|
230
|
+
<span style="color:#ABABAB;">x86:</span> <b>54,621</b> ops/s<br/>
|
|
231
|
+
<span style="color:#ABABAB;">arm:</span> <b>71,793</b> ops/s
|
|
232
|
+
</td>
|
|
233
|
+
<td align="center"> <!-- serial -->
|
|
234
|
+
<span style="color:#ABABAB;">x86:</span> <b>196,413</b> ops/s<br/>
|
|
235
|
+
<span style="color:#ABABAB;">arm:</span> <b>911,370</b> ops/s
|
|
236
|
+
</td>
|
|
237
|
+
<td align="center"> <!-- simsimd -->
|
|
238
|
+
<span style="color:#ABABAB;">x86:</span> <b>19,466,800</b> ops/s<br/>
|
|
239
|
+
<span style="color:#ABABAB;">arm:</span> <b>3,522,760</b> ops/s
|
|
240
|
+
</td>
|
|
241
|
+
</tr>
|
|
242
|
+
<tr>
|
|
243
|
+
<td colspan="4" align="center">eculidean distance between 1536d vectors in <code>float32</code></td>
|
|
244
|
+
</tr>
|
|
245
|
+
<tr>
|
|
246
|
+
<td align="center"> <!-- scipy.spatial.distance.sqeuclidean -->
|
|
247
|
+
<span style="color:#ABABAB;">x86:</span> <b>424,944</b> ops/s<br/>
|
|
248
|
+
<span style="color:#ABABAB;">arm:</span> <b>292,629</b> ops/s
|
|
249
|
+
</td>
|
|
250
|
+
<td align="center"> <!-- serial -->
|
|
251
|
+
<span style="color:#ABABAB;">x86:</span> <b>1,295,210</b> ops/s<br/>
|
|
252
|
+
<span style="color:#ABABAB;">arm:</span> <b>1,055,940</b> ops/s
|
|
253
|
+
</td>
|
|
254
|
+
<td align="center"> <!-- simsimd -->
|
|
255
|
+
<span style="color:#ABABAB;">x86:</span> <b>8,924,100</b> ops/s<br/>
|
|
256
|
+
<span style="color:#ABABAB;">arm:</span> <b>3,602,650</b> ops/s
|
|
257
|
+
</td>
|
|
258
|
+
</tr>
|
|
259
|
+
<tr>
|
|
260
|
+
<td colspan="4" align="center">eculidean distance between 1536d vectors in <code>float64</code></td>
|
|
261
|
+
</tr>
|
|
262
|
+
<tr>
|
|
263
|
+
<td align="center"> <!-- scipy.spatial.distance.sqeuclidean -->
|
|
264
|
+
<span style="color:#ABABAB;">x86:</span> <b>334,929</b> ops/s<br/>
|
|
265
|
+
<span style="color:#ABABAB;">arm:</span> <b>237,505</b> ops/s
|
|
266
|
+
</td>
|
|
267
|
+
<td align="center"> <!-- serial -->
|
|
268
|
+
<span style="color:#ABABAB;">x86:</span> <b>1,215,190</b> ops/s<br/>
|
|
269
|
+
<span style="color:#ABABAB;">arm:</span> <b>905,782</b> ops/s
|
|
270
|
+
</td>
|
|
271
|
+
<td align="center"> <!-- simsimd -->
|
|
272
|
+
<span style="color:#ABABAB;">x86:</span> <b>1,701,740</b> ops/s<br/>
|
|
273
|
+
<span style="color:#ABABAB;">arm:</span> <b>1,735,840</b> ops/s
|
|
274
|
+
</td>
|
|
275
|
+
</tr>
|
|
276
|
+
<!-- Bilinear forms -->
|
|
277
|
+
<!-- Sparse set intersections -->
|
|
278
|
+
</table>
|
|
97
279
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
| `bfloat16` | 4.6 → 26.3 GB/s <br/> + 472 % | 0.8 → 59.5 GB/s <br/> +7,437 % | 2.5 → 29.9 GB/s <br/> + 1,096 % |
|
|
104
|
-
| `int8` | 25.8 → 47.1 GB/s <br/> + 83 % | 33.1 → 65.3 GB/s <br/> + 97 % | 35.2 → 43.5 GB/s <br/> + 24 % |
|
|
105
|
-
| `uint8` | | 32.5 → 66.5 GB/s <br/> + 105 % | |
|
|
280
|
+
> For benchmarks we mostly use 1536-dimensional vectors, like the embeddings produced by the OpenAI Ada API.
|
|
281
|
+
> The code was compiled with GCC 12, using glibc v2.35.
|
|
282
|
+
> The benchmarks performed on Arm-based Graviton3 AWS `c7g` instances and `r7iz` Intel Sapphire Rapids.
|
|
283
|
+
> Most modern Arm-based 64-bit CPUs will have similar relative speedups.
|
|
284
|
+
> Variance withing x86 CPUs will be larger.
|
|
106
285
|
|
|
107
286
|
Similar speedups are often observed even when compared to BLAS and LAPACK libraries underlying most numerical computing libraries, including NumPy and SciPy in Python.
|
|
108
287
|
Broader benchmarking results:
|
|
@@ -162,10 +341,22 @@ dist = simsimd.cosine(vec1, vec2, "int8")
|
|
|
162
341
|
dist = simsimd.cosine(vec1, vec2, "float16")
|
|
163
342
|
dist = simsimd.cosine(vec1, vec2, "float32")
|
|
164
343
|
dist = simsimd.cosine(vec1, vec2, "float64")
|
|
165
|
-
dist = simsimd.hamming(vec1, vec2, "
|
|
344
|
+
dist = simsimd.hamming(vec1, vec2, "bin8")
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
Binary distance functions are computed at a bit-level.
|
|
348
|
+
Meaning a vector of 10x 8-bit integers will be treated as a sequence of 80 individual bits or dimensions.
|
|
349
|
+
This differs from NumPy, that can't handle smaller-than-byte types, but you can still avoid the `bin8` argument by reinterpreting the vector as booleans:
|
|
350
|
+
|
|
351
|
+
```py
|
|
352
|
+
vec1 = np.random.randint(2, size=80).astype(np.uint8).packbits().view(np.bool_)
|
|
353
|
+
vec2 = np.random.randint(2, size=80).astype(np.uint8).packbits().view(np.bool_)
|
|
354
|
+
hamming_distance = simsimd.hamming(vec1, vec2)
|
|
355
|
+
jaccard_distance = simsimd.jaccard(vec1, vec2)
|
|
166
356
|
```
|
|
167
357
|
|
|
168
358
|
With other frameworks, like PyTorch, one can get a richer type-system than NumPy, but the lack of good CPython interoperability makes it hard to pass data without copies.
|
|
359
|
+
Here is an example of using SimSIMD with PyTorch to compute the cosine similarity between two `bfloat16` vectors:
|
|
169
360
|
|
|
170
361
|
```py
|
|
171
362
|
import numpy as np
|
|
@@ -181,7 +372,7 @@ torch.randn(8, out=vec2)
|
|
|
181
372
|
|
|
182
373
|
# Both libs will look into the same memory buffers and report the same results
|
|
183
374
|
dist_slow = 1 - torch.nn.functional.cosine_similarity(vec1, vec2, dim=0)
|
|
184
|
-
dist_fast = simsimd.cosine(buf1, buf2, "
|
|
375
|
+
dist_fast = simsimd.cosine(buf1, buf2, "bfloat16")
|
|
185
376
|
```
|
|
186
377
|
|
|
187
378
|
It also allows using SimSIMD for half-precision complex numbers, which NumPy does not support.
|
|
@@ -254,9 +445,9 @@ distances: DistancesTensor = simsimd.cdist(matrix1, matrix2, metric="cosine")
|
|
|
254
445
|
distances_array: np.ndarray = np.array(distances, copy=True) # now managed by NumPy
|
|
255
446
|
```
|
|
256
447
|
|
|
257
|
-
###
|
|
448
|
+
### Element-wise Kernels
|
|
258
449
|
|
|
259
|
-
SimSIMD also provides mixed-precision
|
|
450
|
+
SimSIMD also provides mixed-precision element-wise kernels, where the input vectors and the output have the same numeric type, but the intermediate accumulators are of a higher precision.
|
|
260
451
|
|
|
261
452
|
```py
|
|
262
453
|
import numpy as np
|
|
@@ -591,9 +782,9 @@ const binaryVectorB = toBinary(vectorB);
|
|
|
591
782
|
const distance = hamming(binaryVectorA, binaryVectorB);
|
|
592
783
|
```
|
|
593
784
|
|
|
594
|
-
## Using SimSIMD in
|
|
785
|
+
## Using SimSIMD in Swift
|
|
595
786
|
|
|
596
|
-
To install, simply add the following dependency to
|
|
787
|
+
To install, simply add the following dependency to your `Package.swift`:
|
|
597
788
|
|
|
598
789
|
```swift
|
|
599
790
|
dependencies: [
|
|
@@ -677,23 +868,29 @@ To override compilation settings and switch between runtime and compile-time dis
|
|
|
677
868
|
#include <simsimd/simsimd.h>
|
|
678
869
|
|
|
679
870
|
int main() {
|
|
871
|
+
simsimd_i8_t i8[1536];
|
|
872
|
+
simsimd_i8_t u8[1536];
|
|
680
873
|
simsimd_f64_t f64s[1536];
|
|
681
874
|
simsimd_f32_t f32s[1536];
|
|
682
875
|
simsimd_f16_t f16s[1536];
|
|
683
|
-
|
|
876
|
+
simsimd_bf16_t bf16s[1536];
|
|
684
877
|
simsimd_distance_t distance;
|
|
685
878
|
|
|
686
879
|
// Cosine distance between two vectors
|
|
687
880
|
simsimd_cos_i8(i8s, i8s, 1536, &distance);
|
|
881
|
+
simsimd_cos_u8(u8s, u8s, 1536, &distance);
|
|
688
882
|
simsimd_cos_f16(f16s, f16s, 1536, &distance);
|
|
689
883
|
simsimd_cos_f32(f32s, f32s, 1536, &distance);
|
|
690
884
|
simsimd_cos_f64(f64s, f64s, 1536, &distance);
|
|
885
|
+
simsimd_cos_bf16(bf16s, bf16s, 1536, &distance);
|
|
691
886
|
|
|
692
887
|
// Euclidean distance between two vectors
|
|
693
888
|
simsimd_l2sq_i8(i8s, i8s, 1536, &distance);
|
|
889
|
+
simsimd_l2sq_u8(u8s, u8s, 1536, &distance);
|
|
694
890
|
simsimd_l2sq_f16(f16s, f16s, 1536, &distance);
|
|
695
891
|
simsimd_l2sq_f32(f32s, f32s, 1536, &distance);
|
|
696
892
|
simsimd_l2sq_f64(f64s, f64s, 1536, &distance);
|
|
893
|
+
simsimd_l2sq_bf16(bf16s, bf16s, 1536, &distance);
|
|
697
894
|
|
|
698
895
|
return 0;
|
|
699
896
|
}
|
|
@@ -705,25 +902,41 @@ int main() {
|
|
|
705
902
|
#include <simsimd/simsimd.h>
|
|
706
903
|
|
|
707
904
|
int main() {
|
|
708
|
-
|
|
709
|
-
|
|
905
|
+
// SimSIMD provides "sized" type-aliases without relying on `stdint.h`
|
|
906
|
+
simsimd_i8_t i8[1536];
|
|
907
|
+
simsimd_i8_t u8[1536];
|
|
710
908
|
simsimd_f16_t f16s[1536];
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
909
|
+
simsimd_f32_t f32s[1536];
|
|
910
|
+
simsimd_f64_t f64s[1536];
|
|
911
|
+
simsimd_bf16_t bf16s[1536];
|
|
912
|
+
simsimd_distance_t product;
|
|
913
|
+
|
|
914
|
+
// Inner product between two real vectors
|
|
915
|
+
simsimd_dot_i8(i8s, i8s, 1536, &product);
|
|
916
|
+
simsimd_dot_u8(u8s, u8s, 1536, &product);
|
|
917
|
+
simsimd_dot_f16(f16s, f16s, 1536, &product);
|
|
918
|
+
simsimd_dot_f32(f32s, f32s, 1536, &product);
|
|
919
|
+
simsimd_dot_f64(f64s, f64s, 1536, &product);
|
|
920
|
+
simsimd_dot_bf16(bf16s, bf16s, 1536, &product);
|
|
921
|
+
|
|
922
|
+
// SimSIMD provides complex types with `real` and `imag` fields
|
|
923
|
+
simsimd_f64c_t f64s[768];
|
|
924
|
+
simsimd_f32c_t f32s[768];
|
|
925
|
+
simsimd_f16c_t f16s[768];
|
|
926
|
+
simsimd_bf16c_t bf16s[768];
|
|
927
|
+
simsimd_distance_t products[2]; // real and imaginary parts
|
|
717
928
|
|
|
718
929
|
// Complex inner product between two vectors
|
|
719
|
-
simsimd_dot_f16c(
|
|
720
|
-
simsimd_dot_f32c(
|
|
721
|
-
simsimd_dot_f64c(
|
|
930
|
+
simsimd_dot_f16c(f16cs, f16cs, 768, &products[0]);
|
|
931
|
+
simsimd_dot_f32c(f32cs, f32cs, 768, &products[0]);
|
|
932
|
+
simsimd_dot_f64c(f64cs, f64cs, 768, &products[0]);
|
|
933
|
+
simsimd_dot_bf16c(bf16cs, bf16cs, 768, &products[0]);
|
|
722
934
|
|
|
723
935
|
// Complex conjugate inner product between two vectors
|
|
724
|
-
simsimd_vdot_f16c(
|
|
725
|
-
simsimd_vdot_f32c(
|
|
726
|
-
simsimd_vdot_f64c(
|
|
936
|
+
simsimd_vdot_f16c(f16cs, f16cs, 768, &products[0]);
|
|
937
|
+
simsimd_vdot_f32c(f32cs, f32cs, 768, &products[0]);
|
|
938
|
+
simsimd_vdot_f64c(f64cs, f64cs, 768, &products[0]);
|
|
939
|
+
simsimd_vdot_bf16c(bf16cs, bf16cs, 768, &products[0]);
|
|
727
940
|
return 0;
|
|
728
941
|
}
|
|
729
942
|
```
|
|
@@ -751,17 +964,17 @@ int main() {
|
|
|
751
964
|
simsimd_f64_t f64s[1536];
|
|
752
965
|
simsimd_f32_t f32s[1536];
|
|
753
966
|
simsimd_f16_t f16s[1536];
|
|
754
|
-
simsimd_distance_t
|
|
967
|
+
simsimd_distance_t divergence;
|
|
755
968
|
|
|
756
969
|
// Jensen-Shannon divergence between two vectors
|
|
757
|
-
simsimd_js_f16(f16s, f16s, 1536, &
|
|
758
|
-
simsimd_js_f32(f32s, f32s, 1536, &
|
|
759
|
-
simsimd_js_f64(f64s, f64s, 1536, &
|
|
970
|
+
simsimd_js_f16(f16s, f16s, 1536, &divergence);
|
|
971
|
+
simsimd_js_f32(f32s, f32s, 1536, &divergence);
|
|
972
|
+
simsimd_js_f64(f64s, f64s, 1536, &divergence);
|
|
760
973
|
|
|
761
974
|
// Kullback-Leibler divergence between two vectors
|
|
762
|
-
simsimd_kl_f16(f16s, f16s, 1536, &
|
|
763
|
-
simsimd_kl_f32(f32s, f32s, 1536, &
|
|
764
|
-
simsimd_kl_f64(f64s, f64s, 1536, &
|
|
975
|
+
simsimd_kl_f16(f16s, f16s, 1536, &divergence);
|
|
976
|
+
simsimd_kl_f32(f32s, f32s, 1536, &divergence);
|
|
977
|
+
simsimd_kl_f64(f64s, f64s, 1536, &divergence);
|
|
765
978
|
return 0;
|
|
766
979
|
}
|
|
767
980
|
```
|