usearch 0.19.2 → 0.20.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/Cargo.toml +1 -1
- package/README.md +1 -1
- package/c/lib.cpp +1 -2
- package/c/test.c +238 -126
- package/conanfile.py +1 -1
- package/cpp/bench.cpp +3 -3
- package/cpp/test.cpp +12 -12
- package/include/usearch/index.hpp +137 -49
- package/include/usearch/index_punned_dense.hpp +1 -1
- package/include/usearch/index_punned_helpers.hpp +2 -0
- package/java/cloud/unum/usearch/cloud_unum_usearch_Index.cpp +25 -23
- package/javascript/lib.cpp +10 -11
- package/javascript/test.js +1 -1
- package/objc/USearchObjective.mm +15 -12
- package/objc/include/USearchObjective.h +3 -3
- package/package.json +2 -2
- package/python/lib.cpp +43 -48
- package/python/usearch/index.py +1 -1
- package/rust/lib.cpp +13 -13
- package/rust/lib.hpp +10 -6
- package/rust/lib.rs +2 -2
- package/swift/Index+Sugar.swift +13 -9
- package/wolfram/lib.cpp +26 -19
package/javascript/test.js
CHANGED
|
@@ -11,7 +11,7 @@ index.add(16, new Float32Array([10, 25]))
|
|
|
11
11
|
assert.equal(index.size(), 2)
|
|
12
12
|
|
|
13
13
|
var results = index.search(new Float32Array([13, 14]), 2)
|
|
14
|
-
assert.deepEqual(results.labels, new
|
|
14
|
+
assert.deepEqual(results.labels, new BigUint64Array([15n, 16n]))
|
|
15
15
|
assert.deepEqual(results.distances, new Float32Array([45, 130]))
|
|
16
16
|
|
|
17
17
|
console.log('JavaScript tests passed!')
|
package/objc/USearchObjective.mm
CHANGED
|
@@ -8,12 +8,15 @@
|
|
|
8
8
|
using namespace unum::usearch;
|
|
9
9
|
using namespace unum;
|
|
10
10
|
|
|
11
|
+
using metric_t = index_punned_dense_metric_t;
|
|
11
12
|
using distance_t = punned_distance_t;
|
|
12
|
-
using
|
|
13
|
-
using add_result_t =
|
|
14
|
-
using search_result_t =
|
|
15
|
-
using serialization_result_t =
|
|
16
|
-
using
|
|
13
|
+
using index_t = punned_small_t;
|
|
14
|
+
using add_result_t = typename index_t::add_result_t;
|
|
15
|
+
using search_result_t = typename index_t::search_result_t;
|
|
16
|
+
using serialization_result_t = typename index_t::serialization_result_t;
|
|
17
|
+
using label_t = typename index_t::label_t;
|
|
18
|
+
using id_t = typename index_t::id_t;
|
|
19
|
+
using shared_index_t = std::shared_ptr<index_t>;
|
|
17
20
|
|
|
18
21
|
metric_kind_t to_native_metric(USearchMetric m) {
|
|
19
22
|
switch (m) {
|
|
@@ -117,11 +120,11 @@ scalar_kind_t to_native_scalar(USearchScalar m) {
|
|
|
117
120
|
index_config_t config;
|
|
118
121
|
|
|
119
122
|
config.connectivity = static_cast<std::size_t>(connectivity);
|
|
120
|
-
shared_index_t ptr = std::make_shared<
|
|
123
|
+
shared_index_t ptr = std::make_shared<index_t>(index_t::make(dims, to_native_metric(metric), config, to_native_scalar(quantization)));
|
|
121
124
|
return [[USearchIndex alloc] initWithIndex:ptr];
|
|
122
125
|
}
|
|
123
126
|
|
|
124
|
-
- (void)addSingle:(
|
|
127
|
+
- (void)addSingle:(USearchLabel)label
|
|
125
128
|
vector:(Float32 const *_Nonnull)vector {
|
|
126
129
|
add_result_t result = _native->add(label, vector);
|
|
127
130
|
|
|
@@ -134,7 +137,7 @@ scalar_kind_t to_native_scalar(USearchScalar m) {
|
|
|
134
137
|
|
|
135
138
|
- (UInt32)searchSingle:(Float32 const *_Nonnull)vector
|
|
136
139
|
count:(UInt32)wanted
|
|
137
|
-
labels:(
|
|
140
|
+
labels:(USearchLabel *_Nullable)labels
|
|
138
141
|
distances:(Float32 *_Nullable)distances {
|
|
139
142
|
search_result_t result = _native->search(vector, static_cast<std::size_t>(wanted));
|
|
140
143
|
|
|
@@ -148,7 +151,7 @@ scalar_kind_t to_native_scalar(USearchScalar m) {
|
|
|
148
151
|
return static_cast<UInt32>(found);
|
|
149
152
|
}
|
|
150
153
|
|
|
151
|
-
- (void)addDouble:(
|
|
154
|
+
- (void)addDouble:(USearchLabel)label
|
|
152
155
|
vector:(Float64 const *_Nonnull)vector {
|
|
153
156
|
add_result_t result = _native->add(label, (f64_t const *)vector);
|
|
154
157
|
|
|
@@ -161,7 +164,7 @@ scalar_kind_t to_native_scalar(USearchScalar m) {
|
|
|
161
164
|
|
|
162
165
|
- (UInt32)searchDouble:(Float64 const *_Nonnull)vector
|
|
163
166
|
count:(UInt32)wanted
|
|
164
|
-
labels:(
|
|
167
|
+
labels:(USearchLabel *_Nullable)labels
|
|
165
168
|
distances:(Float32 *_Nullable)distances {
|
|
166
169
|
search_result_t result = _native->search((f64_t const *)vector, static_cast<std::size_t>(wanted));
|
|
167
170
|
|
|
@@ -175,7 +178,7 @@ scalar_kind_t to_native_scalar(USearchScalar m) {
|
|
|
175
178
|
return static_cast<UInt32>(found);
|
|
176
179
|
}
|
|
177
180
|
|
|
178
|
-
- (void)addHalf:(
|
|
181
|
+
- (void)addHalf:(USearchLabel)label
|
|
179
182
|
vector:(void const *_Nonnull)vector {
|
|
180
183
|
add_result_t result = _native->add(label, (f16_t const *)vector);
|
|
181
184
|
|
|
@@ -188,7 +191,7 @@ scalar_kind_t to_native_scalar(USearchScalar m) {
|
|
|
188
191
|
|
|
189
192
|
- (UInt32)searchHalf:(void const *_Nonnull)vector
|
|
190
193
|
count:(UInt32)wanted
|
|
191
|
-
labels:(
|
|
194
|
+
labels:(USearchLabel *_Nullable)labels
|
|
192
195
|
distances:(Float32 *_Nullable)distances {
|
|
193
196
|
search_result_t result = _native->search((f16_t const *)vector, static_cast<std::size_t>(wanted));
|
|
194
197
|
|
|
@@ -25,7 +25,7 @@ typedef NS_ENUM(NSUInteger, USearchMetric) {
|
|
|
25
25
|
USearchMetricSorensen
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
typedef
|
|
28
|
+
typedef UInt64 USearchLabel;
|
|
29
29
|
|
|
30
30
|
API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0))
|
|
31
31
|
@interface USearchIndex : NSObject
|
|
@@ -80,7 +80,7 @@ API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0))
|
|
|
80
80
|
* @brief Adds a labeled vector to the index.
|
|
81
81
|
* @param vector Double-precision vector.
|
|
82
82
|
*/
|
|
83
|
-
- (void)addDouble:(
|
|
83
|
+
- (void)addDouble:(USearchLabel)label
|
|
84
84
|
vector:(Float64 const *_Nonnull)vector NS_SWIFT_NAME(addDouble(label:vector:));
|
|
85
85
|
|
|
86
86
|
/**
|
|
@@ -100,7 +100,7 @@ API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0))
|
|
|
100
100
|
* @brief Adds a labeled vector to the index.
|
|
101
101
|
* @param vector Half-precision vector.
|
|
102
102
|
*/
|
|
103
|
-
- (void)addHalf:(
|
|
103
|
+
- (void)addHalf:(USearchLabel)label
|
|
104
104
|
vector:(void const *_Nonnull)vector NS_SWIFT_NAME(addHalf(label:vector:));
|
|
105
105
|
|
|
106
106
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "usearch",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.0",
|
|
4
4
|
"description": "Smaller & Faster Single-File Vector Search Engine from Unum",
|
|
5
5
|
"author": "Ashot Vardanian",
|
|
6
6
|
"license": "Apache 2.0",
|
|
@@ -24,6 +24,6 @@
|
|
|
24
24
|
"@semantic-release/exec": "^6.0.3",
|
|
25
25
|
"@semantic-release/git": "^10.0.1",
|
|
26
26
|
"conventional-changelog-eslint": "^3.0.9",
|
|
27
|
-
"semantic-release": "^21.0.
|
|
27
|
+
"semantic-release": "^21.0.7"
|
|
28
28
|
}
|
|
29
29
|
}
|
package/python/lib.cpp
CHANGED
|
@@ -12,11 +12,10 @@
|
|
|
12
12
|
*
|
|
13
13
|
* @copyright Copyright (c) 2023
|
|
14
14
|
*/
|
|
15
|
-
#define PY_SSIZE_T_CLEAN
|
|
16
|
-
#define NOMINMAX // Some of our dependencies call `std::max(x, y)`, which crashes Windows builds
|
|
17
15
|
#include <limits> // `std::numeric_limits`
|
|
18
16
|
#include <thread> // `std::thread`
|
|
19
17
|
|
|
18
|
+
#define PY_SSIZE_T_CLEAN
|
|
20
19
|
#include <pybind11/numpy.h>
|
|
21
20
|
#include <pybind11/pybind11.h>
|
|
22
21
|
|
|
@@ -38,26 +37,23 @@ enum class metric_signature_t {
|
|
|
38
37
|
|
|
39
38
|
namespace py = pybind11;
|
|
40
39
|
using py_shape_t = py::array::ShapeContainer;
|
|
41
|
-
|
|
42
|
-
using
|
|
43
|
-
using distance_t = punned_distance_t;
|
|
40
|
+
using label_t = typename punned_small_t::label_t;
|
|
41
|
+
using id_t = typename punned_small_t::id_t;
|
|
44
42
|
using metric_t = index_punned_dense_metric_t;
|
|
45
|
-
using
|
|
46
|
-
using
|
|
47
|
-
|
|
48
|
-
using
|
|
49
|
-
using punned_add_result_t = typename punned_index_t::add_result_t;
|
|
50
|
-
using punned_search_result_t = typename punned_index_t::search_result_t;
|
|
43
|
+
using distance_t = punned_distance_t;
|
|
44
|
+
using dense_index_t = punned_small_t;
|
|
45
|
+
using dense_add_result_t = typename dense_index_t::add_result_t;
|
|
46
|
+
using dense_search_result_t = typename dense_index_t::search_result_t;
|
|
51
47
|
|
|
52
|
-
struct
|
|
53
|
-
using native_t =
|
|
48
|
+
struct dense_index_py_t : public dense_index_t {
|
|
49
|
+
using native_t = dense_index_t;
|
|
54
50
|
using native_t::add;
|
|
55
51
|
using native_t::capacity;
|
|
56
52
|
using native_t::reserve;
|
|
57
53
|
using native_t::search;
|
|
58
54
|
using native_t::size;
|
|
59
55
|
|
|
60
|
-
|
|
56
|
+
dense_index_py_t(native_t&& base) : native_t(std::move(base)) {}
|
|
61
57
|
};
|
|
62
58
|
|
|
63
59
|
using set_member_t = std::uint32_t;
|
|
@@ -121,7 +117,7 @@ metric_t udf(metric_kind_t kind, metric_signature_t signature, std::uintptr_t me
|
|
|
121
117
|
}
|
|
122
118
|
}
|
|
123
119
|
|
|
124
|
-
static
|
|
120
|
+
static dense_index_py_t make_index( //
|
|
125
121
|
std::size_t dimensions, //
|
|
126
122
|
scalar_kind_t scalar_kind, //
|
|
127
123
|
metric_kind_t metric_kind, //
|
|
@@ -136,14 +132,14 @@ static punned_index_py_t make_index( //
|
|
|
136
132
|
config.connectivity = connectivity;
|
|
137
133
|
|
|
138
134
|
if (tune)
|
|
139
|
-
config =
|
|
135
|
+
config = dense_index_t::optimize(config);
|
|
140
136
|
|
|
141
137
|
if (metric_uintptr)
|
|
142
|
-
return
|
|
138
|
+
return dense_index_t::make( //
|
|
143
139
|
dimensions, udf(metric_kind, metric_signature, metric_uintptr, scalar_kind), config, scalar_kind,
|
|
144
140
|
expansion_add, expansion_search);
|
|
145
141
|
else
|
|
146
|
-
return
|
|
142
|
+
return dense_index_t::make(dimensions, metric_kind, config, scalar_kind, expansion_add, expansion_search);
|
|
147
143
|
}
|
|
148
144
|
|
|
149
145
|
static std::unique_ptr<sparse_index_py_t> make_sparse_index( //
|
|
@@ -173,7 +169,7 @@ scalar_kind_t numpy_string_to_kind(std::string const& name) {
|
|
|
173
169
|
return scalar_kind_t::unknown_k;
|
|
174
170
|
}
|
|
175
171
|
|
|
176
|
-
static void add_one_to_index(
|
|
172
|
+
static void add_one_to_index(dense_index_py_t& index, label_t label, py::buffer vector, bool copy, std::size_t) {
|
|
177
173
|
|
|
178
174
|
py::buffer_info vector_info = vector.request();
|
|
179
175
|
if (vector_info.ndim != 1)
|
|
@@ -203,7 +199,7 @@ static void add_one_to_index(punned_index_py_t& index, label_t label, py::buffer
|
|
|
203
199
|
|
|
204
200
|
template <typename scalar_at>
|
|
205
201
|
static void add_typed_to_index( //
|
|
206
|
-
|
|
202
|
+
dense_index_py_t& index, //
|
|
207
203
|
py::buffer_info const& labels_info, py::buffer_info const& vectors_info, //
|
|
208
204
|
bool copy, std::size_t threads) {
|
|
209
205
|
|
|
@@ -223,8 +219,8 @@ static void add_typed_to_index( //
|
|
|
223
219
|
});
|
|
224
220
|
}
|
|
225
221
|
|
|
226
|
-
static void add_many_to_index(
|
|
227
|
-
|
|
222
|
+
static void add_many_to_index( //
|
|
223
|
+
dense_index_py_t& index, py::buffer labels, py::buffer vectors, //
|
|
228
224
|
bool copy, std::size_t threads) {
|
|
229
225
|
|
|
230
226
|
if (index.limits().threads_add < threads)
|
|
@@ -265,7 +261,7 @@ static void add_many_to_index( //
|
|
|
265
261
|
}
|
|
266
262
|
}
|
|
267
263
|
|
|
268
|
-
static py::tuple search_one_in_index(
|
|
264
|
+
static py::tuple search_one_in_index(dense_index_py_t& index, py::buffer vector, std::size_t wanted, bool exact) {
|
|
269
265
|
|
|
270
266
|
py::buffer_info vector_info = vector.request();
|
|
271
267
|
Py_ssize_t vector_dimensions = vector_info.shape[0];
|
|
@@ -282,7 +278,7 @@ static py::tuple search_one_in_index(punned_index_py_t& index, py::buffer vector
|
|
|
282
278
|
search_config_t config;
|
|
283
279
|
config.exact = exact;
|
|
284
280
|
|
|
285
|
-
auto raise_and_dump = [&](
|
|
281
|
+
auto raise_and_dump = [&](dense_search_result_t result) {
|
|
286
282
|
result.error.raise();
|
|
287
283
|
count = result.dump_to(&labels_py1d(0), &distances_py1d(0));
|
|
288
284
|
};
|
|
@@ -308,9 +304,9 @@ static py::tuple search_one_in_index(punned_index_py_t& index, py::buffer vector
|
|
|
308
304
|
}
|
|
309
305
|
|
|
310
306
|
template <typename scalar_at>
|
|
311
|
-
static void search_typed(
|
|
312
|
-
|
|
313
|
-
std::size_t wanted, bool exact, std::size_t threads,
|
|
307
|
+
static void search_typed( //
|
|
308
|
+
dense_index_py_t& index, py::buffer_info& vectors_info, //
|
|
309
|
+
std::size_t wanted, bool exact, std::size_t threads, //
|
|
314
310
|
py::array_t<label_t>& labels_py, py::array_t<distance_t>& distances_py, py::array_t<Py_ssize_t>& counts_py) {
|
|
315
311
|
|
|
316
312
|
auto labels_py2d = labels_py.template mutable_unchecked<2>();
|
|
@@ -325,7 +321,7 @@ static void search_typed( //
|
|
|
325
321
|
config.thread = thread_idx;
|
|
326
322
|
config.exact = exact;
|
|
327
323
|
scalar_at const* vector = (scalar_at const*)(vectors_data + task_idx * vectors_info.strides[0]);
|
|
328
|
-
|
|
324
|
+
dense_search_result_t result = index.search(vector, wanted, config);
|
|
329
325
|
result.error.raise();
|
|
330
326
|
counts_py1d(task_idx) =
|
|
331
327
|
static_cast<Py_ssize_t>(result.dump_to(&labels_py2d(task_idx, 0), &distances_py2d(task_idx, 0)));
|
|
@@ -344,7 +340,7 @@ static void search_typed( //
|
|
|
344
340
|
* 3. array with match counts.
|
|
345
341
|
*/
|
|
346
342
|
static py::tuple search_many_in_index( //
|
|
347
|
-
|
|
343
|
+
dense_index_py_t& index, py::buffer vectors, std::size_t wanted, bool exact, std::size_t threads) {
|
|
348
344
|
|
|
349
345
|
if (wanted == 0)
|
|
350
346
|
return py::tuple(3);
|
|
@@ -591,7 +587,7 @@ PYBIND11_MODULE(compiled, m) {
|
|
|
591
587
|
h.def_readonly("bytes_for_vectors", &file_head_result_t::bytes_for_vectors);
|
|
592
588
|
h.def_readonly("bytes_checksum", &file_head_result_t::bytes_checksum);
|
|
593
589
|
|
|
594
|
-
auto i = py::class_<
|
|
590
|
+
auto i = py::class_<dense_index_py_t>(m, "Index");
|
|
595
591
|
|
|
596
592
|
i.def(py::init(&make_index), //
|
|
597
593
|
py::kw_only(), //
|
|
@@ -632,30 +628,29 @@ PYBIND11_MODULE(compiled, m) {
|
|
|
632
628
|
py::arg("threads") = 0 //
|
|
633
629
|
);
|
|
634
630
|
|
|
635
|
-
i.def("__len__", &
|
|
636
|
-
i.def_property_readonly("size", &
|
|
637
|
-
i.def_property_readonly("ndim", &
|
|
638
|
-
i.def_property_readonly("connectivity", &
|
|
639
|
-
i.def_property_readonly("capacity", &
|
|
631
|
+
i.def("__len__", &dense_index_py_t::size);
|
|
632
|
+
i.def_property_readonly("size", &dense_index_py_t::size);
|
|
633
|
+
i.def_property_readonly("ndim", &dense_index_py_t::dimensions);
|
|
634
|
+
i.def_property_readonly("connectivity", &dense_index_py_t::connectivity);
|
|
635
|
+
i.def_property_readonly("capacity", &dense_index_py_t::capacity);
|
|
640
636
|
i.def_property_readonly( //
|
|
641
|
-
"dtype", [](
|
|
637
|
+
"dtype", [](dense_index_py_t const& index) -> scalar_kind_t { return index.metric().scalar_kind_; });
|
|
642
638
|
i.def_property_readonly( //
|
|
643
|
-
"memory_usage", [](
|
|
639
|
+
"memory_usage", [](dense_index_py_t const& index) -> std::size_t { return index.memory_usage(); },
|
|
644
640
|
py::call_guard<py::gil_scoped_release>());
|
|
645
641
|
|
|
646
|
-
i.def_property("expansion_add", &
|
|
647
|
-
i.def_property("expansion_search", &
|
|
648
|
-
&punned_index_py_t::change_expansion_search);
|
|
642
|
+
i.def_property("expansion_add", &dense_index_py_t::expansion_add, &dense_index_py_t::change_expansion_add);
|
|
643
|
+
i.def_property("expansion_search", &dense_index_py_t::expansion_search, &dense_index_py_t::change_expansion_search);
|
|
649
644
|
|
|
650
|
-
i.def_property_readonly("labels", &get_all_labels<
|
|
651
|
-
i.def("get_labels", &get_labels<
|
|
652
|
-
i.def("__contains__", &
|
|
653
|
-
i.def("__getitem__", &get_member<
|
|
645
|
+
i.def_property_readonly("labels", &get_all_labels<dense_index_py_t>);
|
|
646
|
+
i.def("get_labels", &get_labels<dense_index_py_t>, py::arg("limit") = std::numeric_limits<std::size_t>::max());
|
|
647
|
+
i.def("__contains__", &dense_index_py_t::contains);
|
|
648
|
+
i.def("__getitem__", &get_member<dense_index_py_t>, py::arg("label"), py::arg("dtype") = scalar_kind_t::f32_k);
|
|
654
649
|
|
|
655
|
-
i.def("save", &save_index<
|
|
656
|
-
i.def("load", &load_index<
|
|
657
|
-
i.def("view", &view_index<
|
|
658
|
-
i.def("clear", &
|
|
650
|
+
i.def("save", &save_index<dense_index_py_t>, py::arg("path"), py::call_guard<py::gil_scoped_release>());
|
|
651
|
+
i.def("load", &load_index<dense_index_py_t>, py::arg("path"), py::call_guard<py::gil_scoped_release>());
|
|
652
|
+
i.def("view", &view_index<dense_index_py_t>, py::arg("path"), py::call_guard<py::gil_scoped_release>());
|
|
653
|
+
i.def("clear", &dense_index_py_t::clear, py::call_guard<py::gil_scoped_release>());
|
|
659
654
|
|
|
660
655
|
auto si = py::class_<sparse_index_py_t>(m, "SparseIndex");
|
|
661
656
|
|
package/python/usearch/index.py
CHANGED
package/rust/lib.cpp
CHANGED
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
using namespace unum::usearch;
|
|
5
5
|
using namespace unum;
|
|
6
6
|
|
|
7
|
-
using
|
|
8
|
-
using add_result_t = typename
|
|
9
|
-
using search_result_t = typename
|
|
10
|
-
using serialization_result_t = typename
|
|
7
|
+
using index_t = typename Index::index_t;
|
|
8
|
+
using add_result_t = typename index_t::add_result_t;
|
|
9
|
+
using search_result_t = typename index_t::search_result_t;
|
|
10
|
+
using serialization_result_t = typename index_t::serialization_result_t;
|
|
11
11
|
|
|
12
|
-
Index::Index(std::unique_ptr<
|
|
12
|
+
Index::Index(std::unique_ptr<index_t> index) : index_(std::move(index)) {}
|
|
13
13
|
|
|
14
|
-
void Index::add_in_thread(
|
|
14
|
+
void Index::add_in_thread(label_t label, rust::Slice<float const> vector, size_t thread) const {
|
|
15
15
|
add_config_t config;
|
|
16
16
|
config.thread = thread;
|
|
17
17
|
index_->add(label, vector.data(), config).error.raise();
|
|
@@ -33,7 +33,7 @@ Matches Index::search_in_thread(rust::Slice<float const> vector, size_t count, s
|
|
|
33
33
|
return matches;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
void Index::add(
|
|
36
|
+
void Index::add(label_t label, rust::Slice<float const> vector) const {
|
|
37
37
|
index_->add(label, vector.data()).error.raise();
|
|
38
38
|
}
|
|
39
39
|
|
|
@@ -64,9 +64,9 @@ void Index::view(rust::Str path) const { index_->view(std::string(path).c_str())
|
|
|
64
64
|
|
|
65
65
|
scalar_kind_t accuracy(rust::Str quant) { return scalar_kind_from_name(quant.data(), quant.size()); }
|
|
66
66
|
|
|
67
|
-
std::unique_ptr<Index> wrap(
|
|
68
|
-
std::unique_ptr<
|
|
69
|
-
punned_ptr.reset(new
|
|
67
|
+
std::unique_ptr<Index> wrap(index_t&& index) {
|
|
68
|
+
std::unique_ptr<index_t> punned_ptr;
|
|
69
|
+
punned_ptr.reset(new index_t(std::move(index)));
|
|
70
70
|
std::unique_ptr<Index> result;
|
|
71
71
|
result.reset(new Index(std::move(punned_ptr)));
|
|
72
72
|
return result;
|
|
@@ -104,7 +104,7 @@ scalar_kind_t rust_to_cpp_scalar(ScalarKind value) {
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
std::unique_ptr<Index> new_index(IndexOptions const& options) {
|
|
107
|
-
return wrap(
|
|
108
|
-
|
|
109
|
-
|
|
107
|
+
return wrap(index_t::make(options.dimensions, rust_to_cpp_metric(options.metric), config(options.connectivity),
|
|
108
|
+
rust_to_cpp_scalar(options.quantization), options.expansion_add,
|
|
109
|
+
options.expansion_search));
|
|
110
110
|
}
|
package/rust/lib.hpp
CHANGED
|
@@ -10,16 +10,20 @@ struct IndexOptions;
|
|
|
10
10
|
|
|
11
11
|
class Index {
|
|
12
12
|
public:
|
|
13
|
-
using
|
|
13
|
+
using metric_t = unum::usearch::index_punned_dense_metric_t;
|
|
14
14
|
using distance_t = unum::usearch::punned_distance_t;
|
|
15
|
-
using
|
|
15
|
+
using index_t = unum::usearch::punned_small_t;
|
|
16
|
+
using add_result_t = typename index_t::add_result_t;
|
|
17
|
+
using search_result_t = typename index_t::search_result_t;
|
|
18
|
+
using label_t = typename index_t::label_t;
|
|
19
|
+
using id_t = typename index_t::id_t;
|
|
16
20
|
|
|
17
|
-
Index(std::unique_ptr<
|
|
21
|
+
Index(std::unique_ptr<index_t> index);
|
|
18
22
|
|
|
19
23
|
void reserve(size_t) const;
|
|
20
24
|
|
|
21
|
-
void add(
|
|
22
|
-
void add_in_thread(
|
|
25
|
+
void add(label_t label, rust::Slice<float const> vector) const;
|
|
26
|
+
void add_in_thread(label_t label, rust::Slice<float const> vector, size_t thread) const;
|
|
23
27
|
|
|
24
28
|
Matches search(rust::Slice<float const> vector, size_t count) const;
|
|
25
29
|
Matches search_in_thread(rust::Slice<float const> vector, size_t count, size_t thread) const;
|
|
@@ -34,7 +38,7 @@ class Index {
|
|
|
34
38
|
void view(rust::Str path) const;
|
|
35
39
|
|
|
36
40
|
private:
|
|
37
|
-
std::unique_ptr<
|
|
41
|
+
std::unique_ptr<index_t> index_;
|
|
38
42
|
};
|
|
39
43
|
|
|
40
44
|
std::unique_ptr<Index> new_index(IndexOptions const& options);
|
package/rust/lib.rs
CHANGED
|
@@ -4,7 +4,7 @@ pub mod ffi {
|
|
|
4
4
|
// Shared structs with fields visible to both languages.
|
|
5
5
|
struct Matches {
|
|
6
6
|
count: usize,
|
|
7
|
-
labels: Vec<
|
|
7
|
+
labels: Vec<u64>,
|
|
8
8
|
distances: Vec<f32>,
|
|
9
9
|
}
|
|
10
10
|
|
|
@@ -51,7 +51,7 @@ pub mod ffi {
|
|
|
51
51
|
pub fn size(self: &Index) -> usize;
|
|
52
52
|
pub fn capacity(self: &Index) -> usize;
|
|
53
53
|
|
|
54
|
-
pub fn add(self: &Index, label:
|
|
54
|
+
pub fn add(self: &Index, label: u64, vector: &[f32]) -> Result<()>;
|
|
55
55
|
pub fn search(self: &Index, query: &[f32], count: usize) -> Result<Matches>;
|
|
56
56
|
|
|
57
57
|
pub fn save(self: &Index, path: &str) -> Result<()>;
|
package/swift/Index+Sugar.swift
CHANGED
|
@@ -7,11 +7,15 @@
|
|
|
7
7
|
|
|
8
8
|
@available(iOS 13, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
|
|
9
9
|
extension USearchIndex {
|
|
10
|
+
public typealias Label = USearchLabel
|
|
11
|
+
public typealias Metric = USearchMetric
|
|
12
|
+
public typealias Scalar = USearchScalar
|
|
13
|
+
|
|
10
14
|
/// Adds a labeled vector to the index.
|
|
11
15
|
/// - Parameter label: Unique identifer for that object.
|
|
12
16
|
/// - Parameter vector: Single-precision vector.
|
|
13
17
|
/// - Throws: If runs out of memory.
|
|
14
|
-
public func add(label:
|
|
18
|
+
public func add(label: USearchLabel, vector: ArraySlice<Float32>) {
|
|
15
19
|
vector.withContiguousStorageIfAvailable {
|
|
16
20
|
addSingle(label: label, vector: $0.baseAddress!)
|
|
17
21
|
}
|
|
@@ -23,8 +27,8 @@ extension USearchIndex {
|
|
|
23
27
|
/// - Parameter count: Upper limit on the number of matches to retrieve.
|
|
24
28
|
/// - Returns: Labels and distances to closest approximate matches in decreasing similarity order.
|
|
25
29
|
/// - Throws: If runs out of memory.
|
|
26
|
-
public func search(vector: ArraySlice<Float32>, count: Int) -> ([
|
|
27
|
-
var matches: [
|
|
30
|
+
public func search(vector: ArraySlice<Float32>, count: Int) -> ([Label], [Float]) {
|
|
31
|
+
var matches: [Label] = Array(repeating: 0, count: count)
|
|
28
32
|
var distances: [Float] = Array(repeating: 0, count: count)
|
|
29
33
|
let results = vector.withContiguousStorageIfAvailable {
|
|
30
34
|
searchSingle(vector: $0.baseAddress!, count: CUnsignedInt(count), labels: &matches, distances: &distances)
|
|
@@ -38,7 +42,7 @@ extension USearchIndex {
|
|
|
38
42
|
/// - Parameter label: Unique identifer for that object.
|
|
39
43
|
/// - Parameter vector: Double-precision vector.
|
|
40
44
|
/// - Throws: If runs out of memory.
|
|
41
|
-
public func add(label:
|
|
45
|
+
public func add(label: Label, vector: ArraySlice<Float64>) {
|
|
42
46
|
vector.withContiguousStorageIfAvailable {
|
|
43
47
|
addDouble(label: label, vector: $0.baseAddress!)
|
|
44
48
|
}
|
|
@@ -49,8 +53,8 @@ extension USearchIndex {
|
|
|
49
53
|
/// - Parameter count: Upper limit on the number of matches to retrieve.
|
|
50
54
|
/// - Returns: Labels and distances to closest approximate matches in decreasing similarity order.
|
|
51
55
|
/// - Throws: If runs out of memory.
|
|
52
|
-
public func search(vector: ArraySlice<Float64>, count: Int) -> ([
|
|
53
|
-
var matches: [
|
|
56
|
+
public func search(vector: ArraySlice<Float64>, count: Int) -> ([Label], [Float]) {
|
|
57
|
+
var matches: [Label] = Array(repeating: 0, count: count)
|
|
54
58
|
var distances: [Float] = Array(repeating: 0, count: count)
|
|
55
59
|
let results = vector.withContiguousStorageIfAvailable {
|
|
56
60
|
searchDouble(vector: $0.baseAddress!, count: CUnsignedInt(count), labels: &matches, distances: &distances)
|
|
@@ -67,7 +71,7 @@ extension USearchIndex {
|
|
|
67
71
|
/// - Parameter vector: Half-precision vector.
|
|
68
72
|
/// - Throws: If runs out of memory.
|
|
69
73
|
@available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *)
|
|
70
|
-
public func add(label:
|
|
74
|
+
public func add(label: Label, vector: ArraySlice<Float16>) {
|
|
71
75
|
vector.withContiguousStorageIfAvailable { buffer in
|
|
72
76
|
addHalf(label: label, vector: buffer.baseAddress!)
|
|
73
77
|
}
|
|
@@ -79,8 +83,8 @@ extension USearchIndex {
|
|
|
79
83
|
/// - Returns: Labels and distances to closest approximate matches in decreasing similarity order.
|
|
80
84
|
/// - Throws: If runs out of memory.
|
|
81
85
|
@available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *)
|
|
82
|
-
public func search(vector: ArraySlice<Float16>, count: Int) -> ([
|
|
83
|
-
var matches: [
|
|
86
|
+
public func search(vector: ArraySlice<Float16>, count: Int) -> ([Label], [Float]) {
|
|
87
|
+
var matches: [Label] = Array(repeating: 0, count: count)
|
|
84
88
|
var distances: [Float] = Array(repeating: 0, count: count)
|
|
85
89
|
let results = vector.withContiguousStorageIfAvailable {
|
|
86
90
|
searchHalf(vector: $0.baseAddress!, count: CUnsignedInt(count), labels: &matches, distances: &distances)
|