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/c/lib.cpp
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#include <cassert>
|
|
2
2
|
|
|
3
|
-
#include <usearch/
|
|
3
|
+
#include <usearch/index_dense.hpp>
|
|
4
4
|
|
|
5
5
|
#ifndef USEARCH_EXPORT
|
|
6
6
|
#define USEARCH_EXPORT
|
|
@@ -13,13 +13,12 @@ extern "C" {
|
|
|
13
13
|
using namespace unum::usearch;
|
|
14
14
|
using namespace unum;
|
|
15
15
|
|
|
16
|
-
using
|
|
17
|
-
using
|
|
18
|
-
using
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
using vector_view_t = span_gt<float>;
|
|
16
|
+
using add_result_t = typename index_dense_t::add_result_t;
|
|
17
|
+
using search_result_t = typename index_dense_t::search_result_t;
|
|
18
|
+
using labeling_result_t = typename index_dense_t::labeling_result_t;
|
|
19
|
+
|
|
20
|
+
static_assert(std::is_same<usearch_key_t, index_dense_t::key_t>::value, "Type mismatch between C and C++");
|
|
21
|
+
static_assert(std::is_same<usearch_distance_t, index_dense_t::distance_t>::value, "Type mismatch between C and C++");
|
|
23
22
|
|
|
24
23
|
// helper functions that are not part of the C ABI
|
|
25
24
|
metric_kind_t to_native_metric(usearch_metric_kind_t kind) {
|
|
@@ -42,133 +41,139 @@ scalar_kind_t to_native_scalar(usearch_scalar_kind_t kind) {
|
|
|
42
41
|
case usearch_scalar_f32_k: return scalar_kind_t::f32_k;
|
|
43
42
|
case usearch_scalar_f64_k: return scalar_kind_t::f64_k;
|
|
44
43
|
case usearch_scalar_f16_k: return scalar_kind_t::f16_k;
|
|
45
|
-
case
|
|
44
|
+
case usearch_scalar_i8_k: return scalar_kind_t::i8_k;
|
|
46
45
|
case usearch_scalar_b1_k: return scalar_kind_t::b1x8_k;
|
|
47
46
|
default: return scalar_kind_t::unknown_k;
|
|
48
47
|
}
|
|
49
48
|
}
|
|
50
49
|
|
|
51
|
-
add_result_t add_(
|
|
50
|
+
add_result_t add_(index_dense_t* index, usearch_key_t key, void const* vector, scalar_kind_t kind) {
|
|
52
51
|
switch (kind) {
|
|
53
|
-
case scalar_kind_t::f32_k: return index->add(
|
|
54
|
-
case scalar_kind_t::f64_k: return index->add(
|
|
55
|
-
case scalar_kind_t::f16_k: return index->add(
|
|
56
|
-
case scalar_kind_t::
|
|
57
|
-
case scalar_kind_t::b1x8_k: return index->add(
|
|
52
|
+
case scalar_kind_t::f32_k: return index->add(key, (f32_t const*)vector);
|
|
53
|
+
case scalar_kind_t::f64_k: return index->add(key, (f64_t const*)vector);
|
|
54
|
+
case scalar_kind_t::f16_k: return index->add(key, (f16_t const*)vector);
|
|
55
|
+
case scalar_kind_t::i8_k: return index->add(key, (i8_bits_t const*)vector);
|
|
56
|
+
case scalar_kind_t::b1x8_k: return index->add(key, (b1x8_t const*)vector);
|
|
58
57
|
default: return add_result_t{}.failed("Unknown scalar kind!");
|
|
59
58
|
}
|
|
60
59
|
}
|
|
61
60
|
|
|
62
|
-
bool get_(
|
|
61
|
+
bool get_(index_dense_t* index, usearch_key_t key, void* vector, scalar_kind_t kind) {
|
|
63
62
|
switch (kind) {
|
|
64
|
-
case scalar_kind_t::f32_k: return index->get(
|
|
65
|
-
case scalar_kind_t::f64_k: return index->get(
|
|
66
|
-
case scalar_kind_t::f16_k: return index->get(
|
|
67
|
-
case scalar_kind_t::
|
|
68
|
-
case scalar_kind_t::b1x8_k: return index->get(
|
|
69
|
-
default: return
|
|
63
|
+
case scalar_kind_t::f32_k: return index->get(key, (f32_t*)vector);
|
|
64
|
+
case scalar_kind_t::f64_k: return index->get(key, (f64_t*)vector);
|
|
65
|
+
case scalar_kind_t::f16_k: return index->get(key, (f16_t*)vector);
|
|
66
|
+
case scalar_kind_t::i8_k: return index->get(key, (i8_bits_t*)vector);
|
|
67
|
+
case scalar_kind_t::b1x8_k: return index->get(key, (b1x8_t*)vector);
|
|
68
|
+
default: return search_result_t().failed("Unknown scalar kind!");
|
|
70
69
|
}
|
|
71
70
|
}
|
|
72
71
|
|
|
73
|
-
search_result_t search_(
|
|
72
|
+
search_result_t search_(index_dense_t* index, void const* vector, scalar_kind_t kind, size_t n) {
|
|
74
73
|
switch (kind) {
|
|
75
74
|
case scalar_kind_t::f32_k: return index->search((f32_t const*)vector, n);
|
|
76
75
|
case scalar_kind_t::f64_k: return index->search((f64_t const*)vector, n);
|
|
77
76
|
case scalar_kind_t::f16_k: return index->search((f16_t const*)vector, n);
|
|
78
|
-
case scalar_kind_t::
|
|
77
|
+
case scalar_kind_t::i8_k: return index->search((i8_bits_t const*)vector, n);
|
|
79
78
|
case scalar_kind_t::b1x8_k: return index->search((b1x8_t const*)vector, n);
|
|
80
|
-
default: return
|
|
79
|
+
default: return search_result_t().failed("Unknown scalar kind!");
|
|
81
80
|
}
|
|
82
81
|
}
|
|
83
82
|
|
|
84
|
-
index_punned_dense_metric_t udf(metric_kind_t kind, usearch_metric_t raw_ptr) {
|
|
85
|
-
index_punned_dense_metric_t result;
|
|
86
|
-
result.kind_ = kind;
|
|
87
|
-
result.func_ = [raw_ptr](punned_vector_view_t a, punned_vector_view_t b) -> distance_t {
|
|
88
|
-
return raw_ptr((void const*)a.data(), (void const*)b.data());
|
|
89
|
-
};
|
|
90
|
-
return result;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
83
|
extern "C" {
|
|
94
84
|
|
|
95
85
|
USEARCH_EXPORT usearch_index_t usearch_init(usearch_init_options_t* options, usearch_error_t* error) {
|
|
96
86
|
|
|
97
87
|
assert(options && error);
|
|
98
88
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
89
|
+
index_dense_config_t config(options->connectivity, options->expansion_add, options->expansion_search);
|
|
90
|
+
metric_kind_t metric_kind = to_native_metric(options->metric_kind);
|
|
91
|
+
scalar_kind_t scalar_kind = to_native_scalar(options->quantization);
|
|
92
|
+
|
|
93
|
+
auto metric_lambda = [options](byte_t const* a, byte_t const* b) -> usearch_distance_t {
|
|
94
|
+
return options->metric((void const*)a, (void const*)b);
|
|
95
|
+
};
|
|
96
|
+
metric_punned_t metric = //
|
|
97
|
+
options->metric ? metric_punned_t(metric_lambda, options->dimensions, metric_kind, scalar_kind)
|
|
98
|
+
: metric_punned_t(options->dimensions, metric_kind, scalar_kind);
|
|
99
|
+
|
|
100
|
+
index_dense_t index = index_dense_t::make(metric, config);
|
|
101
|
+
index_dense_t* result_ptr = new index_dense_t(std::move(index));
|
|
112
102
|
return result_ptr;
|
|
113
103
|
}
|
|
114
104
|
|
|
115
|
-
USEARCH_EXPORT void usearch_free(usearch_index_t index, usearch_error_t*) {
|
|
105
|
+
USEARCH_EXPORT void usearch_free(usearch_index_t index, usearch_error_t*) {
|
|
106
|
+
delete reinterpret_cast<index_dense_t*>(index);
|
|
107
|
+
}
|
|
116
108
|
|
|
117
109
|
USEARCH_EXPORT void usearch_save(usearch_index_t index, char const* path, usearch_error_t* error) {
|
|
118
|
-
|
|
110
|
+
|
|
111
|
+
assert(index && path && error);
|
|
112
|
+
serialization_result_t result = reinterpret_cast<index_dense_t*>(index)->save(path);
|
|
119
113
|
if (!result)
|
|
120
114
|
*error = result.error.what();
|
|
121
115
|
}
|
|
122
116
|
|
|
123
117
|
USEARCH_EXPORT void usearch_load(usearch_index_t index, char const* path, usearch_error_t* error) {
|
|
124
|
-
|
|
118
|
+
|
|
119
|
+
assert(index && path && error);
|
|
120
|
+
serialization_result_t result = reinterpret_cast<index_dense_t*>(index)->load(path);
|
|
125
121
|
if (!result)
|
|
126
122
|
*error = result.error.what();
|
|
127
123
|
}
|
|
128
124
|
|
|
129
125
|
USEARCH_EXPORT void usearch_view(usearch_index_t index, char const* path, usearch_error_t* error) {
|
|
130
|
-
|
|
126
|
+
|
|
127
|
+
assert(index && path && error);
|
|
128
|
+
serialization_result_t result = reinterpret_cast<index_dense_t*>(index)->view(path);
|
|
131
129
|
if (!result)
|
|
132
130
|
*error = result.error.what();
|
|
133
131
|
}
|
|
134
132
|
|
|
135
133
|
USEARCH_EXPORT size_t usearch_size(usearch_index_t index, usearch_error_t*) { //
|
|
136
|
-
return reinterpret_cast<
|
|
134
|
+
return reinterpret_cast<index_dense_t*>(index)->size();
|
|
137
135
|
}
|
|
138
136
|
|
|
139
137
|
USEARCH_EXPORT size_t usearch_capacity(usearch_index_t index, usearch_error_t*) {
|
|
140
|
-
return reinterpret_cast<
|
|
138
|
+
return reinterpret_cast<index_dense_t*>(index)->capacity();
|
|
141
139
|
}
|
|
142
140
|
|
|
143
141
|
USEARCH_EXPORT size_t usearch_dimensions(usearch_index_t index, usearch_error_t*) {
|
|
144
|
-
return reinterpret_cast<
|
|
142
|
+
return reinterpret_cast<index_dense_t*>(index)->dimensions();
|
|
145
143
|
}
|
|
146
144
|
|
|
147
145
|
USEARCH_EXPORT size_t usearch_connectivity(usearch_index_t index, usearch_error_t*) {
|
|
148
|
-
return reinterpret_cast<
|
|
146
|
+
return reinterpret_cast<index_dense_t*>(index)->connectivity();
|
|
149
147
|
}
|
|
150
148
|
|
|
151
|
-
USEARCH_EXPORT void usearch_reserve(usearch_index_t index, size_t capacity, usearch_error_t*) {
|
|
152
|
-
|
|
153
|
-
reinterpret_cast<
|
|
149
|
+
USEARCH_EXPORT void usearch_reserve(usearch_index_t index, size_t capacity, usearch_error_t* error) {
|
|
150
|
+
assert(index && error);
|
|
151
|
+
if (!reinterpret_cast<index_dense_t*>(index)->reserve(capacity))
|
|
152
|
+
*error = "Out of memory!";
|
|
154
153
|
}
|
|
155
154
|
|
|
156
|
-
USEARCH_EXPORT void usearch_add(
|
|
157
|
-
usearch_index_t index,
|
|
155
|
+
USEARCH_EXPORT void usearch_add( //
|
|
156
|
+
usearch_index_t index, usearch_key_t key, void const* vector, usearch_scalar_kind_t kind, //
|
|
158
157
|
usearch_error_t* error) {
|
|
159
|
-
|
|
158
|
+
|
|
159
|
+
assert(index && vector && error);
|
|
160
|
+
add_result_t result = add_(reinterpret_cast<index_dense_t*>(index), key, vector, to_native_scalar(kind));
|
|
160
161
|
if (!result)
|
|
161
162
|
*error = result.error.what();
|
|
162
163
|
}
|
|
163
164
|
|
|
164
|
-
USEARCH_EXPORT bool usearch_contains(usearch_index_t index,
|
|
165
|
-
|
|
165
|
+
USEARCH_EXPORT bool usearch_contains(usearch_index_t index, usearch_key_t key, usearch_error_t*) {
|
|
166
|
+
assert(index);
|
|
167
|
+
return reinterpret_cast<index_dense_t*>(index)->contains(key);
|
|
166
168
|
}
|
|
167
169
|
|
|
168
|
-
USEARCH_EXPORT size_t usearch_search(
|
|
170
|
+
USEARCH_EXPORT size_t usearch_search( //
|
|
169
171
|
usearch_index_t index, void const* vector, usearch_scalar_kind_t kind, size_t results_limit, //
|
|
170
|
-
|
|
171
|
-
|
|
172
|
+
usearch_key_t* found_labels, usearch_distance_t* found_distances, usearch_error_t* error) {
|
|
173
|
+
|
|
174
|
+
assert(index && vector && error);
|
|
175
|
+
search_result_t result =
|
|
176
|
+
search_(reinterpret_cast<index_dense_t*>(index), vector, to_native_scalar(kind), results_limit);
|
|
172
177
|
if (!result) {
|
|
173
178
|
*error = result.error.what();
|
|
174
179
|
return 0;
|
|
@@ -177,14 +182,20 @@ USEARCH_EXPORT size_t usearch_search(
|
|
|
177
182
|
return result.dump_to(found_labels, found_distances);
|
|
178
183
|
}
|
|
179
184
|
|
|
180
|
-
USEARCH_EXPORT bool usearch_get(
|
|
181
|
-
usearch_index_t index,
|
|
185
|
+
USEARCH_EXPORT bool usearch_get( //
|
|
186
|
+
usearch_index_t index, usearch_key_t key, //
|
|
182
187
|
void* vector, usearch_scalar_kind_t kind, usearch_error_t*) {
|
|
183
|
-
|
|
188
|
+
|
|
189
|
+
assert(index && vector);
|
|
190
|
+
return get_(reinterpret_cast<index_dense_t*>(index), key, vector, to_native_scalar(kind));
|
|
184
191
|
}
|
|
185
192
|
|
|
186
|
-
USEARCH_EXPORT
|
|
187
|
-
|
|
188
|
-
|
|
193
|
+
USEARCH_EXPORT bool usearch_remove(usearch_index_t index, usearch_key_t key, usearch_error_t* error) {
|
|
194
|
+
|
|
195
|
+
assert(index && error);
|
|
196
|
+
labeling_result_t result = reinterpret_cast<index_dense_t*>(index)->remove(key);
|
|
197
|
+
if (!result)
|
|
198
|
+
*error = result.error.what();
|
|
199
|
+
return result.completed;
|
|
189
200
|
}
|
|
190
201
|
}
|
package/c/test.c
CHANGED
|
@@ -107,8 +107,8 @@ void test_add_vector(size_t vectors_count, size_t vector_dimension, float const*
|
|
|
107
107
|
|
|
108
108
|
// Add vectors
|
|
109
109
|
for (size_t i = 0; i < vectors_count; ++i) {
|
|
110
|
-
|
|
111
|
-
usearch_add(idx,
|
|
110
|
+
usearch_key_t key = i;
|
|
111
|
+
usearch_add(idx, key, data + i * vector_dimension, usearch_scalar_f32_k, &error);
|
|
112
112
|
ASSERT(!error, error);
|
|
113
113
|
}
|
|
114
114
|
|
|
@@ -117,10 +117,10 @@ void test_add_vector(size_t vectors_count, size_t vector_dimension, float const*
|
|
|
117
117
|
|
|
118
118
|
// Check vectors in the index
|
|
119
119
|
for (size_t i = 0; i < vectors_count; ++i) {
|
|
120
|
-
|
|
121
|
-
ASSERT(usearch_contains(idx,
|
|
120
|
+
usearch_key_t key = i;
|
|
121
|
+
ASSERT(usearch_contains(idx, key, &error), error);
|
|
122
122
|
}
|
|
123
|
-
ASSERT(!usearch_contains(idx, -1, &error), error); // Non existing
|
|
123
|
+
ASSERT(!usearch_contains(idx, -1, &error), error); // Non existing key
|
|
124
124
|
|
|
125
125
|
usearch_free(idx, &error);
|
|
126
126
|
printf("Test: Add Vector - PASSED\n");
|
|
@@ -137,21 +137,21 @@ void test_find_vector(size_t vectors_count, size_t vector_dimension, float const
|
|
|
137
137
|
|
|
138
138
|
// Create result buffers
|
|
139
139
|
int results_count = 10;
|
|
140
|
-
|
|
140
|
+
usearch_key_t* keys = (usearch_key_t*)malloc(results_count * sizeof(usearch_key_t));
|
|
141
141
|
float* distances = (float*)malloc(results_count * sizeof(float));
|
|
142
|
-
ASSERT(
|
|
142
|
+
ASSERT(keys && distances, "Failed to allocate memory");
|
|
143
143
|
|
|
144
144
|
// Add vectors
|
|
145
145
|
for (size_t i = 0; i < vectors_count; ++i) {
|
|
146
|
-
|
|
147
|
-
usearch_add(idx,
|
|
146
|
+
usearch_key_t key = i;
|
|
147
|
+
usearch_add(idx, key, data + i * vector_dimension, usearch_scalar_f32_k, &error);
|
|
148
148
|
ASSERT(!error, error);
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
// Find the vectors
|
|
152
152
|
for (size_t i = 0; i < vectors_count; i++) {
|
|
153
153
|
const void *query_vector = data + i * vector_dimension;
|
|
154
|
-
size_t found_count = usearch_search(idx, query_vector, usearch_scalar_f32_k, results_count,
|
|
154
|
+
size_t found_count = usearch_search(idx, query_vector, usearch_scalar_f32_k, results_count, keys, distances, &error);
|
|
155
155
|
ASSERT(!error, error);
|
|
156
156
|
ASSERT(found_count = results_count, "Vector is missing");
|
|
157
157
|
}
|
|
@@ -171,15 +171,15 @@ void test_remove_vector(size_t vectors_count, size_t vector_dimension, float con
|
|
|
171
171
|
|
|
172
172
|
// Add vectors
|
|
173
173
|
for (size_t i = 0; i < vectors_count; ++i) {
|
|
174
|
-
|
|
175
|
-
usearch_add(idx,
|
|
174
|
+
usearch_key_t key = i;
|
|
175
|
+
usearch_add(idx, key, data + i * vector_dimension, usearch_scalar_f32_k, &error);
|
|
176
176
|
ASSERT(!error, error);
|
|
177
177
|
}
|
|
178
178
|
|
|
179
179
|
// Remove the vectors
|
|
180
180
|
for (size_t i = 0; i < vectors_count; i++) {
|
|
181
|
-
|
|
182
|
-
usearch_remove(idx,
|
|
181
|
+
usearch_key_t key = i;
|
|
182
|
+
usearch_remove(idx, key, &error);
|
|
183
183
|
ASSERT(error, "Currently, Remove is not supported");
|
|
184
184
|
}
|
|
185
185
|
|
|
@@ -198,8 +198,8 @@ void test_save_load(size_t vectors_count, size_t vector_dimension, float const*
|
|
|
198
198
|
|
|
199
199
|
// Add vectors
|
|
200
200
|
for (size_t i = 0; i < vectors_count; ++i) {
|
|
201
|
-
|
|
202
|
-
usearch_add(idx,
|
|
201
|
+
usearch_key_t key = i;
|
|
202
|
+
usearch_add(idx, key, data + i * vector_dimension, usearch_scalar_f32_k, &error);
|
|
203
203
|
ASSERT(!error, error);
|
|
204
204
|
}
|
|
205
205
|
|
|
@@ -224,8 +224,8 @@ void test_save_load(size_t vectors_count, size_t vector_dimension, float const*
|
|
|
224
224
|
|
|
225
225
|
// Check vectors in the index
|
|
226
226
|
for (size_t i = 0; i < vectors_count; ++i) {
|
|
227
|
-
|
|
228
|
-
ASSERT(usearch_contains(idx,
|
|
227
|
+
usearch_key_t key = i;
|
|
228
|
+
ASSERT(usearch_contains(idx, key, &error), error);
|
|
229
229
|
}
|
|
230
230
|
|
|
231
231
|
usearch_free(idx, &error);
|
|
@@ -243,8 +243,8 @@ void test_view(size_t vectors_count, size_t vector_dimension, float const* data)
|
|
|
243
243
|
|
|
244
244
|
// Add vectors
|
|
245
245
|
for (size_t i = 0; i < vectors_count; ++i) {
|
|
246
|
-
|
|
247
|
-
usearch_add(idx,
|
|
246
|
+
usearch_key_t key = i;
|
|
247
|
+
usearch_add(idx, key, data + i * vector_dimension, usearch_scalar_f32_k, &error);
|
|
248
248
|
ASSERT(!error, error);
|
|
249
249
|
}
|
|
250
250
|
|
package/c/usearch.h
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#ifndef UNUM_USEARCH_H
|
|
2
2
|
#define UNUM_USEARCH_H
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
#ifdef __cplusplus
|
|
5
5
|
extern "C" {
|
|
6
6
|
#endif
|
|
@@ -11,79 +11,179 @@ extern "C" {
|
|
|
11
11
|
#include <stdint.h> // `size_t`
|
|
12
12
|
|
|
13
13
|
USEARCH_EXPORT typedef void* usearch_index_t;
|
|
14
|
-
USEARCH_EXPORT typedef
|
|
14
|
+
USEARCH_EXPORT typedef uint64_t usearch_key_t;
|
|
15
15
|
USEARCH_EXPORT typedef float usearch_distance_t;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @brief Pointer to a null-terminated error message.
|
|
19
|
+
* Returned error messages @b don't need to be deallocated.
|
|
20
|
+
*/
|
|
16
21
|
USEARCH_EXPORT typedef char const* usearch_error_t;
|
|
17
22
|
|
|
23
|
+
/**
|
|
24
|
+
* @brief Type-punned callback for "metrics" or "distance functions",
|
|
25
|
+
* that accepts pointers to two vectors and measures their @b dis-similarity.
|
|
26
|
+
*/
|
|
18
27
|
USEARCH_EXPORT typedef usearch_distance_t (*usearch_metric_t)(void const*, void const*);
|
|
19
28
|
|
|
29
|
+
/**
|
|
30
|
+
* @brief Enumerator for the most common kinds of `usearch_metric_t`.
|
|
31
|
+
* Those are supported out of the box, with SIMD-optimizations for most common hardware.
|
|
32
|
+
*/
|
|
20
33
|
USEARCH_EXPORT typedef enum usearch_metric_kind_t {
|
|
21
|
-
|
|
22
|
-
usearch_metric_l2sq_k,
|
|
34
|
+
usearch_metric_unknown_k = 0,
|
|
23
35
|
usearch_metric_cos_k,
|
|
36
|
+
usearch_metric_ip_k,
|
|
37
|
+
usearch_metric_l2sq_k,
|
|
24
38
|
usearch_metric_haversine_k,
|
|
25
39
|
usearch_metric_pearson_k,
|
|
26
40
|
usearch_metric_jaccard_k,
|
|
27
41
|
usearch_metric_hamming_k,
|
|
28
42
|
usearch_metric_tanimoto_k,
|
|
29
43
|
usearch_metric_sorensen_k,
|
|
30
|
-
usearch_metric_unknown_k,
|
|
31
44
|
} usearch_metric_kind_t;
|
|
32
45
|
|
|
33
46
|
USEARCH_EXPORT typedef enum usearch_scalar_kind_t {
|
|
34
|
-
|
|
47
|
+
usearch_scalar_unknown_k = 0,
|
|
48
|
+
usearch_scalar_f32_k,
|
|
35
49
|
usearch_scalar_f64_k,
|
|
36
50
|
usearch_scalar_f16_k,
|
|
37
|
-
|
|
51
|
+
usearch_scalar_i8_k,
|
|
38
52
|
usearch_scalar_b1_k,
|
|
39
|
-
usearch_scalar_unknown_k,
|
|
40
53
|
} usearch_scalar_kind_t;
|
|
41
54
|
|
|
42
55
|
USEARCH_EXPORT typedef struct usearch_init_options_t {
|
|
43
|
-
|
|
56
|
+
/**
|
|
57
|
+
* @brief The metric kind used for distance calculation between vectors.
|
|
58
|
+
*/
|
|
44
59
|
usearch_metric_kind_t metric_kind;
|
|
60
|
+
/**
|
|
61
|
+
* @brief The @b optional custom distance metric function used for distance calculation between vectors.
|
|
62
|
+
* If the `metric_kind` is set to `usearch_metric_unknown_k`, this function pointer mustn't be `NULL`.
|
|
63
|
+
*/
|
|
45
64
|
usearch_metric_t metric;
|
|
46
|
-
|
|
65
|
+
/**
|
|
66
|
+
* @brief The scalar kind used for quantization of vector data during indexing.
|
|
67
|
+
*/
|
|
47
68
|
usearch_scalar_kind_t quantization;
|
|
69
|
+
/**
|
|
70
|
+
* @brief The number of dimensions in the vectors to be indexed.
|
|
71
|
+
* Must be defined for most metrics, but can be avoided for `usearch_metric_haversine_k`.
|
|
72
|
+
*/
|
|
48
73
|
size_t dimensions;
|
|
74
|
+
/**
|
|
75
|
+
* @brief The @b optional connectivity parameter that limits connections-per-node in graph.
|
|
76
|
+
*/
|
|
49
77
|
size_t connectivity;
|
|
78
|
+
/**
|
|
79
|
+
* @brief The @b optional expansion factor used for index construction when adding vectors.
|
|
80
|
+
*/
|
|
50
81
|
size_t expansion_add;
|
|
82
|
+
/**
|
|
83
|
+
* @brief The @b optional expansion factor used for index construction during search operations.
|
|
84
|
+
*/
|
|
51
85
|
size_t expansion_search;
|
|
52
86
|
} usearch_init_options_t;
|
|
53
87
|
|
|
54
|
-
|
|
55
|
-
|
|
88
|
+
/**
|
|
89
|
+
* @brief Initializes a new instance of the index.
|
|
90
|
+
* @param options Pointer to the `usearch_init_options_t` structure containing initialization options.
|
|
91
|
+
* @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
|
|
92
|
+
* @return A handle to the initialized USearch index, or `NULL` on failure.
|
|
93
|
+
*/
|
|
94
|
+
USEARCH_EXPORT usearch_index_t usearch_init(usearch_init_options_t* options, usearch_error_t* error);
|
|
56
95
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
96
|
+
/**
|
|
97
|
+
* @brief Frees the resources associated with the index.
|
|
98
|
+
* @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
|
|
99
|
+
*/
|
|
100
|
+
USEARCH_EXPORT void usearch_free(usearch_index_t, usearch_error_t* error);
|
|
60
101
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
102
|
+
/**
|
|
103
|
+
* @brief Saves the index to a file.
|
|
104
|
+
* @param[in] path The file path where the index will be saved.
|
|
105
|
+
* @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
|
|
106
|
+
*/
|
|
107
|
+
USEARCH_EXPORT void usearch_save(usearch_index_t, char const* path, usearch_error_t* error);
|
|
65
108
|
|
|
66
|
-
|
|
109
|
+
/**
|
|
110
|
+
* @brief Loads the index from a file.
|
|
111
|
+
* @param[in] path The file path from where the index will be loaded.
|
|
112
|
+
* @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
|
|
113
|
+
*/
|
|
114
|
+
USEARCH_EXPORT void usearch_load(usearch_index_t, char const* path, usearch_error_t* error);
|
|
67
115
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
116
|
+
/**
|
|
117
|
+
* @brief Creates a view of the index from a file without loading it into memory.
|
|
118
|
+
* @param[in] path The file path from where the view will be created.
|
|
119
|
+
* @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
|
|
120
|
+
*/
|
|
121
|
+
USEARCH_EXPORT void usearch_view(usearch_index_t, char const* path, usearch_error_t* error);
|
|
71
122
|
|
|
72
|
-
USEARCH_EXPORT
|
|
123
|
+
USEARCH_EXPORT size_t usearch_size(usearch_index_t, usearch_error_t* error);
|
|
124
|
+
USEARCH_EXPORT size_t usearch_capacity(usearch_index_t, usearch_error_t* error);
|
|
125
|
+
USEARCH_EXPORT size_t usearch_dimensions(usearch_index_t, usearch_error_t* error);
|
|
126
|
+
USEARCH_EXPORT size_t usearch_connectivity(usearch_index_t, usearch_error_t* error);
|
|
73
127
|
|
|
74
128
|
/**
|
|
75
|
-
* @brief
|
|
76
|
-
* @
|
|
129
|
+
* @brief Reserves memory for a specified number of incoming vectors.
|
|
130
|
+
* @param[in] capacity The desired total capacity including current size.
|
|
131
|
+
* @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
|
|
77
132
|
*/
|
|
78
|
-
USEARCH_EXPORT size_t
|
|
133
|
+
USEARCH_EXPORT void usearch_reserve(usearch_index_t, size_t capacity, usearch_error_t* error);
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* @brief Adds a vector with a key to the index.
|
|
137
|
+
* @param[in] key The key associated with the vector.
|
|
138
|
+
* @param[in] vector Pointer to the vector data.
|
|
139
|
+
* @param[in] vector_kind The scalar type used in the vector data.
|
|
140
|
+
* @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
|
|
141
|
+
*/
|
|
142
|
+
USEARCH_EXPORT void usearch_add( //
|
|
143
|
+
usearch_index_t, usearch_key_t key, //
|
|
144
|
+
void const* vector, usearch_scalar_kind_t vector_kind, usearch_error_t* error);
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* @brief Checks if the index contains a vector with a specific key.
|
|
148
|
+
* @param[in] key The key to be checked.
|
|
149
|
+
* @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
|
|
150
|
+
* @return `true` if the index contains the vector with the given key, `false` otherwise.
|
|
151
|
+
*/
|
|
152
|
+
USEARCH_EXPORT bool usearch_contains(usearch_index_t, usearch_key_t, usearch_error_t* error);
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* @brief Performs k-Approximate Nearest Neighbors (kANN) Search for closest vectors to query.
|
|
156
|
+
* @param[in] query_vector Pointer to the query vector data.
|
|
157
|
+
* @param[in] query_kind The scalar type used in the query vector data.
|
|
158
|
+
* @param[in] results_limit Upper bound on the number of neighbors to search, the "k" in "kANN".
|
|
159
|
+
* @param[out] found_keys Output buffer for up to `results_limit` nearest neighbors keys.
|
|
160
|
+
* @param[out] found_distances Output buffer for up to `results_limit` distances to nearest neighbors.
|
|
161
|
+
* @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
|
|
162
|
+
* @return Number of found matches.
|
|
163
|
+
*/
|
|
164
|
+
USEARCH_EXPORT size_t usearch_search( //
|
|
79
165
|
usearch_index_t, void const* query_vector, usearch_scalar_kind_t query_kind, size_t results_limit, //
|
|
80
|
-
|
|
166
|
+
usearch_key_t* found_keys, usearch_distance_t* found_distances, usearch_error_t* error);
|
|
81
167
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
168
|
+
/**
|
|
169
|
+
* @brief Retrieves the vector associated with the given key from the index.
|
|
170
|
+
* @param[in] key The key of the vector to retrieve.
|
|
171
|
+
* @param[out] vector Pointer to the memory where the vector data will be copied.
|
|
172
|
+
* @param[in] vector_kind The scalar type used in the vector data.
|
|
173
|
+
* @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
|
|
174
|
+
* @return `true` if the vector is successfully retrieved, `false` if the vector is not found.
|
|
175
|
+
*/
|
|
176
|
+
USEARCH_EXPORT bool usearch_get( //
|
|
177
|
+
usearch_index_t, usearch_key_t key, //
|
|
178
|
+
void* vector, usearch_scalar_kind_t vector_kind, usearch_error_t* error);
|
|
85
179
|
|
|
86
|
-
|
|
180
|
+
/**
|
|
181
|
+
* @brief Removes the vector associated with the given key from the index.
|
|
182
|
+
* @param[in] key The key of the vector to be removed.
|
|
183
|
+
* @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
|
|
184
|
+
* @return `true` if the vector is successfully removed, `false` if the vector is not found.
|
|
185
|
+
*/
|
|
186
|
+
USEARCH_EXPORT bool usearch_remove(usearch_index_t, usearch_key_t key, usearch_error_t* error);
|
|
87
187
|
|
|
88
188
|
#ifdef __cplusplus
|
|
89
189
|
}
|
package/conanfile.py
CHANGED
|
@@ -4,7 +4,7 @@ from conans import ConanFile
|
|
|
4
4
|
class USearchConan(ConanFile):
|
|
5
5
|
|
|
6
6
|
name = 'USearch'
|
|
7
|
-
version = '
|
|
7
|
+
version = '1.1.0'
|
|
8
8
|
license = 'Apache 2.0'
|
|
9
9
|
url = 'https://github.com/unum-cloud/usearch'
|
|
10
10
|
description = 'Smaller & Faster Single-File Vector Search Engine from Unum'
|
package/cpp/CMakeLists.txt
CHANGED
|
@@ -83,6 +83,7 @@ if(${USEARCH_BUILD_TEST})
|
|
|
83
83
|
target_link_libraries(test PRIVATE Threads::Threads)
|
|
84
84
|
target_include_directories(test PRIVATE ${USEARCH_PUNNED_INCLUDE_DIRS})
|
|
85
85
|
set_target_properties(test PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
|
86
|
+
set_target_properties(test PROPERTIES CXX_STANDARD 17)
|
|
86
87
|
|
|
87
88
|
if(${CMAKE_VERSION} VERSION_EQUAL 3.13 OR ${CMAKE_VERSION} VERSION_GREATER 3.13)
|
|
88
89
|
include(CTest)
|
|
@@ -96,6 +97,7 @@ if(${USEARCH_BUILD_BENCHMARK})
|
|
|
96
97
|
target_link_libraries(bench PRIVATE Threads::Threads)
|
|
97
98
|
target_include_directories(bench PRIVATE ${USEARCH_PUNNED_INCLUDE_DIRS})
|
|
98
99
|
set_target_properties(bench PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
|
100
|
+
set_target_properties(bench PROPERTIES CXX_STANDARD 17)
|
|
99
101
|
|
|
100
102
|
if(${USEARCH_USE_SIMSIMD})
|
|
101
103
|
target_compile_definitions(bench PRIVATE USEARCH_USE_SIMSIMD=1)
|
|
@@ -107,6 +109,6 @@ if(${USEARCH_BUILD_BENCHMARK})
|
|
|
107
109
|
endif()
|
|
108
110
|
|
|
109
111
|
if(${USEARCH_USE_JEMALLOC})
|
|
110
|
-
target_link_libraries(bench PRIVATE ${JEMALLOC_LIBRARIES})
|
|
112
|
+
target_link_libraries(bench PRIVATE ${JEMALLOC_LIBRARIES})
|
|
111
113
|
endif()
|
|
112
114
|
endif()
|