usearch 0.1.9 → 0.1.10
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/.vscode/settings.json +1 -0
- package/CMakeLists.txt +26 -8
- package/CMakeListsInstructions.md +49 -33
- package/Cargo.toml +2 -2
- package/LICENSE +201 -0
- package/README.md +18 -12
- package/VERSION +1 -1
- package/assets/usearch-neighbor-types.png +0 -0
- package/build.gradle +1 -1
- package/include/usearch/usearch.hpp +24 -0
- package/package.json +2 -2
- package/python/bench.py +41 -71
- package/python/lib.cpp +17 -11
- package/python/test.py +28 -2
- package/python/usearch/client.py +34 -0
- package/python/usearch/io.py +67 -0
- package/python/usearch/server.py +51 -0
- package/setup.py +1 -1
- package/simsimd/.vscode/settings.json +3 -1
- package/simsimd/include/simsimd/simsimd.h +14 -7
- package/src/advanced.hpp +69 -10
- package/src/bench.cpp +30 -2
- package/wolfram/CMakeLists.txt +17 -0
- package/wolfram/lib.cpp +139 -4
- package/wolfram/test.wls +27 -0
- package/docs/Makefile +0 -20
package/src/bench.cpp
CHANGED
|
@@ -26,6 +26,8 @@
|
|
|
26
26
|
using namespace unum::usearch;
|
|
27
27
|
using namespace unum;
|
|
28
28
|
|
|
29
|
+
using vector_id_t = std::uint32_t;
|
|
30
|
+
|
|
29
31
|
template <typename element_at>
|
|
30
32
|
std::size_t offset_of(element_at const* begin, element_at const* end, element_at v) noexcept {
|
|
31
33
|
auto iterator = begin;
|
|
@@ -344,6 +346,34 @@ void run_big_or_small(dataset_at& dataset, args_t const& args, config_t config)
|
|
|
344
346
|
run_type_punned<auto_index_gt<std::size_t, neighbor_id_at>>(dataset, args, config);
|
|
345
347
|
}
|
|
346
348
|
|
|
349
|
+
void report_expected_losses(persisted_dataset_gt<float, vector_id_t> const& dataset) {
|
|
350
|
+
|
|
351
|
+
auto vec1 = dataset.vector(0);
|
|
352
|
+
auto vec2 = dataset.query(0);
|
|
353
|
+
std::vector<f16_converted_t> vec1f16(dataset.dimensions());
|
|
354
|
+
std::vector<f16_converted_t> vec2f16(dataset.dimensions());
|
|
355
|
+
std::transform(vec1, vec1 + dataset.dimensions(), vec1f16.data(), [](float v) { return v; });
|
|
356
|
+
std::transform(vec2, vec2 + dataset.dimensions(), vec2f16.data(), [](float v) { return v; });
|
|
357
|
+
std::vector<i8q100_converted_t> vec1i8(dataset.dimensions());
|
|
358
|
+
std::vector<i8q100_converted_t> vec2i8(dataset.dimensions());
|
|
359
|
+
std::transform(vec1, vec1 + dataset.dimensions(), vec1i8.data(), [](float v) { return v; });
|
|
360
|
+
std::transform(vec2, vec2 + dataset.dimensions(), vec2i8.data(), [](float v) { return v; });
|
|
361
|
+
|
|
362
|
+
#if 0
|
|
363
|
+
auto ip_default = ip_gt<float>{}(vec1, vec2, dataset.dimensions());
|
|
364
|
+
auto ip_sve = 1.f - simsimd_dot_f32sve(vec1, vec2, dataset.dimensions());
|
|
365
|
+
auto ip_neon = 1.f - simsimd_dot_f32x4neon(vec1, vec2, dataset.dimensions());
|
|
366
|
+
auto ip_f16 = ip_gt<f16_converted_t>{}(vec1f16.data(), vec2f16.data(), dataset.dimensions());
|
|
367
|
+
auto ip_f16sve = 1.f - simsimd_dot_f16sve((simsimd_f16_t const*)vec1f16.data(),
|
|
368
|
+
(simsimd_f16_t const*)vec2f16.data(), dataset.dimensions());
|
|
369
|
+
auto ip_f16neon = 1.f - simsimd_dot_f16x8neon((simsimd_f16_t const*)vec1f16.data(),
|
|
370
|
+
(simsimd_f16_t const*)vec2f16.data(), dataset.dimensions());
|
|
371
|
+
auto ip_i8 = ip_i8q100_converted_t{}(vec1i8.data(), vec2i8.data(), dataset.dimensions());
|
|
372
|
+
|
|
373
|
+
exit(0);
|
|
374
|
+
#endif
|
|
375
|
+
}
|
|
376
|
+
|
|
347
377
|
int main(int argc, char** argv) {
|
|
348
378
|
|
|
349
379
|
// Print backtrace if something goes wrong.
|
|
@@ -393,8 +423,6 @@ int main(int argc, char** argv) {
|
|
|
393
423
|
std::printf("-- Query vectors path: %s\n", args.path_queries.c_str());
|
|
394
424
|
std::printf("-- Ground truth neighbors path: %s\n", args.path_neighbors.c_str());
|
|
395
425
|
|
|
396
|
-
using vector_id_t = std::uint32_t;
|
|
397
|
-
|
|
398
426
|
persisted_dataset_gt<float, vector_id_t> dataset{
|
|
399
427
|
args.path_vectors.c_str(),
|
|
400
428
|
args.path_queries.c_str(),
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
|
|
2
|
+
if(NOT WOLFRAM_PATH)
|
|
3
|
+
set(WOLFRAM_PATH "/usr/local/Wolfram/Mathematica")
|
|
4
|
+
endif()
|
|
5
|
+
|
|
6
|
+
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${WOLFRAM_PATH}/SystemFiles/Links/WSTP/DeveloperKit/Linux-x86-64/CompilerAdditions/")
|
|
7
|
+
include(WSTP)
|
|
8
|
+
include_directories("${WOLFRAM_PATH}/SystemFiles/IncludeFiles/C/")
|
|
9
|
+
link_directories("${WOLFRAM_PATH}/SystemFiles/Libraries/Linux-x86-64/")
|
|
10
|
+
|
|
11
|
+
add_library(usearchWFM SHARED lib.cpp)
|
|
12
|
+
|
|
13
|
+
# Link against the Wolfram LibraryLink library
|
|
14
|
+
target_link_libraries(usearchWFM WSTP::STATIC_LIBRARY)
|
|
15
|
+
|
|
16
|
+
# Set the output name of the library to be compatible with Wolfram Language
|
|
17
|
+
set_target_properties(usearchWFM PROPERTIES PREFIX "" OUTPUT_NAME "usearchWFM")
|
package/wolfram/lib.cpp
CHANGED
|
@@ -1,21 +1,156 @@
|
|
|
1
1
|
#include "WolframLibrary.h"
|
|
2
|
+
#include "advanced.hpp"
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
using namespace unum::usearch;
|
|
5
|
+
using distance_t = punned_distance_t;
|
|
6
|
+
using native_index_t = auto_index_gt<int>;
|
|
7
|
+
using span_t = span_gt<float>;
|
|
8
|
+
|
|
9
|
+
EXTERN_C DLLEXPORT int WolframLibrary_initialize(WolframLibraryData libData) { return LIBRARY_NO_ERROR; }
|
|
5
10
|
EXTERN_C DLLEXPORT void WolframLibrary_uninitialize(WolframLibraryData libData) { return; }
|
|
6
11
|
|
|
7
|
-
EXTERN_C DLLEXPORT int
|
|
12
|
+
EXTERN_C DLLEXPORT int IndexCreate(WolframLibraryData libData, mint Argc, MArgument* Args, MArgument Res) {
|
|
13
|
+
config_t config;
|
|
14
|
+
char* accuracy_cstr = nullptr;
|
|
15
|
+
char* metric_cstr = nullptr;
|
|
16
|
+
try {
|
|
17
|
+
accuracy_cstr = MArgument_getUTF8String(Args[1]);
|
|
18
|
+
metric_cstr = MArgument_getUTF8String(Args[0]);
|
|
19
|
+
long dimensions = static_cast<std::size_t>(MArgument_getInteger(Args[2]));
|
|
20
|
+
config.max_elements = static_cast<std::size_t>(MArgument_getInteger(Args[3]));
|
|
21
|
+
config.connectivity = static_cast<std::size_t>(MArgument_getInteger(Args[4]));
|
|
22
|
+
config.expansion_add = static_cast<std::size_t>(MArgument_getInteger(Args[5]));
|
|
23
|
+
config.expansion_search = static_cast<std::size_t>(MArgument_getInteger(Args[6]));
|
|
24
|
+
config.max_threads_add = 4;
|
|
25
|
+
config.max_threads_search = 4;
|
|
26
|
+
|
|
27
|
+
accuracy_t accuracy = accuracy_from_name(accuracy_cstr, strlen(accuracy_cstr));
|
|
28
|
+
native_index_t index = index_from_name<native_index_t>( //
|
|
29
|
+
metric_cstr, strlen(metric_cstr), dimensions, accuracy, config);
|
|
30
|
+
|
|
31
|
+
native_index_t* result_ptr = new native_index_t(std::move(index));
|
|
32
|
+
MArgument_setInteger(Res, (long)result_ptr);
|
|
33
|
+
|
|
34
|
+
} catch (...) {
|
|
35
|
+
return LIBRARY_FUNCTION_ERROR;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
libData->UTF8String_disown(accuracy_cstr);
|
|
39
|
+
libData->UTF8String_disown(metric_cstr);
|
|
40
|
+
return LIBRARY_NO_ERROR;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
EXTERN_C DLLEXPORT int IndexSave(WolframLibraryData libData, mint Argc, MArgument* Args, MArgument Res) {
|
|
44
|
+
char* path_cstr = nullptr;
|
|
45
|
+
native_index_t* c_ptr = (native_index_t*)MArgument_getUTF8String(Args[0]);
|
|
46
|
+
try {
|
|
47
|
+
path_cstr = MArgument_getUTF8String(Args[1]);
|
|
48
|
+
c_ptr->save(path_cstr);
|
|
49
|
+
} catch (...) {
|
|
50
|
+
return LIBRARY_FUNCTION_ERROR;
|
|
51
|
+
}
|
|
52
|
+
libData->UTF8String_disown(path_cstr);
|
|
53
|
+
return LIBRARY_NO_ERROR;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
EXTERN_C DLLEXPORT int IndexLoad(WolframLibraryData libData, mint Argc, MArgument* Args, MArgument Res) {
|
|
57
|
+
char* path_cstr = nullptr;
|
|
58
|
+
native_index_t* c_ptr = (native_index_t*)MArgument_getUTF8String(Args[0]);
|
|
59
|
+
try {
|
|
60
|
+
path_cstr = MArgument_getUTF8String(Args[1]);
|
|
61
|
+
c_ptr->load(path_cstr);
|
|
62
|
+
} catch (...) {
|
|
63
|
+
return LIBRARY_FUNCTION_ERROR;
|
|
64
|
+
}
|
|
65
|
+
libData->UTF8String_disown(path_cstr);
|
|
66
|
+
return LIBRARY_NO_ERROR;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
EXTERN_C DLLEXPORT int IndexView(WolframLibraryData libData, mint Argc, MArgument* Args, MArgument Res) {
|
|
70
|
+
char* path_cstr = nullptr;
|
|
71
|
+
native_index_t* c_ptr = (native_index_t*)MArgument_getUTF8String(Args[0]);
|
|
72
|
+
try {
|
|
73
|
+
path_cstr = MArgument_getUTF8String(Args[1]);
|
|
74
|
+
c_ptr->view(path_cstr);
|
|
75
|
+
} catch (...) {
|
|
76
|
+
return LIBRARY_FUNCTION_ERROR;
|
|
77
|
+
}
|
|
78
|
+
libData->UTF8String_disown(path_cstr);
|
|
79
|
+
return LIBRARY_NO_ERROR;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
EXTERN_C DLLEXPORT int IndexDestroy(WolframLibraryData libData, mint Argc, MArgument* Args, MArgument Res) {
|
|
83
|
+
delete (native_index_t*)MArgument_getUTF8String(Args[0]);
|
|
84
|
+
return LIBRARY_NO_ERROR;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
EXTERN_C DLLEXPORT int IndexSize(WolframLibraryData libData, mint Argc, MArgument* Args, MArgument Res) {
|
|
88
|
+
size_t res = ((native_index_t*)MArgument_getUTF8String(Args[0]))->size();
|
|
89
|
+
MArgument_setInteger(Res, res);
|
|
90
|
+
return LIBRARY_NO_ERROR;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
EXTERN_C DLLEXPORT int IndexConnectivity(WolframLibraryData libData, mint Argc, MArgument* Args, MArgument Res) {
|
|
94
|
+
size_t res = ((native_index_t*)MArgument_getUTF8String(Args[0]))->connectivity();
|
|
95
|
+
MArgument_setInteger(Res, res);
|
|
8
96
|
return LIBRARY_NO_ERROR;
|
|
9
97
|
}
|
|
10
98
|
|
|
11
|
-
EXTERN_C DLLEXPORT int
|
|
99
|
+
EXTERN_C DLLEXPORT int IndexDimensions(WolframLibraryData libData, mint Argc, MArgument* Args, MArgument Res) {
|
|
100
|
+
size_t res = ((native_index_t*)MArgument_getUTF8String(Args[0]))->dimensions();
|
|
101
|
+
MArgument_setInteger(Res, res);
|
|
102
|
+
return LIBRARY_NO_ERROR;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
EXTERN_C DLLEXPORT int IndexCapacity(WolframLibraryData libData, mint Argc, MArgument* Args, MArgument Res) {
|
|
106
|
+
size_t res = ((native_index_t*)MArgument_getUTF8String(Args[0]))->capacity();
|
|
107
|
+
MArgument_setInteger(Res, res);
|
|
12
108
|
return LIBRARY_NO_ERROR;
|
|
13
109
|
}
|
|
14
110
|
|
|
15
111
|
EXTERN_C DLLEXPORT int IndexAdd(WolframLibraryData libData, mint Argc, MArgument* Args, MArgument Res) {
|
|
112
|
+
char* path_cstr = nullptr;
|
|
113
|
+
native_index_t* c_ptr = (native_index_t*)MArgument_getUTF8String(Args[0]);
|
|
114
|
+
float* vector_data = nullptr;
|
|
115
|
+
try {
|
|
116
|
+
int label = MArgument_getInteger(Args[1]);
|
|
117
|
+
MTensor tens = MArgument_getMTensor(Args[2]);
|
|
118
|
+
size_t len = libData->MTensor_getFlattenedLength(tens);
|
|
119
|
+
vector_data = (float*)libData->MTensor_getRealData(tens);
|
|
120
|
+
span_t vector_span = span_t{vector_data, len};
|
|
121
|
+
c_ptr->add(label, vector_span);
|
|
122
|
+
} catch (...) {
|
|
123
|
+
return LIBRARY_FUNCTION_ERROR;
|
|
124
|
+
}
|
|
16
125
|
return LIBRARY_NO_ERROR;
|
|
17
126
|
}
|
|
18
127
|
|
|
19
128
|
EXTERN_C DLLEXPORT int IndexSearch(WolframLibraryData libData, mint Argc, MArgument* Args, MArgument Res) {
|
|
129
|
+
native_index_t* c_ptr = (native_index_t*)MArgument_getUTF8String(Args[0]);
|
|
130
|
+
MTensor matches;
|
|
131
|
+
mint dims[] = {1};
|
|
132
|
+
int wanted = MArgument_getInteger(Args[2]);
|
|
133
|
+
float* vector_data = nullptr;
|
|
134
|
+
int* matches_data = nullptr;
|
|
135
|
+
std::size_t found = 0;
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
libData->MTensor_new(MType_Integer, 1, dims, &matches);
|
|
139
|
+
|
|
140
|
+
MTensor tens = MArgument_getMTensor(Args[1]);
|
|
141
|
+
size_t len = libData->MTensor_getFlattenedLength(tens);
|
|
142
|
+
vector_data = (float*)libData->MTensor_getRealData(tens);
|
|
143
|
+
span_t vector_span = span_t{vector_data, len};
|
|
144
|
+
|
|
145
|
+
matches_data = (int*)std::malloc(sizeof(int) * wanted);
|
|
146
|
+
found = c_ptr->search(vector_span, (size_t)wanted, matches_data, nullptr);
|
|
147
|
+
for (mint i = 0; i < found; i++)
|
|
148
|
+
libData->MTensor_setInteger(matches, &i, matches_data[i]);
|
|
149
|
+
|
|
150
|
+
MArgument_setMTensor(Res, matches);
|
|
151
|
+
} catch (...) {
|
|
152
|
+
return LIBRARY_FUNCTION_ERROR;
|
|
153
|
+
}
|
|
154
|
+
std::free(matches_data);
|
|
20
155
|
return LIBRARY_NO_ERROR;
|
|
21
156
|
}
|
package/wolfram/test.wls
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env wolframscript
|
|
2
|
+
|
|
3
|
+
IndexCreate = LibraryFunctionLoad["wolfram/usearchWFM.so", "IndexCreate", {"UTF8String", "UTF8String", Integer, Integer, Integer, Integer, Integer}, Integer]
|
|
4
|
+
IndexSave = LibraryFunctionLoad["wolfram/usearchWFM.so", "IndexSave", {Integer, "UTF8String"}, "Void"]
|
|
5
|
+
IndexLoad = LibraryFunctionLoad["wolfram/usearchWFM.so", "IndexLoad", {Integer, "UTF8String"}, "Void"]
|
|
6
|
+
IndexView = LibraryFunctionLoad["wolfram/usearchWFM.so", "IndexView", {Integer, "UTF8String"}, "Void"]
|
|
7
|
+
IndexDestroy = LibraryFunctionLoad["wolfram/usearchWFM.so", "IndexDestroy", {Integer}, "Void"]
|
|
8
|
+
IndexSize = LibraryFunctionLoad["wolfram/usearchWFM.so", "IndexSize", {Integer}, Integer]
|
|
9
|
+
IndexConnectivity = LibraryFunctionLoad["wolfram/usearchWFM.so", "IndexConnectivity", {Integer}, Integer]
|
|
10
|
+
IndexDimensions = LibraryFunctionLoad["wolfram/usearchWFM.so", "IndexDimensions", {Integer}, Integer]
|
|
11
|
+
IndexCapacity = LibraryFunctionLoad["wolfram/usearchWFM.so", "IndexCapacity", {Integer}, Integer]
|
|
12
|
+
IndexAdd = LibraryFunctionLoad["wolfram/usearchWFM.so", "IndexAdd", {Integer, Integer, {Real, 1}}, "Void"]
|
|
13
|
+
IndexSearch = LibraryFunctionLoad["wolfram/usearchWFM.so", "IndexSearch", {Integer, {Real, 1}, Integer}, {Integer, 1}]
|
|
14
|
+
Print["Functions Loaded"]
|
|
15
|
+
|
|
16
|
+
$index = IndexCreate["cos", "f16", 10, 10, 10, 10, 10]
|
|
17
|
+
Print["New Index Address: ", $index]
|
|
18
|
+
Print["Index Size: ", IndexSize[$index]]
|
|
19
|
+
Print["Index Capacity: ", IndexCapacity[$index]]
|
|
20
|
+
Print["Index Connectivity: ", IndexConnectivity[$index]]
|
|
21
|
+
$arr = {1.0, 2.0, 3.0, 4.0, 5.0};
|
|
22
|
+
IndexAdd[$index, 42, $arr]
|
|
23
|
+
Print["Added Array: ", $arr]
|
|
24
|
+
$res = IndexSearch[$index, $arr, 42]
|
|
25
|
+
Print["Searched: ", $res]
|
|
26
|
+
IndexDestroy[$index]
|
|
27
|
+
Print["Index Destroyed"]
|
package/docs/Makefile
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# Minimal makefile for Sphinx documentation
|
|
2
|
-
#
|
|
3
|
-
|
|
4
|
-
# You can set these variables from the command line, and also
|
|
5
|
-
# from the environment for the first two.
|
|
6
|
-
SPHINXOPTS ?=
|
|
7
|
-
SPHINXBUILD ?= sphinx-build
|
|
8
|
-
SOURCEDIR = .
|
|
9
|
-
BUILDDIR = ../build/docs
|
|
10
|
-
|
|
11
|
-
# Put it first so that "make" without argument is like "make help".
|
|
12
|
-
help:
|
|
13
|
-
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
|
14
|
-
|
|
15
|
-
.PHONY: help Makefile
|
|
16
|
-
|
|
17
|
-
# Catch-all target: route all unknown targets to Sphinx using the new
|
|
18
|
-
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
|
19
|
-
%: Makefile
|
|
20
|
-
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|