usearch 2.7.7 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dockerignore +93 -0
- package/.github/workflows/Dockerfile.libs +6 -2
- package/.github/workflows/prerelease.yml +242 -245
- package/.github/workflows/release.yml +390 -356
- package/.gitignore +1 -0
- package/.vscode/settings.json +3 -1
- package/CITATION.cff +1 -1
- package/CMakeLists.txt +35 -5
- package/Cargo.toml +1 -1
- package/README.md +1 -1
- package/build.gradle +6 -0
- package/c/README.md +3 -3
- package/c/lib.cpp +75 -11
- package/c/usearch.h +22 -1
- package/conanfile.py +1 -1
- package/cpp/README.md +2 -1
- package/cpp/bench.cpp +3 -0
- package/cpp/test.cpp +12 -12
- package/csharp/nuget/nuget-package.props +1 -1
- package/docs/compilation.md +5 -13
- package/golang/lib.go +4 -1
- package/include/usearch/index.hpp +31 -30
- package/include/usearch/index_dense.hpp +49 -48
- package/include/usearch/index_plugins.hpp +70 -8
- package/java/cloud/unum/usearch/Index.java +118 -26
- package/java/cloud/unum/usearch/cloud_unum_usearch_Index.cpp +8 -8
- package/javascript/usearch.js +1 -0
- package/objc/USearchObjective.mm +4 -1
- package/objc/include/USearchObjective.h +1 -0
- package/package.json +1 -1
- package/python/lib.cpp +3 -2
- package/python/scripts/bench.ipynb +24 -2
- package/python/usearch/index.py +8 -3
- package/rust/lib.cpp +14 -12
- package/rust/lib.hpp +13 -13
- package/rust/lib.rs +46 -0
- package/setup.py +15 -3
- package/simsimd/.github/workflows/prerelease.yml +7 -8
- package/simsimd/.github/workflows/release.yml +18 -20
- package/simsimd/README.md +13 -8
- package/simsimd/binding.gyp +1 -1
- package/simsimd/cpp/bench.cxx +17 -3
- package/simsimd/include/simsimd/binary.h +1 -3
- package/simsimd/include/simsimd/probability.h +234 -361
- package/simsimd/include/simsimd/simsimd.h +95 -65
- package/simsimd/include/simsimd/spatial.h +0 -3
- package/simsimd/include/simsimd/types.h +12 -7
- package/simsimd/javascript/test.js +23 -5
- package/simsimd/package.json +2 -2
- package/wasmer.toml +1 -1
- package/wolfram/lib.cpp +1 -1
- package/csharp/eng/build_lib.sh +0 -65
- package/csharp/eng/clean.sh +0 -12
package/.gitignore
CHANGED
package/.vscode/settings.json
CHANGED
package/CITATION.cff
CHANGED
package/CMakeLists.txt
CHANGED
|
@@ -260,13 +260,43 @@ function (setup_target TARGET_NAME)
|
|
|
260
260
|
endif ()
|
|
261
261
|
|
|
262
262
|
target_include_directories(${TARGET_NAME} PRIVATE ${USEARCH_HEADER_INCLUDES})
|
|
263
|
-
set_target_properties(${TARGET_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR})
|
|
264
|
-
set_target_properties(${TARGET_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR})
|
|
265
|
-
set_target_properties(${TARGET_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
|
266
|
-
set_target_properties(${TARGET_NAME} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
|
267
|
-
set_target_properties(${TARGET_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
|
268
263
|
set_target_properties(${TARGET_NAME} PROPERTIES CXX_STANDARD 17)
|
|
269
264
|
|
|
265
|
+
# On Windows, when using multi-configuration CMake builds, the paths will be nested, resulting in
|
|
266
|
+
# "build_debug\Debug" on Windows instead of "build_debug". That's why we override all the configs to use the same
|
|
267
|
+
# output directory.
|
|
268
|
+
set_target_properties(
|
|
269
|
+
${TARGET_NAME}
|
|
270
|
+
PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
|
|
271
|
+
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
|
|
272
|
+
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
|
|
273
|
+
)
|
|
274
|
+
set_target_properties(
|
|
275
|
+
${TARGET_NAME}
|
|
276
|
+
PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}"
|
|
277
|
+
ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}"
|
|
278
|
+
LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}"
|
|
279
|
+
)
|
|
280
|
+
set_target_properties(
|
|
281
|
+
${TARGET_NAME}
|
|
282
|
+
PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}"
|
|
283
|
+
ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}"
|
|
284
|
+
LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}"
|
|
285
|
+
)
|
|
286
|
+
set_target_properties(
|
|
287
|
+
${TARGET_NAME}
|
|
288
|
+
PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_BINARY_DIR}"
|
|
289
|
+
ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_BINARY_DIR}"
|
|
290
|
+
LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_BINARY_DIR}"
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
# On Linux and MacOS our primary shared libraries for C are called `libusearch_c.so` and `libusearch_c.dylib`, while
|
|
294
|
+
# on Windows the "lib" prefix might be missing by default, so let's ensure it's always there
|
|
295
|
+
get_target_property(TARGET_TYPE ${TARGET_NAME} TYPE)
|
|
296
|
+
if (TARGET_TYPE STREQUAL "SHARED_LIBRARY" OR TARGET_TYPE STREQUAL "STATIC_LIBRARY")
|
|
297
|
+
set_target_properties(${TARGET_NAME} PROPERTIES PREFIX "lib")
|
|
298
|
+
endif ()
|
|
299
|
+
|
|
270
300
|
# Core compilation settings affecting "index.hpp"
|
|
271
301
|
target_compile_definitions(${TARGET_NAME} PRIVATE $<$<NOT:$<BOOL:${USEARCH_USE_OPENMP}>>:USEARCH_USE_OPENMP=0>)
|
|
272
302
|
|
package/Cargo.toml
CHANGED
package/README.md
CHANGED
package/build.gradle
CHANGED
|
@@ -36,6 +36,11 @@ task sourcesJar(type: Jar, dependsOn: classes) {
|
|
|
36
36
|
from sourceSets.main.allSource
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
task javadocJar(type: Jar, dependsOn: javadoc) {
|
|
40
|
+
archiveClassifier.set('javadoc')
|
|
41
|
+
from javadoc.destinationDir
|
|
42
|
+
}
|
|
43
|
+
|
|
39
44
|
dependencies {
|
|
40
45
|
testImplementation('junit:junit:4.13.2')
|
|
41
46
|
}
|
|
@@ -117,6 +122,7 @@ publishing {
|
|
|
117
122
|
from components.java
|
|
118
123
|
|
|
119
124
|
artifact sourcesJar
|
|
125
|
+
artifact javadocJar
|
|
120
126
|
|
|
121
127
|
if (project.hasProperty('signArtifacts') && signArtifacts.toBoolean()) {
|
|
122
128
|
signing {
|
package/c/README.md
CHANGED
|
@@ -6,9 +6,9 @@ The simplest form to integrate is to copy the contents of `usearch/c/` into your
|
|
|
6
6
|
To build the library `libusearch_static_c` and `libusearch_c`, pass enable the `USEARCH_BUILD_LIB_C` CMake option:
|
|
7
7
|
|
|
8
8
|
```bash
|
|
9
|
-
cmake -
|
|
10
|
-
|
|
11
|
-
./
|
|
9
|
+
cmake -DCMAKE_BUILD_TYPE=Release -DUSEARCH_BUILD_LIB_C=1 -DUSEARCH_BUILD_TEST_C=1 -DUSEARCH_BUILD_TEST_CPP=0 -DUSEARCH_BUILD_BENCH_CPP=0 -B ./build_release
|
|
10
|
+
cmake --build ./build_release --config Release
|
|
11
|
+
./build_release/test_c
|
|
12
12
|
```
|
|
13
13
|
|
|
14
14
|
## Quickstart
|
package/c/lib.cpp
CHANGED
|
@@ -13,16 +13,16 @@ using add_result_t = typename index_dense_t::add_result_t;
|
|
|
13
13
|
using search_result_t = typename index_dense_t::search_result_t;
|
|
14
14
|
using labeling_result_t = typename index_dense_t::labeling_result_t;
|
|
15
15
|
|
|
16
|
-
static_assert(std::is_same<usearch_key_t, index_dense_t::
|
|
16
|
+
static_assert(std::is_same<usearch_key_t, index_dense_t::vector_key_t>::value, "Type mismatch between C and C++");
|
|
17
17
|
static_assert(std::is_same<usearch_distance_t, index_dense_t::distance_t>::value, "Type mismatch between C and C++");
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
metric_kind_t to_native_metric(usearch_metric_kind_t kind) {
|
|
19
|
+
metric_kind_t metric_kind_to_cpp(usearch_metric_kind_t kind) {
|
|
21
20
|
switch (kind) {
|
|
22
21
|
case usearch_metric_ip_k: return metric_kind_t::ip_k;
|
|
23
22
|
case usearch_metric_l2sq_k: return metric_kind_t::l2sq_k;
|
|
24
23
|
case usearch_metric_cos_k: return metric_kind_t::cos_k;
|
|
25
24
|
case usearch_metric_haversine_k: return metric_kind_t::haversine_k;
|
|
25
|
+
case usearch_metric_divergence_k: return metric_kind_t::divergence_k;
|
|
26
26
|
case usearch_metric_pearson_k: return metric_kind_t::pearson_k;
|
|
27
27
|
case usearch_metric_jaccard_k: return metric_kind_t::jaccard_k;
|
|
28
28
|
case usearch_metric_hamming_k: return metric_kind_t::hamming_k;
|
|
@@ -32,7 +32,22 @@ metric_kind_t to_native_metric(usearch_metric_kind_t kind) {
|
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
usearch_metric_kind_t metric_kind_to_c(metric_kind_t kind) {
|
|
36
|
+
switch (kind) {
|
|
37
|
+
case metric_kind_t::ip_k: return usearch_metric_ip_k;
|
|
38
|
+
case metric_kind_t::l2sq_k: return usearch_metric_l2sq_k;
|
|
39
|
+
case metric_kind_t::cos_k: return usearch_metric_cos_k;
|
|
40
|
+
case metric_kind_t::haversine_k: return usearch_metric_haversine_k;
|
|
41
|
+
case metric_kind_t::divergence_k: return usearch_metric_divergence_k;
|
|
42
|
+
case metric_kind_t::pearson_k: return usearch_metric_pearson_k;
|
|
43
|
+
case metric_kind_t::jaccard_k: return usearch_metric_jaccard_k;
|
|
44
|
+
case metric_kind_t::hamming_k: return usearch_metric_hamming_k;
|
|
45
|
+
case metric_kind_t::tanimoto_k: return usearch_metric_tanimoto_k;
|
|
46
|
+
case metric_kind_t::sorensen_k: return usearch_metric_sorensen_k;
|
|
47
|
+
default: return usearch_metric_unknown_k;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
scalar_kind_t scalar_kind_to_cpp(usearch_scalar_kind_t kind) {
|
|
36
51
|
switch (kind) {
|
|
37
52
|
case usearch_scalar_f32_k: return scalar_kind_t::f32_k;
|
|
38
53
|
case usearch_scalar_f64_k: return scalar_kind_t::f64_k;
|
|
@@ -43,6 +58,17 @@ scalar_kind_t to_native_scalar(usearch_scalar_kind_t kind) {
|
|
|
43
58
|
}
|
|
44
59
|
}
|
|
45
60
|
|
|
61
|
+
usearch_scalar_kind_t scalar_kind_to_c(scalar_kind_t kind) {
|
|
62
|
+
switch (kind) {
|
|
63
|
+
case scalar_kind_t::f32_k: return usearch_scalar_f32_k;
|
|
64
|
+
case scalar_kind_t::f64_k: return usearch_scalar_f64_k;
|
|
65
|
+
case scalar_kind_t::f16_k: return usearch_scalar_f16_k;
|
|
66
|
+
case scalar_kind_t::i8_k: return usearch_scalar_i8_k;
|
|
67
|
+
case scalar_kind_t::b1x8_k: return usearch_scalar_b1_k;
|
|
68
|
+
default: return usearch_scalar_unknown_k;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
46
72
|
add_result_t add_(index_dense_t* index, usearch_key_t key, void const* vector, scalar_kind_t kind) {
|
|
47
73
|
switch (kind) {
|
|
48
74
|
case scalar_kind_t::f32_k: return index->add(key, (f32_t const*)vector);
|
|
@@ -84,8 +110,8 @@ USEARCH_EXPORT usearch_index_t usearch_init(usearch_init_options_t* options, use
|
|
|
84
110
|
|
|
85
111
|
index_dense_config_t config(options->connectivity, options->expansion_add, options->expansion_search);
|
|
86
112
|
config.multi = options->multi;
|
|
87
|
-
metric_kind_t metric_kind =
|
|
88
|
-
scalar_kind_t scalar_kind =
|
|
113
|
+
metric_kind_t metric_kind = metric_kind_to_cpp(options->metric_kind);
|
|
114
|
+
scalar_kind_t scalar_kind = scalar_kind_to_cpp(options->quantization);
|
|
89
115
|
|
|
90
116
|
metric_punned_t metric = //
|
|
91
117
|
!options->metric ? metric_punned_t(options->dimensions, metric_kind, scalar_kind)
|
|
@@ -134,6 +160,24 @@ USEARCH_EXPORT void usearch_view(usearch_index_t index, char const* path, usearc
|
|
|
134
160
|
*error = result.error.release();
|
|
135
161
|
}
|
|
136
162
|
|
|
163
|
+
USEARCH_EXPORT void usearch_metadata(char const* path, usearch_init_options_t* options, usearch_error_t* error) {
|
|
164
|
+
|
|
165
|
+
assert(path && options && error);
|
|
166
|
+
index_dense_metadata_result_t result = index_dense_metadata_from_path(path);
|
|
167
|
+
if (!result)
|
|
168
|
+
*error = result.error.release();
|
|
169
|
+
|
|
170
|
+
options->metric_kind = metric_kind_to_c(result.head.kind_metric);
|
|
171
|
+
options->quantization = scalar_kind_to_c(result.head.kind_scalar);
|
|
172
|
+
options->dimensions = result.head.dimensions;
|
|
173
|
+
options->multi = result.head.multi;
|
|
174
|
+
|
|
175
|
+
options->connectivity = 0;
|
|
176
|
+
options->expansion_add = 0;
|
|
177
|
+
options->expansion_search = 0;
|
|
178
|
+
options->metric = NULL;
|
|
179
|
+
}
|
|
180
|
+
|
|
137
181
|
USEARCH_EXPORT void usearch_save_buffer(usearch_index_t index, void* buffer, size_t length, usearch_error_t* error) {
|
|
138
182
|
|
|
139
183
|
assert(index && buffer && length && error);
|
|
@@ -163,6 +207,26 @@ USEARCH_EXPORT void usearch_view_buffer(usearch_index_t index, void const* buffe
|
|
|
163
207
|
*error = result.error.release();
|
|
164
208
|
}
|
|
165
209
|
|
|
210
|
+
USEARCH_EXPORT void usearch_metadata_buffer(void const* buffer, size_t length, usearch_init_options_t* options,
|
|
211
|
+
usearch_error_t* error) {
|
|
212
|
+
|
|
213
|
+
assert(buffer && length && options && error);
|
|
214
|
+
index_dense_metadata_result_t result =
|
|
215
|
+
index_dense_metadata_from_buffer(memory_mapped_file_t((byte_t*)(buffer), length));
|
|
216
|
+
if (!result)
|
|
217
|
+
*error = result.error.release();
|
|
218
|
+
|
|
219
|
+
options->metric_kind = metric_kind_to_c(result.head.kind_metric);
|
|
220
|
+
options->quantization = scalar_kind_to_c(result.head.kind_scalar);
|
|
221
|
+
options->dimensions = result.head.dimensions;
|
|
222
|
+
options->multi = result.head.multi;
|
|
223
|
+
|
|
224
|
+
options->connectivity = 0;
|
|
225
|
+
options->expansion_add = 0;
|
|
226
|
+
options->expansion_search = 0;
|
|
227
|
+
options->metric = NULL;
|
|
228
|
+
}
|
|
229
|
+
|
|
166
230
|
USEARCH_EXPORT size_t usearch_size(usearch_index_t index, usearch_error_t*) { //
|
|
167
231
|
return reinterpret_cast<index_dense_t*>(index)->size();
|
|
168
232
|
}
|
|
@@ -190,7 +254,7 @@ USEARCH_EXPORT void usearch_add(
|
|
|
190
254
|
usearch_error_t* error) {
|
|
191
255
|
|
|
192
256
|
assert(index && vector && error);
|
|
193
|
-
add_result_t result = add_(reinterpret_cast<index_dense_t*>(index), key, vector,
|
|
257
|
+
add_result_t result = add_(reinterpret_cast<index_dense_t*>(index), key, vector, scalar_kind_to_cpp(kind));
|
|
194
258
|
if (!result)
|
|
195
259
|
*error = result.error.release();
|
|
196
260
|
}
|
|
@@ -211,7 +275,7 @@ USEARCH_EXPORT size_t usearch_search(
|
|
|
211
275
|
|
|
212
276
|
assert(index && vector && error);
|
|
213
277
|
search_result_t result =
|
|
214
|
-
search_(reinterpret_cast<index_dense_t*>(index), vector,
|
|
278
|
+
search_(reinterpret_cast<index_dense_t*>(index), vector, scalar_kind_to_cpp(kind), results_limit);
|
|
215
279
|
if (!result) {
|
|
216
280
|
*error = result.error.release();
|
|
217
281
|
return 0;
|
|
@@ -225,7 +289,7 @@ USEARCH_EXPORT size_t usearch_get( //
|
|
|
225
289
|
void* vectors, usearch_scalar_kind_t kind, usearch_error_t*) {
|
|
226
290
|
|
|
227
291
|
assert(index && vectors);
|
|
228
|
-
return get_(reinterpret_cast<index_dense_t*>(index), key, count, vectors,
|
|
292
|
+
return get_(reinterpret_cast<index_dense_t*>(index), key, count, vectors, scalar_kind_to_cpp(kind));
|
|
229
293
|
}
|
|
230
294
|
|
|
231
295
|
USEARCH_EXPORT size_t usearch_remove(usearch_index_t index, usearch_key_t key, usearch_error_t* error) {
|
|
@@ -253,7 +317,7 @@ USEARCH_EXPORT usearch_distance_t usearch_distance( //
|
|
|
253
317
|
usearch_metric_kind_t metric_kind, usearch_error_t* error) {
|
|
254
318
|
|
|
255
319
|
(void)error;
|
|
256
|
-
metric_punned_t metric(dimensions,
|
|
320
|
+
metric_punned_t metric(dimensions, metric_kind_to_cpp(metric_kind), scalar_kind_to_cpp(scalar_kind));
|
|
257
321
|
return metric((byte_t const*)vector_first, (byte_t const*)vector_second);
|
|
258
322
|
}
|
|
259
323
|
|
|
@@ -266,7 +330,7 @@ USEARCH_EXPORT void usearch_exact_search( //
|
|
|
266
330
|
usearch_distance_t* distances, size_t distances_stride, //
|
|
267
331
|
usearch_error_t* error) {
|
|
268
332
|
|
|
269
|
-
metric_punned_t metric(dimensions,
|
|
333
|
+
metric_punned_t metric(dimensions, metric_kind_to_cpp(metric_kind), scalar_kind_to_cpp(scalar_kind));
|
|
270
334
|
executor_default_t executor(threads);
|
|
271
335
|
static exact_search_t search;
|
|
272
336
|
exact_search_results_t result = search( //
|
package/c/usearch.h
CHANGED
|
@@ -14,7 +14,8 @@ extern "C" {
|
|
|
14
14
|
#endif
|
|
15
15
|
|
|
16
16
|
#include <stdbool.h> // `bool`
|
|
17
|
-
#include <
|
|
17
|
+
#include <stddef.h> // `size_t`
|
|
18
|
+
#include <stdint.h> // `uint64_t`
|
|
18
19
|
|
|
19
20
|
USEARCH_EXPORT typedef void* usearch_index_t;
|
|
20
21
|
USEARCH_EXPORT typedef uint64_t usearch_key_t;
|
|
@@ -42,6 +43,7 @@ USEARCH_EXPORT typedef enum usearch_metric_kind_t {
|
|
|
42
43
|
usearch_metric_ip_k,
|
|
43
44
|
usearch_metric_l2sq_k,
|
|
44
45
|
usearch_metric_haversine_k,
|
|
46
|
+
usearch_metric_divergence_k,
|
|
45
47
|
usearch_metric_pearson_k,
|
|
46
48
|
usearch_metric_jaccard_k,
|
|
47
49
|
usearch_metric_hamming_k,
|
|
@@ -136,6 +138,15 @@ USEARCH_EXPORT void usearch_load(usearch_index_t, char const* path, usearch_erro
|
|
|
136
138
|
*/
|
|
137
139
|
USEARCH_EXPORT void usearch_view(usearch_index_t, char const* path, usearch_error_t* error);
|
|
138
140
|
|
|
141
|
+
/**
|
|
142
|
+
* @brief Loads index metadata from a file.
|
|
143
|
+
* @param[in] path The file path from where the index will be loaded.
|
|
144
|
+
* @param[out] options Pointer to the `usearch_init_options_t` structure to be populated.
|
|
145
|
+
* @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
|
|
146
|
+
* @return A handle to the initialized USearch index, or `NULL` on failure.
|
|
147
|
+
*/
|
|
148
|
+
USEARCH_EXPORT void usearch_metadata(char const* path, usearch_init_options_t* options, usearch_error_t* error);
|
|
149
|
+
|
|
139
150
|
/**
|
|
140
151
|
* @brief Saves the index to an in-memory buffer.
|
|
141
152
|
* @param[in] buffer The in-memory continuous buffer where the index will be saved.
|
|
@@ -157,6 +168,16 @@ USEARCH_EXPORT void usearch_load_buffer(usearch_index_t, void const* buffer, siz
|
|
|
157
168
|
*/
|
|
158
169
|
USEARCH_EXPORT void usearch_view_buffer(usearch_index_t, void const* buffer, size_t length, usearch_error_t* error);
|
|
159
170
|
|
|
171
|
+
/**
|
|
172
|
+
* @brief Loads index metadata from an in-memory buffer.
|
|
173
|
+
* @param[in] path The file path from where the index will be loaded.
|
|
174
|
+
* @param[out] options Pointer to the `usearch_init_options_t` structure to be populated.
|
|
175
|
+
* @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
|
|
176
|
+
* @return A handle to the initialized USearch index, or `NULL` on failure.
|
|
177
|
+
*/
|
|
178
|
+
USEARCH_EXPORT void usearch_metadata_buffer(void const* buffer, size_t length, usearch_init_options_t* options,
|
|
179
|
+
usearch_error_t* error);
|
|
180
|
+
|
|
160
181
|
USEARCH_EXPORT size_t usearch_size(usearch_index_t, usearch_error_t* error);
|
|
161
182
|
USEARCH_EXPORT size_t usearch_capacity(usearch_index_t, usearch_error_t* error);
|
|
162
183
|
USEARCH_EXPORT size_t usearch_dimensions(usearch_index_t, usearch_error_t* error);
|
package/conanfile.py
CHANGED
|
@@ -7,7 +7,7 @@ required_conan_version = ">=1.53.0"
|
|
|
7
7
|
class USearchConan(ConanFile):
|
|
8
8
|
|
|
9
9
|
name = "usearch"
|
|
10
|
-
version = '2.
|
|
10
|
+
version = '2.8.0'
|
|
11
11
|
license = "Apache-2.0"
|
|
12
12
|
description = "Smaller & Faster Single-File Vector Search Engine from Unum"
|
|
13
13
|
homepage = "https://github.com/unum-cloud/usearch"
|
package/cpp/README.md
CHANGED
|
@@ -21,7 +21,7 @@ using namespace unum::usearch;
|
|
|
21
21
|
metric_punned_t metric(256, metric_kind_t::l2sq_k, scalar_kind_t::f32_k);
|
|
22
22
|
|
|
23
23
|
// If you plan to store more than 4 Billion entries - use `index_dense_big_t`.
|
|
24
|
-
// Or directly instantiate the template variant you need - `index_dense_gt<
|
|
24
|
+
// Or directly instantiate the template variant you need - `index_dense_gt<vector_key_t, internal_id_t>`.
|
|
25
25
|
index_dense_t index = index_dense_t::make(metric);
|
|
26
26
|
float vec[3] = {0.1, 0.3, 0.2};
|
|
27
27
|
|
|
@@ -76,6 +76,7 @@ The following distances are pre-packaged:
|
|
|
76
76
|
- `metric_sorensen_gt<scalar_t>` for "Dice-Sorensen" coefficient for bit-strings.
|
|
77
77
|
- `metric_pearson_gt<scalar_t>` for "Pearson" correlation between probability distributions.
|
|
78
78
|
- `metric_haversine_gt<scalar_t>` for "Haversine" or "Great Circle" distance between coordinates used in GIS applications.
|
|
79
|
+
- `metric_divergence_gt<scalar_t>` for the "Jensen Shannon" similarity between probability distributions.
|
|
79
80
|
|
|
80
81
|
## Multi-Threading
|
|
81
82
|
|
package/cpp/bench.cpp
CHANGED
|
@@ -447,6 +447,7 @@ struct args_t {
|
|
|
447
447
|
bool metric_l2 = false;
|
|
448
448
|
bool metric_cos = false;
|
|
449
449
|
bool metric_haversine = false;
|
|
450
|
+
bool metric_divergence = false;
|
|
450
451
|
bool metric_hamming = false;
|
|
451
452
|
bool metric_tanimoto = false;
|
|
452
453
|
bool metric_sorensen = false;
|
|
@@ -458,6 +459,8 @@ struct args_t {
|
|
|
458
459
|
return metric_kind_t::cos_k;
|
|
459
460
|
if (metric_haversine)
|
|
460
461
|
return metric_kind_t::haversine_k;
|
|
462
|
+
if (metric_divergence)
|
|
463
|
+
return metric_kind_t::divergence_k;
|
|
461
464
|
if (metric_hamming)
|
|
462
465
|
return metric_kind_t::hamming_k;
|
|
463
466
|
if (metric_tanimoto)
|
package/cpp/test.cpp
CHANGED
|
@@ -25,15 +25,15 @@ void test_cosine(index_at& index, std::vector<std::vector<scalar_at>> const& vec
|
|
|
25
25
|
|
|
26
26
|
using scalar_t = scalar_at;
|
|
27
27
|
using index_t = index_at;
|
|
28
|
-
using
|
|
28
|
+
using vector_key_t = typename index_t::vector_key_t;
|
|
29
29
|
using distance_t = typename index_t::distance_t;
|
|
30
30
|
|
|
31
31
|
// Generate some keys starting from end,
|
|
32
32
|
// for three vectors from the dataset
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
vector_key_t const key_max = default_free_value<vector_key_t>() - 1;
|
|
34
|
+
vector_key_t const key_first = key_max - 0;
|
|
35
|
+
vector_key_t const key_second = key_max - 1;
|
|
36
|
+
vector_key_t const key_third = key_max - 2;
|
|
37
37
|
scalar_t const* vector_first = vectors[0].data();
|
|
38
38
|
scalar_t const* vector_second = vectors[1].data();
|
|
39
39
|
scalar_t const* vector_third = vectors[2].data();
|
|
@@ -50,7 +50,7 @@ void test_cosine(index_at& index, std::vector<std::vector<scalar_at>> const& vec
|
|
|
50
50
|
index.add(key_first, vector_first, args...);
|
|
51
51
|
|
|
52
52
|
// Default approximate search
|
|
53
|
-
|
|
53
|
+
vector_key_t matched_keys[10] = {0};
|
|
54
54
|
distance_t matched_distances[10] = {0};
|
|
55
55
|
std::size_t matched_count = index.search(vector_first, 5, args...).dump_to(matched_keys, matched_distances);
|
|
56
56
|
|
|
@@ -69,7 +69,7 @@ void test_cosine(index_at& index, std::vector<std::vector<scalar_at>> const& vec
|
|
|
69
69
|
// Validate scans
|
|
70
70
|
std::size_t count = 0;
|
|
71
71
|
for (auto member : index) {
|
|
72
|
-
|
|
72
|
+
vector_key_t id = member.key;
|
|
73
73
|
expect(id <= key_first && id >= key_third);
|
|
74
74
|
count++;
|
|
75
75
|
}
|
|
@@ -159,10 +159,10 @@ template <typename scalar_at, typename key_at, typename slot_at> //
|
|
|
159
159
|
void test_cosine(std::size_t collection_size, std::size_t dimensions) {
|
|
160
160
|
|
|
161
161
|
using scalar_t = scalar_at;
|
|
162
|
-
using
|
|
162
|
+
using vector_key_t = key_at;
|
|
163
163
|
using slot_t = slot_at;
|
|
164
164
|
|
|
165
|
-
using index_typed_t = index_gt<float,
|
|
165
|
+
using index_typed_t = index_gt<float, vector_key_t, slot_t>;
|
|
166
166
|
using member_cref_t = typename index_typed_t::member_cref_t;
|
|
167
167
|
using member_citerator_t = typename index_typed_t::member_citerator_t;
|
|
168
168
|
|
|
@@ -205,7 +205,7 @@ void test_cosine(std::size_t collection_size, std::size_t dimensions) {
|
|
|
205
205
|
for (bool multi : {false, true}) {
|
|
206
206
|
for (std::size_t connectivity : {3, 13, 50}) {
|
|
207
207
|
std::printf("- punned with connectivity %zu \n", connectivity);
|
|
208
|
-
using index_t = index_dense_gt<
|
|
208
|
+
using index_t = index_dense_gt<vector_key_t, slot_t>;
|
|
209
209
|
metric_punned_t metric(dimensions, metric_kind_t::cos_k, scalar_kind<scalar_at>());
|
|
210
210
|
index_dense_config_t config(connectivity);
|
|
211
211
|
config.multi = multi;
|
|
@@ -217,10 +217,10 @@ void test_cosine(std::size_t collection_size, std::size_t dimensions) {
|
|
|
217
217
|
|
|
218
218
|
template <typename key_at, typename slot_at> void test_tanimoto(std::size_t dimensions, std::size_t connectivity) {
|
|
219
219
|
|
|
220
|
-
using
|
|
220
|
+
using vector_key_t = key_at;
|
|
221
221
|
using slot_t = slot_at;
|
|
222
222
|
|
|
223
|
-
using index_punned_t = index_dense_gt<
|
|
223
|
+
using index_punned_t = index_dense_gt<vector_key_t, slot_t>;
|
|
224
224
|
std::size_t words = divide_round_up<CHAR_BIT>(dimensions);
|
|
225
225
|
metric_punned_t metric(words, metric_kind_t::tanimoto_k, scalar_kind_t::b1x8_k);
|
|
226
226
|
index_config_t config(connectivity);
|
package/docs/compilation.md
CHANGED
|
@@ -23,6 +23,7 @@ cmake -B ./build_release \
|
|
|
23
23
|
-DUSEARCH_BUILD_BENCH_CPP=1 \
|
|
24
24
|
-DUSEARCH_BUILD_LIB_C=1 \
|
|
25
25
|
-DUSEARCH_BUILD_TEST_C=1 \
|
|
26
|
+
-DUSEARCH_USE_NATIVE_F16=1 \
|
|
26
27
|
&& \
|
|
27
28
|
make -C ./build_release -j
|
|
28
29
|
```
|
|
@@ -157,18 +158,6 @@ swift test -v
|
|
|
157
158
|
There are a few ways to compile the C 99 USearch SDK.
|
|
158
159
|
Using the Makefile, specifying the targets you need:
|
|
159
160
|
|
|
160
|
-
```sh
|
|
161
|
-
make -C ./c libusearch_c.so
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
With options:
|
|
165
|
-
|
|
166
|
-
```sh
|
|
167
|
-
make USEARCH_USE_OPENMP=1 USEARCH_USE_SIMSIMD=1 -C ./c libusearch_c.so
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
Using CMake:
|
|
171
|
-
|
|
172
161
|
```sh
|
|
173
162
|
cmake -B ./build_release -DUSEARCH_BUILD_LIB_C=1 -DUSEARCH_BUILD_TEST_C=1 -DUSEARCH_USE_OPENMP=1 -DUSEARCH_USE_SIMSIMD=1
|
|
174
163
|
cmake --build ./build_release --config Release -j
|
|
@@ -183,7 +172,10 @@ GoLang bindings are based on C.
|
|
|
183
172
|
So one should first compile the C library, link it with GoLang, and only then run tests.
|
|
184
173
|
|
|
185
174
|
```sh
|
|
186
|
-
|
|
175
|
+
cmake -B ./build_release -DUSEARCH_BUILD_LIB_C=1 -DUSEARCH_BUILD_TEST_C=1 -DUSEARCH_USE_OPENMP=1 -DUSEARCH_USE_SIMSIMD=1
|
|
176
|
+
cmake --build ./build_release --config Release -j
|
|
177
|
+
mv ./c/libusearch_c.so ./golang/
|
|
178
|
+
cp ./c/usearch.h ./golang/
|
|
187
179
|
cd golang && go test -v ; cd ..
|
|
188
180
|
```
|
|
189
181
|
|
package/golang/lib.go
CHANGED
|
@@ -6,7 +6,7 @@ import (
|
|
|
6
6
|
)
|
|
7
7
|
|
|
8
8
|
/*
|
|
9
|
-
#cgo LDFLAGS: -L. -lusearch_c
|
|
9
|
+
#cgo LDFLAGS: -L. -L/usr/local/lib -lusearch_c
|
|
10
10
|
#include "usearch.h"
|
|
11
11
|
#include <stdlib.h>
|
|
12
12
|
*/
|
|
@@ -21,6 +21,7 @@ const (
|
|
|
21
21
|
Cosine
|
|
22
22
|
L2sq
|
|
23
23
|
Haversine
|
|
24
|
+
Divergence
|
|
24
25
|
Pearson
|
|
25
26
|
Hamming
|
|
26
27
|
Tanimoto
|
|
@@ -37,6 +38,8 @@ func (m Metric) String() string {
|
|
|
37
38
|
return "cos"
|
|
38
39
|
case Haversine:
|
|
39
40
|
return "haversine"
|
|
41
|
+
case Divergence:
|
|
42
|
+
return "divergence"
|
|
40
43
|
case Pearson:
|
|
41
44
|
return "pearson"
|
|
42
45
|
case Hamming:
|