usearch 2.9.2 → 2.10.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.
Files changed (172) hide show
  1. package/README.md +39 -38
  2. package/javascript/{types → dist/cjs}/usearch.d.ts +90 -115
  3. package/javascript/dist/cjs/usearch.js +531 -0
  4. package/javascript/dist/esm/usearch.d.ts +212 -0
  5. package/javascript/{usearch.js → dist/esm/usearch.js} +199 -153
  6. package/package.json +25 -23
  7. package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
  8. package/prebuilds/linux-arm64/usearch.node +0 -0
  9. package/prebuilds/linux-x64/usearch.node +0 -0
  10. package/prebuilds/win32-ia32/usearch.node +0 -0
  11. package/prebuilds/win32-x64/usearch.node +0 -0
  12. package/.clang-format +0 -10
  13. package/.clang-tidy +0 -60
  14. package/.cmake-format.py +0 -19
  15. package/.dockerignore +0 -93
  16. package/.gitattributes +0 -9
  17. package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -90
  18. package/.github/ISSUE_TEMPLATE/config.yml +0 -5
  19. package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -64
  20. package/.github/workflows/Dockerfile.libs +0 -36
  21. package/.github/workflows/prerelease.yml +0 -331
  22. package/.github/workflows/release.yml +0 -722
  23. package/.github/workflows/update_version.sh +0 -15
  24. package/.gitmodules +0 -9
  25. package/.releaserc +0 -90
  26. package/CITATION.cff +0 -11
  27. package/CMakeLists.txt +0 -324
  28. package/CODE_OF_CONDUCT.md +0 -128
  29. package/CONTRIBUTING.md +0 -361
  30. package/Cargo.toml +0 -19
  31. package/Dockerfile +0 -16
  32. package/VERSION +0 -1
  33. package/assets/unum.png +0 -0
  34. package/assets/usearch-approaches-transparent.png +0 -0
  35. package/assets/usearch-approaches-white.png +0 -0
  36. package/assets/usearch-neighbor-types.png +0 -0
  37. package/binding.gyp +0 -87
  38. package/build.gradle +0 -204
  39. package/build.rs +0 -18
  40. package/c/CMakeLists.txt +0 -25
  41. package/c/README.md +0 -34
  42. package/c/lib.cpp +0 -358
  43. package/c/test.c +0 -382
  44. package/c/usearch.h +0 -311
  45. package/cmake/clipp.cmake +0 -7
  46. package/cmake/config.cmake.in +0 -15
  47. package/cmake/emscripten.cmake +0 -8
  48. package/cmake/jemalloc.cmake +0 -62
  49. package/cmake/pkg-config.pc.in +0 -4
  50. package/cmake/usearchConfigVersion.cmake.in +0 -20
  51. package/conanfile.py +0 -26
  52. package/cpp/CMakeLists.txt +0 -14
  53. package/cpp/README.md +0 -161
  54. package/cpp/bench.cpp +0 -618
  55. package/cpp/test.cpp +0 -323
  56. package/fp16/CMakeLists.txt +0 -176
  57. package/fp16/LICENSE +0 -11
  58. package/fp16/README.md +0 -20
  59. package/fp16/bench/alt-element.cc +0 -89
  60. package/fp16/bench/from-alt-array.cc +0 -175
  61. package/fp16/bench/from-ieee-array.cc +0 -399
  62. package/fp16/bench/ieee-element.cc +0 -272
  63. package/fp16/bench/to-alt-array.cc +0 -91
  64. package/fp16/bench/to-ieee-array.cc +0 -303
  65. package/fp16/cmake/DownloadGoogleBenchmark.cmake +0 -15
  66. package/fp16/cmake/DownloadGoogleTest.cmake +0 -15
  67. package/fp16/cmake/DownloadPSimd.cmake +0 -15
  68. package/fp16/configure.py +0 -65
  69. package/fp16/confu.yaml +0 -8
  70. package/fp16/include/fp16/__init__.py +0 -0
  71. package/fp16/include/fp16/avx.py +0 -50
  72. package/fp16/include/fp16/avx2.py +0 -53
  73. package/fp16/include/fp16/bitcasts.h +0 -92
  74. package/fp16/include/fp16/fp16.h +0 -451
  75. package/fp16/include/fp16/psimd.h +0 -131
  76. package/fp16/include/fp16.h +0 -11
  77. package/fp16/jni/Android.mk +0 -6
  78. package/fp16/jni/Application.mk +0 -4
  79. package/fp16/test/alt-from-fp32-value.cc +0 -498
  80. package/fp16/test/alt-to-fp32-bits.cc +0 -263
  81. package/fp16/test/alt-to-fp32-psimd.cc +0 -145
  82. package/fp16/test/alt-to-fp32-value.cc +0 -348
  83. package/fp16/test/alt-to-fp32x2-psimd.cc +0 -245
  84. package/fp16/test/bitcasts.cc +0 -56
  85. package/fp16/test/ieee-from-fp32-value.cc +0 -523
  86. package/fp16/test/ieee-to-fp32-bits.cc +0 -333
  87. package/fp16/test/ieee-to-fp32-psimd.cc +0 -312
  88. package/fp16/test/ieee-to-fp32-value.cc +0 -420
  89. package/fp16/test/ieee-to-fp32x2-psimd.cc +0 -541
  90. package/fp16/test/peachpy/alt-xmm-to-fp32-xmm-avx.cc +0 -96
  91. package/fp16/test/peachpy/alt-xmm-to-fp32-ymm-avx2.cc +0 -96
  92. package/fp16/test/peachpy/stubs.py +0 -38
  93. package/fp16/test/tables.cc +0 -530
  94. package/fp16/test/tables.h +0 -13
  95. package/fp16/third-party/THHalf.h +0 -92
  96. package/fp16/third-party/eigen-half.h +0 -170
  97. package/fp16/third-party/float16-compressor.h +0 -80
  98. package/fp16/third-party/half.hpp +0 -2916
  99. package/fp16/third-party/npy-halffloat.h +0 -328
  100. package/include/usearch/index.hpp +0 -3836
  101. package/include/usearch/index_dense.hpp +0 -2004
  102. package/include/usearch/index_plugins.hpp +0 -2213
  103. package/javascript/lib.cpp +0 -341
  104. package/javascript/types/usearch.d.ts.map +0 -1
  105. package/javascript/usearch.test.js +0 -74
  106. package/package-ci.json +0 -10
  107. package/pyproject.toml +0 -51
  108. package/setup.py +0 -201
  109. package/simsimd/.releaserc +0 -86
  110. package/simsimd/CONTRIBUTING.md +0 -88
  111. package/simsimd/Cargo.lock +0 -709
  112. package/simsimd/Cargo.toml +0 -44
  113. package/simsimd/LICENSE +0 -201
  114. package/simsimd/README.md +0 -317
  115. package/simsimd/binding.gyp +0 -36
  116. package/simsimd/build.rs +0 -20
  117. package/simsimd/include/simsimd/binary.h +0 -245
  118. package/simsimd/include/simsimd/complex.h +0 -174
  119. package/simsimd/include/simsimd/probability.h +0 -548
  120. package/simsimd/include/simsimd/simsimd.h +0 -465
  121. package/simsimd/include/simsimd/spatial.h +0 -1267
  122. package/simsimd/include/simsimd/types.h +0 -208
  123. package/simsimd/javascript/bench.js +0 -127
  124. package/simsimd/javascript/fallback.ts +0 -193
  125. package/simsimd/javascript/lib.c +0 -102
  126. package/simsimd/javascript/node-gyp-build.d.ts +0 -1
  127. package/simsimd/javascript/simsimd.ts +0 -124
  128. package/simsimd/javascript/test.mjs +0 -153
  129. package/simsimd/javascript/tsconfig-base.json +0 -25
  130. package/simsimd/javascript/tsconfig-cjs.json +0 -8
  131. package/simsimd/javascript/tsconfig-esm.json +0 -8
  132. package/simsimd/package-lock.json +0 -1688
  133. package/simsimd/package.json +0 -61
  134. package/simsimd/rust/benches/cosine.rs +0 -27
  135. package/simsimd/rust/benches/native.rs +0 -30
  136. package/simsimd/rust/benches/sqeuclidean.rs +0 -27
  137. package/simsimd/rust/lib.c +0 -45
  138. package/simsimd/rust/lib.rs +0 -550
  139. package/sqlite/README.md +0 -178
  140. package/sqlite/lib.cpp +0 -325
  141. package/stringzilla/CONTRIBUTING.md +0 -446
  142. package/stringzilla/Cargo.lock +0 -25
  143. package/stringzilla/Cargo.toml +0 -26
  144. package/stringzilla/LICENSE +0 -201
  145. package/stringzilla/README.md +0 -1422
  146. package/stringzilla/VERSION +0 -1
  147. package/stringzilla/assets/cover-strinzilla.jpeg +0 -0
  148. package/stringzilla/assets/meme-stringzilla-v2.jpeg +0 -0
  149. package/stringzilla/assets/meme-stringzilla-v3.jpeg +0 -0
  150. package/stringzilla/binding.gyp +0 -16
  151. package/stringzilla/build.rs +0 -87
  152. package/stringzilla/c/lib.c +0 -337
  153. package/stringzilla/cli/README.md +0 -65
  154. package/stringzilla/cli/__init__.py +0 -0
  155. package/stringzilla/cli/split.py +0 -105
  156. package/stringzilla/cli/wc.py +0 -117
  157. package/stringzilla/include/stringzilla/experimental.h +0 -845
  158. package/stringzilla/include/stringzilla/module.modulemap +0 -9
  159. package/stringzilla/include/stringzilla/stringzilla.h +0 -5370
  160. package/stringzilla/include/stringzilla/stringzilla.hpp +0 -3838
  161. package/stringzilla/javascript/lib.c +0 -125
  162. package/stringzilla/javascript/stringzilla.js +0 -22
  163. package/stringzilla/package-ci.json +0 -10
  164. package/stringzilla/package.json +0 -32
  165. package/stringzilla/rust/lib.rs +0 -873
  166. package/stringzilla/swift/StringProtocol+StringZilla.swift +0 -280
  167. package/stringzilla/swift/Test.swift +0 -60
  168. package/tsconfig.json +0 -21
  169. package/wasmer.toml +0 -12
  170. package/winlibinstaller.bat +0 -42
  171. /package/{simsimd/javascript/dist-package-cjs.json → javascript/dist/cjs/package.json} +0 -0
  172. /package/{simsimd/javascript/dist-package-esm.json → javascript/dist/esm/package.json} +0 -0
@@ -1,341 +0,0 @@
1
- /**
2
- * @file javascript.cpp
3
- * @author Ash Vardanian
4
- * @brief JavaScript bindings for Unum USearch.
5
- * @date 2023-04-26
6
- *
7
- * @copyright Copyright (c) 2023
8
- *
9
- * @see NodeJS docs: https://nodejs.org/api/addons.html#hello-world
10
- *
11
- */
12
- #include <new> // `std::bad_alloc`
13
-
14
- #define NAPI_CPP_EXCEPTIONS
15
- #include <napi.h>
16
- #include <node_api.h>
17
-
18
- #include <usearch/index_dense.hpp>
19
-
20
- using namespace unum::usearch;
21
- using namespace unum;
22
-
23
- class CompiledIndex : public Napi::ObjectWrap<CompiledIndex> {
24
- public:
25
- static Napi::Object Init(Napi::Env env, Napi::Object exports);
26
- CompiledIndex(Napi::CallbackInfo const& ctx);
27
-
28
- private:
29
- Napi::Value GetDimensions(Napi::CallbackInfo const& ctx);
30
- Napi::Value GetSize(Napi::CallbackInfo const& ctx);
31
- Napi::Value GetCapacity(Napi::CallbackInfo const& ctx);
32
- Napi::Value GetConnectivity(Napi::CallbackInfo const& ctx);
33
-
34
- void Save(Napi::CallbackInfo const& ctx);
35
- void Load(Napi::CallbackInfo const& ctx);
36
- void View(Napi::CallbackInfo const& ctx);
37
-
38
- void Add(Napi::CallbackInfo const& ctx);
39
- Napi::Value Search(Napi::CallbackInfo const& ctx);
40
- Napi::Value Remove(Napi::CallbackInfo const& ctx);
41
- Napi::Value Contains(Napi::CallbackInfo const& ctx);
42
- Napi::Value Count(Napi::CallbackInfo const& ctx);
43
-
44
- std::unique_ptr<index_dense_t> native_;
45
- };
46
-
47
- Napi::Object CompiledIndex::Init(Napi::Env env, Napi::Object exports) {
48
- Napi::Function func = DefineClass( //
49
- env, "CompiledIndex",
50
- {
51
- InstanceMethod("dimensions", &CompiledIndex::GetDimensions),
52
- InstanceMethod("size", &CompiledIndex::GetSize),
53
- InstanceMethod("capacity", &CompiledIndex::GetCapacity),
54
- InstanceMethod("connectivity", &CompiledIndex::GetConnectivity),
55
- InstanceMethod("add", &CompiledIndex::Add),
56
- InstanceMethod("search", &CompiledIndex::Search),
57
- InstanceMethod("remove", &CompiledIndex::Remove),
58
- InstanceMethod("contains", &CompiledIndex::Contains),
59
- InstanceMethod("count", &CompiledIndex::Count),
60
- InstanceMethod("save", &CompiledIndex::Save),
61
- InstanceMethod("load", &CompiledIndex::Load),
62
- InstanceMethod("view", &CompiledIndex::View),
63
- });
64
-
65
- Napi::FunctionReference* constructor = new Napi::FunctionReference();
66
- *constructor = Napi::Persistent(func);
67
- env.SetInstanceData(constructor);
68
-
69
- exports.Set("CompiledIndex", func);
70
- return exports;
71
- }
72
-
73
- std::size_t napi_argument_to_size(Napi::Value v) {
74
- return static_cast<std::size_t>(v.As<Napi::Number>().DoubleValue());
75
- }
76
-
77
- CompiledIndex::CompiledIndex(Napi::CallbackInfo const& ctx) : Napi::ObjectWrap<CompiledIndex>(ctx) {
78
-
79
- // Directly assign the parameters without checks
80
- std::size_t dimensions = napi_argument_to_size(ctx[0]);
81
- metric_kind_t metric_kind = metric_from_name(ctx[1].As<Napi::String>().Utf8Value().c_str());
82
- scalar_kind_t quantization = scalar_kind_from_name(ctx[2].As<Napi::String>().Utf8Value().c_str());
83
- std::size_t connectivity = napi_argument_to_size(ctx[3]);
84
- std::size_t expansion_add = napi_argument_to_size(ctx[4]);
85
- std::size_t expansion_search = napi_argument_to_size(ctx[5]);
86
- bool multi = ctx[6].As<Napi::Boolean>().Value();
87
-
88
- metric_punned_t metric(dimensions, metric_kind, quantization);
89
- index_dense_config_t config(connectivity, expansion_add, expansion_search);
90
- config.multi = multi;
91
-
92
- native_.reset(new index_dense_t(index_dense_t::make(metric, config)));
93
- if (!native_)
94
- Napi::Error::New(ctx.Env(), "Out of memory!").ThrowAsJavaScriptException();
95
- }
96
-
97
- Napi::Value CompiledIndex::GetDimensions(Napi::CallbackInfo const& ctx) {
98
- return Napi::Number::New(ctx.Env(), static_cast<std::uint64_t>(native_->dimensions()));
99
- }
100
- Napi::Value CompiledIndex::GetConnectivity(Napi::CallbackInfo const& ctx) {
101
- return Napi::Number::New(ctx.Env(), static_cast<std::uint64_t>(native_->connectivity()));
102
- }
103
- Napi::Value CompiledIndex::GetSize(Napi::CallbackInfo const& ctx) {
104
- return Napi::Number::New(ctx.Env(), static_cast<std::uint64_t>(native_->size()));
105
- }
106
- Napi::Value CompiledIndex::GetCapacity(Napi::CallbackInfo const& ctx) {
107
- return Napi::Number::New(ctx.Env(), static_cast<std::uint64_t>(native_->capacity()));
108
- }
109
-
110
- void CompiledIndex::Save(Napi::CallbackInfo const& ctx) {
111
- try {
112
- std::string path = ctx[0].As<Napi::String>();
113
- auto result = native_->save(path.c_str());
114
- if (!result)
115
- Napi::TypeError::New(ctx.Env(), result.error.release()).ThrowAsJavaScriptException();
116
-
117
- } catch (...) {
118
- Napi::TypeError::New(ctx.Env(), "Serialization failed").ThrowAsJavaScriptException();
119
- }
120
- }
121
-
122
- void CompiledIndex::Load(Napi::CallbackInfo const& ctx) {
123
- try {
124
- std::string path = ctx[0].As<Napi::String>();
125
- auto result = native_->load(path.c_str());
126
- if (!result)
127
- Napi::TypeError::New(ctx.Env(), result.error.release()).ThrowAsJavaScriptException();
128
-
129
- } catch (...) {
130
- Napi::TypeError::New(ctx.Env(), "Loading failed").ThrowAsJavaScriptException();
131
- }
132
- }
133
-
134
- void CompiledIndex::View(Napi::CallbackInfo const& ctx) {
135
-
136
- try {
137
- std::string path = ctx[0].As<Napi::String>();
138
- auto result = native_->view(path.c_str());
139
- if (!result)
140
- Napi::TypeError::New(ctx.Env(), result.error.release()).ThrowAsJavaScriptException();
141
-
142
- } catch (...) {
143
- Napi::TypeError::New(ctx.Env(), "Memory-mapping failed").ThrowAsJavaScriptException();
144
- }
145
- }
146
-
147
- void CompiledIndex::Add(Napi::CallbackInfo const& ctx) {
148
- // Extract keys and vectors from arguments
149
- Napi::BigUint64Array keys = ctx[0].As<Napi::BigUint64Array>();
150
- std::size_t tasks = keys.ElementLength();
151
-
152
- // Ensure there is enough capacity
153
- if (native_->size() + tasks >= native_->capacity())
154
- native_->reserve(ceil2(native_->size() + tasks));
155
-
156
- // Create an instance of the executor with the default number of threads
157
- auto run_parallel = [&](auto vectors) {
158
- executor_stl_t executor;
159
- executor.fixed(tasks, [&](std::size_t /*thread_idx*/, std::size_t task_idx) {
160
- native_->add(static_cast<default_key_t>(keys[task_idx]), vectors + task_idx * native_->dimensions());
161
- });
162
- };
163
-
164
- Napi::TypedArray vectors = ctx[1].As<Napi::TypedArray>();
165
- if (vectors.TypedArrayType() == napi_float32_array) {
166
- run_parallel(vectors.As<Napi::Float32Array>().Data());
167
- } else if (vectors.TypedArrayType() == napi_float64_array) {
168
- run_parallel(vectors.As<Napi::Float64Array>().Data());
169
- } else if (vectors.TypedArrayType() == napi_int8_array) {
170
- run_parallel(vectors.As<Napi::Int8Array>().Data());
171
- } else {
172
- Napi::TypeError::New(ctx.Env(),
173
- "Unsupported TypedArray. Supported types are Float32Array, Float64Array, and Int8Array.")
174
- .ThrowAsJavaScriptException();
175
- }
176
- }
177
-
178
- Napi::Value CompiledIndex::Search(Napi::CallbackInfo const& ctx) {
179
- Napi::Env env = ctx.Env();
180
- Napi::TypedArray queries = ctx[0].As<Napi::TypedArray>();
181
- std::size_t tasks = queries.ElementLength() / native_->dimensions();
182
- std::size_t wanted = napi_argument_to_size(ctx[1]);
183
-
184
- auto run_parallel = [&](auto vectors) -> Napi::Value {
185
- Napi::Array result_js = Napi::Array::New(env, 3);
186
- Napi::BigUint64Array matches_js = Napi::BigUint64Array::New(env, tasks * wanted);
187
- Napi::Float32Array distances_js = Napi::Float32Array::New(env, tasks * wanted);
188
- Napi::BigUint64Array counts_js = Napi::BigUint64Array::New(env, tasks);
189
-
190
- auto matches_data = matches_js.Data();
191
- auto distances_data = distances_js.Data();
192
- auto counts_data = counts_js.Data();
193
-
194
- try {
195
- bool failed = false;
196
- executor_stl_t executor;
197
- executor.fixed(tasks, [&](std::size_t /*thread_idx*/, std::size_t task_idx) {
198
- auto result = native_->search(vectors + task_idx * native_->dimensions(), wanted);
199
- if (!result) {
200
- failed = true;
201
- Napi::TypeError::New(env, result.error.release()).ThrowAsJavaScriptException();
202
- } else {
203
- counts_data[task_idx] = result.dump_to(matches_data + task_idx * native_->dimensions(),
204
- distances_data + task_idx * native_->dimensions());
205
- }
206
- });
207
-
208
- if (failed)
209
- return env.Null();
210
-
211
- } catch (std::bad_alloc const&) {
212
- Napi::TypeError::New(env, "Out of memory").ThrowAsJavaScriptException();
213
- return env.Null();
214
-
215
- } catch (...) {
216
- Napi::TypeError::New(env, "Search failed").ThrowAsJavaScriptException();
217
- return env.Null();
218
- }
219
-
220
- result_js.Set(0u, matches_js);
221
- result_js.Set(1u, distances_js);
222
- result_js.Set(2u, counts_js);
223
- return result_js;
224
- };
225
-
226
- if (queries.TypedArrayType() == napi_float32_array) {
227
- return run_parallel(queries.As<Napi::Float32Array>().Data());
228
- } else if (queries.TypedArrayType() == napi_float64_array) {
229
- return run_parallel(queries.As<Napi::Float64Array>().Data());
230
- } else if (queries.TypedArrayType() == napi_int8_array) {
231
- return run_parallel(queries.As<Napi::Int8Array>().Data());
232
- } else {
233
- Napi::TypeError::New(env,
234
- "Unsupported TypedArray. Supported types are Float32Array, Float64Array, and Int8Array.")
235
- .ThrowAsJavaScriptException();
236
- return env.Null();
237
- }
238
- }
239
-
240
- Napi::Value CompiledIndex::Remove(Napi::CallbackInfo const& ctx) {
241
- Napi::Env env = ctx.Env();
242
- Napi::BigUint64Array keys = ctx[0].As<Napi::BigUint64Array>();
243
- std::size_t length = keys.ElementLength();
244
- Napi::Array result = Napi::Array::New(env, length);
245
- for (std::size_t i = 0; i < length; ++i) {
246
- result[i] = Napi::Number::New(env, native_->remove(static_cast<default_key_t>(keys[i])).completed);
247
- }
248
- return result;
249
- }
250
-
251
- Napi::Value CompiledIndex::Contains(Napi::CallbackInfo const& ctx) {
252
- Napi::Env env = ctx.Env();
253
- Napi::BigUint64Array keys = ctx[0].As<Napi::BigUint64Array>();
254
- std::size_t length = keys.ElementLength();
255
- Napi::Array result = Napi::Array::New(env, length);
256
- for (std::size_t i = 0; i < length; ++i)
257
- result[i] = Napi::Boolean::New(env, native_->contains(static_cast<default_key_t>(keys[i])));
258
- return result;
259
- }
260
-
261
- Napi::Value CompiledIndex::Count(Napi::CallbackInfo const& ctx) {
262
- Napi::Env env = ctx.Env();
263
- Napi::BigUint64Array keys = ctx[0].As<Napi::BigUint64Array>();
264
- std::size_t length = keys.ElementLength();
265
- Napi::Array result = Napi::Array::New(env, length);
266
- for (std::size_t i = 0; i < length; ++i)
267
- result[i] = Napi::Boolean::New(env, native_->count(static_cast<default_key_t>(keys[i])));
268
- return result;
269
- }
270
-
271
- Napi::Value exactSearch(Napi::CallbackInfo const& ctx) {
272
- Napi::Env env = ctx.Env();
273
-
274
- // Extracting parameters directly without additional type checks.
275
- Napi::TypedArray dataset = ctx[0].As<Napi::TypedArray>();
276
- Napi::ArrayBuffer datasetBuffer = dataset.ArrayBuffer();
277
- Napi::TypedArray queries = ctx[1].As<Napi::TypedArray>();
278
- Napi::ArrayBuffer queriesBuffer = queries.ArrayBuffer();
279
- std::uint64_t dimensions = napi_argument_to_size(ctx[2]);
280
- std::uint64_t wanted = napi_argument_to_size(ctx[3]);
281
- metric_kind_t metric_kind = metric_from_name(ctx[4].As<Napi::String>().Utf8Value().c_str());
282
-
283
- scalar_kind_t quantization;
284
- std::size_t bytes_per_scalar;
285
- switch (queries.TypedArrayType()) {
286
- case napi_float64_array: quantization = scalar_kind_t::f64_k, bytes_per_scalar = 8; break;
287
- case napi_int8_array: quantization = scalar_kind_t::i8_k, bytes_per_scalar = 1; break;
288
- default: quantization = scalar_kind_t::f32_k, bytes_per_scalar = 4; break;
289
- }
290
-
291
- metric_punned_t metric(dimensions, metric_kind, quantization);
292
- executor_default_t executor;
293
- exact_search_t search;
294
-
295
- // Performing the exact search.
296
- std::size_t dataset_size = dataset.ElementLength() / dimensions;
297
- std::size_t queries_size = queries.ElementLength() / dimensions;
298
- auto results = search( //
299
- reinterpret_cast<byte_t const*>(datasetBuffer.Data()), //
300
- dataset_size, //
301
- dimensions * bytes_per_scalar, //
302
- reinterpret_cast<byte_t const*>(queriesBuffer.Data()), //
303
- queries_size, //
304
- dimensions * bytes_per_scalar, //
305
- wanted, metric, executor);
306
-
307
- if (!results)
308
- Napi::TypeError::New(env, "Out of memory").ThrowAsJavaScriptException();
309
-
310
- // Constructing the result object
311
- Napi::Array result_js = Napi::Array::New(env, 3);
312
- Napi::BigUint64Array matches_js = Napi::BigUint64Array::New(env, queries_size * wanted);
313
- Napi::Float32Array distances_js = Napi::Float32Array::New(env, queries_size * wanted);
314
- Napi::BigUint64Array counts_js = Napi::BigUint64Array::New(env, queries_size);
315
-
316
- auto matches_data = matches_js.Data();
317
- auto distances_data = distances_js.Data();
318
- auto counts_data = counts_js.Data();
319
-
320
- // Export into JS buffers
321
- for (std::size_t task_idx = 0; task_idx != queries_size; ++task_idx) {
322
- auto result = results.at(task_idx);
323
- counts_data[task_idx] = wanted;
324
- for (std::size_t result_idx = 0; result_idx != wanted; ++result_idx) {
325
- matches_data[task_idx * wanted + result_idx] = result[result_idx].offset;
326
- distances_data[task_idx * wanted + result_idx] = result[result_idx].distance;
327
- }
328
- }
329
-
330
- result_js.Set(0u, matches_js);
331
- result_js.Set(1u, distances_js);
332
- result_js.Set(2u, counts_js);
333
- return result_js;
334
- }
335
-
336
- Napi::Object InitAll(Napi::Env env, Napi::Object exports) {
337
- exports.Set("exactSearch", Napi::Function::New(env, exactSearch));
338
- return CompiledIndex::Init(env, exports);
339
- }
340
-
341
- NODE_API_MODULE(usearch, InitAll)
@@ -1 +0,0 @@
1
- {"version":3,"file":"usearch.d.ts","sourceRoot":"","sources":["../usearch.js"],"names":[],"mappings":"AAsIA;IAEI;;;;;;;;;;;OAWG;IACH;oBATkC,MAAM;gBAAU,UAAU;sBAAiC,UAAU;sBAAiC,MAAM;uBAAqB,MAAM;0BAAwB,MAAM;eAAa,OAAO;gBAChN,UAAU,iBACV,UAAU,iBACV,MAAM,kBACN,MAAM,qBACN,MAAM,UACN,OAAO,EAmCjB;IADG,oBAAwI;IAG5I;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,UAPW,MAAM,GAAC,MAAM,EAAE,GAAC,cAAc,WAE9B,YAAY,GAAC,YAAY,GAAC,SAAS,QAoB7C;IAED;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,gBANW,YAAY,GAAC,YAAY,GAAC,SAAS,GAAC,MAAM,MAAM,MAAM,CAAC,CAAC,KACxD,MAAM,GACL,OAAO,GAAC,YAAY,CAqB/B;IAED;;;;;;;;;OASG;IACH,eAJW,MAAM,GAAC,MAAM,EAAE,GAAC,cAAc,GAC7B,OAAO,GAAC,OAAO,EAAE,CAU5B;IAED;;;;;;OAMG;IACH,YAJW,MAAM,GAAC,MAAM,EAAE,GAAC,cAAc,GAC7B,MAAM,GAAC,MAAM,EAAE,CAU1B;IAED;;;;;;;;;OASG;IACH,aAJW,MAAM,GAAC,MAAM,EAAE,GAAC,cAAc,GAC7B,MAAM,GAAC,MAAM,EAAE,CAU1B;IAED;;;OAGG;IACH,cAFY,MAAM,CAEsC;IAExD;;;OAGG;IACH,gBAFY,MAAM,CAE0C;IAE5D;;;OAGG;IACH,QAFY,MAAM,CAE0B;IAE5C;;;OAGG;IACH,YAFY,MAAM,CAEkC;IAEpD;;;;OAIG;IACH,WAHW,MAAM,QAMhB;IAED;;;;OAIG;IACH,WAHW,MAAM,QAMhB;IAED;;;;OAIG;IACH,WAHW,MAAM,QAMhB;CACJ;;;;yBA5WS,MAAM;;;;;;;;;;;;;;;;;yBAmBN,MAAM;;;;;;;;;;AAYhB;;GAEG;AACH;IACI;;;;;OAKG;IACH,kBAHW,cAAc,aACd,YAAY,EAKtB;IAFG,qBAAgB;IAChB,wBAA0B;CAEjC;AAED;;GAEG;AACH;IACI;;;;;;;OAOG;IACH,kBALW,cAAc,aACd,YAAY,UACZ,cAAc,KACd,MAAM,EAOhB;IAJG,qBAAgB;IAChB,wBAA0B;IAC1B,uBAAoB;IACpB,UAAU;IAGd;;;;;OAKG;IACH,OAHW,MAAM,GACJ,OAAO,CAQnB;CACJ;AA+RD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,qCA1BW,YAAY,GAAC,YAAY,GAAC,SAAS,GAAC,MAAM,MAAM,MAAM,CAAC,CAAC,WACxD,YAAY,GAAC,YAAY,GAAC,SAAS,GAAC,MAAM,MAAM,MAAM,CAAC,CAAC,cACxD,MAAM,SACN,MAAM,UACN,UAAU,GACT,OAAO,GAAC,YAAY,CA0D/B"}
@@ -1,74 +0,0 @@
1
- const test = require('node:test');
2
- const assert = require('node:assert');
3
- const usearch = require('./usearch.js');
4
-
5
- test('Single-entry operations', () => {
6
- const index = new usearch.Index(2, 'l2sq');
7
-
8
- assert.equal(index.connectivity(), 16, 'connectivity should be 16');
9
- assert.equal(index.dimensions(), 2, 'dimensions should be 2');
10
- assert.equal(index.size(), 0, 'initial size should be 0');
11
-
12
- index.add(15n, new Float32Array([10, 20]));
13
- index.add(16n, new Float32Array([10, 25]));
14
-
15
- assert.equal(index.size(), 2, 'size after adding elements should be 2');
16
- assert.equal(index.contains(15), true, 'entry must be present after insertion');
17
-
18
- const results = index.search(new Float32Array([13, 14]), 2);
19
-
20
- assert.deepEqual(results.keys, new BigUint64Array([15n, 16n]), 'keys should be 15 and 16');
21
- assert.deepEqual(results.distances, new Float32Array([45, 130]), 'distances should be 45 and 130');
22
- });
23
-
24
- test('Batch operations', () => {
25
- const indexBatch = new usearch.Index(2, 'l2sq');
26
-
27
- const keys = [15n, 16n];
28
- const vectors = [new Float32Array([10, 20]), new Float32Array([10, 25])];
29
-
30
- indexBatch.add(keys, vectors);
31
- assert.equal(indexBatch.size(), 2, 'size after adding batch should be 2');
32
-
33
- const results = indexBatch.search(new Float32Array([13, 14]), 2);
34
-
35
- assert.deepEqual(results.keys, new BigUint64Array([15n, 16n]), 'keys should be 15 and 16');
36
- assert.deepEqual(results.distances, new Float32Array([45, 130]), 'distances should be 45 and 130');
37
- });
38
-
39
- test("Expected results", () => {
40
- var index = new usearch.Index({
41
- metric: "cos",
42
- connectivity: 16,
43
- dimensions: 3,
44
- });
45
- index.add(42n, new Float32Array([0.2, 0.6, 0.4]));
46
- var results = index.search(new Float32Array([0.2, 0.6, 0.4]), 10);
47
-
48
- assert.equal(index.size(), 1);
49
- assert.deepEqual(results.keys, new BigUint64Array([42n]));
50
- assert.deepEqual(results.distances, new Float32Array([0]));
51
- });
52
-
53
-
54
-
55
- test('Operations with invalid values', () => {
56
- const indexBatch = new usearch.Index(2, 'l2sq');
57
-
58
- const keys = [NaN, 16n];
59
- const vectors = [new Float32Array([10, 30]), new Float32Array([1, 5])];
60
-
61
- try {
62
- indexBatch.add(keys, vectors);
63
- throw new Error('indexBatch.add should have thrown an error.');
64
- } catch (err) {
65
- assert.equal(err.message, 'All keys must be integers or bigints.');
66
- }
67
-
68
- try {
69
- indexBatch.search(NaN, 2);
70
- throw new Error('indexBatch.search should have thrown an error.');
71
- } catch (err) {
72
- assert.equal(err.message, 'Vectors must be a TypedArray or an array of arrays.');
73
- }
74
- });
package/package-ci.json DELETED
@@ -1,10 +0,0 @@
1
- {
2
- "name": "usearch-ci",
3
- "version": "1.0.0",
4
- "devDependencies": {
5
- "@semantic-release/exec": "^6.0.3",
6
- "@semantic-release/git": "^10.0.1",
7
- "conventional-changelog-eslint": "^3.0.9",
8
- "semantic-release": "^21.1.2"
9
- }
10
- }
package/pyproject.toml DELETED
@@ -1,51 +0,0 @@
1
- [build-system]
2
- requires = ["setuptools>=42", "wheel", "cmake>=3.22", "pybind11", "numpy"]
3
- build-backend = "setuptools.build_meta"
4
-
5
- [tool.pytest.ini_options]
6
- minversion = "6.0"
7
- addopts = ["-ra", "--showlocals", "--strict-markers", "--strict-config"]
8
- xfail_strict = true
9
- filterwarnings = ["error"]
10
-
11
- # Avoid running tests, as everything is happening in a super slow container
12
- # We have already run all the relavent Python tests in `prerelease.yml`
13
- # test-requires = ["pytest", "numpy"]
14
- # test-command = "pytest {project}/python/scripts"
15
- [tool.cibuildwheel]
16
- test-requires = []
17
- test-command = ""
18
- build-verbosity = 0
19
- skip = ["*musllinux*", "*i686*", "pp*", "cp36-*"]
20
-
21
- [tool.cibuildwheel.linux]
22
- before-build = [
23
- "rm -rf {project}/CMakeCache.txt {project}/build {project}/build_debug {project}/CMakeFiles.txt {project}/_deps {project}/.pytest_cache",
24
- "mkdir -p build/usearch",
25
- "git submodule update --init --recursive",
26
- ]
27
- manylinux-x86_64-image = "manylinux_2_28"
28
- manylinux-aarch64-image = "manylinux_2_28"
29
-
30
- archs = ["x86_64", "aarch64"]
31
- before-all = ["yum install -y glibc-devel wget python3-devel"]
32
- repair-wheel-command = "auditwheel repair --lib-sdir . -w {dest_dir} {wheel}"
33
-
34
- [tool.cibuildwheel.macos]
35
- before-build = [
36
- "rm -rf {project}/CMakeCache.txt {project}/build {project}/build_debug {project}/CMakeFiles.txt {project}/_deps {project}/.pytest_cache",
37
- "mkdir -p build/usearch",
38
- "git submodule update --init --recursive",
39
- ]
40
- archs = ["x86_64", "universal2", "arm64"]
41
- repair-wheel-command = "delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel}"
42
-
43
-
44
- [tool.cibuildwheel.windows]
45
- before-build = [
46
- "rd /s /q {project}\\CMakeCache.txt {project}\\build {project}\\build_debug {project}\\CMakeFiles.txt {project}\\_deps {project}\\.pytest_cache || echo Done",
47
- "md build\\usearch",
48
- "git submodule update --init --recursive",
49
- ]
50
- archs = ["x86", "AMD64"]
51
- skip = ["*win32*", "pp*", "cp36-*"]
package/setup.py DELETED
@@ -1,201 +0,0 @@
1
- import os
2
- import sys
3
- import subprocess
4
- from setuptools import setup
5
-
6
- from pybind11.setup_helpers import Pybind11Extension
7
-
8
- sources = ["python/lib.cpp"]
9
- compile_args = []
10
- link_args = []
11
- macros_args = []
12
-
13
-
14
- def get_bool_env(name: str, preference: bool) -> bool:
15
- return os.environ.get(name, "1" if preference else "0") == "1"
16
-
17
-
18
- def get_bool_env_w_name(name: str, preference: bool) -> tuple:
19
- return name, "1" if get_bool_env(name, preference) else "0"
20
-
21
-
22
- # Check the environment variables
23
- is_linux: bool = sys.platform == "linux"
24
- is_macos: bool = sys.platform == "darwin"
25
- is_windows: bool = sys.platform == "win32"
26
-
27
-
28
- is_gcc = False
29
- if is_linux:
30
- cxx = os.environ.get("CXX")
31
- if cxx:
32
- try:
33
- command = "where" if os.name == "nt" else "which"
34
- full_path = subprocess.check_output([command, cxx], text=True).strip()
35
- compiler_name = os.path.basename(full_path)
36
- is_gcc = ("g++" in compiler_name) and ("clang++" not in compiler_name)
37
- except subprocess.CalledProcessError:
38
- pass
39
-
40
-
41
- prefer_simsimd: bool = is_linux or is_macos
42
- prefer_fp16lib: bool = True
43
- prefer_openmp: bool = is_linux and is_gcc
44
-
45
- use_simsimd: bool = get_bool_env("USEARCH_USE_SIMSIMD", prefer_simsimd)
46
- use_fp16lib: bool = get_bool_env("USEARCH_USE_FP16LIB", prefer_fp16lib)
47
- use_openmp: bool = get_bool_env("USEARCH_USE_OPENMP", prefer_openmp)
48
-
49
-
50
- # Common arguments for all platforms
51
- macros_args.append(("USEARCH_USE_OPENMP", "1" if use_openmp else "0"))
52
- macros_args.append(("USEARCH_USE_SIMSIMD", "1" if use_simsimd else "0"))
53
- macros_args.append(("USEARCH_USE_FP16LIB", "1" if use_fp16lib else "0"))
54
-
55
- if is_linux:
56
- compile_args.append("-std=c++17")
57
- compile_args.append("-O3") # Maximize performance
58
- compile_args.append("-ffast-math") # Maximize floating-point performance
59
- compile_args.append("-Wno-unknown-pragmas")
60
- compile_args.append("-fdiagnostics-color=always")
61
-
62
- # Simplify debugging, but the normal `-g` may make builds much longer!
63
- compile_args.append("-g1")
64
-
65
- if use_openmp:
66
- compile_args.append("-fopenmp")
67
- link_args.append("-lgomp")
68
-
69
- if use_simsimd:
70
- macros_args.extend(
71
- [
72
- get_bool_env_w_name("SIMSIMD_TARGET_X86_AVX512", True),
73
- get_bool_env_w_name("SIMSIMD_TARGET_ARM_SVE", True),
74
- get_bool_env_w_name("SIMSIMD_TARGET_X86_AVX2", True),
75
- get_bool_env_w_name("SIMSIMD_TARGET_ARM_NEON", True),
76
- ]
77
- )
78
-
79
- if is_macos:
80
- # MacOS 10.15 or higher is needed for `aligned_alloc` support.
81
- # https://github.com/unum-cloud/usearch/actions/runs/4975434891/jobs/8902603392
82
- compile_args.append("-mmacosx-version-min=10.15")
83
- compile_args.append("-std=c++17")
84
- compile_args.append("-O3") # Maximize performance
85
- compile_args.append("-ffast-math") # Maximize floating-point performance
86
- compile_args.append("-fcolor-diagnostics")
87
- compile_args.append("-Wno-unknown-pragmas")
88
-
89
- # Simplify debugging, but the normal `-g` may make builds much longer!
90
- compile_args.append("-g1")
91
-
92
- # Linking OpenMP requires additional preparation in CIBuildWheel.
93
- # We must install `brew install llvm` ahead of time.
94
- # import subprocess as cli
95
- # llvm_base = cli.check_output(["brew", "--prefix", "llvm"]).strip().decode("utf-8")
96
- # if len(llvm_base):
97
- # compile_args.append(f"-I{llvm_base}/include")
98
- # compile_args.append("-Xpreprocessor -fopenmp")
99
- # link_args.append(f"-L{llvm_base}/lib")
100
- # link_args.append("-lomp")
101
- # macros_args.append(("USEARCH_USE_OPENMP", "1"))
102
-
103
- if use_simsimd:
104
- macros_args.extend(
105
- [
106
- get_bool_env_w_name("SIMSIMD_TARGET_X86_AVX512", False),
107
- get_bool_env_w_name("SIMSIMD_TARGET_ARM_SVE", False),
108
- get_bool_env_w_name("SIMSIMD_TARGET_X86_AVX2", True),
109
- get_bool_env_w_name("SIMSIMD_TARGET_ARM_NEON", True),
110
- ]
111
- )
112
-
113
- if is_windows:
114
- compile_args.append("/std:c++17")
115
- compile_args.append("/O2")
116
- compile_args.append("/fp:fast") # Enable fast math for MSVC
117
- compile_args.append("/W1") # Reduce warnings verbosity
118
-
119
- # We don't actually want to use any SimSIMD stuff,
120
- # as GCC attributes aren't compatible with MSVC
121
- if use_simsimd:
122
- macros_args.extend(
123
- [
124
- get_bool_env_w_name("SIMSIMD_TARGET_X86_AVX512", False),
125
- get_bool_env_w_name("SIMSIMD_TARGET_ARM_SVE", False),
126
- get_bool_env_w_name("SIMSIMD_TARGET_X86_AVX2", False),
127
- get_bool_env_w_name("SIMSIMD_TARGET_ARM_NEON", False),
128
- ]
129
- )
130
-
131
- if is_linux or is_macos:
132
- sources.append("sqlite/lib.cpp")
133
- link_args.append("-lsqlite3")
134
-
135
- ext_modules = [
136
- Pybind11Extension(
137
- "usearch.compiled",
138
- sources,
139
- extra_compile_args=compile_args,
140
- extra_link_args=link_args,
141
- define_macros=macros_args,
142
- ),
143
- ]
144
-
145
- __version__ = open("VERSION", "r").read().strip()
146
- __lib_name__ = "usearch"
147
-
148
- this_directory = os.path.abspath(os.path.dirname(__file__))
149
- with open(os.path.join(this_directory, "README.md")) as f:
150
- long_description = f.read()
151
-
152
- # Depending on the macros, adjust the include directories
153
- include_dirs = [
154
- "include",
155
- "python",
156
- "stringzilla/include",
157
- ]
158
- if use_simsimd:
159
- include_dirs.append("simsimd/include")
160
- if use_fp16lib:
161
- include_dirs.append("fp16/include")
162
-
163
- setup(
164
- name=__lib_name__,
165
- version=__version__,
166
- packages=["usearch"],
167
- package_dir={"usearch": "python/usearch"},
168
- description="Smaller & Faster Single-File Vector Search Engine from Unum",
169
- author="Ash Vardanian",
170
- author_email="info@unum.cloud",
171
- long_description=long_description,
172
- long_description_content_type="text/markdown",
173
- license="Apache-2.0",
174
- classifiers=[
175
- "Development Status :: 5 - Production/Stable",
176
- "Natural Language :: English",
177
- "Intended Audience :: Developers",
178
- "Intended Audience :: Information Technology",
179
- "License :: OSI Approved :: Apache Software License",
180
- "Programming Language :: C++",
181
- "Programming Language :: Python :: 3 :: Only",
182
- "Programming Language :: Python :: Implementation :: CPython",
183
- "Programming Language :: Java",
184
- "Programming Language :: JavaScript",
185
- "Programming Language :: Objective C",
186
- "Programming Language :: Rust",
187
- "Programming Language :: Other",
188
- "Operating System :: MacOS",
189
- "Operating System :: Unix",
190
- "Operating System :: Microsoft :: Windows",
191
- "Topic :: System :: Clustering",
192
- "Topic :: Database :: Database Engines/Servers",
193
- "Topic :: Scientific/Engineering :: Artificial Intelligence",
194
- ],
195
- include_dirs=include_dirs,
196
- ext_modules=ext_modules,
197
- install_requires=[
198
- "numpy",
199
- "tqdm",
200
- ],
201
- )