usearch 0.13.0 → 0.15.0
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/.github/workflows/release.yml +62 -7
- package/.github/workflows/update_version.sh +6 -1
- package/.vscode/launch.json +21 -22
- package/.vscode/settings.json +7 -1
- package/CITATION.cff +4 -4
- package/CMakeLists.txt +1 -1
- package/Cargo.toml +1 -1
- package/Package.swift +0 -1
- package/README.md +100 -27
- package/binding.gyp +0 -1
- package/build.gradle +1 -1
- package/build.rs +3 -3
- package/c/lib.cpp +32 -9
- package/c/usearch.h +67 -36
- package/conanfile.py +1 -1
- package/{src → cpp}/bench.cpp +52 -36
- package/{src → cpp}/test.cpp +17 -7
- package/docs/benchmarks.md +33 -10
- package/docs/c/index.rst +11 -0
- package/docs/c/reference.rst +7 -0
- package/docs/compilation.md +24 -8
- package/docs/conf.dox +6 -6
- package/docs/conf.py +3 -1
- package/docs/cpp/index.rst +11 -0
- package/docs/cpp/reference.rst +7 -0
- package/docs/index.rst +10 -0
- package/docs/java/index.rst +11 -0
- package/docs/java/reference.rst +7 -0
- package/docs/javascript/index.rst +11 -0
- package/docs/javascript/reference.rst +9 -0
- package/docs/python/index.rst +11 -0
- package/docs/python/reference.rst +35 -0
- package/golang/lib.go +1 -1
- package/include/usearch/{usearch.hpp → index.hpp} +152 -148
- package/include/usearch/index_punned_dense.hpp +633 -0
- package/include/usearch/index_punned_helpers.hpp +528 -0
- package/java/cloud/unum/usearch/cloud_unum_usearch_Index.cpp +8 -7
- package/javascript/lib.cpp +26 -50
- package/javascript/usearch.js +117 -2
- package/objc/USearchObjective.mm +145 -49
- package/objc/include/USearchObjective.h +106 -30
- package/package.json +2 -2
- package/python/lib.cpp +178 -320
- package/python/scripts/bench.ipynb +170 -0
- package/python/scripts/bench.py +102 -185
- package/python/scripts/index_faiss.py +100 -0
- package/python/scripts/test.py +57 -34
- package/python/usearch/eval.py +353 -0
- package/python/usearch/index.py +138 -117
- package/python/usearch/io.py +7 -2
- package/python/usearch/join.py +100 -0
- package/python/usearch/numba.py +101 -0
- package/rust/lib.cpp +27 -14
- package/rust/lib.hpp +4 -10
- package/rust/lib.rs +50 -17
- package/setup.py +12 -2
- package/simsimd/include/simsimd/simsimd.h +32 -3
- package/swift/Index+Sugar.swift +55 -29
- package/swift/Test.swift +1 -1
- package/wolfram/lib.cpp +4 -4
- package/python/scripts/bench_params.py +0 -161
- package/python/usearch/synthetic.py +0 -32
- package/src/punned.hpp +0 -887
- /package/{src → cpp}/CMakeLists.txt +0 -0
|
@@ -27,8 +27,9 @@ jobs:
|
|
|
27
27
|
- uses: actions/setup-node@v3
|
|
28
28
|
- run: npm install --save-dev @semantic-release/exec @semantic-release/git conventional-changelog-eslint semantic-release && npx semantic-release
|
|
29
29
|
|
|
30
|
+
|
|
30
31
|
rebase:
|
|
31
|
-
name: Rebase
|
|
32
|
+
name: Rebase Development Branch
|
|
32
33
|
needs: versioning
|
|
33
34
|
runs-on: ubuntu-latest
|
|
34
35
|
steps:
|
|
@@ -41,11 +42,59 @@ jobs:
|
|
|
41
42
|
run: |
|
|
42
43
|
git checkout main-dev
|
|
43
44
|
git rebase main
|
|
45
|
+
|
|
44
46
|
- name: Push changes
|
|
45
|
-
uses:
|
|
47
|
+
uses: CasperWA/push-protected@v2
|
|
46
48
|
with:
|
|
47
|
-
|
|
49
|
+
token: ${{ secrets.SEMANTIC_REBASE_TOKEN }}
|
|
48
50
|
branch: main-dev
|
|
51
|
+
unprotect_reviews: True
|
|
52
|
+
force: True
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
publish_hashes:
|
|
56
|
+
name: Add hashes to release notes
|
|
57
|
+
runs-on: ubuntu-latest
|
|
58
|
+
needs: versioning
|
|
59
|
+
steps:
|
|
60
|
+
- name: Get last release ID
|
|
61
|
+
id: last_release
|
|
62
|
+
run: |
|
|
63
|
+
response=$(curl -s -H "Authorization: Bearer ${{ secrets.SEMANTIC_RELEASE_TOKEN }}" \
|
|
64
|
+
"https://api.github.com/repos/${{ github.repository }}/releases/latest")
|
|
65
|
+
echo "last_release_id=$(echo "$response" | jq -r '.id')" >> $GITHUB_OUTPUT
|
|
66
|
+
|
|
67
|
+
- uses: robinraju/release-downloader@v1.8
|
|
68
|
+
name: Download release assets
|
|
69
|
+
with:
|
|
70
|
+
latest: true
|
|
71
|
+
fileName: "*"
|
|
72
|
+
out-file-path: "downloads"
|
|
73
|
+
tarBall: true
|
|
74
|
+
zipBall: true
|
|
75
|
+
|
|
76
|
+
- name: Calculate source hashes
|
|
77
|
+
id: hashes
|
|
78
|
+
run: |
|
|
79
|
+
source_zip_path=$(find $GITHUB_WORKSPACE/downloads -name "*.zip")
|
|
80
|
+
zip_hash=$(sha256sum "$source_zip_path" | awk '{print $1}')
|
|
81
|
+
source_tar_path=$(find $GITHUB_WORKSPACE/downloads -name "*.tar.gz" ! -name "docs.tar.gz")
|
|
82
|
+
tar_hash=$(sha256sum "$source_tar_path" | awk '{print $1}')
|
|
83
|
+
echo "zip_hash=$zip_hash" >> $GITHUB_OUTPUT
|
|
84
|
+
echo "tar_hash=$tar_hash" >> $GITHUB_OUTPUT
|
|
85
|
+
|
|
86
|
+
- name: Upload hashes to release
|
|
87
|
+
uses: irongut/EditRelease@v1.2.0
|
|
88
|
+
with:
|
|
89
|
+
token: ${{ secrets.SEMANTIC_RELEASE_TOKEN }}
|
|
90
|
+
id: ${{ steps.last_release.outputs.last_release_id }}
|
|
91
|
+
prerelease: false
|
|
92
|
+
replacebody: false
|
|
93
|
+
body: |
|
|
94
|
+
## Hashes
|
|
95
|
+
* Source code (zip) : `${{ steps.hashes.outputs.zip_hash }}`
|
|
96
|
+
* Source code (tar.gz) : `${{ steps.hashes.outputs.tar_hash }}`
|
|
97
|
+
|
|
49
98
|
|
|
50
99
|
build_wheels:
|
|
51
100
|
name: Build Wheels for ${{ matrix.os }}
|
|
@@ -236,11 +285,15 @@ jobs:
|
|
|
236
285
|
with:
|
|
237
286
|
ref: 'main'
|
|
238
287
|
- name: Install dependencies
|
|
239
|
-
run:
|
|
288
|
+
run: |
|
|
289
|
+
sudo apt update &&
|
|
290
|
+
sudo apt install -y doxygen graphviz dia git &&
|
|
291
|
+
pip install sphinx sphinx-js breathe furo m2r2 sphinxcontrib-googleanalytics==0.2.dev20220708 sphinxcontrib-jquery &&
|
|
292
|
+
npm install -g jsdoc
|
|
240
293
|
- name: Install USearch from PyPi
|
|
241
294
|
run: pip install usearch
|
|
242
295
|
- name: Build documentation
|
|
243
|
-
run: cd docs && make html
|
|
296
|
+
run: cd docs && doxygen conf.dox && make html
|
|
244
297
|
- name: Copy assets
|
|
245
298
|
run: cp -r assets build/docs/html/
|
|
246
299
|
- name: Compress assets
|
|
@@ -260,16 +313,19 @@ jobs:
|
|
|
260
313
|
url: ${{ steps.deployment.outputs.page_url }}
|
|
261
314
|
runs-on: ubuntu-22.04
|
|
262
315
|
needs: build_docs
|
|
263
|
-
if: ${{ github.event.build_docs.conclusion == 'success' }}
|
|
264
316
|
steps:
|
|
265
317
|
- uses: robinraju/release-downloader@v1.8
|
|
266
318
|
with:
|
|
267
319
|
latest: true
|
|
268
320
|
fileName: docs.tar.gz
|
|
321
|
+
- name: Unpack docs
|
|
322
|
+
run: tar -xf ./docs.tar.gz
|
|
269
323
|
- name: Setup GitHub Pages
|
|
270
324
|
uses: actions/configure-pages@v2
|
|
271
325
|
- name: Upload artifacts
|
|
272
326
|
uses: actions/upload-pages-artifact@v1
|
|
327
|
+
with:
|
|
328
|
+
path: ./build/docs/html
|
|
273
329
|
- name: Deploy to GitHub Pages
|
|
274
330
|
id: deployment
|
|
275
331
|
uses: actions/deploy-pages@v1
|
|
@@ -278,7 +334,6 @@ jobs:
|
|
|
278
334
|
name: Deploy Vercel
|
|
279
335
|
runs-on: ubuntu-22.04
|
|
280
336
|
needs: build_docs
|
|
281
|
-
if: ${{ github.event.build_docs.conclusion == 'success' }}
|
|
282
337
|
steps:
|
|
283
338
|
- name: Notify Vercel
|
|
284
339
|
uses: fjogeleit/http-request-action@v1
|
|
@@ -4,4 +4,9 @@ echo $1 > VERSION &&
|
|
|
4
4
|
sed -i "s/\"version\": \".*\"/\"version\": \"$1\"/" package.json &&
|
|
5
5
|
sed -i "s/^version: .*/version: $1/" CITATION.cff &&
|
|
6
6
|
sed -i "s/version = \".*\"/version = \"$1\"/" Cargo.toml &&
|
|
7
|
-
sed -i "s/version = '.*'/version = '$1'/" conanfile.py
|
|
7
|
+
sed -i "s/version = '.*'/version = '$1'/" conanfile.py &&
|
|
8
|
+
sed -i "s/^\(#define USEARCH_VERSION_MAJOR \).*/\1$(echo "$1" | cut -d. -f1)/" ./include/usearch/index.hpp &&
|
|
9
|
+
sed -i "s/^\(#define USEARCH_VERSION_MINOR \).*/\1$(echo "$1" | cut -d. -f2)/" ./include/usearch/index.hpp &&
|
|
10
|
+
sed -i "s/^\(#define USEARCH_VERSION_PATCH \).*/\1$(echo "$1" | cut -d. -f3)/" ./include/usearch/index.hpp &&
|
|
11
|
+
sed -i "s/<version>[0-9]\+\.[0-9]\+\.[0-9]\+/<version>$1/" README.md &&
|
|
12
|
+
sed -i "s/version = {0\.[0-9]\+\.[0-9]\+}/version = {$1}/" README.md
|
package/.vscode/launch.json
CHANGED
|
@@ -113,33 +113,32 @@
|
|
|
113
113
|
"MIMode": "gdb"
|
|
114
114
|
},
|
|
115
115
|
{
|
|
116
|
-
"name": "Debug
|
|
117
|
-
"type": "
|
|
116
|
+
"name": "Debug PyTest",
|
|
117
|
+
"type": "python",
|
|
118
118
|
"request": "launch",
|
|
119
|
-
"
|
|
120
|
-
"
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
"
|
|
125
|
-
"request": "attach",
|
|
126
|
-
"program": "/Users/av/miniconda3/bin/python",
|
|
127
|
-
"processId": "",
|
|
128
|
-
"MIMode": "lldb",
|
|
129
|
-
"setupCommands": [
|
|
130
|
-
{
|
|
131
|
-
"description": "Enable pretty-printing for gdb",
|
|
132
|
-
"text": "-enable-pretty-printing",
|
|
133
|
-
"ignoreFailures": true
|
|
134
|
-
}
|
|
135
|
-
]
|
|
119
|
+
"module": "pytest",
|
|
120
|
+
"console": "internalConsole",
|
|
121
|
+
"args": [
|
|
122
|
+
"${file}"
|
|
123
|
+
],
|
|
124
|
+
"justMyCode": true
|
|
136
125
|
},
|
|
137
126
|
{
|
|
138
|
-
"name": "Python
|
|
127
|
+
"name": "Debug Python Benchmark",
|
|
139
128
|
"type": "python",
|
|
140
129
|
"request": "launch",
|
|
141
|
-
"program": "
|
|
142
|
-
"console": "
|
|
130
|
+
"program": "python/scripts/bench.py",
|
|
131
|
+
"console": "internalConsole",
|
|
132
|
+
"args": [
|
|
133
|
+
"speed",
|
|
134
|
+
"--vectors",
|
|
135
|
+
"datasets/wiki_1M/base.1M.fbin",
|
|
136
|
+
"--queries",
|
|
137
|
+
"datasets/wiki_1M/query.public.100K.fbin",
|
|
138
|
+
"--neighbors",
|
|
139
|
+
"datasets/wiki_1M/groundtruth.public.100K.ibin",
|
|
140
|
+
],
|
|
141
|
+
"justMyCode": true
|
|
143
142
|
}
|
|
144
143
|
]
|
|
145
144
|
}
|
package/.vscode/settings.json
CHANGED
|
@@ -107,6 +107,7 @@
|
|
|
107
107
|
"arange",
|
|
108
108
|
"astype",
|
|
109
109
|
"Availible",
|
|
110
|
+
"bidict",
|
|
110
111
|
"BLAS",
|
|
111
112
|
"cflags",
|
|
112
113
|
"citerator",
|
|
@@ -146,5 +147,10 @@
|
|
|
146
147
|
"usecases"
|
|
147
148
|
],
|
|
148
149
|
"autoDocstring.docstringFormat": "sphinx",
|
|
149
|
-
"java.configuration.updateBuildConfiguration": "interactive"
|
|
150
|
+
"java.configuration.updateBuildConfiguration": "interactive",
|
|
151
|
+
"python.testing.pytestArgs": [
|
|
152
|
+
"python"
|
|
153
|
+
],
|
|
154
|
+
"python.testing.unittestEnabled": false,
|
|
155
|
+
"python.testing.pytestEnabled": true
|
|
150
156
|
}
|
package/CITATION.cff
CHANGED
|
@@ -2,10 +2,10 @@ cff-version: 1.2.0
|
|
|
2
2
|
message: "If you use this software, please cite it as below."
|
|
3
3
|
authors:
|
|
4
4
|
- family-names: "Vardanian"
|
|
5
|
-
given-names: "
|
|
5
|
+
given-names: "Ash"
|
|
6
6
|
orcid: "https://orcid.org/0000-0002-4882-1815"
|
|
7
|
-
title: "USearch"
|
|
8
|
-
version: 0.
|
|
7
|
+
title: "USearch by Unum Cloud"
|
|
8
|
+
version: 0.13.0
|
|
9
9
|
doi: 10.5281/zenodo.7949416
|
|
10
10
|
date-released: 2022-06-12
|
|
11
|
-
url: "https://github.com/unum-cloud/usearch"
|
|
11
|
+
url: "https://github.com/unum-cloud/usearch"
|
package/CMakeLists.txt
CHANGED
package/Cargo.toml
CHANGED
package/Package.swift
CHANGED
|
@@ -18,7 +18,6 @@ let package = Package(
|
|
|
18
18
|
sources: ["USearchObjective.mm"],
|
|
19
19
|
cxxSettings: [
|
|
20
20
|
.headerSearchPath("../include/"),
|
|
21
|
-
.headerSearchPath("../src/"),
|
|
22
21
|
.headerSearchPath("../fp16/include/"),
|
|
23
22
|
.headerSearchPath("../robin-map/include/"),
|
|
24
23
|
.headerSearchPath("../simismd/include/")
|
package/README.md
CHANGED
|
@@ -48,9 +48,9 @@ Linux • MacOS • Windows • Docker • WebAssembly 🔜
|
|
|
48
48
|
- [ ] Thread-safe `reserve`.
|
|
49
49
|
- [ ] On-the-fly deletions.
|
|
50
50
|
- [x] USearch + UForm Transformers = [Semantic Search](#ai--vector-search--semantic-search).
|
|
51
|
-
- [x] USearch + RDKit = [
|
|
51
|
+
- [x] USearch + RDKit = [Molecule Search](#ai--vector-search--semantic-search).
|
|
52
52
|
|
|
53
|
-
[usearch-header]: https://github.com/unum-cloud/usearch/blob/main/include/usearch/
|
|
53
|
+
[usearch-header]: https://github.com/unum-cloud/usearch/blob/main/include/usearch/index.hpp
|
|
54
54
|
[obscure-use-cases]: https://ashvardanian.com/posts/abusing-vector-search
|
|
55
55
|
|
|
56
56
|
---
|
|
@@ -133,14 +133,14 @@ Of course, the latency of external memory access will be higher, but it is in pa
|
|
|
133
133
|
|
|
134
134
|
There are two usage patters:
|
|
135
135
|
|
|
136
|
-
1. Bare-bones with `usearch/
|
|
136
|
+
1. Bare-bones with `usearch/index.hpp`, only available in C++.
|
|
137
137
|
2. Full-fat version with it's own threads, mutexes, type-punning, quantization, that is available both in C++ and is wrapped for higher-level bindings.
|
|
138
138
|
|
|
139
139
|
### C++
|
|
140
140
|
|
|
141
141
|
#### Installation
|
|
142
142
|
|
|
143
|
-
To use in a C++ project simply copy the `include/usearch/
|
|
143
|
+
To use in a C++ project simply copy the `include/usearch/index.hpp` header into your project.
|
|
144
144
|
Alternatively fetch it with CMake:
|
|
145
145
|
|
|
146
146
|
```cmake
|
|
@@ -164,7 +164,7 @@ index.add(/* label: */ 42, /* vector: */ {&vec[0], 3});
|
|
|
164
164
|
auto results = index.search(/* query: */ {&vec[0], 3}, 5 /* neighbors */);
|
|
165
165
|
|
|
166
166
|
for (std::size_t i = 0; i != results.size(); ++i)
|
|
167
|
-
results[i].
|
|
167
|
+
results[i].element.label, results[i].element.vector, results[i].distance;
|
|
168
168
|
```
|
|
169
169
|
|
|
170
170
|
The `add` is thread-safe for concurrent index construction.
|
|
@@ -205,9 +205,9 @@ The following distances are pre-packaged:
|
|
|
205
205
|
- `ip_gt<scalar_t>` for "Inner Product" or "Dot Product" distance.
|
|
206
206
|
- `l2sq_gt<scalar_t>` for the squared "L2" or "Euclidean" distance.
|
|
207
207
|
- `jaccard_gt<scalar_t>` for "Jaccard" distance between two ordered sets of unique elements.
|
|
208
|
-
- `
|
|
209
|
-
- `
|
|
210
|
-
- `
|
|
208
|
+
- `hamming_gt<scalar_t>` for "Hamming" distance, as the number of shared bits in hashes.
|
|
209
|
+
- `tanimoto_gt<scalar_t>` for "Tanimoto" coefficient for bit-strings.
|
|
210
|
+
- `sorensen_gt<scalar_t>` for "Dice-Sorensen" coefficient for bit-strings.
|
|
211
211
|
- `pearson_correlation_gt<scalar_t>` for "Pearson" correlation between probability distributions.
|
|
212
212
|
- `haversine_gt<scalar_t>` for "Haversine" or "Great Circle" distance between coordinates used in GIS applications.
|
|
213
213
|
|
|
@@ -299,19 +299,19 @@ Luckily, with the help of [Numba][numba], we can JIT compile a function with a m
|
|
|
299
299
|
```py
|
|
300
300
|
from numba import cfunc, types, carray
|
|
301
301
|
|
|
302
|
+
ndim = 256
|
|
302
303
|
signature = types.float32(
|
|
303
304
|
types.CPointer(types.float32),
|
|
304
|
-
types.CPointer(types.float32)
|
|
305
|
-
types.uint64, types.uint64)
|
|
305
|
+
types.CPointer(types.float32))
|
|
306
306
|
|
|
307
307
|
@cfunc(signature)
|
|
308
|
-
def python_dot(a, b
|
|
309
|
-
a_array = carray(a,
|
|
310
|
-
b_array = carray(b,
|
|
308
|
+
def python_dot(a, b):
|
|
309
|
+
a_array = carray(a, ndim)
|
|
310
|
+
b_array = carray(b, ndim)
|
|
311
311
|
c = 0.0
|
|
312
|
-
for i in range(
|
|
312
|
+
for i in range(ndim):
|
|
313
313
|
c += a_array[i] * b_array[i]
|
|
314
|
-
return c
|
|
314
|
+
return 1 - c
|
|
315
315
|
|
|
316
316
|
index = Index(ndim=ndim, metric=python_dot.address)
|
|
317
317
|
```
|
|
@@ -374,8 +374,17 @@ cargo add usearch
|
|
|
374
374
|
#### Quickstart
|
|
375
375
|
|
|
376
376
|
```rust
|
|
377
|
-
|
|
378
|
-
let
|
|
377
|
+
|
|
378
|
+
let options = IndexOptions {
|
|
379
|
+
dimensions: 5,
|
|
380
|
+
metric: MetricKind::IP,
|
|
381
|
+
quantization: ScalarKind::F16,
|
|
382
|
+
connectivity: 0,
|
|
383
|
+
expansion_add: 0,
|
|
384
|
+
expansion_search: 0
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
let index = new_index(&options).unwrap();
|
|
379
388
|
|
|
380
389
|
assert!(index.reserve(10).is_ok());
|
|
381
390
|
assert!(index.capacity() >= 10);
|
|
@@ -497,11 +506,6 @@ func main() {
|
|
|
497
506
|
|
|
498
507
|
### Wolfram
|
|
499
508
|
|
|
500
|
-
## TODO
|
|
501
|
-
|
|
502
|
-
- JavaScript: Allow calling from "worker threads".
|
|
503
|
-
- Rust: Allow passing a custom thread ID.
|
|
504
|
-
- C# .NET bindings.
|
|
505
509
|
|
|
506
510
|
## Application Examples
|
|
507
511
|
|
|
@@ -538,12 +542,33 @@ def search(query: str) -> np.ndarray:
|
|
|
538
542
|
server.run()
|
|
539
543
|
```
|
|
540
544
|
|
|
545
|
+
We have pre-processed some commonly used datasets, cleaning the images, producing the vectors, and pre-building the index.
|
|
546
|
+
|
|
547
|
+
| Dataset | Size | Images | Preprocessed |
|
|
548
|
+
| :---------------------------------- | ---: | -----: | --------------------: |
|
|
549
|
+
| [Unsplash 25K][unsplash-25k-origin] | - | 25 K | [HF][unsplash-25k-hf] |
|
|
550
|
+
| [Unsplash 2M][unsplash-2m-origin] | - | 2 M | [HF][unsplash-2m-hf] |
|
|
551
|
+
| [LAION 400M][laion-400m-origin] | - | 400 M | [HF][laion-400m-hf] |
|
|
552
|
+
| [LAION 5B][laion-5b-origin] | - | 5 B | [HF][laion-5b-hf] |
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
[unsplash-25k-origin]: https://unum.cloud
|
|
556
|
+
[unsplash-2m-origin]: https://unum.cloud
|
|
557
|
+
[laion-400m-origin]: https://unum.cloud
|
|
558
|
+
[laion-5b-origin]: https://unum.cloud
|
|
559
|
+
[unsplash-25k-hf]: https://unum.cloud
|
|
560
|
+
[unsplash-2m-hf]: https://unum.cloud
|
|
561
|
+
[laion-400m-hf]: https://unum.cloud
|
|
562
|
+
[laion-5b-hf]: https://unum.cloud
|
|
563
|
+
|
|
541
564
|
### USearch + RDKit = Molecular Search
|
|
542
565
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
566
|
+
Comparing molecule graphs and searching for similar structures is expensive and slow.
|
|
567
|
+
It can be seen as a special case of the NP-Complete Subgraph Isomorphism problem.
|
|
568
|
+
Luckily, domain-specific approximate methods exists.
|
|
569
|
+
The one commonly used in Chemistry, is to generate structures from [SMILES][smiles], and later hash them into binary fingerprints.
|
|
570
|
+
The later are searchable with bitwise similarity metrics, like the Tanimoto coefficient.
|
|
571
|
+
Below is na example using the RDKit package.
|
|
547
572
|
|
|
548
573
|
```python
|
|
549
574
|
from usearch.index import Index, MetricKind
|
|
@@ -565,10 +590,58 @@ index.add(labels, fingerprints)
|
|
|
565
590
|
matches = index.search(fingerprints, 10)
|
|
566
591
|
```
|
|
567
592
|
|
|
568
|
-
RDKit [provides][rdkit-fingerprints]
|
|
593
|
+
RDKit [provides][rdkit-fingerprints] following fingerprinting techniques:
|
|
594
|
+
|
|
595
|
+
- Atom-Pair,
|
|
596
|
+
- Topological Torsion,
|
|
597
|
+
- Morgan,
|
|
598
|
+
- Layered Fingerprints.
|
|
599
|
+
|
|
600
|
+
We have preprocessed some of the most commonly used datasets, and made it available for free on the HuggingFace portal, together with visual interface.
|
|
601
|
+
|
|
602
|
+
| Dataset | Size | Molecules | Preprocessed |
|
|
603
|
+
| :------------------------ | -------: | ----------: | ---------------: |
|
|
604
|
+
| [PubChem][pubchem-origin] | 8 GB | 115'034'339 | [HF][pubchem-hf] |
|
|
605
|
+
| [GDB 13][gdb13-origin] | 2.3 GB | 977'468'301 | [HF][gdb13-hf] |
|
|
606
|
+
| [REAL][real-origin] | > 100 GB | 6 B | [HF][real-hf] |
|
|
569
607
|
|
|
608
|
+
[smiles]: https://en.wikipedia.org/wiki/Simplified_molecular-input_line-entry_system
|
|
570
609
|
[rdkit-fingerprints]: https://www.rdkit.org/docs/RDKit_Book.html#additional-information-about-the-fingerprints
|
|
571
610
|
|
|
611
|
+
[gdb13-origin]: https://zenodo.org/record/5172018/files/gdb13.tgz?download=1
|
|
612
|
+
[pubchem-origin]: ftp://ftp.ncbi.nlm.nih.gov/pubchem/Compound/Extras/CID-SMILES.gz
|
|
613
|
+
[real-origin]: https://enamine.net/compound-collections/real-compounds/real-database
|
|
614
|
+
[pubchem-hf]: https://unum.cloud
|
|
615
|
+
[gdb13-hf]: https://unum.cloud
|
|
616
|
+
[real-hf]: https://unum.cloud
|
|
617
|
+
|
|
618
|
+
## TODO
|
|
619
|
+
|
|
620
|
+
- JavaScript: Allow calling from "worker threads".
|
|
621
|
+
- Rust: Allow passing a custom thread ID.
|
|
622
|
+
- C# .NET bindings.
|
|
623
|
+
|
|
624
|
+
## Integrations
|
|
625
|
+
|
|
626
|
+
- [x] GPT-Cache.
|
|
627
|
+
- [ ] Langchain.
|
|
628
|
+
- [ ] Microsoft Semantic Kernel.
|
|
629
|
+
- [ ] PyTorch.
|
|
630
|
+
|
|
631
|
+
## Citations
|
|
632
|
+
|
|
633
|
+
```txt
|
|
634
|
+
@software{Vardanian_USearch_2022,
|
|
635
|
+
doi = {10.5281/zenodo.7949416},
|
|
636
|
+
author = {Vardanian, Ash},
|
|
637
|
+
title = {{USearch by Unum Cloud}},
|
|
638
|
+
url = {https://github.com/unum-cloud/usearch},
|
|
639
|
+
version = {0.13.0},
|
|
640
|
+
year = {2022}
|
|
641
|
+
month = jun,
|
|
642
|
+
}
|
|
643
|
+
```
|
|
644
|
+
|
|
572
645
|
---
|
|
573
646
|
|
|
574
647
|
Check [that](https://github.com/ashvardanian/image-search) and [other](https://github.com/unum-cloud/examples) examples on our corporate GitHub 🤗
|
package/binding.gyp
CHANGED
package/build.gradle
CHANGED
|
@@ -45,7 +45,7 @@ model {
|
|
|
45
45
|
include "**/*.cpp"
|
|
46
46
|
}
|
|
47
47
|
exportedHeaders {
|
|
48
|
-
srcDirs "include", "
|
|
48
|
+
srcDirs "include", "fp16/include", "robin-map/include", "simsimd/include", "${Jvm.current().javaHome}/include"
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
}
|
package/build.rs
CHANGED
|
@@ -5,7 +5,6 @@ fn main() {
|
|
|
5
5
|
.flag_if_supported("-Wno-unknown-pragmas")
|
|
6
6
|
.include("include")
|
|
7
7
|
.include("rust")
|
|
8
|
-
.include("src")
|
|
9
8
|
.include("fp16/include")
|
|
10
9
|
.include("robin-map/include")
|
|
11
10
|
.include("simsimd/include")
|
|
@@ -14,6 +13,7 @@ fn main() {
|
|
|
14
13
|
println!("cargo:rerun-if-changed=rust/lib.rs");
|
|
15
14
|
println!("cargo:rerun-if-changed=rust/lib.cpp");
|
|
16
15
|
println!("cargo:rerun-if-changed=rust/lib.hpp");
|
|
17
|
-
println!("cargo:rerun-if-changed=
|
|
18
|
-
println!("cargo:rerun-if-changed=include/
|
|
16
|
+
println!("cargo:rerun-if-changed=include/index_punned_helpers.hpp");
|
|
17
|
+
println!("cargo:rerun-if-changed=include/index_punned_dense.hpp");
|
|
18
|
+
println!("cargo:rerun-if-changed=include/usearch/index.hpp");
|
|
19
19
|
}
|
package/c/lib.cpp
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#include "../src/
|
|
1
|
+
#include "../src/index_punned_dense.hpp"
|
|
2
2
|
|
|
3
3
|
extern "C" {
|
|
4
4
|
#include "usearch.h"
|
|
@@ -9,13 +9,36 @@ using namespace unum;
|
|
|
9
9
|
|
|
10
10
|
using label_t = int;
|
|
11
11
|
using distance_t = float;
|
|
12
|
-
using punned_index_t =
|
|
12
|
+
using punned_index_t = index_punned_dense_gt<label_t>;
|
|
13
13
|
using span_t = span_gt<float>;
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
metric_kind_t to_native_metric(usearch_metric_kind_t kind) {
|
|
16
|
+
switch (kind) {
|
|
17
|
+
case usearch_metric_ip_k: return metric_kind_t::ip_k;
|
|
18
|
+
case usearch_metric_l2sq_k: return metric_kind_t::l2sq_k;
|
|
19
|
+
case usearch_metric_cos_k: return metric_kind_t::cos_k;
|
|
20
|
+
case usearch_metric_haversine_k: return metric_kind_t::haversine_k;
|
|
21
|
+
case usearch_metric_pearson_k: return metric_kind_t::pearson_k;
|
|
22
|
+
case usearch_metric_jaccard_k: return metric_kind_t::jaccard_k;
|
|
23
|
+
case usearch_metric_hamming_k: return metric_kind_t::hamming_k;
|
|
24
|
+
case usearch_metric_tanimoto_k: return metric_kind_t::tanimoto_k;
|
|
25
|
+
case usearch_metric_sorensen_k: return metric_kind_t::sorensen_k;
|
|
26
|
+
default: return metric_kind_t::unknown_k;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
scalar_kind_t to_native_scalar(usearch_scalar_kind_t kind) {
|
|
31
|
+
switch (kind) {
|
|
32
|
+
case usearch_scalar_f32_k: return scalar_kind_t::f32_k;
|
|
33
|
+
case usearch_scalar_f64_k: return scalar_kind_t::f64_k;
|
|
34
|
+
case usearch_scalar_f16_k: return scalar_kind_t::f16_k;
|
|
35
|
+
case usearch_scalar_f8_k: return scalar_kind_t::f8_k;
|
|
36
|
+
case usearch_scalar_b1_k: return scalar_kind_t::b1_k;
|
|
37
|
+
default: return scalar_kind_t::unknown_k;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
void usearch_init(usearch_init_options_t* options, usearch_index_t* index, usearch_error_t* error) {
|
|
19
42
|
|
|
20
43
|
try {
|
|
21
44
|
config_t config;
|
|
@@ -37,8 +60,8 @@ void* usearch_new( //
|
|
|
37
60
|
// std::size_t bytes_to_alloc = sizeof(punned_index_t) + bytes_for_error_messages;
|
|
38
61
|
// safe_punned_index_t* result = (safe_punned_index_t*)std::malloc(bytes_to_alloc);
|
|
39
62
|
|
|
40
|
-
|
|
41
|
-
|
|
63
|
+
scalar_kind_t accuracy = scalar_kind_from_name(accuracy_str, accuracy_len);
|
|
64
|
+
metric_kind_t metric_kind = metric_from_name(metric_str, metric_len);
|
|
42
65
|
punned_index_t index = make_punned<punned_index_t>( //
|
|
43
66
|
metric_kind, static_cast<std::size_t>(dimensions), accuracy, config);
|
|
44
67
|
|
|
@@ -49,7 +72,7 @@ void* usearch_new( //
|
|
|
49
72
|
return NULL;
|
|
50
73
|
}
|
|
51
74
|
|
|
52
|
-
void
|
|
75
|
+
void usearch_free(punned_index_t* index) { delete index; }
|
|
53
76
|
|
|
54
77
|
char const* usearch_save(punned_index_t* index, char const* path) {
|
|
55
78
|
try {
|