usearch 0.22.3 → 1.1.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/prerelease.yml +3 -3
- package/.releaserc +10 -2
- package/.vscode/launch.json +10 -10
- package/.vscode/settings.json +9 -1
- package/.vscode/tasks.json +4 -4
- package/CMakeLists.txt +6 -1
- package/Cargo.toml +2 -2
- package/README.md +35 -41
- package/build.rs +2 -2
- package/c/CMakeLists.txt +48 -0
- package/c/README.md +34 -0
- package/c/lib.cpp +83 -72
- package/c/test.c +20 -20
- package/c/usearch.h +132 -32
- package/conanfile.py +1 -1
- package/cpp/CMakeLists.txt +3 -1
- package/cpp/README.md +16 -16
- package/cpp/bench.cpp +50 -126
- package/cpp/test.cpp +164 -80
- package/docs/benchmarks.md +26 -5
- package/docs/c/reference.rst +3 -3
- package/docs/compilation.md +31 -49
- package/docs/cpp/index.rst +1 -1
- package/docs/cpp/reference.rst +4 -4
- package/golang/lib.go +275 -141
- package/golang/lib_test.go +105 -0
- package/include/usearch/index.hpp +1681 -1656
- package/include/usearch/index_dense.hpp +1400 -0
- package/include/usearch/index_plugins.hpp +1263 -0
- package/java/README.md +1 -1
- package/java/cloud/unum/usearch/Index.java +10 -10
- package/java/cloud/unum/usearch/cloud_unum_usearch_Index.cpp +34 -37
- package/java/test/IndexTest.java +1 -1
- package/javascript/README.md +6 -6
- package/javascript/lib.cpp +156 -55
- package/javascript/test.js +26 -11
- package/javascript/usearch.d.ts +102 -0
- package/javascript/usearch.js +2 -118
- package/objc/USearchObjective.mm +57 -31
- package/objc/include/USearchObjective.h +32 -22
- package/package.json +5 -3
- package/python/README.md +23 -14
- package/python/lib.cpp +468 -444
- package/python/scripts/bench.ipynb +3 -2
- package/python/scripts/bench.py +4 -4
- package/python/scripts/index_faiss.py +5 -5
- package/python/scripts/join.py +4 -4
- package/python/scripts/test.py +152 -61
- package/python/scripts/test_jit.py +10 -12
- package/python/scripts/test_sparse.py +32 -0
- package/python/usearch/client.py +26 -28
- package/python/usearch/eval.py +73 -23
- package/python/usearch/index.py +520 -228
- package/python/usearch/io.py +57 -25
- package/python/usearch/numba.py +4 -4
- package/python/usearch/server.py +10 -10
- package/rust/lib.cpp +34 -30
- package/rust/lib.hpp +14 -12
- package/rust/lib.rs +8 -7
- package/setup.py +5 -2
- package/simsimd/.github/workflows/prerelease.yml +73 -0
- package/simsimd/.github/workflows/release.yml +110 -0
- package/simsimd/.github/workflows/update_version.sh +3 -0
- package/simsimd/.releaserc +77 -0
- package/simsimd/.vscode/launch.json +27 -1
- package/simsimd/.vscode/settings.json +22 -1
- package/simsimd/.vscode/tasks.json +6 -0
- package/simsimd/CMakeLists.txt +3 -2
- package/simsimd/README.md +82 -46
- package/simsimd/bench.cxx +63 -24
- package/simsimd/include/simsimd/simsimd.h +88 -66
- package/simsimd/include/simsimd/simsimd_chem.h +126 -0
- package/simsimd/package.json +8 -0
- package/simsimd/pyproject.toml +42 -0
- package/simsimd/python/python.c +81 -0
- package/simsimd/python/run.sh +1 -0
- package/simsimd/python/test.c +109 -0
- package/simsimd/python/test.py +23 -0
- package/simsimd/setup.py +44 -0
- package/swift/Index+Sugar.swift +75 -23
- package/swift/README.md +26 -2
- package/swift/Test.swift +19 -7
- package/swift/USearch.swift +2 -2
- package/tsconfig.json +8 -0
- package/wasm/CMakeLists.txt +1 -0
- package/wasmer.toml +1 -1
- package/wolfram/CMakeLists.txt +1 -0
- package/wolfram/lib.cpp +11 -13
- package/golang/usearch.h +0 -9
- package/golang/usearch_par_test.go +0 -40
- package/golang/usearch_test.go +0 -82
- package/include/usearch/index_punned_dense.hpp +0 -1001
- package/include/usearch/index_punned_helpers.hpp +0 -676
package/cpp/test.cpp
CHANGED
|
@@ -3,8 +3,11 @@
|
|
|
3
3
|
*/
|
|
4
4
|
#include <algorithm>
|
|
5
5
|
#include <stdexcept>
|
|
6
|
+
#include <unordered_map>
|
|
6
7
|
|
|
7
|
-
#include <usearch/
|
|
8
|
+
#include <usearch/index.hpp>
|
|
9
|
+
#include <usearch/index_dense.hpp>
|
|
10
|
+
#include <usearch/index_plugins.hpp>
|
|
8
11
|
|
|
9
12
|
using namespace unum::usearch;
|
|
10
13
|
using namespace unum;
|
|
@@ -14,94 +17,197 @@ void expect(bool must_be_true) {
|
|
|
14
17
|
throw std::runtime_error("Failed!");
|
|
15
18
|
}
|
|
16
19
|
|
|
17
|
-
template <
|
|
20
|
+
template <bool punned_ak, typename index_at, typename scalar_at, typename... extra_args_at>
|
|
21
|
+
void test_cosine(index_at& index, std::vector<std::vector<scalar_at>> const& vectors, extra_args_at&&... args) {
|
|
18
22
|
|
|
19
23
|
using scalar_t = scalar_at;
|
|
20
|
-
using
|
|
21
|
-
using
|
|
24
|
+
using index_t = index_at;
|
|
25
|
+
using key_t = typename index_t::key_t;
|
|
22
26
|
using distance_t = typename index_t::distance_t;
|
|
23
|
-
using label_t = typename index_t::label_t;
|
|
24
27
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
// Generate some keys starting from end,
|
|
29
|
+
// for three vectors from the dataset
|
|
30
|
+
key_t const key_max = default_free_value<key_t>() - 1;
|
|
31
|
+
key_t const key_first = key_max - 0;
|
|
32
|
+
key_t const key_second = key_max - 1;
|
|
33
|
+
key_t const key_third = key_max - 2;
|
|
34
|
+
scalar_t const* vector_first = vectors[0].data();
|
|
35
|
+
scalar_t const* vector_second = vectors[1].data();
|
|
36
|
+
scalar_t const* vector_third = vectors[2].data();
|
|
37
|
+
std::size_t dimensions = vectors[0].size();
|
|
28
38
|
|
|
29
39
|
index.reserve(10);
|
|
30
|
-
index.add(
|
|
40
|
+
index.add(key_first, vector_first, args...);
|
|
31
41
|
|
|
32
42
|
// Default approximate search
|
|
33
|
-
|
|
43
|
+
key_t matched_labels[10] = {0};
|
|
34
44
|
distance_t matched_distances[10] = {0};
|
|
35
|
-
std::size_t matched_count = index.search(
|
|
45
|
+
std::size_t matched_count = index.search(vector_first, 5, args...).dump_to(matched_labels, matched_distances);
|
|
36
46
|
|
|
37
47
|
expect(matched_count == 1);
|
|
38
|
-
expect(matched_labels[0] ==
|
|
48
|
+
expect(matched_labels[0] == key_first);
|
|
39
49
|
expect(std::abs(matched_distances[0]) < 0.01);
|
|
40
50
|
|
|
41
51
|
// Add more entries
|
|
42
|
-
|
|
52
|
+
index_search_config_t search_config;
|
|
43
53
|
search_config.exact = true;
|
|
44
|
-
index.add(
|
|
45
|
-
index.add(
|
|
54
|
+
index.add(key_second, vector_second, args...);
|
|
55
|
+
index.add(key_third, vector_third, args...);
|
|
46
56
|
expect(index.size() == 3);
|
|
47
57
|
|
|
48
58
|
// Perform exact search
|
|
49
|
-
matched_count = index.search(
|
|
59
|
+
matched_count = index.search(vector_first, 5, args..., search_config).dump_to(matched_labels, matched_distances);
|
|
50
60
|
|
|
51
61
|
// Validate scans
|
|
52
62
|
std::size_t count = 0;
|
|
53
63
|
for (auto member : index) {
|
|
54
|
-
|
|
55
|
-
expect(id
|
|
64
|
+
key_t id = member.key;
|
|
65
|
+
expect(id <= key_first && id >= key_third);
|
|
56
66
|
count++;
|
|
57
67
|
}
|
|
58
68
|
expect((count == 3));
|
|
59
69
|
expect((index.stats(0).nodes == 3));
|
|
60
70
|
|
|
71
|
+
// Try removals and replacements
|
|
72
|
+
if constexpr (punned_ak) {
|
|
73
|
+
using labeling_result_t = typename index_t::labeling_result_t;
|
|
74
|
+
labeling_result_t result = index.remove(key_third);
|
|
75
|
+
expect(bool(result));
|
|
76
|
+
expect(index.size() == 2);
|
|
77
|
+
index.add(key_third, vector_third, args...);
|
|
78
|
+
expect(index.size() == 3);
|
|
79
|
+
}
|
|
80
|
+
|
|
61
81
|
// Search again over reconstructed index
|
|
62
82
|
index.save("tmp.usearch");
|
|
63
83
|
index.load("tmp.usearch");
|
|
64
|
-
matched_count = index.search(
|
|
84
|
+
matched_count = index.search(vector_first, 5, args...).dump_to(matched_labels, matched_distances);
|
|
65
85
|
expect(matched_count == 3);
|
|
66
|
-
expect(matched_labels[0] ==
|
|
86
|
+
expect(matched_labels[0] == key_first);
|
|
67
87
|
expect(std::abs(matched_distances[0]) < 0.01);
|
|
68
88
|
|
|
89
|
+
if constexpr (punned_ak) {
|
|
90
|
+
std::vector<scalar_t> vec_recovered_from_load(dimensions);
|
|
91
|
+
index.get(key_second, vec_recovered_from_load.data());
|
|
92
|
+
expect(std::equal(vector_second, vector_second + dimensions, vec_recovered_from_load.data()));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Try batch requests
|
|
96
|
+
executor_default_t executor;
|
|
97
|
+
index.reserve({vectors.size(), executor.size()});
|
|
98
|
+
executor.execute_bulk(vectors.size() - 3, [&](std::size_t thread, std::size_t task) {
|
|
99
|
+
index_update_config_t config;
|
|
100
|
+
config.thread = thread;
|
|
101
|
+
index.add(key_max - task - 3, vectors[task + 3].data(), args..., config);
|
|
102
|
+
});
|
|
103
|
+
|
|
69
104
|
// Search again over mapped index
|
|
70
|
-
file_head_result_t head =
|
|
71
|
-
expect(head.size == 3);
|
|
105
|
+
// file_head_result_t head = index_dense_metadata("tmp.usearch");
|
|
106
|
+
// expect(head.size == 3);
|
|
72
107
|
index.view("tmp.usearch");
|
|
73
|
-
matched_count = index.search(
|
|
108
|
+
matched_count = index.search(vector_first, 5, args...).dump_to(matched_labels, matched_distances);
|
|
74
109
|
expect(matched_count == 3);
|
|
75
|
-
expect(matched_labels[0] ==
|
|
110
|
+
expect(matched_labels[0] == key_first);
|
|
76
111
|
expect(std::abs(matched_distances[0]) < 0.01);
|
|
77
112
|
|
|
113
|
+
if constexpr (punned_ak) {
|
|
114
|
+
std::vector<scalar_t> vec_recovered_from_view(dimensions);
|
|
115
|
+
index.get(key_second, vec_recovered_from_view.data());
|
|
116
|
+
expect(std::equal(vector_second, vector_second + dimensions, vec_recovered_from_view.data()));
|
|
117
|
+
|
|
118
|
+
auto compaction_result = index.compact();
|
|
119
|
+
expect(bool(compaction_result));
|
|
120
|
+
}
|
|
121
|
+
|
|
78
122
|
expect(index.memory_usage() > 0);
|
|
79
123
|
expect(index.stats().max_edges > 0);
|
|
124
|
+
|
|
125
|
+
// Check metadata
|
|
126
|
+
if constexpr (punned_ak) {
|
|
127
|
+
index_dense_metadata_result_t meta = index_dense_metadata("tmp.usearch");
|
|
128
|
+
expect(bool(meta));
|
|
129
|
+
}
|
|
80
130
|
}
|
|
81
131
|
|
|
82
|
-
template <typename scalar_at, typename
|
|
132
|
+
template <typename scalar_at, typename key_at, typename slot_at> //
|
|
133
|
+
void test_cosine(std::size_t collection_size, std::size_t dimensions) {
|
|
83
134
|
|
|
84
135
|
using scalar_t = scalar_at;
|
|
85
|
-
using
|
|
86
|
-
using
|
|
136
|
+
using key_t = key_at;
|
|
137
|
+
using slot_t = slot_at;
|
|
87
138
|
|
|
88
|
-
|
|
89
|
-
|
|
139
|
+
using index_typed_t = index_gt<float, key_t, slot_t>;
|
|
140
|
+
using member_cref_t = typename index_typed_t::member_cref_t;
|
|
141
|
+
using member_citerator_t = typename index_typed_t::member_citerator_t;
|
|
90
142
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
143
|
+
std::vector<std::vector<scalar_at>> matrix(collection_size);
|
|
144
|
+
for (std::vector<scalar_at>& vector : matrix) {
|
|
145
|
+
vector.resize(dimensions);
|
|
146
|
+
std::generate(vector.begin(), vector.end(), [=] { return float(std::rand()) / float(INT_MAX); });
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
struct metric_t {
|
|
150
|
+
std::vector<std::vector<scalar_at>> const* matrix_ptr;
|
|
151
|
+
std::size_t dimensions;
|
|
152
|
+
|
|
153
|
+
scalar_t const* row(std::size_t i) const noexcept { return (*matrix_ptr)[i].data(); }
|
|
154
|
+
|
|
155
|
+
float operator()(member_cref_t const& a, member_cref_t const& b) const {
|
|
156
|
+
return metric_cos_gt<scalar_t>{}(row(get_slot(b)), row(get_slot(a)), dimensions);
|
|
157
|
+
}
|
|
158
|
+
float operator()(scalar_t const* some_vector, member_cref_t const& member) const {
|
|
159
|
+
return metric_cos_gt<scalar_t>{}(some_vector, row(get_slot(member)), dimensions);
|
|
160
|
+
}
|
|
161
|
+
float operator()(member_citerator_t const& a, member_citerator_t const& b) const {
|
|
162
|
+
return metric_cos_gt<scalar_t>{}(row(get_slot(b)), row(get_slot(a)), dimensions);
|
|
163
|
+
}
|
|
164
|
+
float operator()(scalar_t const* some_vector, member_citerator_t const& member) const {
|
|
165
|
+
return metric_cos_gt<scalar_t>{}(some_vector, row(get_slot(member)), dimensions);
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// Template:
|
|
170
|
+
for (std::size_t connectivity : {3, 13, 50}) {
|
|
171
|
+
std::printf("- templates with connectivity %zu \n", connectivity);
|
|
172
|
+
metric_t metric{&matrix, dimensions};
|
|
173
|
+
index_config_t config(connectivity);
|
|
174
|
+
index_typed_t index_typed(config);
|
|
175
|
+
test_cosine<false>(index_typed, matrix, metric);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Type-punned:
|
|
179
|
+
for (std::size_t connectivity : {3, 13, 50}) {
|
|
180
|
+
std::printf("- punned with connectivity %zu \n", connectivity);
|
|
181
|
+
using index_t = index_dense_gt<key_t, slot_t>;
|
|
182
|
+
metric_punned_t metric(dimensions, metric_kind_t::cos_k, scalar_kind<scalar_at>());
|
|
183
|
+
index_config_t config(connectivity);
|
|
184
|
+
index_t index = index_t::make(metric, config);
|
|
185
|
+
test_cosine<true>(index, matrix);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
template <typename key_at, typename slot_at> void test_tanimoto(std::size_t dimensions, std::size_t connectivity) {
|
|
190
|
+
|
|
191
|
+
using key_t = key_at;
|
|
192
|
+
using slot_t = slot_at;
|
|
193
|
+
|
|
194
|
+
using index_punned_t = index_dense_gt<key_t, slot_t>;
|
|
195
|
+
std::size_t words = divide_round_up<CHAR_BIT>(dimensions);
|
|
196
|
+
metric_punned_t metric(words, metric_kind_t::tanimoto_k, scalar_kind_t::b1x8_k);
|
|
197
|
+
index_config_t config(connectivity);
|
|
198
|
+
index_punned_t index = index_punned_t::make(metric, config);
|
|
199
|
+
|
|
200
|
+
executor_default_t executor;
|
|
201
|
+
std::size_t batch_size = 1000;
|
|
202
|
+
std::vector<b1x8_t> scalars(batch_size * index.scalar_words());
|
|
203
|
+
std::generate(scalars.begin(), scalars.end(), [] { return static_cast<b1x8_t>(std::rand()); });
|
|
204
|
+
|
|
205
|
+
index.reserve({batch_size + index.size(), executor.size()});
|
|
206
|
+
executor.execute_bulk(batch_size, [&](std::size_t thread, std::size_t task) {
|
|
207
|
+
index_update_config_t config;
|
|
208
|
+
config.thread = thread;
|
|
209
|
+
index.add(task + 25000, scalars.data() + index.scalar_words() * task, config);
|
|
210
|
+
});
|
|
105
211
|
}
|
|
106
212
|
|
|
107
213
|
template <typename index_at> void test_sets(index_at&& index) {
|
|
@@ -122,18 +228,18 @@ template <typename index_at> void test_sets(index_at&& index) {
|
|
|
122
228
|
expect(index.size() == 3);
|
|
123
229
|
}
|
|
124
230
|
|
|
125
|
-
template <typename index_at> void test_sets_moved() {
|
|
231
|
+
template <typename index_at> void test_sets_moved(index_config_t const& config) {
|
|
126
232
|
{
|
|
127
|
-
index_at index;
|
|
233
|
+
index_at index{config};
|
|
128
234
|
test_sets(index);
|
|
129
235
|
}
|
|
130
236
|
{
|
|
131
|
-
index_at index;
|
|
237
|
+
index_at index{config};
|
|
132
238
|
index.reserve(1);
|
|
133
239
|
test_sets(index_at(std::move(index)));
|
|
134
240
|
}
|
|
135
241
|
{
|
|
136
|
-
index_at index;
|
|
242
|
+
index_at index{config};
|
|
137
243
|
index.reserve(1);
|
|
138
244
|
index_at index_moved = std::move(index);
|
|
139
245
|
test_sets(index_moved);
|
|
@@ -142,39 +248,17 @@ template <typename index_at> void test_sets_moved() {
|
|
|
142
248
|
|
|
143
249
|
int main(int, char**) {
|
|
144
250
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
using big_point_id_t = std::int64_t;
|
|
158
|
-
test3d<float>(index_gt<cos_gt<float>, big_point_id_t, std::uint32_t>{});
|
|
159
|
-
test3d<float>(index_gt<l2sq_gt<float>, big_point_id_t, std::uint32_t>{});
|
|
160
|
-
|
|
161
|
-
test3d<double>(index_gt<cos_gt<double>, big_point_id_t, std::uint32_t>{});
|
|
162
|
-
test3d<double>(index_gt<l2sq_gt<double>, big_point_id_t, std::uint32_t>{});
|
|
163
|
-
|
|
164
|
-
test3d<float>(punned_small_t::make(3, metric_kind_t::cos_k));
|
|
165
|
-
test3d<float>(punned_small_t::make(3, metric_kind_t::l2sq_k));
|
|
166
|
-
|
|
167
|
-
test3d<double>(punned_small_t::make(3, metric_kind_t::cos_k));
|
|
168
|
-
test3d<double>(punned_small_t::make(3, metric_kind_t::l2sq_k));
|
|
169
|
-
|
|
170
|
-
test3d_punned<float>(punned_small_t::make(3, metric_kind_t::cos_k));
|
|
171
|
-
test3d_punned<float>(punned_small_t::make(3, metric_kind_t::l2sq_k));
|
|
172
|
-
|
|
173
|
-
test_sets(index_gt<jaccard_gt<std::int32_t, float>, big_point_id_t, std::uint32_t>{});
|
|
174
|
-
test_sets(index_gt<jaccard_gt<std::int64_t, float>, big_point_id_t, std::uint32_t>{});
|
|
175
|
-
|
|
176
|
-
test_sets_moved<index_gt<jaccard_gt<std::int32_t, float>, big_point_id_t, std::uint32_t>>();
|
|
177
|
-
test_sets_moved<index_gt<jaccard_gt<std::int64_t, float>, big_point_id_t, std::uint32_t>>();
|
|
251
|
+
for (std::size_t collection_size : {10, 500})
|
|
252
|
+
for (std::size_t dimensions : {97, 256}) {
|
|
253
|
+
std::printf("Indexing %zu vectors with cos: <float, std::int64_t, std::uint32_t> \n", collection_size);
|
|
254
|
+
test_cosine<float, std::int64_t, std::uint32_t>(collection_size, dimensions);
|
|
255
|
+
std::printf("Indexing %zu vectors with cos: <float, std::int64_t, uint40_t> \n", collection_size);
|
|
256
|
+
test_cosine<float, std::int64_t, uint40_t>(collection_size, dimensions);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
for (std::size_t connectivity : {3, 13, 50})
|
|
260
|
+
for (std::size_t dimensions : {97, 256})
|
|
261
|
+
test_tanimoto<std::int64_t, std::uint32_t>(dimensions, connectivity);
|
|
178
262
|
|
|
179
263
|
return 0;
|
|
180
264
|
}
|
package/docs/benchmarks.md
CHANGED
|
@@ -39,24 +39,24 @@ The main columns are:
|
|
|
39
39
|
| `f32` x256 | 16 | 64 | 32 | 128'644 | 228'422 | 97.2% |
|
|
40
40
|
| `f32` x256 | 16 | 256 | 128 | 39'981 | 69'065 | 99.2% |
|
|
41
41
|
|
|
42
|
-
### Different vectors "
|
|
42
|
+
### Different vectors "quantization"
|
|
43
43
|
|
|
44
44
|
| Vectors | Connectivity | EF @ A | EF @ S | **Add**, QPS | **Search**, QPS | **Recall @1** |
|
|
45
45
|
| :----------- | :----------: | :----: | :----: | :----------: | :-------------: | ------------: |
|
|
46
46
|
| `f32` x256 | 16 | 128 | 64 | 87'995 | 171'856 | 99.1% |
|
|
47
47
|
| `f16` x256 | 16 | 128 | 64 | 87'270 | 153'788 | 98.4% |
|
|
48
48
|
| `f16` x256 ✳️ | 16 | 128 | 64 | 71'454 | 132'673 | 98.4% |
|
|
49
|
-
| `
|
|
49
|
+
| `i8` x256 | 16 | 128 | 64 | 115'923 | 274'653 | 98.9% |
|
|
50
50
|
|
|
51
|
-
As seen on the chart, for `f16`
|
|
52
|
-
Also worth noting, 8-bit quantization results in almost no
|
|
51
|
+
As seen on the chart, for `f16` quantization, performance may differ depending on native hardware support for that numeric type.
|
|
52
|
+
Also worth noting, 8-bit quantization results in almost no quantization loss and may perform better than `f16`.
|
|
53
53
|
|
|
54
54
|
## Utilities
|
|
55
55
|
|
|
56
56
|
Within this repository you will find two commonly used utilities:
|
|
57
57
|
|
|
58
58
|
- `cpp/bench.cpp` the produces the `bench` binary for broad USearch benchmarks.
|
|
59
|
-
- `python/bench.py` for
|
|
59
|
+
- `python/bench.py` and `python/bench.ipynb` for interactive charts against FAISS.
|
|
60
60
|
|
|
61
61
|
To achieve best highest results we suggest compiling locally for the target architecture.
|
|
62
62
|
|
|
@@ -112,6 +112,27 @@ OPTIONS
|
|
|
112
112
|
-h, --help Print this help information on this tool and exit
|
|
113
113
|
```
|
|
114
114
|
|
|
115
|
+
Here is an example of running the C++ benchmark:
|
|
116
|
+
|
|
117
|
+
```sh
|
|
118
|
+
./build_release/bench \
|
|
119
|
+
--vectors datasets/wiki_1M/base.1M.fbin \
|
|
120
|
+
--queries datasets/wiki_1M/query.public.100K.fbin \
|
|
121
|
+
--neighbors datasets/wiki_1M/groundtruth.public.100K.ibin
|
|
122
|
+
|
|
123
|
+
./build_release/bench \
|
|
124
|
+
--vectors datasets/t2i_1B/base.1B.fbin \
|
|
125
|
+
--queries datasets/t2i_1B/query.public.100K.fbin \
|
|
126
|
+
--neighbors datasets/t2i_1B/groundtruth.public.100K.ibin \
|
|
127
|
+
--output datasets/t2i_1B/index.usearch \
|
|
128
|
+
--cos
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
> Optional parameters include `connectivity`, `expansion_add`, `expansion_search`.
|
|
133
|
+
|
|
134
|
+
For Python, jut open the Jupyter Notebook and start playing around.
|
|
135
|
+
|
|
115
136
|
## Datasets
|
|
116
137
|
|
|
117
138
|
BigANN benchmark is a good starting point, if you are searching for large collections of high-dimensional vectors.
|
package/docs/c/reference.rst
CHANGED
package/docs/compilation.md
CHANGED
|
@@ -44,10 +44,10 @@ cmake -B ./build_release \
|
|
|
44
44
|
Linting:
|
|
45
45
|
|
|
46
46
|
```sh
|
|
47
|
-
cppcheck --enable=all --suppress=cstyleCast --suppress=unusedFunction \
|
|
47
|
+
cppcheck --enable=all --force --suppress=cstyleCast --suppress=unusedFunction \
|
|
48
48
|
include/usearch/index.hpp \
|
|
49
|
-
include/
|
|
50
|
-
include/
|
|
49
|
+
include/index_dense.hpp \
|
|
50
|
+
include/index_plugins.hpp
|
|
51
51
|
```
|
|
52
52
|
|
|
53
53
|
Testing:
|
|
@@ -56,22 +56,6 @@ Testing:
|
|
|
56
56
|
cmake -DCMAKE_CXX_COMPILER=gcc-12 -DCMAKE_CXX_COMPILER=g++-12 -DCMAKE_BUILD_TYPE=Debug -B ./build_debug && make -C ./build_debug && ./build_debug/test
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
-
Benchmarking:
|
|
60
|
-
|
|
61
|
-
```sh
|
|
62
|
-
./build_release/bench \
|
|
63
|
-
--vectors datasets/wiki_1M/base.1M.fbin \
|
|
64
|
-
--queries datasets/wiki_1M/query.public.100K.fbin \
|
|
65
|
-
--neighbors datasets/wiki_1M/groundtruth.public.100K.ibin
|
|
66
|
-
|
|
67
|
-
./build_release/bench \
|
|
68
|
-
--vectors datasets/t2i_1B/base.1B.fbin \
|
|
69
|
-
--queries datasets/t2i_1B/query.public.100K.fbin \
|
|
70
|
-
--neighbors datasets/t2i_1B/groundtruth.public.100K.ibin \
|
|
71
|
-
--output datasets/t2i_1B/index.usearch \
|
|
72
|
-
--cos
|
|
73
|
-
```
|
|
74
|
-
|
|
75
59
|
## Python 3
|
|
76
60
|
|
|
77
61
|
Use PyTest to validate the build.
|
|
@@ -96,25 +80,6 @@ pip install cibuildwheel
|
|
|
96
80
|
cibuildwheel --platform linux
|
|
97
81
|
```
|
|
98
82
|
|
|
99
|
-
Benchmarking:
|
|
100
|
-
|
|
101
|
-
```sh
|
|
102
|
-
pip install faiss-cpu
|
|
103
|
-
python python/scripts/bench.py speed \
|
|
104
|
-
--vectors datasets/wiki_1M/base.1M.fbin \
|
|
105
|
-
--queries datasets/wiki_1M/query.public.100K.fbin \
|
|
106
|
-
--neighbors datasets/wiki_1M/groundtruth.public.100K.ibin
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
> Optional parameters include `connectivity`, `expansion_add`, `expansion_search`.
|
|
110
|
-
|
|
111
|
-
Checking the effect of different embedding dimensions on construction speed:
|
|
112
|
-
|
|
113
|
-
```sh
|
|
114
|
-
python python/scripts/bench.py dimensions ...
|
|
115
|
-
python python/scripts/bench.py connectivity ...
|
|
116
|
-
```
|
|
117
|
-
|
|
118
83
|
## JavaScript
|
|
119
84
|
|
|
120
85
|
Node.JS:
|
|
@@ -178,34 +143,51 @@ java -cp . -Djava.library.path="$(pwd)/java/cloud/unum/usearch/" Index.java
|
|
|
178
143
|
java -cp . -Djava.library.path="$(pwd)/java" cloud.unum.usearch.Index
|
|
179
144
|
```
|
|
180
145
|
|
|
181
|
-
##
|
|
146
|
+
## Objective-C and Swift
|
|
182
147
|
|
|
183
148
|
```sh
|
|
184
|
-
|
|
149
|
+
swift build
|
|
150
|
+
swift test -v
|
|
185
151
|
```
|
|
186
152
|
|
|
187
|
-
##
|
|
153
|
+
## C 99
|
|
154
|
+
|
|
155
|
+
There are a few ways to compile the C 99 USearch SDK.
|
|
156
|
+
Using the Makefile:
|
|
188
157
|
|
|
189
158
|
```sh
|
|
190
|
-
|
|
191
|
-
go test -v
|
|
159
|
+
make -C ./c build
|
|
192
160
|
```
|
|
193
161
|
|
|
194
|
-
|
|
162
|
+
Using CMake:
|
|
195
163
|
|
|
196
164
|
```sh
|
|
197
|
-
|
|
198
|
-
swift test -v
|
|
165
|
+
cmake -B ./build_release -DUSEARCH_BUILD_C=1 && make -C ./build_release -j
|
|
199
166
|
```
|
|
200
167
|
|
|
201
|
-
## C99
|
|
202
|
-
|
|
203
168
|
Linux:
|
|
204
169
|
|
|
205
170
|
```sh
|
|
206
|
-
g++ -shared -fPIC lib.cpp -I
|
|
171
|
+
g++ -std=c++11 -shared -fPIC c/lib.cpp -I ./include/ -I ./fp16/include/ -I ./robin-map/include/ -o libusearch.so
|
|
207
172
|
```
|
|
208
173
|
|
|
174
|
+
|
|
175
|
+
## GoLang
|
|
176
|
+
|
|
177
|
+
GoLang bindings are based on C.
|
|
178
|
+
So one should first compile the C library, link it with GoLang, and only then run tests.
|
|
179
|
+
|
|
180
|
+
```sh
|
|
181
|
+
cd golang && make -C ../c build && mv ../c/libusearch.so libusearch.so && go test -v
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Wolfram
|
|
185
|
+
|
|
186
|
+
```sh
|
|
187
|
+
brew install --cask wolfram-engine
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
|
|
209
191
|
## Docker
|
|
210
192
|
|
|
211
193
|
```sh
|
package/docs/cpp/index.rst
CHANGED
package/docs/cpp/reference.rst
CHANGED
|
@@ -7,11 +7,11 @@ usearch/index.hpp
|
|
|
7
7
|
.. doxygenfile:: index.hpp
|
|
8
8
|
|
|
9
9
|
=================================
|
|
10
|
-
usearch/
|
|
10
|
+
usearch/index_plugins.hpp
|
|
11
11
|
=================================
|
|
12
|
-
.. doxygenfile::
|
|
12
|
+
.. doxygenfile:: index_plugins.hpp
|
|
13
13
|
|
|
14
14
|
=================================
|
|
15
|
-
usearch/
|
|
15
|
+
usearch/index_dense.hpp
|
|
16
16
|
=================================
|
|
17
|
-
.. doxygenfile::
|
|
17
|
+
.. doxygenfile:: index_dense.hpp
|