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.
- package/README.md +39 -38
- package/javascript/{types → dist/cjs}/usearch.d.ts +90 -115
- package/javascript/dist/cjs/usearch.js +531 -0
- package/javascript/dist/esm/usearch.d.ts +212 -0
- package/javascript/{usearch.js → dist/esm/usearch.js} +199 -153
- package/package.json +25 -23
- package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
- package/prebuilds/linux-arm64/usearch.node +0 -0
- package/prebuilds/linux-x64/usearch.node +0 -0
- package/prebuilds/win32-ia32/usearch.node +0 -0
- package/prebuilds/win32-x64/usearch.node +0 -0
- package/.clang-format +0 -10
- package/.clang-tidy +0 -60
- package/.cmake-format.py +0 -19
- package/.dockerignore +0 -93
- package/.gitattributes +0 -9
- package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -90
- package/.github/ISSUE_TEMPLATE/config.yml +0 -5
- package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -64
- package/.github/workflows/Dockerfile.libs +0 -36
- package/.github/workflows/prerelease.yml +0 -331
- package/.github/workflows/release.yml +0 -722
- package/.github/workflows/update_version.sh +0 -15
- package/.gitmodules +0 -9
- package/.releaserc +0 -90
- package/CITATION.cff +0 -11
- package/CMakeLists.txt +0 -324
- package/CODE_OF_CONDUCT.md +0 -128
- package/CONTRIBUTING.md +0 -361
- package/Cargo.toml +0 -19
- package/Dockerfile +0 -16
- package/VERSION +0 -1
- package/assets/unum.png +0 -0
- package/assets/usearch-approaches-transparent.png +0 -0
- package/assets/usearch-approaches-white.png +0 -0
- package/assets/usearch-neighbor-types.png +0 -0
- package/binding.gyp +0 -87
- package/build.gradle +0 -204
- package/build.rs +0 -18
- package/c/CMakeLists.txt +0 -25
- package/c/README.md +0 -34
- package/c/lib.cpp +0 -358
- package/c/test.c +0 -382
- package/c/usearch.h +0 -311
- package/cmake/clipp.cmake +0 -7
- package/cmake/config.cmake.in +0 -15
- package/cmake/emscripten.cmake +0 -8
- package/cmake/jemalloc.cmake +0 -62
- package/cmake/pkg-config.pc.in +0 -4
- package/cmake/usearchConfigVersion.cmake.in +0 -20
- package/conanfile.py +0 -26
- package/cpp/CMakeLists.txt +0 -14
- package/cpp/README.md +0 -161
- package/cpp/bench.cpp +0 -618
- package/cpp/test.cpp +0 -323
- package/fp16/CMakeLists.txt +0 -176
- package/fp16/LICENSE +0 -11
- package/fp16/README.md +0 -20
- package/fp16/bench/alt-element.cc +0 -89
- package/fp16/bench/from-alt-array.cc +0 -175
- package/fp16/bench/from-ieee-array.cc +0 -399
- package/fp16/bench/ieee-element.cc +0 -272
- package/fp16/bench/to-alt-array.cc +0 -91
- package/fp16/bench/to-ieee-array.cc +0 -303
- package/fp16/cmake/DownloadGoogleBenchmark.cmake +0 -15
- package/fp16/cmake/DownloadGoogleTest.cmake +0 -15
- package/fp16/cmake/DownloadPSimd.cmake +0 -15
- package/fp16/configure.py +0 -65
- package/fp16/confu.yaml +0 -8
- package/fp16/include/fp16/__init__.py +0 -0
- package/fp16/include/fp16/avx.py +0 -50
- package/fp16/include/fp16/avx2.py +0 -53
- package/fp16/include/fp16/bitcasts.h +0 -92
- package/fp16/include/fp16/fp16.h +0 -451
- package/fp16/include/fp16/psimd.h +0 -131
- package/fp16/include/fp16.h +0 -11
- package/fp16/jni/Android.mk +0 -6
- package/fp16/jni/Application.mk +0 -4
- package/fp16/test/alt-from-fp32-value.cc +0 -498
- package/fp16/test/alt-to-fp32-bits.cc +0 -263
- package/fp16/test/alt-to-fp32-psimd.cc +0 -145
- package/fp16/test/alt-to-fp32-value.cc +0 -348
- package/fp16/test/alt-to-fp32x2-psimd.cc +0 -245
- package/fp16/test/bitcasts.cc +0 -56
- package/fp16/test/ieee-from-fp32-value.cc +0 -523
- package/fp16/test/ieee-to-fp32-bits.cc +0 -333
- package/fp16/test/ieee-to-fp32-psimd.cc +0 -312
- package/fp16/test/ieee-to-fp32-value.cc +0 -420
- package/fp16/test/ieee-to-fp32x2-psimd.cc +0 -541
- package/fp16/test/peachpy/alt-xmm-to-fp32-xmm-avx.cc +0 -96
- package/fp16/test/peachpy/alt-xmm-to-fp32-ymm-avx2.cc +0 -96
- package/fp16/test/peachpy/stubs.py +0 -38
- package/fp16/test/tables.cc +0 -530
- package/fp16/test/tables.h +0 -13
- package/fp16/third-party/THHalf.h +0 -92
- package/fp16/third-party/eigen-half.h +0 -170
- package/fp16/third-party/float16-compressor.h +0 -80
- package/fp16/third-party/half.hpp +0 -2916
- package/fp16/third-party/npy-halffloat.h +0 -328
- package/include/usearch/index.hpp +0 -3836
- package/include/usearch/index_dense.hpp +0 -2004
- package/include/usearch/index_plugins.hpp +0 -2213
- package/javascript/lib.cpp +0 -341
- package/javascript/types/usearch.d.ts.map +0 -1
- package/javascript/usearch.test.js +0 -74
- package/package-ci.json +0 -10
- package/pyproject.toml +0 -51
- package/setup.py +0 -201
- package/simsimd/.releaserc +0 -86
- package/simsimd/CONTRIBUTING.md +0 -88
- package/simsimd/Cargo.lock +0 -709
- package/simsimd/Cargo.toml +0 -44
- package/simsimd/LICENSE +0 -201
- package/simsimd/README.md +0 -317
- package/simsimd/binding.gyp +0 -36
- package/simsimd/build.rs +0 -20
- package/simsimd/include/simsimd/binary.h +0 -245
- package/simsimd/include/simsimd/complex.h +0 -174
- package/simsimd/include/simsimd/probability.h +0 -548
- package/simsimd/include/simsimd/simsimd.h +0 -465
- package/simsimd/include/simsimd/spatial.h +0 -1267
- package/simsimd/include/simsimd/types.h +0 -208
- package/simsimd/javascript/bench.js +0 -127
- package/simsimd/javascript/fallback.ts +0 -193
- package/simsimd/javascript/lib.c +0 -102
- package/simsimd/javascript/node-gyp-build.d.ts +0 -1
- package/simsimd/javascript/simsimd.ts +0 -124
- package/simsimd/javascript/test.mjs +0 -153
- package/simsimd/javascript/tsconfig-base.json +0 -25
- package/simsimd/javascript/tsconfig-cjs.json +0 -8
- package/simsimd/javascript/tsconfig-esm.json +0 -8
- package/simsimd/package-lock.json +0 -1688
- package/simsimd/package.json +0 -61
- package/simsimd/rust/benches/cosine.rs +0 -27
- package/simsimd/rust/benches/native.rs +0 -30
- package/simsimd/rust/benches/sqeuclidean.rs +0 -27
- package/simsimd/rust/lib.c +0 -45
- package/simsimd/rust/lib.rs +0 -550
- package/sqlite/README.md +0 -178
- package/sqlite/lib.cpp +0 -325
- package/stringzilla/CONTRIBUTING.md +0 -446
- package/stringzilla/Cargo.lock +0 -25
- package/stringzilla/Cargo.toml +0 -26
- package/stringzilla/LICENSE +0 -201
- package/stringzilla/README.md +0 -1422
- package/stringzilla/VERSION +0 -1
- package/stringzilla/assets/cover-strinzilla.jpeg +0 -0
- package/stringzilla/assets/meme-stringzilla-v2.jpeg +0 -0
- package/stringzilla/assets/meme-stringzilla-v3.jpeg +0 -0
- package/stringzilla/binding.gyp +0 -16
- package/stringzilla/build.rs +0 -87
- package/stringzilla/c/lib.c +0 -337
- package/stringzilla/cli/README.md +0 -65
- package/stringzilla/cli/__init__.py +0 -0
- package/stringzilla/cli/split.py +0 -105
- package/stringzilla/cli/wc.py +0 -117
- package/stringzilla/include/stringzilla/experimental.h +0 -845
- package/stringzilla/include/stringzilla/module.modulemap +0 -9
- package/stringzilla/include/stringzilla/stringzilla.h +0 -5370
- package/stringzilla/include/stringzilla/stringzilla.hpp +0 -3838
- package/stringzilla/javascript/lib.c +0 -125
- package/stringzilla/javascript/stringzilla.js +0 -22
- package/stringzilla/package-ci.json +0 -10
- package/stringzilla/package.json +0 -32
- package/stringzilla/rust/lib.rs +0 -873
- package/stringzilla/swift/StringProtocol+StringZilla.swift +0 -280
- package/stringzilla/swift/Test.swift +0 -60
- package/tsconfig.json +0 -21
- package/wasmer.toml +0 -12
- package/winlibinstaller.bat +0 -42
- /package/{simsimd/javascript/dist-package-cjs.json → javascript/dist/cjs/package.json} +0 -0
- /package/{simsimd/javascript/dist-package-esm.json → javascript/dist/esm/package.json} +0 -0
package/javascript/lib.cpp
DELETED
|
@@ -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
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
|
-
)
|