usearch 0.1.10 → 0.2.2
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 +12 -1
- package/.vscode/launch.json +5 -4
- package/.vscode/settings.json +7 -1
- package/CMakeLists.txt +11 -6
- package/CMakeListsInstructions.md +39 -17
- package/Cargo.toml +1 -1
- package/Package.swift +40 -0
- package/README.md +36 -18
- package/VERSION +1 -1
- package/build.gradle +5 -1
- package/cmake/jemalloc.cmake +0 -2
- package/conanfile.py +18 -0
- package/include/usearch/usearch.hpp +337 -228
- package/javascript/lib.cpp +8 -2
- package/objc/USearchObjective.mm +150 -0
- package/objc/include/USearchObjective.h +69 -0
- package/package.json +1 -1
- package/pyproject.toml +18 -4
- package/python/bench.py +14 -2
- package/python/lib.cpp +353 -43
- package/python/test.py +10 -4
- package/python/usearch/__init__.py +0 -0
- package/rust/lib.cpp +13 -2
- package/setup.py +8 -3
- package/simsimd/include/simsimd/simsimd.h +15 -0
- package/src/advanced.hpp +232 -122
- package/src/bench.cpp +249 -79
- package/swift/Index+Sugar.swift +70 -0
- package/swift/Test.swift +20 -0
- package/swift/USearch.swift +8 -0
- package/java/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/java/gradle/wrapper/gradle-wrapper.properties +0 -6
- package/java/gradlew +0 -244
|
@@ -32,7 +32,7 @@ jobs:
|
|
|
32
32
|
# needs: versioning
|
|
33
33
|
strategy:
|
|
34
34
|
matrix:
|
|
35
|
-
os: [ubuntu-20.04, macOS-11]
|
|
35
|
+
os: [ubuntu-20.04, macOS-11, windows-2022]
|
|
36
36
|
|
|
37
37
|
steps:
|
|
38
38
|
- uses: actions/checkout@v3
|
|
@@ -130,6 +130,17 @@ jobs:
|
|
|
130
130
|
env:
|
|
131
131
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
132
132
|
|
|
133
|
+
publish_swift:
|
|
134
|
+
name: Publish ObjC & Swift
|
|
135
|
+
runs-on: macos-latest
|
|
136
|
+
steps:
|
|
137
|
+
- uses: actions/checkout@v3
|
|
138
|
+
- run: git submodule update --init --recursive
|
|
139
|
+
- name: Build
|
|
140
|
+
run: swift build
|
|
141
|
+
- name: Run tests
|
|
142
|
+
run: swift test
|
|
143
|
+
|
|
133
144
|
deploy_docs:
|
|
134
145
|
name: Deploy Docs
|
|
135
146
|
environment:
|
package/.vscode/launch.json
CHANGED
|
@@ -36,18 +36,19 @@
|
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
38
|
{
|
|
39
|
-
"name": "Debug C++ Bench on Text-to-Image
|
|
39
|
+
"name": "Debug C++ Bench on Text-to-Image 1B @Cos",
|
|
40
40
|
"type": "cppdbg",
|
|
41
41
|
"request": "launch",
|
|
42
42
|
"program": "${workspaceFolder}/build_debug/bench",
|
|
43
43
|
"cwd": "${workspaceFolder}",
|
|
44
44
|
"args": [
|
|
45
45
|
"--vectors",
|
|
46
|
-
"datasets/
|
|
46
|
+
"datasets/t2i_1B/base.1B.fbin",
|
|
47
47
|
"--queries",
|
|
48
|
-
"datasets/
|
|
48
|
+
"datasets/t2i_1B/query.public.100K.fbin",
|
|
49
49
|
"--neighbors",
|
|
50
|
-
"datasets/
|
|
50
|
+
"datasets/t2i_1B/groundtruth.public.100K.ibin",
|
|
51
|
+
"--cos"
|
|
51
52
|
],
|
|
52
53
|
"environment": [
|
|
53
54
|
{
|
package/.vscode/settings.json
CHANGED
|
@@ -97,13 +97,19 @@
|
|
|
97
97
|
"__memory": "cpp",
|
|
98
98
|
"filesystem": "cpp",
|
|
99
99
|
"__availability": "cpp",
|
|
100
|
-
"version": "cpp"
|
|
100
|
+
"version": "cpp",
|
|
101
|
+
"future": "cpp"
|
|
101
102
|
},
|
|
102
103
|
"cSpell.words": [
|
|
104
|
+
"astype",
|
|
105
|
+
"dtype",
|
|
103
106
|
"equidimensional",
|
|
107
|
+
"hashable",
|
|
104
108
|
"jaccard",
|
|
109
|
+
"longlong",
|
|
105
110
|
"memmap",
|
|
106
111
|
"ndim",
|
|
112
|
+
"preprocess",
|
|
107
113
|
"simsimd",
|
|
108
114
|
"usearch"
|
|
109
115
|
],
|
package/CMakeLists.txt
CHANGED
|
@@ -17,22 +17,18 @@ if(NOT CMAKE_BUILD_TYPE)
|
|
|
17
17
|
set(CMAKE_BUILD_TYPE Release)
|
|
18
18
|
endif()
|
|
19
19
|
|
|
20
|
-
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -O0")
|
|
21
|
-
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
|
|
22
|
-
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -O3 -pg -g")
|
|
23
|
-
|
|
24
20
|
# List of all possible compiler IDs:
|
|
25
21
|
# https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_COMPILER_ID.html
|
|
26
22
|
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
|
27
23
|
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=address")
|
|
28
|
-
set(
|
|
24
|
+
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall -Wextra -Wno-conversion -Wno-unknown-pragmas")
|
|
29
25
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
|
|
30
26
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fmax-errors=1")
|
|
31
27
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp")
|
|
32
28
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic")
|
|
33
29
|
|
|
34
30
|
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
|
35
|
-
set(
|
|
31
|
+
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wfatal-errors")
|
|
36
32
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp")
|
|
37
33
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic")
|
|
38
34
|
|
|
@@ -46,6 +42,15 @@ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "NVIDIA" OR CMAKE_CXX_COMPILER_ID STREQUAL
|
|
|
46
42
|
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM")
|
|
47
43
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -w")
|
|
48
44
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ferror-limit=1")
|
|
45
|
+
|
|
46
|
+
elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
|
47
|
+
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /DEBUG")
|
|
48
|
+
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /O2")
|
|
49
|
+
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /O2 /DEBUG")
|
|
50
|
+
else()
|
|
51
|
+
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -O0")
|
|
52
|
+
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
|
|
53
|
+
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -O3 -pg -g")
|
|
49
54
|
endif()
|
|
50
55
|
|
|
51
56
|
if(APPLE)
|
|
@@ -12,6 +12,7 @@ git submodule update --init --recursive
|
|
|
12
12
|
|
|
13
13
|
```sh
|
|
14
14
|
cmake -B ./build_release \
|
|
15
|
+
-DCMAKE_CXX_COMPILER="g++-12" \
|
|
15
16
|
-DCMAKE_BUILD_TYPE=Release \
|
|
16
17
|
-DUSEARCH_USE_SIMD=1 \
|
|
17
18
|
-DUSEARCH_USE_OPENMP=1 \
|
|
@@ -24,6 +25,14 @@ cmake -B ./build_release \
|
|
|
24
25
|
--queries datasets/wiki_1M/query.public.100K.fbin \
|
|
25
26
|
--neighbors datasets/wiki_1M/groundtruth.public.100K.ibin
|
|
26
27
|
|
|
28
|
+
# Large benchmark on a 1TB dataset:
|
|
29
|
+
./build_release/bench \
|
|
30
|
+
--vectors datasets/t2i_1B/base.1B.fbin \
|
|
31
|
+
--queries datasets/t2i_1B/query.public.100K.fbin \
|
|
32
|
+
--neighbors datasets/t2i_1B/groundtruth.public.100K.ibin \
|
|
33
|
+
--output datasets/t2i_1B/index.usearch \
|
|
34
|
+
--cos
|
|
35
|
+
|
|
27
36
|
# To benchmark in Python:
|
|
28
37
|
python python/bench.py \
|
|
29
38
|
--vectors datasets/wiki_1M/base.1M.fbin \
|
|
@@ -110,44 +119,57 @@ brew install --cask wolfram-engine
|
|
|
110
119
|
BigANN benchmark is a good starting point, if you are searching for large collections of high-dimensional vectors.
|
|
111
120
|
Those often come with precomputed ground-truth neighbors, which is handy for recall evaluation.
|
|
112
121
|
|
|
113
|
-
| Dataset
|
|
114
|
-
|
|
|
115
|
-
| [
|
|
116
|
-
| [
|
|
117
|
-
|
|
|
118
|
-
| [
|
|
122
|
+
| Dataset | Scalar Type | Dimensions | Metric | Size |
|
|
123
|
+
| :-------------------------------------- | :---------: | :--------: | :----: | :-------: |
|
|
124
|
+
| [Unum UForm Wiki][unum-wiki] | float32 | 256 | IP | 1 GB |
|
|
125
|
+
| [Yandex Text-to-Image Sample][unum-t2i] | float32 | 200 | Cos | 1 GB |
|
|
126
|
+
| | | | | |
|
|
127
|
+
| [Microsoft SPACEV][spacev] | int8 | 100 | L2 | 93 GB |
|
|
128
|
+
| [Microsoft Turing-ANNS][turing] | float32 | 100 | L2 | 373 GB |
|
|
129
|
+
| [Yandex Deep1B][deep] | float32 | 96 | L2 | 358 GB |
|
|
130
|
+
| [Yandex Text-to-Image][t2i] | float32 | 200 | Cos | 750 GB |
|
|
131
|
+
| | | | | |
|
|
132
|
+
| [ViT-L/12 LAION][laion] | float32 | 2048 | Cos | 2 - 10 TB |
|
|
119
133
|
|
|
120
134
|
Luckily, smaller samples of those datasets are available.
|
|
121
135
|
|
|
136
|
+
[unum-wiki]: https://huggingface.co/datasets/unum-cloud/ann-wiki-1m
|
|
137
|
+
[unum-t2i]: https://huggingface.co/datasets/unum-cloud/ann-t2i-1m
|
|
122
138
|
[spacev]: https://github.com/microsoft/SPTAG/tree/main/datasets/SPACEV1B
|
|
123
139
|
[turing]: https://learning2hash.github.io/publications/microsoftturinganns1B/
|
|
124
140
|
[t2i]: https://research.yandex.com/blog/benchmarks-for-billion-scale-similarity-search
|
|
125
141
|
[deep]: https://research.yandex.com/blog/benchmarks-for-billion-scale-similarity-search
|
|
142
|
+
[laion]: https://laion.ai/blog/laion-5b/#download-the-data
|
|
126
143
|
|
|
127
|
-
###
|
|
128
|
-
|
|
129
|
-
There is a 10M subset available.
|
|
144
|
+
### Unum UForm Wiki
|
|
130
145
|
|
|
131
146
|
```sh
|
|
132
|
-
mkdir -p datasets/
|
|
133
|
-
wget -nc https://
|
|
134
|
-
wget -nc https://
|
|
135
|
-
wget -nc https://
|
|
136
|
-
wget -nc https://storage.yandexcloud.net/yandex-research/ann-datasets/DEEP/groundtruth.public.10K.ibin -P datasets/deep_1B/
|
|
147
|
+
mkdir -p datasets/wiki_1M/ && \
|
|
148
|
+
wget -nc https://huggingface.co/datasets/unum-cloud/ann-wiki-1m/resolve/main/base.1M.fbin -P datasets/wiki_1M/ &&
|
|
149
|
+
wget -nc https://huggingface.co/datasets/unum-cloud/ann-wiki-1m/resolve/main/query.public.100K.fbin -P datasets/wiki_1M/ &&
|
|
150
|
+
wget -nc https://huggingface.co/datasets/unum-cloud/ann-wiki-1m/resolve/main/groundtruth.public.100K.ibin -P datasets/wiki_1M/
|
|
137
151
|
```
|
|
138
152
|
|
|
139
153
|
### Yandex Text-to-Image
|
|
140
154
|
|
|
141
|
-
There is a 1M subset available.
|
|
142
|
-
|
|
143
155
|
```sh
|
|
144
|
-
mkdir -p datasets/
|
|
156
|
+
mkdir -p datasets/t2i_1B/ && \
|
|
145
157
|
wget -nc https://storage.yandexcloud.net/yandex-research/ann-datasets/T2I/base.1B.fbin -P datasets/t2i_1B/ &&
|
|
146
158
|
wget -nc https://storage.yandexcloud.net/yandex-research/ann-datasets/T2I/base.1M.fbin -P datasets/t2i_1B/ &&
|
|
147
159
|
wget -nc https://storage.yandexcloud.net/yandex-research/ann-datasets/T2I/query.public.100K.fbin -P datasets/t2i_1B/ &&
|
|
148
160
|
wget -nc https://storage.yandexcloud.net/yandex-research/ann-datasets/T2I/groundtruth.public.100K.ibin -P datasets/t2i_1B/
|
|
149
161
|
```
|
|
150
162
|
|
|
163
|
+
### Yandex Deep1B
|
|
164
|
+
|
|
165
|
+
```sh
|
|
166
|
+
mkdir -p datasets/deep_1B/ && \
|
|
167
|
+
wget -nc https://storage.yandexcloud.net/yandex-research/ann-datasets/DEEP/base.1B.fbin -P datasets/deep_1B/ &&
|
|
168
|
+
wget -nc https://storage.yandexcloud.net/yandex-research/ann-datasets/DEEP/base.10M.fbin -P datasets/deep_1B/ &&
|
|
169
|
+
wget -nc https://storage.yandexcloud.net/yandex-research/ann-datasets/DEEP/query.public.10K.fbin -P datasets/deep_1B/ &&
|
|
170
|
+
wget -nc https://storage.yandexcloud.net/yandex-research/ann-datasets/DEEP/groundtruth.public.10K.ibin -P datasets/deep_1B/
|
|
171
|
+
```
|
|
172
|
+
|
|
151
173
|
### Profiling
|
|
152
174
|
|
|
153
175
|
With `perf`:
|
package/Cargo.toml
CHANGED
package/Package.swift
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// swift-tools-version:5.3
|
|
2
|
+
|
|
3
|
+
import PackageDescription
|
|
4
|
+
|
|
5
|
+
let package = Package(
|
|
6
|
+
name: "USearch",
|
|
7
|
+
products: [
|
|
8
|
+
.library(
|
|
9
|
+
name: "USearch",
|
|
10
|
+
targets: ["USearchObjective", "USearch"]
|
|
11
|
+
)
|
|
12
|
+
],
|
|
13
|
+
dependencies: [],
|
|
14
|
+
targets: [
|
|
15
|
+
.target(
|
|
16
|
+
name: "USearchObjective",
|
|
17
|
+
path: "objc",
|
|
18
|
+
sources: ["USearchObjective.mm"],
|
|
19
|
+
cxxSettings: [
|
|
20
|
+
.headerSearchPath("../include/"),
|
|
21
|
+
.headerSearchPath("../src/"),
|
|
22
|
+
.headerSearchPath("../fp16/include/"),
|
|
23
|
+
.headerSearchPath("../simismd/include/")
|
|
24
|
+
]
|
|
25
|
+
),
|
|
26
|
+
.target(
|
|
27
|
+
name: "USearch",
|
|
28
|
+
dependencies: ["USearchObjective"],
|
|
29
|
+
path: "swift",
|
|
30
|
+
sources: ["USearch.swift", "Index+Sugar.swift"]
|
|
31
|
+
),
|
|
32
|
+
.testTarget(
|
|
33
|
+
name: "USearchTests",
|
|
34
|
+
dependencies: ["USearch"],
|
|
35
|
+
path: "swift",
|
|
36
|
+
sources: ["Test.swift"]
|
|
37
|
+
)
|
|
38
|
+
],
|
|
39
|
+
cxxLanguageStandard: CXXLanguageStandard.cxx11
|
|
40
|
+
)
|
package/README.md
CHANGED
|
@@ -30,7 +30,7 @@ Vector Search Engine<br/>
|
|
|
30
30
|
- [x] [Bring your threads](#bring-your-threads), like OpenMP.
|
|
31
31
|
- [x] Multiple vectors per label.
|
|
32
32
|
- [x] [Python](#python) bindings: `pip install usearch`.
|
|
33
|
-
- [x] [JavaScript](#
|
|
33
|
+
- [x] [JavaScript](#javascript) bindings: `npm install usearch`.
|
|
34
34
|
- [x] [Rust](#rust) bindings: `cargo add usearch`.
|
|
35
35
|
- [x] [Java](#java) bindings: `cloud.unum:usearch` on GitHub.
|
|
36
36
|
- [ ] GoLang bindings.
|
|
@@ -108,7 +108,7 @@ So, if you are working on large datasets, but don't need the in-RAM throughput,
|
|
|
108
108
|
### Quantize on the Fly
|
|
109
109
|
|
|
110
110
|
Most modern CPU have at least partial support for `half`-precision `f16_t` arithmetic.
|
|
111
|
-
USearch supports automatic down-casting and up-casting between `f32_t`, `f16_t`, `f64_t`, and `
|
|
111
|
+
USearch supports automatic down-casting and up-casting between `f32_t`, `f16_t`, `f64_t`, and `f8_t` representations.
|
|
112
112
|
|
|
113
113
|
> Making vectors smaller will help pack more of them in-memory, while also increasing performance on CPUs implementing native support for target type.
|
|
114
114
|
|
|
@@ -160,7 +160,7 @@ That can be one of the following templates:
|
|
|
160
160
|
|
|
161
161
|
- `cos_gt<float>` for "Cosine" or "Angular" distance.
|
|
162
162
|
- `ip_gt<float>` for "Inner Product" or "Dot Product" distance.
|
|
163
|
-
- `
|
|
163
|
+
- `l2sq_gt<float>` for the squared "L2" or "Euclidean" distance.
|
|
164
164
|
- `jaccard_gt<int>` for "Jaccard" distance between two ordered sets of unique elements.
|
|
165
165
|
- `bit_hamming_gt<uint>` for "Hamming" distance, as the number of shared bits in hashes.
|
|
166
166
|
- `pearson_correlation_gt<float>` for "Pearson" correlation between probability distributions.
|
|
@@ -216,17 +216,26 @@ Assuming the presence of Global Interpreter Lock in Python, on large insertions
|
|
|
216
216
|
$ pip install usearch
|
|
217
217
|
|
|
218
218
|
import numpy as np
|
|
219
|
-
import
|
|
219
|
+
from usearch.index import Index
|
|
220
220
|
|
|
221
|
-
index =
|
|
221
|
+
index = Index(
|
|
222
222
|
ndim=256, # Define the number of dimensions in input vectors
|
|
223
223
|
metric='cos', # Choose the "metric" or "distance", default = 'ip', optional
|
|
224
|
-
dtype='f32', # Quantize to 'f16' or '
|
|
224
|
+
dtype='f32', # Quantize to 'f16' or 'f8' if needed, default = 'f32', optional
|
|
225
225
|
connectivity=16, # How frequent should the connections in the graph be, optional
|
|
226
226
|
expansion_add=128, # Control the recall of indexing, optional
|
|
227
227
|
expansion_search=64, # Control the quality of search, optional
|
|
228
228
|
)
|
|
229
229
|
|
|
230
|
+
vector = np.random.uniform(0, 0.3, (index.ndim)).astype(np.float32)
|
|
231
|
+
index.add(42, vector)
|
|
232
|
+
matches, distances, count = index.search(vector, 10)
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Same can be done with batches, rather than single entries.
|
|
236
|
+
Under the hood, worker threads will be spawned, to parallelize the procedure.
|
|
237
|
+
|
|
238
|
+
```py
|
|
230
239
|
n = 100
|
|
231
240
|
labels = np.array(range(n), dtype=np.longlong)
|
|
232
241
|
vectors = np.random.uniform(0, 0.3, (n, index.ndim)).astype(np.float32)
|
|
@@ -234,9 +243,6 @@ vectors = np.random.uniform(0, 0.3, (n, index.ndim)).astype(np.float32)
|
|
|
234
243
|
# You can avoid copying the data
|
|
235
244
|
# Handy when build 1B+ indexes of memory-mapped files
|
|
236
245
|
index.add(labels, vectors, copy=True)
|
|
237
|
-
assert len(index) == n
|
|
238
|
-
|
|
239
|
-
# You can search a batch at once
|
|
240
246
|
matches, distances, counts = index.search(vectors, 10)
|
|
241
247
|
```
|
|
242
248
|
|
|
@@ -267,7 +273,7 @@ Aside from the `add` and `search`, it also provides `add_in_thread` and `search_
|
|
|
267
273
|
// cargo add usearch
|
|
268
274
|
|
|
269
275
|
let quant: &str = "f16";
|
|
270
|
-
let index = new_ip(5,
|
|
276
|
+
let index = new_ip(5, &quant, 0, 0, 0).unwrap();
|
|
271
277
|
|
|
272
278
|
assert!(index.reserve(10).is_ok());
|
|
273
279
|
assert!(index.capacity() >= 10);
|
|
@@ -292,8 +298,8 @@ assert!(index.load("index.usearch").is_ok());
|
|
|
292
298
|
assert!(index.view("index.usearch").is_ok());
|
|
293
299
|
|
|
294
300
|
// There are more "metrics" available
|
|
295
|
-
assert!(new_l2(5,
|
|
296
|
-
assert!(new_cos(5,
|
|
301
|
+
assert!(new_l2(5, &quant, 0, 0, 0).is_ok());
|
|
302
|
+
assert!(new_cos(5, &quant, 0, 0, 0).is_ok());
|
|
297
303
|
assert!(new_haversine(&quant, 0, 0, 0).is_ok());
|
|
298
304
|
```
|
|
299
305
|
|
|
@@ -306,6 +312,19 @@ index.add(42, vec);
|
|
|
306
312
|
int[] labels = index.search(vec, 5);
|
|
307
313
|
```
|
|
308
314
|
|
|
315
|
+
### Objective-C and Swift
|
|
316
|
+
|
|
317
|
+
```swift
|
|
318
|
+
let index = Index.l2(dimensions: 4, connectivity: 8)
|
|
319
|
+
let vectorA: [Float32] = [0.3, 0.5, 1.2, 1.4]
|
|
320
|
+
let vectorB: [Float32] = [0.4, 0.2, 1.2, 1.1]
|
|
321
|
+
index.add(label: 42, vector: vectorA[...])
|
|
322
|
+
index.add(label: 43, vector: vectorB[...])
|
|
323
|
+
|
|
324
|
+
let results = index.search(vector: vectorA[...], count: 10)
|
|
325
|
+
assert(results.0[0] == 42)
|
|
326
|
+
```
|
|
327
|
+
|
|
309
328
|
### GoLang
|
|
310
329
|
|
|
311
330
|
### Wolfram
|
|
@@ -394,28 +413,27 @@ One can take an encoder model, like the multi-modal UForm, and a web-programming
|
|
|
394
413
|
```python
|
|
395
414
|
import ucall.rich_posix as ucall
|
|
396
415
|
import uform
|
|
397
|
-
import
|
|
416
|
+
from usearch.index import Index
|
|
398
417
|
|
|
399
418
|
import numpy as np
|
|
400
419
|
from PIL import Image
|
|
401
420
|
|
|
402
421
|
server = ucall.Server()
|
|
403
422
|
model = uform.get_model('unum-cloud/uform-vl-multilingual')
|
|
404
|
-
index =
|
|
423
|
+
index = Index(ndim=256)
|
|
405
424
|
|
|
406
425
|
@server
|
|
407
426
|
def add(label: int, photo: Image.Image):
|
|
408
427
|
image = model.preprocess_image(photo)
|
|
409
428
|
vector = model.encode_image(image).detach().numpy()
|
|
410
|
-
|
|
411
|
-
index.add(labels, vector, copy=True)
|
|
429
|
+
index.add(label, vector.flatten(), copy=True)
|
|
412
430
|
|
|
413
431
|
@server
|
|
414
432
|
def search(query: str) -> np.ndarray:
|
|
415
433
|
tokens = model.preprocess_text(query)
|
|
416
434
|
vector = model.encode_text(tokens).detach().numpy()
|
|
417
|
-
neighbors = index.search(vector, 3)
|
|
418
|
-
return neighbors
|
|
435
|
+
neighbors, _, _ = index.search(vector.flatten(), 3)
|
|
436
|
+
return neighbors
|
|
419
437
|
|
|
420
438
|
server.run()
|
|
421
439
|
```
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.2.2
|
package/build.gradle
CHANGED
|
@@ -56,11 +56,15 @@ model {
|
|
|
56
56
|
if (targetPlatform.operatingSystem.linux) {
|
|
57
57
|
cppCompiler.args '-I', "${Jvm.current().javaHome}/include/linux"
|
|
58
58
|
cppCompiler.args '-D_FILE_OFFSET_BITS=64'
|
|
59
|
+
cppCompiler.args '-std=c++11'
|
|
59
60
|
} else if (targetPlatform.operatingSystem.macOsX) {
|
|
60
61
|
cppCompiler.args '-I', "${Jvm.current().javaHome}/include/darwin"
|
|
61
62
|
cppCompiler.args '-D_FILE_OFFSET_BITS=64'
|
|
63
|
+
cppCompiler.args '-std=c++11'
|
|
64
|
+
} else if (targetPlatform.operatingSystem.windows){
|
|
65
|
+
cppCompiler.args "-I${Jvm.current().javaHome}/include/win32"
|
|
66
|
+
cppCompiler.args '/std:c++11'
|
|
62
67
|
}
|
|
63
|
-
cppCompiler.args '-std=c++11'
|
|
64
68
|
}
|
|
65
69
|
}
|
|
66
70
|
}
|
package/cmake/jemalloc.cmake
CHANGED
package/conanfile.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from conans import ConanFile
|
|
2
|
+
|
|
3
|
+
class USearchConan(ConanFile):
|
|
4
|
+
|
|
5
|
+
name = 'USearch'
|
|
6
|
+
version = '0.2.2'
|
|
7
|
+
license = 'Apache 2.0'
|
|
8
|
+
url = 'https://github.com/unum-cloud/usearch'
|
|
9
|
+
description = 'Smaller & Faster Single-File Vector Search Engine from Unum'
|
|
10
|
+
|
|
11
|
+
# No settings/options are necessary, this is header only
|
|
12
|
+
# Potentially add unit-tests in the future:
|
|
13
|
+
# https://docs.conan.io/1/howtos/header_only.html#with-unit-tests
|
|
14
|
+
exports_sources = 'include/*'
|
|
15
|
+
no_copy_source = True
|
|
16
|
+
|
|
17
|
+
def package(self):
|
|
18
|
+
self.copy('*.h')
|