usearch 0.2.4 → 0.8.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/.clang-tidy +60 -0
- package/.github/ISSUE_TEMPLATE/bug_report.yml +90 -0
- package/.github/ISSUE_TEMPLATE/config.yml +5 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +64 -0
- package/.github/workflows/release.yml +47 -20
- package/.github/workflows/update_version.sh +1 -0
- package/.vscode/launch.json +22 -0
- package/.vscode/settings.json +9 -1
- package/.vscode/tasks.json +4 -4
- package/CITATION.cff +11 -0
- package/CMakeLists.txt +108 -95
- package/CODE_OF_CONDUCT.md +128 -0
- package/CONTRIBUTING.md +12 -0
- package/Cargo.toml +1 -1
- package/Dockerfile +14 -0
- package/README.md +21 -12
- package/VERSION +1 -1
- package/binding.gyp +13 -9
- package/build.rs +2 -1
- package/cmake/config.cmake.in +15 -0
- package/cmake/pkg-config.pc.in +4 -0
- package/cmake/usearchConfigVersion.cmake.in +20 -0
- package/conanfile.py +1 -1
- package/docs/{Benchmarking.md → benchmarks.md} +11 -2
- package/docs/benchmarks.rst +5 -0
- package/docs/{Compilation.md → compilation.md} +54 -27
- package/docs/compilation.rst +5 -0
- package/docs/conf.dox +2668 -0
- package/docs/index.rst +7 -0
- package/include/usearch/usearch.hpp +833 -439
- package/java/cloud/unum/usearch/cloud_unum_usearch_Index.cpp +17 -16
- package/javascript/lib.cpp +94 -20
- package/javascript/test.js +1 -1
- package/objc/USearchObjective.mm +47 -30
- package/objc/include/USearchObjective.h +18 -26
- package/package.json +1 -1
- package/pyproject.toml +3 -2
- package/python/lib.cpp +216 -130
- package/python/{bench.py → scripts/bench.py} +6 -1
- package/python/scripts/bench_params.py +112 -0
- package/python/{test.py → scripts/test.py} +32 -13
- package/python/usearch/client.py +100 -14
- package/python/usearch/server.py +104 -23
- package/rust/lib.cpp +20 -15
- package/rust/lib.hpp +5 -5
- package/rust/lib.rs +3 -3
- package/setup.py +7 -0
- package/src/CMakeLists.txt +107 -0
- package/src/bench.cpp +54 -19
- package/src/{advanced.hpp → punned.hpp} +235 -203
- package/src/test.cpp +62 -0
- package/swift/Index+Sugar.swift +1 -0
- package/swift/Test.swift +2 -1
- package/wolfram/lib.cpp +14 -14
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
|
|
5
5
|
#include <thread>
|
|
6
6
|
|
|
7
|
-
#include "
|
|
7
|
+
#include "punned.hpp"
|
|
8
8
|
|
|
9
9
|
using namespace unum::usearch;
|
|
10
10
|
using namespace unum;
|
|
11
11
|
|
|
12
12
|
using label_t = jint;
|
|
13
13
|
using distance_t = punned_distance_t;
|
|
14
|
-
using
|
|
14
|
+
using punned_t = punned_gt<label_t>;
|
|
15
15
|
using span_t = span_gt<float>;
|
|
16
16
|
|
|
17
17
|
JNIEXPORT jlong JNICALL Java_cloud_unum_usearch_Index_c_1create( //
|
|
@@ -39,10 +39,10 @@ JNIEXPORT jlong JNICALL Java_cloud_unum_usearch_Index_c_1create( //
|
|
|
39
39
|
std::size_t accuracy_length = (*env).GetStringUTFLength(accuracy);
|
|
40
40
|
|
|
41
41
|
accuracy_t accuracy = accuracy_from_name(accuracy_cstr, accuracy_length);
|
|
42
|
-
|
|
42
|
+
punned_t index = index_from_name<punned_t>( //
|
|
43
43
|
metric_cstr, metric_length, static_cast<std::size_t>(dimensions), accuracy, config);
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
punned_t* result_ptr = new punned_t(std::move(index));
|
|
46
46
|
std::memcpy(&result, &result_ptr, sizeof(jlong));
|
|
47
47
|
} catch (...) {
|
|
48
48
|
jclass jc = (*env).FindClass("java/lang/Error");
|
|
@@ -59,7 +59,7 @@ JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1save(JNIEnv* env, jclass
|
|
|
59
59
|
char const* path_cstr{};
|
|
60
60
|
try {
|
|
61
61
|
path_cstr = (*env).GetStringUTFChars(path, 0);
|
|
62
|
-
reinterpret_cast<
|
|
62
|
+
reinterpret_cast<punned_t*>(c_ptr)->save(path_cstr);
|
|
63
63
|
} catch (...) {
|
|
64
64
|
jclass jc = (*env).FindClass("java/lang/Error");
|
|
65
65
|
if (jc)
|
|
@@ -72,7 +72,7 @@ JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1load(JNIEnv* env, jclass
|
|
|
72
72
|
char const* path_cstr{};
|
|
73
73
|
try {
|
|
74
74
|
path_cstr = (*env).GetStringUTFChars(path, 0);
|
|
75
|
-
reinterpret_cast<
|
|
75
|
+
reinterpret_cast<punned_t*>(c_ptr)->load(path_cstr);
|
|
76
76
|
} catch (...) {
|
|
77
77
|
jclass jc = (*env).FindClass("java/lang/Error");
|
|
78
78
|
if (jc)
|
|
@@ -85,7 +85,7 @@ JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1view(JNIEnv* env, jclass
|
|
|
85
85
|
char const* path_cstr{};
|
|
86
86
|
try {
|
|
87
87
|
path_cstr = (*env).GetStringUTFChars(path, 0);
|
|
88
|
-
reinterpret_cast<
|
|
88
|
+
reinterpret_cast<punned_t*>(c_ptr)->view(path_cstr);
|
|
89
89
|
} catch (...) {
|
|
90
90
|
jclass jc = (*env).FindClass("java/lang/Error");
|
|
91
91
|
if (jc)
|
|
@@ -95,28 +95,28 @@ JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1view(JNIEnv* env, jclass
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1destroy(JNIEnv*, jclass, jlong c_ptr) {
|
|
98
|
-
delete reinterpret_cast<
|
|
98
|
+
delete reinterpret_cast<punned_t*>(c_ptr);
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
JNIEXPORT jlong JNICALL Java_cloud_unum_usearch_Index_c_1size(JNIEnv*, jclass, jlong c_ptr) {
|
|
102
|
-
return reinterpret_cast<
|
|
102
|
+
return reinterpret_cast<punned_t*>(c_ptr)->size();
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
JNIEXPORT jlong JNICALL Java_cloud_unum_usearch_Index_c_1connectivity(JNIEnv*, jclass, jlong c_ptr) {
|
|
106
|
-
return reinterpret_cast<
|
|
106
|
+
return reinterpret_cast<punned_t*>(c_ptr)->connectivity();
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
JNIEXPORT jlong JNICALL Java_cloud_unum_usearch_Index_c_1dimensions(JNIEnv*, jclass, jlong c_ptr) {
|
|
110
|
-
return reinterpret_cast<
|
|
110
|
+
return reinterpret_cast<punned_t*>(c_ptr)->dimensions();
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
JNIEXPORT jlong JNICALL Java_cloud_unum_usearch_Index_c_1capacity(JNIEnv*, jclass, jlong c_ptr) {
|
|
114
|
-
return reinterpret_cast<
|
|
114
|
+
return reinterpret_cast<punned_t*>(c_ptr)->capacity();
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1reserve(JNIEnv* env, jclass, jlong c_ptr, jlong capacity) {
|
|
118
118
|
try {
|
|
119
|
-
return reinterpret_cast<
|
|
119
|
+
return reinterpret_cast<punned_t*>(c_ptr)->reserve(static_cast<std::size_t>(capacity));
|
|
120
120
|
} catch (...) {
|
|
121
121
|
jclass jc = (*env).FindClass("java/lang/Error");
|
|
122
122
|
if (jc)
|
|
@@ -132,7 +132,7 @@ JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1add( //
|
|
|
132
132
|
vector_data = (*env).GetFloatArrayElements(vector, 0);
|
|
133
133
|
jsize vector_dims = (*env).GetArrayLength(vector);
|
|
134
134
|
span_t vector_span = span_t{vector_data, static_cast<std::size_t>(vector_dims)};
|
|
135
|
-
reinterpret_cast<
|
|
135
|
+
reinterpret_cast<punned_t*>(c_ptr)->add(label, vector_span);
|
|
136
136
|
} catch (...) {
|
|
137
137
|
jclass jc = (*env).FindClass("java/lang/Error");
|
|
138
138
|
if (jc)
|
|
@@ -159,8 +159,9 @@ JNIEXPORT jintArray JNICALL Java_cloud_unum_usearch_Index_c_1search( //
|
|
|
159
159
|
vector_data = (*env).GetFloatArrayElements(vector, 0);
|
|
160
160
|
jsize vector_dims = (*env).GetArrayLength(vector);
|
|
161
161
|
span_t vector_span = span_t{vector_data, static_cast<std::size_t>(vector_dims)};
|
|
162
|
-
found = reinterpret_cast<
|
|
163
|
-
|
|
162
|
+
found = reinterpret_cast<punned_t*>(c_ptr)
|
|
163
|
+
->search(vector_span, static_cast<std::size_t>(wanted))
|
|
164
|
+
.dump_to(matches_data, NULL);
|
|
164
165
|
(*env).SetIntArrayRegion(matches, 0, found, matches_data);
|
|
165
166
|
} catch (...) {
|
|
166
167
|
jclass jc = (*env).FindClass("java/lang/Error");
|
package/javascript/lib.cpp
CHANGED
|
@@ -15,17 +15,19 @@
|
|
|
15
15
|
#define NAPI_CPP_EXCEPTIONS
|
|
16
16
|
#endif
|
|
17
17
|
|
|
18
|
+
#include <new> // `std::bad_alloc`
|
|
19
|
+
|
|
18
20
|
#include <napi.h>
|
|
19
21
|
#include <node_api.h>
|
|
20
22
|
|
|
21
|
-
#include "
|
|
23
|
+
#include "punned.hpp"
|
|
22
24
|
|
|
23
25
|
using namespace unum::usearch;
|
|
24
26
|
using namespace unum;
|
|
25
27
|
|
|
26
28
|
using label_t = std::uint32_t;
|
|
27
29
|
using distance_t = punned_distance_t;
|
|
28
|
-
using
|
|
30
|
+
using punned_t = punned_gt<label_t>;
|
|
29
31
|
|
|
30
32
|
class Index : public Napi::ObjectWrap<Index> {
|
|
31
33
|
public:
|
|
@@ -38,10 +40,14 @@ class Index : public Napi::ObjectWrap<Index> {
|
|
|
38
40
|
Napi::Value GetCapacity(Napi::CallbackInfo const& ctx);
|
|
39
41
|
Napi::Value GetConnectivity(Napi::CallbackInfo const& ctx);
|
|
40
42
|
|
|
43
|
+
void Save(Napi::CallbackInfo const& ctx);
|
|
44
|
+
void Load(Napi::CallbackInfo const& ctx);
|
|
45
|
+
void View(Napi::CallbackInfo const& ctx);
|
|
46
|
+
|
|
41
47
|
void Add(Napi::CallbackInfo const& ctx);
|
|
42
48
|
Napi::Value Search(Napi::CallbackInfo const& ctx);
|
|
43
49
|
|
|
44
|
-
std::unique_ptr<
|
|
50
|
+
std::unique_ptr<punned_t> native_;
|
|
45
51
|
};
|
|
46
52
|
|
|
47
53
|
Napi::Object Index::Init(Napi::Env env, Napi::Object exports) {
|
|
@@ -54,6 +60,9 @@ Napi::Object Index::Init(Napi::Env env, Napi::Object exports) {
|
|
|
54
60
|
InstanceMethod("connectivity", &Index::GetConnectivity),
|
|
55
61
|
InstanceMethod("add", &Index::Add),
|
|
56
62
|
InstanceMethod("search", &Index::Search),
|
|
63
|
+
InstanceMethod("save", &Index::Save),
|
|
64
|
+
InstanceMethod("load", &Index::Load),
|
|
65
|
+
InstanceMethod("view", &Index::View),
|
|
57
66
|
});
|
|
58
67
|
|
|
59
68
|
Napi::FunctionReference* constructor = new Napi::FunctionReference();
|
|
@@ -70,7 +79,7 @@ Index::Index(Napi::CallbackInfo const& ctx) : Napi::ObjectWrap<Index>(ctx) {
|
|
|
70
79
|
int length = ctx.Length();
|
|
71
80
|
if (length == 0 || length >= 2 || !ctx[0].IsObject()) {
|
|
72
81
|
Napi::TypeError::New(
|
|
73
|
-
env, "Pass args as named objects: dimensions: uint, capacity: uint, metric: [ip, cos,
|
|
82
|
+
env, "Pass args as named objects: dimensions: uint, capacity: uint, metric: [ip, cos, l2sq, haversine]")
|
|
74
83
|
.ThrowAsJavaScriptException();
|
|
75
84
|
return;
|
|
76
85
|
}
|
|
@@ -96,7 +105,7 @@ Index::Index(Napi::CallbackInfo const& ctx) : Napi::ObjectWrap<Index>(ctx) {
|
|
|
96
105
|
else if (accuracy_str == "f8")
|
|
97
106
|
accuracy = accuracy_t::f8_k;
|
|
98
107
|
else {
|
|
99
|
-
Napi::TypeError::New(env, "Supported metrics are: [ip, cos,
|
|
108
|
+
Napi::TypeError::New(env, "Supported metrics are: [ip, cos, l2sq, haversine]")
|
|
100
109
|
.ThrowAsJavaScriptException();
|
|
101
110
|
return;
|
|
102
111
|
}
|
|
@@ -105,28 +114,28 @@ Index::Index(Napi::CallbackInfo const& ctx) : Napi::ObjectWrap<Index>(ctx) {
|
|
|
105
114
|
// By default we use the Inner Product similarity
|
|
106
115
|
if (params.Has("metric")) {
|
|
107
116
|
std::string name = params.Get("metric").As<Napi::String>().Utf8Value();
|
|
108
|
-
if (name == "
|
|
117
|
+
if (name == "l2sq" || name == "euclidean_sq") {
|
|
109
118
|
if (!dimensions) {
|
|
110
119
|
Napi::TypeError::New(env, "Please define the number of dimensions").ThrowAsJavaScriptException();
|
|
111
120
|
return;
|
|
112
121
|
}
|
|
113
|
-
native_.reset(new
|
|
122
|
+
native_.reset(new punned_t(punned_t::l2sq(dimensions, accuracy, config)));
|
|
114
123
|
} else if (name == "ip" || name == "inner" || name == "dot") {
|
|
115
124
|
if (!dimensions) {
|
|
116
125
|
Napi::TypeError::New(env, "Please define the number of dimensions").ThrowAsJavaScriptException();
|
|
117
126
|
return;
|
|
118
127
|
}
|
|
119
|
-
native_.reset(new
|
|
128
|
+
native_.reset(new punned_t(punned_t::ip(dimensions, accuracy, config)));
|
|
120
129
|
} else if (name == "cos" || name == "angular") {
|
|
121
130
|
if (!dimensions) {
|
|
122
131
|
Napi::TypeError::New(env, "Please define the number of dimensions").ThrowAsJavaScriptException();
|
|
123
132
|
return;
|
|
124
133
|
}
|
|
125
|
-
native_.reset(new
|
|
134
|
+
native_.reset(new punned_t(punned_t::cos(dimensions, accuracy, config)));
|
|
126
135
|
} else if (name == "haversine") {
|
|
127
|
-
native_.reset(new
|
|
136
|
+
native_.reset(new punned_t(punned_t::haversine(accuracy, config)));
|
|
128
137
|
} else {
|
|
129
|
-
Napi::TypeError::New(env, "Supported metrics are: [ip, cos,
|
|
138
|
+
Napi::TypeError::New(env, "Supported metrics are: [ip, cos, l2sq, haversine]")
|
|
130
139
|
.ThrowAsJavaScriptException();
|
|
131
140
|
return;
|
|
132
141
|
}
|
|
@@ -135,7 +144,7 @@ Index::Index(Napi::CallbackInfo const& ctx) : Napi::ObjectWrap<Index>(ctx) {
|
|
|
135
144
|
Napi::TypeError::New(env, "Please define the number of dimensions").ThrowAsJavaScriptException();
|
|
136
145
|
return;
|
|
137
146
|
}
|
|
138
|
-
native_.reset(new
|
|
147
|
+
native_.reset(new punned_t(punned_t::ip(dimensions, accuracy, config)));
|
|
139
148
|
}
|
|
140
149
|
}
|
|
141
150
|
|
|
@@ -150,6 +159,57 @@ Napi::Value Index::GetCapacity(Napi::CallbackInfo const& ctx) {
|
|
|
150
159
|
return Napi::Number::New(ctx.Env(), native_->capacity());
|
|
151
160
|
}
|
|
152
161
|
|
|
162
|
+
void Index::Save(Napi::CallbackInfo const& ctx) {
|
|
163
|
+
Napi::Env env = ctx.Env();
|
|
164
|
+
|
|
165
|
+
int length = ctx.Length();
|
|
166
|
+
if (length == 0 || !ctx[0].IsString()) {
|
|
167
|
+
Napi::TypeError::New(env, "Function expects a string path argument").ThrowAsJavaScriptException();
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
try {
|
|
172
|
+
std::string path = ctx[0].As<Napi::String>();
|
|
173
|
+
native_->save(path.c_str());
|
|
174
|
+
} catch (...) {
|
|
175
|
+
Napi::TypeError::New(env, "Serialization failed").ThrowAsJavaScriptException();
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
void Index::Load(Napi::CallbackInfo const& ctx) {
|
|
180
|
+
Napi::Env env = ctx.Env();
|
|
181
|
+
|
|
182
|
+
int length = ctx.Length();
|
|
183
|
+
if (length == 0 || !ctx[0].IsString()) {
|
|
184
|
+
Napi::TypeError::New(env, "Function expects a string path argument").ThrowAsJavaScriptException();
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
try {
|
|
189
|
+
std::string path = ctx[0].As<Napi::String>();
|
|
190
|
+
native_->load(path.c_str());
|
|
191
|
+
} catch (...) {
|
|
192
|
+
Napi::TypeError::New(env, "Loading failed").ThrowAsJavaScriptException();
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
void Index::View(Napi::CallbackInfo const& ctx) {
|
|
197
|
+
Napi::Env env = ctx.Env();
|
|
198
|
+
|
|
199
|
+
int length = ctx.Length();
|
|
200
|
+
if (length == 0 || !ctx[0].IsString()) {
|
|
201
|
+
Napi::TypeError::New(env, "Function expects a string path argument").ThrowAsJavaScriptException();
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
try {
|
|
206
|
+
std::string path = ctx[0].As<Napi::String>();
|
|
207
|
+
native_->view(path.c_str());
|
|
208
|
+
} catch (...) {
|
|
209
|
+
Napi::TypeError::New(env, "Memory-mapping failed").ThrowAsJavaScriptException();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
153
213
|
void Index::Add(Napi::CallbackInfo const& ctx) {
|
|
154
214
|
Napi::Env env = ctx.Env();
|
|
155
215
|
if (ctx.Length() < 2 || !ctx[0].IsNumber() || !ctx[1].IsTypedArray())
|
|
@@ -166,7 +226,14 @@ void Index::Add(Napi::CallbackInfo const& ctx) {
|
|
|
166
226
|
|
|
167
227
|
if (native_->size() + 1 >= native_->capacity())
|
|
168
228
|
native_->reserve(ceil2(native_->size() + 1));
|
|
169
|
-
|
|
229
|
+
|
|
230
|
+
try {
|
|
231
|
+
native_->add(label, vector);
|
|
232
|
+
} catch (std::bad_alloc const&) {
|
|
233
|
+
Napi::TypeError::New(env, "Out of memory").ThrowAsJavaScriptException();
|
|
234
|
+
} catch (...) {
|
|
235
|
+
Napi::TypeError::New(env, "Insertion failed").ThrowAsJavaScriptException();
|
|
236
|
+
}
|
|
170
237
|
}
|
|
171
238
|
|
|
172
239
|
Napi::Value Index::Search(Napi::CallbackInfo const& ctx) {
|
|
@@ -190,13 +257,20 @@ Napi::Value Index::Search(Napi::CallbackInfo const& ctx) {
|
|
|
190
257
|
|
|
191
258
|
Napi::Uint32Array matches_js = Napi::Uint32Array::New(env, wanted);
|
|
192
259
|
Napi::Float32Array distances_js = Napi::Float32Array::New(env, wanted);
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
260
|
+
try {
|
|
261
|
+
std::size_t count = native_->search(vector, wanted).dump_to(matches_js.Data(), distances_js.Data());
|
|
262
|
+
Napi::Object result_js = Napi::Object::New(env);
|
|
263
|
+
result_js.Set("labels", matches_js);
|
|
264
|
+
result_js.Set("distances", distances_js);
|
|
265
|
+
result_js.Set("count", Napi::Number::New(env, count));
|
|
266
|
+
return result_js;
|
|
267
|
+
} catch (std::bad_alloc const&) {
|
|
268
|
+
Napi::TypeError::New(env, "Out of memory").ThrowAsJavaScriptException();
|
|
269
|
+
return {};
|
|
270
|
+
} catch (...) {
|
|
271
|
+
Napi::TypeError::New(env, "Search failed").ThrowAsJavaScriptException();
|
|
272
|
+
return {};
|
|
273
|
+
}
|
|
200
274
|
}
|
|
201
275
|
|
|
202
276
|
Napi::Object InitAll(Napi::Env env, Napi::Object exports) { return Index::Init(env, exports); }
|
package/javascript/test.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
var assert = require('assert');
|
|
2
2
|
var usearch = require('bindings')('usearch');
|
|
3
3
|
|
|
4
|
-
var index = new usearch.Index({ metric: '
|
|
4
|
+
var index = new usearch.Index({ metric: 'l2sq', connectivity: 16, dimensions: 2 })
|
|
5
5
|
assert.equal(index.connectivity(), 16)
|
|
6
6
|
assert.equal(index.dimensions(), 2)
|
|
7
7
|
assert.equal(index.size(), 0)
|
package/objc/USearchObjective.mm
CHANGED
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
#pragma clang diagnostic push
|
|
4
4
|
#pragma clang diagnostic ignored "-Wdocumentation"
|
|
5
|
-
#import "
|
|
5
|
+
#import "punned.hpp"
|
|
6
6
|
#pragma clang diagnostic pop
|
|
7
7
|
|
|
8
8
|
using namespace unum::usearch;
|
|
9
9
|
using namespace unum;
|
|
10
10
|
|
|
11
11
|
using distance_t = punned_distance_t;
|
|
12
|
-
using
|
|
13
|
-
using shared_index_t = std::shared_ptr<
|
|
12
|
+
using punned_t = punned_gt<UInt32>;
|
|
13
|
+
using shared_index_t = std::shared_ptr<punned_t>;
|
|
14
14
|
|
|
15
15
|
@interface Index ()
|
|
16
16
|
|
|
@@ -59,91 +59,108 @@ using shared_index_t = std::shared_ptr<native_index_t>;
|
|
|
59
59
|
+ (instancetype)indexIP:(UInt32)dimensions connectivity:(UInt32)connectivity {
|
|
60
60
|
std::size_t dims = static_cast<std::size_t>(dimensions);
|
|
61
61
|
config_t config;
|
|
62
|
+
|
|
62
63
|
config.connectivity = static_cast<std::size_t>(connectivity);
|
|
63
|
-
shared_index_t ptr = std::make_shared<
|
|
64
|
+
shared_index_t ptr = std::make_shared<punned_t>(punned_t::ip(dims, accuracy_t::f32_k, config));
|
|
64
65
|
return [[Index alloc] initWithIndex:ptr];
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
+ (instancetype)
|
|
68
|
+
+ (instancetype)indexL2sq:(UInt32)dimensions connectivity:(UInt32)connectivity {
|
|
68
69
|
std::size_t dims = static_cast<std::size_t>(dimensions);
|
|
69
70
|
config_t config;
|
|
71
|
+
|
|
70
72
|
config.connectivity = static_cast<std::size_t>(connectivity);
|
|
71
|
-
shared_index_t ptr = std::make_shared<
|
|
73
|
+
shared_index_t ptr = std::make_shared<punned_t>(punned_t::l2sq(dims, accuracy_t::f32_k, config));
|
|
72
74
|
return [[Index alloc] initWithIndex:ptr];
|
|
73
75
|
}
|
|
74
76
|
|
|
75
77
|
+ (instancetype)indexHaversine:(UInt32)connectivity {
|
|
76
78
|
config_t config;
|
|
79
|
+
|
|
77
80
|
config.connectivity = static_cast<std::size_t>(connectivity);
|
|
78
|
-
shared_index_t ptr = std::make_shared<
|
|
81
|
+
shared_index_t ptr = std::make_shared<punned_t>(punned_t::haversine(accuracy_t::f32_k, config));
|
|
79
82
|
return [[Index alloc] initWithIndex:ptr];
|
|
80
83
|
}
|
|
81
84
|
|
|
82
85
|
- (void)addSingle:(UInt32)label
|
|
83
|
-
vector:(Float32 const *
|
|
86
|
+
vector:(Float32 const *_Nonnull)vector {
|
|
84
87
|
_native->add(label, vector);
|
|
85
88
|
}
|
|
86
89
|
|
|
87
|
-
- (UInt32)searchSingle:(Float32 const*
|
|
90
|
+
- (UInt32)searchSingle:(Float32 const *_Nonnull)vector
|
|
88
91
|
count:(UInt32)wanted
|
|
89
|
-
labels:(UInt32*
|
|
90
|
-
distances:(Float32*
|
|
91
|
-
std::size_t found = _native->search(vector, static_cast<std::size_t>(wanted)
|
|
92
|
+
labels:(UInt32 *_Nullable)labels
|
|
93
|
+
distances:(Float32 *_Nullable)distances {
|
|
94
|
+
std::size_t found = _native->search(vector, static_cast<std::size_t>(wanted)).dump_to(labels, distances);
|
|
95
|
+
|
|
92
96
|
return static_cast<UInt32>(found);
|
|
93
97
|
}
|
|
94
98
|
|
|
95
99
|
- (void)addPrecise:(UInt32)label
|
|
96
|
-
vector:(Float64 const *
|
|
100
|
+
vector:(Float64 const *_Nonnull)vector {
|
|
97
101
|
_native->add(label, (f64_t const *)vector);
|
|
98
102
|
}
|
|
99
103
|
|
|
100
|
-
- (UInt32)searchPrecise:(Float64 const*
|
|
104
|
+
- (UInt32)searchPrecise:(Float64 const *_Nonnull)vector
|
|
101
105
|
count:(UInt32)wanted
|
|
102
|
-
labels:(UInt32*
|
|
103
|
-
distances:(Float32*
|
|
104
|
-
std::size_t found = _native->search((f64_t const *)vector, static_cast<std::size_t>(wanted)
|
|
106
|
+
labels:(UInt32 *_Nullable)labels
|
|
107
|
+
distances:(Float32 *_Nullable)distances {
|
|
108
|
+
std::size_t found = _native->search((f64_t const *)vector, static_cast<std::size_t>(wanted)).dump_to(labels, distances);
|
|
109
|
+
|
|
105
110
|
return static_cast<UInt32>(found);
|
|
106
111
|
}
|
|
107
112
|
|
|
108
113
|
- (void)addImprecise:(UInt32)label
|
|
109
|
-
vector:(void const *
|
|
110
|
-
_native->add(label, (
|
|
114
|
+
vector:(void const *_Nonnull)vector {
|
|
115
|
+
_native->add(label, (f16_bits_t const *)vector);
|
|
111
116
|
}
|
|
112
117
|
|
|
113
|
-
- (UInt32)searchImprecise:(void const*
|
|
118
|
+
- (UInt32)searchImprecise:(void const *_Nonnull)vector
|
|
114
119
|
count:(UInt32)wanted
|
|
115
|
-
labels:(UInt32*
|
|
116
|
-
distances:(Float32*
|
|
117
|
-
std::size_t found = _native->search((
|
|
120
|
+
labels:(UInt32 *_Nullable)labels
|
|
121
|
+
distances:(Float32 *_Nullable)distances {
|
|
122
|
+
std::size_t found = _native->search((f16_bits_t const *)vector, static_cast<std::size_t>(wanted)).dump_to(labels, distances);
|
|
123
|
+
|
|
118
124
|
return static_cast<UInt32>(found);
|
|
119
125
|
}
|
|
120
126
|
|
|
121
|
-
- (void)clear {
|
|
127
|
+
- (void)clear {
|
|
128
|
+
_native->clear();
|
|
129
|
+
}
|
|
122
130
|
|
|
123
|
-
- (void)save:(NSString*)path {
|
|
131
|
+
- (void)save:(NSString *)path {
|
|
124
132
|
char const *path_c = [path UTF8String];
|
|
125
|
-
|
|
133
|
+
|
|
134
|
+
if (!path_c) {
|
|
126
135
|
@throw [NSException exceptionWithName:@"Can't save to disk"
|
|
127
136
|
reason:@"The path must be convertible to UTF8"
|
|
128
137
|
userInfo:nil];
|
|
138
|
+
}
|
|
139
|
+
|
|
129
140
|
_native->save(path_c);
|
|
130
141
|
}
|
|
131
142
|
|
|
132
|
-
- (void)load:(NSString*)path {
|
|
143
|
+
- (void)load:(NSString *)path {
|
|
133
144
|
char const *path_c = [path UTF8String];
|
|
134
|
-
|
|
145
|
+
|
|
146
|
+
if (!path_c) {
|
|
135
147
|
@throw [NSException exceptionWithName:@"Can't load from disk"
|
|
136
148
|
reason:@"The path must be convertible to UTF8"
|
|
137
149
|
userInfo:nil];
|
|
150
|
+
}
|
|
151
|
+
|
|
138
152
|
_native->load(path_c);
|
|
139
153
|
}
|
|
140
154
|
|
|
141
|
-
- (void)view:(NSString*)path {
|
|
155
|
+
- (void)view:(NSString *)path {
|
|
142
156
|
char const *path_c = [path UTF8String];
|
|
143
|
-
|
|
157
|
+
|
|
158
|
+
if (!path_c) {
|
|
144
159
|
@throw [NSException exceptionWithName:@"Can't view from disk"
|
|
145
160
|
reason:@"The path must be convertible to UTF8"
|
|
146
161
|
userInfo:nil];
|
|
162
|
+
}
|
|
163
|
+
|
|
147
164
|
_native->view(path_c);
|
|
148
165
|
}
|
|
149
166
|
|
|
@@ -11,7 +11,7 @@ typedef NS_ENUM(NSUInteger, Quantization) {
|
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0))
|
|
14
|
-
@interface Index: NSObject
|
|
14
|
+
@interface Index : NSObject
|
|
15
15
|
|
|
16
16
|
@property (readonly) UInt32 dimensions;
|
|
17
17
|
@property (readonly) UInt32 connectivity;
|
|
@@ -22,47 +22,39 @@ API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0))
|
|
|
22
22
|
@property (readonly) UInt32 capacity;
|
|
23
23
|
@property (readonly) Boolean isEmpty;
|
|
24
24
|
|
|
25
|
-
- (instancetype)init
|
|
26
|
-
NS_UNAVAILABLE;
|
|
25
|
+
- (instancetype)init NS_UNAVAILABLE;
|
|
27
26
|
|
|
28
27
|
+ (instancetype)indexIP:(UInt32)dimensions connectivity:(UInt32)connectivity NS_SWIFT_NAME(indexIP(dimensions:connectivity:));
|
|
29
|
-
+ (instancetype)
|
|
28
|
+
+ (instancetype)indexL2sq:(UInt32)dimensions connectivity:(UInt32)connectivity NS_SWIFT_NAME(l2sq(dimensions:connectivity:));
|
|
30
29
|
+ (instancetype)indexHaversine:(UInt32)connectivity NS_SWIFT_NAME(indexHaversine(connectivity:));
|
|
31
30
|
|
|
32
31
|
- (void)addSingle:(UInt32)label
|
|
33
|
-
vector:(Float32 const*
|
|
34
|
-
NS_SWIFT_NAME(addSingle(label:vector:));
|
|
32
|
+
vector:(Float32 const *_Nonnull)vector NS_SWIFT_NAME(addSingle(label:vector:));
|
|
35
33
|
|
|
36
|
-
- (UInt32)searchSingle:(Float32 const*
|
|
34
|
+
- (UInt32)searchSingle:(Float32 const *_Nonnull)vector
|
|
37
35
|
count:(UInt32)count
|
|
38
|
-
labels:(UInt32*
|
|
39
|
-
distances:(Float32*
|
|
40
|
-
NS_SWIFT_NAME(searchSingle(vector:count:labels:distances:));
|
|
36
|
+
labels:(UInt32 *_Nullable)labels
|
|
37
|
+
distances:(Float32 *_Nullable)distances NS_SWIFT_NAME(searchSingle(vector:count:labels:distances:));
|
|
41
38
|
|
|
42
39
|
- (void)addPrecise:(UInt32)label
|
|
43
|
-
vector:(Float64 const*
|
|
44
|
-
NS_SWIFT_NAME(addPrecise(label:vector:));
|
|
40
|
+
vector:(Float64 const *_Nonnull)vector NS_SWIFT_NAME(addPrecise(label:vector:));
|
|
45
41
|
|
|
46
|
-
- (UInt32)searchPrecise:(Float64 const*
|
|
42
|
+
- (UInt32)searchPrecise:(Float64 const *_Nonnull)vector
|
|
47
43
|
count:(UInt32)count
|
|
48
|
-
labels:(UInt32*
|
|
49
|
-
distances:(Float32*
|
|
50
|
-
NS_SWIFT_NAME(searchPrecise(vector:count:labels:distances:));
|
|
44
|
+
labels:(UInt32 *_Nullable)labels
|
|
45
|
+
distances:(Float32 *_Nullable)distances NS_SWIFT_NAME(searchPrecise(vector:count:labels:distances:));
|
|
51
46
|
|
|
52
47
|
- (void)addImprecise:(UInt32)label
|
|
53
|
-
vector:(void const*
|
|
54
|
-
NS_SWIFT_NAME(addImprecise(label:vector:));
|
|
48
|
+
vector:(void const *_Nonnull)vector NS_SWIFT_NAME(addImprecise(label:vector:));
|
|
55
49
|
|
|
56
|
-
- (UInt32)searchImprecise:(void const*
|
|
50
|
+
- (UInt32)searchImprecise:(void const *_Nonnull)vector
|
|
57
51
|
count:(UInt32)count
|
|
58
|
-
labels:(UInt32*
|
|
59
|
-
distances:(Float32*
|
|
60
|
-
NS_SWIFT_NAME(searchImprecise(vector:count:labels:distances:));
|
|
52
|
+
labels:(UInt32 *_Nullable)labels
|
|
53
|
+
distances:(Float32 *_Nullable)distances NS_SWIFT_NAME(searchImprecise(vector:count:labels:distances:));
|
|
61
54
|
|
|
62
|
-
|
|
63
|
-
- (void)
|
|
64
|
-
- (void)
|
|
65
|
-
- (void)view:(NSString*)path NS_SWIFT_NAME(view(path:));
|
|
55
|
+
- (void)save:(NSString *)path NS_SWIFT_NAME(dump(path:));
|
|
56
|
+
- (void)load:(NSString *)path NS_SWIFT_NAME(load(path:));
|
|
57
|
+
- (void)view:(NSString *)path NS_SWIFT_NAME(view(path:));
|
|
66
58
|
- (void)clear NS_SWIFT_NAME(clear());
|
|
67
59
|
|
|
68
60
|
@end
|
package/package.json
CHANGED
package/pyproject.toml
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
[build-system]
|
|
2
|
-
requires = ["setuptools>=42", "wheel", "cmake>=3.22", "pybind11"]
|
|
2
|
+
requires = ["setuptools>=42", "wheel", "cmake>=3.22", "pybind11", "numpy"]
|
|
3
3
|
build-backend = "setuptools.build_meta"
|
|
4
4
|
|
|
5
5
|
[tool.pytest.ini_options]
|
|
@@ -9,8 +9,9 @@ xfail_strict = true
|
|
|
9
9
|
filterwarnings = ["error"]
|
|
10
10
|
|
|
11
11
|
[tool.cibuildwheel]
|
|
12
|
+
test-requires = ["pytest", "numpy"]
|
|
13
|
+
test-command = "pytest {project}/python/test.py"
|
|
12
14
|
build-verbosity = 0
|
|
13
|
-
|
|
14
15
|
skip = ["*musllinux*", "*i686*", "pp*"]
|
|
15
16
|
|
|
16
17
|
[tool.cibuildwheel.linux]
|