usearch 0.11.1 → 0.12.1
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 +2 -5
- package/.github/workflows/release.yml +22 -2
- package/.gitignore +84 -0
- package/.vscode/launch.json +7 -1
- package/.vscode/settings.json +15 -1
- package/Cargo.toml +1 -1
- package/README.md +43 -8
- package/binding.gyp +2 -2
- package/c/lib.cpp +141 -0
- package/c/usearch.h +43 -0
- package/conanfile.py +1 -1
- package/docs/compilation.md +14 -3
- package/golang/go.mod +3 -0
- package/golang/lib.go +238 -0
- package/golang/usearch.h +9 -0
- package/golang/usearch_par_test.go +40 -0
- package/golang/usearch_test.go +82 -0
- package/include/usearch/usearch.hpp +595 -248
- package/java/cloud/unum/usearch/Index.java +1 -1
- package/java/cloud/unum/usearch/cloud_unum_usearch_Index.cpp +36 -44
- package/javascript/lib.cpp +10 -6
- package/javascript/usearch.js +3 -0
- package/objc/USearchObjective.mm +3 -3
- package/package.json +4 -3
- package/python/lib.cpp +354 -181
- package/python/scripts/bench.py +2 -2
- package/python/scripts/test.py +88 -29
- package/python/usearch/index.py +132 -57
- package/rust/lib.cpp +33 -24
- package/rust/lib.hpp +2 -2
- package/setup.py +4 -1
- package/src/CMakeLists.txt +4 -4
- package/src/bench.cpp +22 -19
- package/src/punned.hpp +108 -79
- package/src/test.cpp +77 -27
- package/wolfram/lib.cpp +7 -8
- package/Dockerfile +0 -16
- package/VERSION +0 -1
|
@@ -10,9 +10,13 @@ using namespace unum::usearch;
|
|
|
10
10
|
using namespace unum;
|
|
11
11
|
|
|
12
12
|
using label_t = jint;
|
|
13
|
+
using span_t = span_gt<float>;
|
|
13
14
|
using distance_t = punned_distance_t;
|
|
14
15
|
using punned_t = punned_gt<label_t>;
|
|
15
|
-
|
|
16
|
+
|
|
17
|
+
using add_result_t = typename punned_t::add_result_t;
|
|
18
|
+
using search_result_t = typename punned_t::search_result_t;
|
|
19
|
+
using serialization_result_t = typename punned_t::serialization_result_t;
|
|
16
20
|
|
|
17
21
|
JNIEXPORT jlong JNICALL Java_cloud_unum_usearch_Index_c_1create( //
|
|
18
22
|
JNIEnv* env, jclass, //
|
|
@@ -25,13 +29,10 @@ JNIEXPORT jlong JNICALL Java_cloud_unum_usearch_Index_c_1create( //
|
|
|
25
29
|
char const* accuracy_cstr{};
|
|
26
30
|
try {
|
|
27
31
|
|
|
28
|
-
|
|
32
|
+
index_config_t config;
|
|
29
33
|
config.expansion_add = static_cast<std::size_t>(expansion_add);
|
|
30
34
|
config.expansion_search = static_cast<std::size_t>(expansion_search);
|
|
31
35
|
config.connectivity = static_cast<std::size_t>(connectivity);
|
|
32
|
-
config.max_elements = static_cast<std::size_t>(capacity);
|
|
33
|
-
config.max_threads_add = std::thread::hardware_concurrency();
|
|
34
|
-
config.max_threads_search = std::thread::hardware_concurrency();
|
|
35
36
|
|
|
36
37
|
metric_cstr = (*env).GetStringUTFChars(metric, 0);
|
|
37
38
|
std::size_t metric_length = (*env).GetStringUTFLength(metric);
|
|
@@ -39,11 +40,17 @@ JNIEXPORT jlong JNICALL Java_cloud_unum_usearch_Index_c_1create( //
|
|
|
39
40
|
std::size_t accuracy_length = (*env).GetStringUTFLength(accuracy);
|
|
40
41
|
|
|
41
42
|
accuracy_t accuracy = accuracy_from_name(accuracy_cstr, accuracy_length);
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
common_metric_kind_t metric_kind = common_metric_from_name(metric_cstr, metric_length);
|
|
44
|
+
punned_t index = make_punned<punned_t>(metric_kind, static_cast<std::size_t>(dimensions), accuracy, config);
|
|
45
|
+
if (!index.reserve(static_cast<std::size_t>(capacity))) {
|
|
46
|
+
jclass jc = (*env).FindClass("java/lang/Error");
|
|
47
|
+
if (jc)
|
|
48
|
+
(*env).ThrowNew(jc, "Failed to reserve desired capacity!");
|
|
49
|
+
} else {
|
|
50
|
+
punned_t* result_ptr = new punned_t(std::move(index));
|
|
51
|
+
std::memcpy(&result, &result_ptr, sizeof(jlong));
|
|
52
|
+
}
|
|
44
53
|
|
|
45
|
-
punned_t* result_ptr = new punned_t(std::move(index));
|
|
46
|
-
std::memcpy(&result, &result_ptr, sizeof(jlong));
|
|
47
54
|
} catch (...) {
|
|
48
55
|
jclass jc = (*env).FindClass("java/lang/Error");
|
|
49
56
|
if (jc)
|
|
@@ -56,11 +63,8 @@ JNIEXPORT jlong JNICALL Java_cloud_unum_usearch_Index_c_1create( //
|
|
|
56
63
|
}
|
|
57
64
|
|
|
58
65
|
JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1save(JNIEnv* env, jclass, jlong c_ptr, jstring path) {
|
|
59
|
-
char const* path_cstr
|
|
60
|
-
|
|
61
|
-
path_cstr = (*env).GetStringUTFChars(path, 0);
|
|
62
|
-
reinterpret_cast<punned_t*>(c_ptr)->save(path_cstr);
|
|
63
|
-
} catch (...) {
|
|
66
|
+
char const* path_cstr = (*env).GetStringUTFChars(path, 0);
|
|
67
|
+
if (!reinterpret_cast<punned_t*>(c_ptr)->save(path_cstr)) {
|
|
64
68
|
jclass jc = (*env).FindClass("java/lang/Error");
|
|
65
69
|
if (jc)
|
|
66
70
|
(*env).ThrowNew(jc, "Failed to dump vector index to path!");
|
|
@@ -69,11 +73,8 @@ JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1save(JNIEnv* env, jclass
|
|
|
69
73
|
}
|
|
70
74
|
|
|
71
75
|
JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1load(JNIEnv* env, jclass, jlong c_ptr, jstring path) {
|
|
72
|
-
char const* path_cstr
|
|
73
|
-
|
|
74
|
-
path_cstr = (*env).GetStringUTFChars(path, 0);
|
|
75
|
-
reinterpret_cast<punned_t*>(c_ptr)->load(path_cstr);
|
|
76
|
-
} catch (...) {
|
|
76
|
+
char const* path_cstr = (*env).GetStringUTFChars(path, 0);
|
|
77
|
+
if (!reinterpret_cast<punned_t*>(c_ptr)->load(path_cstr)) {
|
|
77
78
|
jclass jc = (*env).FindClass("java/lang/Error");
|
|
78
79
|
if (jc)
|
|
79
80
|
(*env).ThrowNew(jc, "Failed to load vector index from path!");
|
|
@@ -82,11 +83,8 @@ JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1load(JNIEnv* env, jclass
|
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1view(JNIEnv* env, jclass, jlong c_ptr, jstring path) {
|
|
85
|
-
char const* path_cstr
|
|
86
|
-
|
|
87
|
-
path_cstr = (*env).GetStringUTFChars(path, 0);
|
|
88
|
-
reinterpret_cast<punned_t*>(c_ptr)->view(path_cstr);
|
|
89
|
-
} catch (...) {
|
|
86
|
+
char const* path_cstr = (*env).GetStringUTFChars(path, 0);
|
|
87
|
+
if (!reinterpret_cast<punned_t*>(c_ptr)->view(path_cstr)) {
|
|
90
88
|
jclass jc = (*env).FindClass("java/lang/Error");
|
|
91
89
|
if (jc)
|
|
92
90
|
(*env).ThrowNew(jc, "Failed to view vector index from path!");
|
|
@@ -115,9 +113,7 @@ JNIEXPORT jlong JNICALL Java_cloud_unum_usearch_Index_c_1capacity(JNIEnv*, jclas
|
|
|
115
113
|
}
|
|
116
114
|
|
|
117
115
|
JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1reserve(JNIEnv* env, jclass, jlong c_ptr, jlong capacity) {
|
|
118
|
-
|
|
119
|
-
return reinterpret_cast<punned_t*>(c_ptr)->reserve(static_cast<std::size_t>(capacity));
|
|
120
|
-
} catch (...) {
|
|
116
|
+
if (!reinterpret_cast<punned_t*>(c_ptr)->reserve(static_cast<std::size_t>(capacity))) {
|
|
121
117
|
jclass jc = (*env).FindClass("java/lang/Error");
|
|
122
118
|
if (jc)
|
|
123
119
|
(*env).ThrowNew(jc, "Failed to grow vector index!");
|
|
@@ -127,13 +123,11 @@ JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1reserve(JNIEnv* env, jcl
|
|
|
127
123
|
JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1add( //
|
|
128
124
|
JNIEnv* env, jclass, jlong c_ptr, jint label, jfloatArray vector) {
|
|
129
125
|
|
|
130
|
-
jfloat* vector_data
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
reinterpret_cast<punned_t*>(c_ptr)->add(label, vector_span);
|
|
136
|
-
} catch (...) {
|
|
126
|
+
jfloat* vector_data = (*env).GetFloatArrayElements(vector, 0);
|
|
127
|
+
jsize vector_dims = (*env).GetArrayLength(vector);
|
|
128
|
+
span_t vector_span = span_t{vector_data, static_cast<std::size_t>(vector_dims)};
|
|
129
|
+
|
|
130
|
+
if (!reinterpret_cast<punned_t*>(c_ptr)->add(label, vector_span)) {
|
|
137
131
|
jclass jc = (*env).FindClass("java/lang/Error");
|
|
138
132
|
if (jc)
|
|
139
133
|
(*env).ThrowNew(jc, "Failed to insert a new point in vector index!");
|
|
@@ -153,21 +147,19 @@ JNIEXPORT jintArray JNICALL Java_cloud_unum_usearch_Index_c_1search( //
|
|
|
153
147
|
if (matches_data == NULL)
|
|
154
148
|
return NULL;
|
|
155
149
|
|
|
156
|
-
jfloat* vector_data
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
found = reinterpret_cast<punned_t*>(c_ptr)
|
|
163
|
-
->search(vector_span, static_cast<std::size_t>(wanted))
|
|
164
|
-
.dump_to(matches_data, NULL);
|
|
150
|
+
jfloat* vector_data = (*env).GetFloatArrayElements(vector, 0);
|
|
151
|
+
jsize vector_dims = (*env).GetArrayLength(vector);
|
|
152
|
+
span_t vector_span = span_t{vector_data, static_cast<std::size_t>(vector_dims)};
|
|
153
|
+
search_result_t result = reinterpret_cast<punned_t*>(c_ptr)->search(vector_span, static_cast<std::size_t>(wanted));
|
|
154
|
+
if (result) {
|
|
155
|
+
std::size_t found = result.dump_to(matches_data, NULL);
|
|
165
156
|
(*env).SetIntArrayRegion(matches, 0, found, matches_data);
|
|
166
|
-
}
|
|
157
|
+
} else {
|
|
167
158
|
jclass jc = (*env).FindClass("java/lang/Error");
|
|
168
159
|
if (jc)
|
|
169
160
|
(*env).ThrowNew(jc, "Failed to find in vector index!");
|
|
170
161
|
}
|
|
162
|
+
|
|
171
163
|
(*env).ReleaseFloatArrayElements(vector, vector_data, 0);
|
|
172
164
|
std::free(matches_data);
|
|
173
165
|
return matches;
|
package/javascript/lib.cpp
CHANGED
|
@@ -87,9 +87,10 @@ Index::Index(Napi::CallbackInfo const& ctx) : Napi::ObjectWrap<Index>(ctx) {
|
|
|
87
87
|
Napi::Object params = ctx[0].As<Napi::Object>();
|
|
88
88
|
std::size_t dimensions = params.Has("dimensions") ? params.Get("dimensions").As<Napi::Number>().Uint32Value() : 0;
|
|
89
89
|
|
|
90
|
-
|
|
90
|
+
index_config_t config;
|
|
91
|
+
index_limits_t limits;
|
|
91
92
|
if (params.Has("capacity"))
|
|
92
|
-
|
|
93
|
+
limits.elements = params.Get("capacity").As<Napi::Number>().Uint32Value();
|
|
93
94
|
if (params.Has("connectivity"))
|
|
94
95
|
config.connectivity = params.Get("connectivity").As<Napi::Number>().Uint32Value();
|
|
95
96
|
|
|
@@ -105,8 +106,7 @@ Index::Index(Napi::CallbackInfo const& ctx) : Napi::ObjectWrap<Index>(ctx) {
|
|
|
105
106
|
else if (accuracy_str == "f8")
|
|
106
107
|
accuracy = accuracy_t::f8_k;
|
|
107
108
|
else {
|
|
108
|
-
Napi::TypeError::New(env, "Supported metrics are: [ip, cos, l2sq, haversine]")
|
|
109
|
-
.ThrowAsJavaScriptException();
|
|
109
|
+
Napi::TypeError::New(env, "Supported metrics are: [ip, cos, l2sq, haversine]").ThrowAsJavaScriptException();
|
|
110
110
|
return;
|
|
111
111
|
}
|
|
112
112
|
}
|
|
@@ -120,23 +120,26 @@ Index::Index(Napi::CallbackInfo const& ctx) : Napi::ObjectWrap<Index>(ctx) {
|
|
|
120
120
|
return;
|
|
121
121
|
}
|
|
122
122
|
native_.reset(new punned_t(punned_t::l2sq(dimensions, accuracy, config)));
|
|
123
|
+
native_->reserve(limits);
|
|
123
124
|
} else if (name == "ip" || name == "inner" || name == "dot") {
|
|
124
125
|
if (!dimensions) {
|
|
125
126
|
Napi::TypeError::New(env, "Please define the number of dimensions").ThrowAsJavaScriptException();
|
|
126
127
|
return;
|
|
127
128
|
}
|
|
128
129
|
native_.reset(new punned_t(punned_t::ip(dimensions, accuracy, config)));
|
|
130
|
+
native_->reserve(limits);
|
|
129
131
|
} else if (name == "cos" || name == "angular") {
|
|
130
132
|
if (!dimensions) {
|
|
131
133
|
Napi::TypeError::New(env, "Please define the number of dimensions").ThrowAsJavaScriptException();
|
|
132
134
|
return;
|
|
133
135
|
}
|
|
134
136
|
native_.reset(new punned_t(punned_t::cos(dimensions, accuracy, config)));
|
|
137
|
+
native_->reserve(limits);
|
|
135
138
|
} else if (name == "haversine") {
|
|
136
139
|
native_.reset(new punned_t(punned_t::haversine(accuracy, config)));
|
|
140
|
+
native_->reserve(limits);
|
|
137
141
|
} else {
|
|
138
|
-
Napi::TypeError::New(env, "Supported metrics are: [ip, cos, l2sq, haversine]")
|
|
139
|
-
.ThrowAsJavaScriptException();
|
|
142
|
+
Napi::TypeError::New(env, "Supported metrics are: [ip, cos, l2sq, haversine]").ThrowAsJavaScriptException();
|
|
140
143
|
return;
|
|
141
144
|
}
|
|
142
145
|
} else {
|
|
@@ -145,6 +148,7 @@ Index::Index(Napi::CallbackInfo const& ctx) : Napi::ObjectWrap<Index>(ctx) {
|
|
|
145
148
|
return;
|
|
146
149
|
}
|
|
147
150
|
native_.reset(new punned_t(punned_t::ip(dimensions, accuracy, config)));
|
|
151
|
+
native_->reserve(limits);
|
|
148
152
|
}
|
|
149
153
|
}
|
|
150
154
|
|
package/objc/USearchObjective.mm
CHANGED
|
@@ -58,7 +58,7 @@ using shared_index_t = std::shared_ptr<punned_t>;
|
|
|
58
58
|
|
|
59
59
|
+ (instancetype)indexIP:(UInt32)dimensions connectivity:(UInt32)connectivity {
|
|
60
60
|
std::size_t dims = static_cast<std::size_t>(dimensions);
|
|
61
|
-
|
|
61
|
+
index_config_t config;
|
|
62
62
|
|
|
63
63
|
config.connectivity = static_cast<std::size_t>(connectivity);
|
|
64
64
|
shared_index_t ptr = std::make_shared<punned_t>(punned_t::ip(dims, accuracy_t::f32_k, config));
|
|
@@ -67,7 +67,7 @@ using shared_index_t = std::shared_ptr<punned_t>;
|
|
|
67
67
|
|
|
68
68
|
+ (instancetype)indexL2sq:(UInt32)dimensions connectivity:(UInt32)connectivity {
|
|
69
69
|
std::size_t dims = static_cast<std::size_t>(dimensions);
|
|
70
|
-
|
|
70
|
+
index_config_t config;
|
|
71
71
|
|
|
72
72
|
config.connectivity = static_cast<std::size_t>(connectivity);
|
|
73
73
|
shared_index_t ptr = std::make_shared<punned_t>(punned_t::l2sq(dims, accuracy_t::f32_k, config));
|
|
@@ -75,7 +75,7 @@ using shared_index_t = std::shared_ptr<punned_t>;
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
+ (instancetype)indexHaversine:(UInt32)connectivity {
|
|
78
|
-
|
|
78
|
+
index_config_t config;
|
|
79
79
|
|
|
80
80
|
config.connectivity = static_cast<std::size_t>(connectivity);
|
|
81
81
|
shared_index_t ptr = std::make_shared<punned_t>(punned_t::haversine(accuracy_t::f32_k, config));
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "usearch",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.1",
|
|
4
4
|
"description": "Smaller & Faster Single-File Vector Search Engine from Unum",
|
|
5
5
|
"author": "Ashot Vardanian",
|
|
6
6
|
"license": "Apache 2.0",
|
|
7
|
+
"main": "javascript/usearch.js",
|
|
7
8
|
"repository": {
|
|
8
9
|
"type": "git",
|
|
9
10
|
"url": "https://github.com/unum-cloud/usearch.git"
|
|
@@ -23,6 +24,6 @@
|
|
|
23
24
|
"@semantic-release/exec": "^6.0.3",
|
|
24
25
|
"@semantic-release/git": "^10.0.1",
|
|
25
26
|
"conventional-changelog-eslint": "^3.0.9",
|
|
26
|
-
"semantic-release": "^21.0.
|
|
27
|
+
"semantic-release": "^21.0.3"
|
|
27
28
|
}
|
|
28
|
-
}
|
|
29
|
+
}
|