usearch 2.7.7 → 2.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dockerignore +93 -0
- package/.github/workflows/Dockerfile.libs +6 -2
- package/.github/workflows/prerelease.yml +242 -245
- package/.github/workflows/release.yml +399 -357
- 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/pyproject.toml +10 -8
- 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 +47 -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
|
@@ -44,10 +44,22 @@
|
|
|
44
44
|
// Propagate the `f16` settings
|
|
45
45
|
#define SIMSIMD_NATIVE_F16 USEARCH_USE_NATIVE_F16
|
|
46
46
|
#if defined(USEARCH_DEFINED_LINUX)
|
|
47
|
+
#define SIMSIMD_TARGET_X86_AVX512 1
|
|
48
|
+
#define SIMSIMD_TARGET_ARM_SVE 1
|
|
49
|
+
#define SIMSIMD_TARGET_X86_AVX2 1
|
|
50
|
+
#define SIMSIMD_TARGET_ARM_NEON 1
|
|
47
51
|
#include <simsimd/simsimd.h>
|
|
48
52
|
#elif defined(USEARCH_DEFINED_APPLE)
|
|
49
53
|
#define SIMSIMD_TARGET_X86_AVX512 0
|
|
50
54
|
#define SIMSIMD_TARGET_ARM_SVE 0
|
|
55
|
+
#define SIMSIMD_TARGET_X86_AVX2 1
|
|
56
|
+
#define SIMSIMD_TARGET_ARM_NEON 1
|
|
57
|
+
#include <simsimd/simsimd.h>
|
|
58
|
+
#else
|
|
59
|
+
#define SIMSIMD_TARGET_X86_AVX512 0
|
|
60
|
+
#define SIMSIMD_TARGET_ARM_SVE 0
|
|
61
|
+
#define SIMSIMD_TARGET_X86_AVX2 0
|
|
62
|
+
#define SIMSIMD_TARGET_ARM_NEON 0
|
|
51
63
|
#include <simsimd/simsimd.h>
|
|
52
64
|
#endif
|
|
53
65
|
#endif
|
|
@@ -100,6 +112,7 @@ enum class metric_kind_t : std::uint8_t {
|
|
|
100
112
|
// Custom:
|
|
101
113
|
pearson_k = 'p',
|
|
102
114
|
haversine_k = 'h',
|
|
115
|
+
divergence_k = 'd',
|
|
103
116
|
|
|
104
117
|
// Sets:
|
|
105
118
|
jaccard_k = 'j',
|
|
@@ -227,6 +240,7 @@ inline char const* metric_kind_name(metric_kind_t metric) noexcept {
|
|
|
227
240
|
case metric_kind_t::l2sq_k: return "l2sq";
|
|
228
241
|
case metric_kind_t::pearson_k: return "pearson";
|
|
229
242
|
case metric_kind_t::haversine_k: return "haversine";
|
|
243
|
+
case metric_kind_t::divergence_k: return "divergence";
|
|
230
244
|
case metric_kind_t::jaccard_k: return "jaccard";
|
|
231
245
|
case metric_kind_t::hamming_k: return "hamming";
|
|
232
246
|
case metric_kind_t::tanimoto_k: return "tanimoto";
|
|
@@ -263,6 +277,8 @@ inline expected_gt<metric_kind_t> metric_from_name(char const* name, std::size_t
|
|
|
263
277
|
parsed.result = metric_kind_t::cos_k;
|
|
264
278
|
} else if (str_equals(name, len, "haversine")) {
|
|
265
279
|
parsed.result = metric_kind_t::haversine_k;
|
|
280
|
+
} else if (str_equals(name, len, "divergence")) {
|
|
281
|
+
parsed.result = metric_kind_t::divergence_k;
|
|
266
282
|
} else if (str_equals(name, len, "pearson")) {
|
|
267
283
|
parsed.result = metric_kind_t::pearson_k;
|
|
268
284
|
} else if (str_equals(name, len, "hamming")) {
|
|
@@ -272,8 +288,8 @@ inline expected_gt<metric_kind_t> metric_from_name(char const* name, std::size_t
|
|
|
272
288
|
} else if (str_equals(name, len, "sorensen")) {
|
|
273
289
|
parsed.result = metric_kind_t::sorensen_k;
|
|
274
290
|
} else
|
|
275
|
-
parsed.failed(
|
|
276
|
-
|
|
291
|
+
parsed.failed("Unknown distance, choose: l2sq, ip, cos, haversine, divergence, jaccard, pearson, hamming, "
|
|
292
|
+
"tanimoto, sorensen");
|
|
277
293
|
return parsed;
|
|
278
294
|
}
|
|
279
295
|
|
|
@@ -556,7 +572,9 @@ class aligned_allocator_gt {
|
|
|
556
572
|
using size_type = std::size_t;
|
|
557
573
|
using pointer = element_at*;
|
|
558
574
|
using const_pointer = element_at const*;
|
|
559
|
-
template <typename other_element_at> struct rebind {
|
|
575
|
+
template <typename other_element_at> struct rebind {
|
|
576
|
+
using other = aligned_allocator_gt<other_element_at>;
|
|
577
|
+
};
|
|
560
578
|
|
|
561
579
|
constexpr std::size_t alignment() const { return alignment_ak; }
|
|
562
580
|
|
|
@@ -1166,6 +1184,32 @@ template <typename scalar_at = float, typename result_at = float> struct metric_
|
|
|
1166
1184
|
}
|
|
1167
1185
|
};
|
|
1168
1186
|
|
|
1187
|
+
/**
|
|
1188
|
+
* @brief Measures Jensen-Shannon Divergence between two probability distributions.
|
|
1189
|
+
*/
|
|
1190
|
+
template <typename scalar_at = float, typename result_at = float> struct metric_divergence_gt {
|
|
1191
|
+
using scalar_t = scalar_at;
|
|
1192
|
+
using result_t = result_at;
|
|
1193
|
+
|
|
1194
|
+
inline result_t operator()(scalar_t const* p, scalar_t const* q, std::size_t dim) const noexcept {
|
|
1195
|
+
result_t kld_pm{}, kld_qm{};
|
|
1196
|
+
scalar_t epsilon = std::numeric_limits<scalar_t>::epsilon();
|
|
1197
|
+
#if USEARCH_USE_OPENMP
|
|
1198
|
+
#pragma omp simd reduction(+ : kld_pm, kld_qm)
|
|
1199
|
+
#elif defined(USEARCH_DEFINED_CLANG)
|
|
1200
|
+
#pragma clang loop vectorize(enable)
|
|
1201
|
+
#elif defined(USEARCH_DEFINED_GCC)
|
|
1202
|
+
#pragma GCC ivdep
|
|
1203
|
+
#endif
|
|
1204
|
+
for (std::size_t i = 0; i != dim; ++i) {
|
|
1205
|
+
result_t mi = result_t(p[i] + q[i]) / 2 + epsilon;
|
|
1206
|
+
kld_pm += p[i] * std::log((p[i] + epsilon) / mi);
|
|
1207
|
+
kld_qm += q[i] * std::log((q[i] + epsilon) / mi);
|
|
1208
|
+
}
|
|
1209
|
+
return (kld_pm + kld_qm) / 2;
|
|
1210
|
+
}
|
|
1211
|
+
};
|
|
1212
|
+
|
|
1169
1213
|
struct cos_i8_t {
|
|
1170
1214
|
using scalar_t = i8_t;
|
|
1171
1215
|
using result_t = f32_t;
|
|
@@ -1344,8 +1388,8 @@ class metric_punned_t {
|
|
|
1344
1388
|
}
|
|
1345
1389
|
|
|
1346
1390
|
private:
|
|
1347
|
-
bool configure_with_simsimd() noexcept {
|
|
1348
1391
|
#if USEARCH_USE_SIMSIMD
|
|
1392
|
+
bool configure_with_simsimd(simsimd_capability_t simd_caps) noexcept {
|
|
1349
1393
|
simsimd_metric_kind_t kind = simsimd_metric_unknown_k;
|
|
1350
1394
|
simsimd_datatype_t datatype = simsimd_datatype_unknown_k;
|
|
1351
1395
|
simsimd_capability_t allowed = simsimd_cap_any_k;
|
|
@@ -1355,6 +1399,7 @@ class metric_punned_t {
|
|
|
1355
1399
|
case metric_kind_t::l2sq_k: kind = simsimd_metric_l2sq_k; break;
|
|
1356
1400
|
case metric_kind_t::hamming_k: kind = simsimd_metric_hamming_k; break;
|
|
1357
1401
|
case metric_kind_t::jaccard_k: kind = simsimd_metric_jaccard_k; break;
|
|
1402
|
+
default: break;
|
|
1358
1403
|
}
|
|
1359
1404
|
switch (scalar_kind_) {
|
|
1360
1405
|
case scalar_kind_t::f32_k: datatype = simsimd_datatype_f32_k; break;
|
|
@@ -1362,20 +1407,25 @@ class metric_punned_t {
|
|
|
1362
1407
|
case scalar_kind_t::f16_k: datatype = simsimd_datatype_f16_k; break;
|
|
1363
1408
|
case scalar_kind_t::i8_k: datatype = simsimd_datatype_i8_k; break;
|
|
1364
1409
|
case scalar_kind_t::b1x8_k: datatype = simsimd_datatype_b8_k; break;
|
|
1410
|
+
default: break;
|
|
1365
1411
|
}
|
|
1366
1412
|
simsimd_metric_punned_t simd_metric = NULL;
|
|
1367
1413
|
simsimd_capability_t simd_kind = simsimd_cap_any_k;
|
|
1368
|
-
simsimd_find_metric_punned(kind, datatype,
|
|
1414
|
+
simsimd_find_metric_punned(kind, datatype, simd_caps, allowed, &simd_metric, &simd_kind);
|
|
1369
1415
|
if (simd_metric == nullptr)
|
|
1370
1416
|
return false;
|
|
1371
1417
|
|
|
1372
1418
|
raw_ptr_ = (punned_ptr_t)simd_metric;
|
|
1373
1419
|
isa_kind_ = simd_kind;
|
|
1374
1420
|
return true;
|
|
1421
|
+
}
|
|
1422
|
+
bool configure_with_simsimd() noexcept {
|
|
1423
|
+
static simsimd_capability_t static_capabilities = simsimd_capabilities();
|
|
1424
|
+
return configure_with_simsimd(static_capabilities);
|
|
1425
|
+
}
|
|
1375
1426
|
#else
|
|
1376
|
-
|
|
1427
|
+
bool configure_with_simsimd() noexcept { return false; }
|
|
1377
1428
|
#endif
|
|
1378
|
-
}
|
|
1379
1429
|
|
|
1380
1430
|
void configure_with_auto_vectorized() noexcept {
|
|
1381
1431
|
switch (metric_kind_) {
|
|
@@ -1432,6 +1482,17 @@ class metric_punned_t {
|
|
|
1432
1482
|
}
|
|
1433
1483
|
break;
|
|
1434
1484
|
}
|
|
1485
|
+
case metric_kind_t::divergence_k: {
|
|
1486
|
+
switch (scalar_kind_) {
|
|
1487
|
+
case scalar_kind_t::f16_k:
|
|
1488
|
+
raw_ptr_ = (punned_ptr_t)&equidimensional_<metric_divergence_gt<f16_t, f32_t>>;
|
|
1489
|
+
break;
|
|
1490
|
+
case scalar_kind_t::f32_k: raw_ptr_ = (punned_ptr_t)&equidimensional_<metric_divergence_gt<f32_t>>; break;
|
|
1491
|
+
case scalar_kind_t::f64_k: raw_ptr_ = (punned_ptr_t)&equidimensional_<metric_divergence_gt<f64_t>>; break;
|
|
1492
|
+
default: raw_ptr_ = nullptr; break;
|
|
1493
|
+
}
|
|
1494
|
+
break;
|
|
1495
|
+
}
|
|
1435
1496
|
case metric_kind_t::jaccard_k: // Equivalent to Tanimoto
|
|
1436
1497
|
case metric_kind_t::tanimoto_k:
|
|
1437
1498
|
raw_ptr_ = (punned_ptr_t)&equidimensional_<metric_tanimoto_gt<b1x8_t>>,
|
|
@@ -2118,7 +2179,8 @@ class flat_hash_multi_set_gt {
|
|
|
2118
2179
|
slot_ref_t slot = slot_ref(slot_index);
|
|
2119
2180
|
if ((~slot.header.populated & slot.mask) | (slot.header.deleted & slot.mask)) {
|
|
2120
2181
|
// Found an empty or deleted slot
|
|
2121
|
-
|
|
2182
|
+
populate_slot(slot, element);
|
|
2183
|
+
++populated_slots_;
|
|
2122
2184
|
return true;
|
|
2123
2185
|
}
|
|
2124
2186
|
// Move to the next slot
|
|
@@ -1,83 +1,170 @@
|
|
|
1
1
|
package cloud.unum.usearch;
|
|
2
2
|
|
|
3
3
|
import java.io.File;
|
|
4
|
+
import java.io.InputStream;
|
|
4
5
|
import java.nio.file.Files;
|
|
5
6
|
import java.nio.file.StandardCopyOption;
|
|
6
|
-
import java.io.InputStream;
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
9
|
+
* Java bindings for Unum USearch.
|
|
10
|
+
* <p>
|
|
11
|
+
* Provides interface to interact with USearch library and perform various operations related to indexing and searching.
|
|
12
|
+
*
|
|
13
|
+
* @see <a href="https://nachtimwald.com/2017/06/06/wrapping-a-c-library-in-java/">Wrapping a C library in Java</a>
|
|
14
|
+
* @see <a href="https://www3.ntu.edu.sg/home/ehchua/programming/java/javanativeinterface.html">Java Native Interface tutorial</a>
|
|
14
15
|
*/
|
|
15
16
|
public class Index {
|
|
16
17
|
|
|
17
18
|
private long c_ptr = 0;
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Creates a new instance of Index with specified parameters.
|
|
22
|
+
*
|
|
23
|
+
* @param metric the metric type for distance calculation between vectors
|
|
24
|
+
* @param quantization the scalar type for quantization of vector data
|
|
25
|
+
* @param dimensions the number of dimensions in the vectors
|
|
26
|
+
* @param capacity the initial capacity of the index
|
|
27
|
+
* @param connectivity the connectivity parameter that limits connections-per-node in graph
|
|
28
|
+
* @param expansion_add the expansion factor used for index construction when adding vectors
|
|
29
|
+
* @param expansion_search the expansion factor used for index construction during search operations
|
|
30
|
+
*/
|
|
31
|
+
public Index(
|
|
32
|
+
String metric,
|
|
33
|
+
String quantization, //
|
|
34
|
+
long dimensions,
|
|
35
|
+
long capacity,
|
|
36
|
+
long connectivity, //
|
|
37
|
+
long expansion_add,
|
|
38
|
+
long expansion_search
|
|
39
|
+
) {
|
|
40
|
+
c_ptr =
|
|
41
|
+
c_create(
|
|
23
42
|
metric,
|
|
24
43
|
quantization,
|
|
25
44
|
dimensions,
|
|
26
45
|
capacity,
|
|
27
46
|
connectivity,
|
|
28
47
|
expansion_add,
|
|
29
|
-
expansion_search
|
|
48
|
+
expansion_search
|
|
49
|
+
);
|
|
30
50
|
}
|
|
31
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Retrieves the current size of the index.
|
|
54
|
+
*
|
|
55
|
+
* @return the number of vectors currently indexed.
|
|
56
|
+
*/
|
|
32
57
|
public long size() {
|
|
33
58
|
return c_size(c_ptr);
|
|
34
59
|
}
|
|
35
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Retrieves the connectivity parameter of the index.
|
|
63
|
+
*
|
|
64
|
+
* @return the connectivity parameter that limits connections-per-node in graph.
|
|
65
|
+
*/
|
|
36
66
|
public long connectivity() {
|
|
37
67
|
return c_connectivity(c_ptr);
|
|
38
68
|
}
|
|
39
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Retrieves the number of dimensions of the vectors in the index.
|
|
72
|
+
*
|
|
73
|
+
* @return the number of dimensions in the vectors.
|
|
74
|
+
*/
|
|
40
75
|
public long dimensions() {
|
|
41
76
|
return c_dimensions(c_ptr);
|
|
42
77
|
}
|
|
43
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Retrieves the current capacity of the index.
|
|
81
|
+
*
|
|
82
|
+
* @return the total capacity including current size.
|
|
83
|
+
*/
|
|
44
84
|
public long capacity() {
|
|
45
85
|
return c_capacity(c_ptr);
|
|
46
86
|
}
|
|
47
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Reserves memory for a specified number of incoming vectors.
|
|
90
|
+
*
|
|
91
|
+
* @param capacity the desired total capacity including current size.
|
|
92
|
+
*/
|
|
48
93
|
public void reserve(long capacity) {
|
|
49
94
|
c_reserve(c_ptr, capacity);
|
|
50
95
|
}
|
|
51
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Adds a vector with a specified key to the index.
|
|
99
|
+
*
|
|
100
|
+
* @param key the key associated with the vector
|
|
101
|
+
* @param vector the vector data
|
|
102
|
+
*/
|
|
52
103
|
public void add(int key, float vector[]) {
|
|
53
104
|
c_add(c_ptr, key, vector);
|
|
54
105
|
}
|
|
55
106
|
|
|
107
|
+
/**
|
|
108
|
+
* Searches for closest vectors to the specified query vector.
|
|
109
|
+
*
|
|
110
|
+
* @param vector the query vector data
|
|
111
|
+
* @param count the number of nearest neighbors to search
|
|
112
|
+
* @return an array of keys of the nearest neighbors
|
|
113
|
+
*/
|
|
56
114
|
public int[] search(float vector[], long count) {
|
|
57
115
|
return c_search(c_ptr, vector, count);
|
|
58
116
|
}
|
|
59
117
|
|
|
118
|
+
/**
|
|
119
|
+
* Saves the index to a file.
|
|
120
|
+
*
|
|
121
|
+
* @param path the file path where the index will be saved.
|
|
122
|
+
*/
|
|
60
123
|
public void save(String path) {
|
|
61
124
|
c_save(c_ptr, path);
|
|
62
125
|
}
|
|
63
126
|
|
|
127
|
+
/**
|
|
128
|
+
* Loads the index from a file.
|
|
129
|
+
*
|
|
130
|
+
* @param path the file path from where the index will be loaded.
|
|
131
|
+
*/
|
|
64
132
|
public void load(String path) {
|
|
65
133
|
c_load(c_ptr, path);
|
|
66
134
|
}
|
|
67
135
|
|
|
136
|
+
/**
|
|
137
|
+
* Creates a view of the index from a file without copying it into memory.
|
|
138
|
+
*
|
|
139
|
+
* @param path the file path from where the view will be created.
|
|
140
|
+
*/
|
|
68
141
|
public void view(String path) {
|
|
69
142
|
c_view(c_ptr, path);
|
|
70
143
|
}
|
|
71
144
|
|
|
145
|
+
/**
|
|
146
|
+
* Removes the vector associated with the given key from the index.
|
|
147
|
+
*
|
|
148
|
+
* @param key the key of the vector to be removed.
|
|
149
|
+
* @return {@code true} if the vector was successfully removed, {@code false} otherwise.
|
|
150
|
+
*/
|
|
72
151
|
public boolean remove(int key) {
|
|
73
152
|
return c_remove(c_ptr, key);
|
|
74
153
|
}
|
|
75
|
-
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Renames the vector to map to a different key.
|
|
157
|
+
*
|
|
158
|
+
* @param from the key of the vector to be renamed.
|
|
159
|
+
* @param to the new key for the vector.
|
|
160
|
+
* @return {@code true} if the vector was successfully renamed, {@code false} otherwise.
|
|
161
|
+
*/
|
|
76
162
|
public boolean rename(int from, int to) {
|
|
77
163
|
return c_rename(c_ptr, from, to);
|
|
78
164
|
}
|
|
79
165
|
|
|
80
166
|
public static class Config {
|
|
167
|
+
|
|
81
168
|
private String _metric = "ip";
|
|
82
169
|
private String _quantization = "f32";
|
|
83
170
|
private long _dimensions = 0;
|
|
@@ -86,18 +173,18 @@ public class Index {
|
|
|
86
173
|
private long _expansion_add = 0;
|
|
87
174
|
private long _expansion_search = 0;
|
|
88
175
|
|
|
89
|
-
public Config() {
|
|
90
|
-
}
|
|
176
|
+
public Config() {}
|
|
91
177
|
|
|
92
178
|
public Index build() {
|
|
93
179
|
return new Index(
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
180
|
+
_metric,
|
|
181
|
+
_quantization,
|
|
182
|
+
_dimensions,
|
|
183
|
+
_capacity,
|
|
184
|
+
_connectivity,
|
|
185
|
+
_expansion_add,
|
|
186
|
+
_expansion_search
|
|
187
|
+
);
|
|
101
188
|
}
|
|
102
189
|
|
|
103
190
|
public Config metric(String _metric) {
|
|
@@ -146,10 +233,15 @@ public class Index {
|
|
|
146
233
|
System.out.println("Java tests passed!");
|
|
147
234
|
}
|
|
148
235
|
|
|
149
|
-
private static native long c_create(//
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
236
|
+
private static native long c_create( //
|
|
237
|
+
String metric,
|
|
238
|
+
String quantization, //
|
|
239
|
+
long dimensions,
|
|
240
|
+
long capacity,
|
|
241
|
+
long connectivity, //
|
|
242
|
+
long expansion_add,
|
|
243
|
+
long expansion_search
|
|
244
|
+
);
|
|
153
245
|
|
|
154
246
|
private static native void c_destroy(long ptr);
|
|
155
247
|
|
|
@@ -176,4 +268,4 @@ public class Index {
|
|
|
176
268
|
private static native boolean c_remove(long ptr, int key);
|
|
177
269
|
|
|
178
270
|
private static native boolean c_rename(long ptr, int from, int to);
|
|
179
|
-
}
|
|
271
|
+
}
|
|
@@ -124,10 +124,10 @@ JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1add( //
|
|
|
124
124
|
jsize vector_dims = (*env).GetArrayLength(vector);
|
|
125
125
|
float_span_t vector_span = float_span_t{vector_data, static_cast<std::size_t>(vector_dims)};
|
|
126
126
|
|
|
127
|
-
using
|
|
127
|
+
using vector_key_t = typename index_dense_t::vector_key_t;
|
|
128
128
|
using add_result_t = typename index_dense_t::add_result_t;
|
|
129
129
|
|
|
130
|
-
add_result_t result = reinterpret_cast<index_dense_t*>(c_ptr)->add(static_cast<
|
|
130
|
+
add_result_t result = reinterpret_cast<index_dense_t*>(c_ptr)->add(static_cast<vector_key_t>(key), vector_span);
|
|
131
131
|
if (!result) {
|
|
132
132
|
jclass jc = (*env).FindClass("java/lang/Error");
|
|
133
133
|
if (jc)
|
|
@@ -152,13 +152,13 @@ JNIEXPORT jintArray JNICALL Java_cloud_unum_usearch_Index_c_1search( //
|
|
|
152
152
|
jsize vector_dims = (*env).GetArrayLength(vector);
|
|
153
153
|
float_span_t vector_span = float_span_t{vector_data, static_cast<std::size_t>(vector_dims)};
|
|
154
154
|
|
|
155
|
-
using
|
|
155
|
+
using vector_key_t = typename index_dense_t::vector_key_t;
|
|
156
156
|
using search_result_t = typename index_dense_t::search_result_t;
|
|
157
157
|
|
|
158
158
|
search_result_t result =
|
|
159
159
|
reinterpret_cast<index_dense_t*>(c_ptr)->search(vector_span, static_cast<std::size_t>(wanted));
|
|
160
160
|
if (result) {
|
|
161
|
-
std::size_t found = result.dump_to(reinterpret_cast<
|
|
161
|
+
std::size_t found = result.dump_to(reinterpret_cast<vector_key_t*>(matches_data), NULL);
|
|
162
162
|
(*env).SetIntArrayRegion(matches, 0, found, matches_data);
|
|
163
163
|
} else {
|
|
164
164
|
jclass jc = (*env).FindClass("java/lang/Error");
|
|
@@ -172,9 +172,9 @@ JNIEXPORT jintArray JNICALL Java_cloud_unum_usearch_Index_c_1search( //
|
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
JNIEXPORT bool JNICALL Java_cloud_unum_usearch_Index_c_1remove(JNIEnv* env, jclass, jlong c_ptr, jlong key) {
|
|
175
|
-
using
|
|
175
|
+
using vector_key_t = typename index_dense_t::vector_key_t;
|
|
176
176
|
using labeling_result_t = typename index_dense_t::labeling_result_t;
|
|
177
|
-
labeling_result_t result = reinterpret_cast<index_dense_t*>(c_ptr)->remove(static_cast<
|
|
177
|
+
labeling_result_t result = reinterpret_cast<index_dense_t*>(c_ptr)->remove(static_cast<vector_key_t>(key));
|
|
178
178
|
if (!result) {
|
|
179
179
|
jclass jc = (*env).FindClass("java/lang/Error");
|
|
180
180
|
if (jc)
|
|
@@ -184,10 +184,10 @@ JNIEXPORT bool JNICALL Java_cloud_unum_usearch_Index_c_1remove(JNIEnv* env, jcla
|
|
|
184
184
|
}
|
|
185
185
|
|
|
186
186
|
JNIEXPORT bool JNICALL Java_cloud_unum_usearch_Index_c_1rename(JNIEnv* env, jclass, jlong c_ptr, jlong from, jlong to) {
|
|
187
|
-
using
|
|
187
|
+
using vector_key_t = typename index_dense_t::vector_key_t;
|
|
188
188
|
using labeling_result_t = typename index_dense_t::labeling_result_t;
|
|
189
189
|
labeling_result_t result =
|
|
190
|
-
reinterpret_cast<index_dense_t*>(c_ptr)->rename(static_cast<
|
|
190
|
+
reinterpret_cast<index_dense_t*>(c_ptr)->rename(static_cast<vector_key_t>(from), static_cast<vector_key_t>(to));
|
|
191
191
|
if (!result) {
|
|
192
192
|
jclass jc = (*env).FindClass("java/lang/Error");
|
|
193
193
|
if (jc)
|
package/javascript/usearch.js
CHANGED
package/objc/USearchObjective.mm
CHANGED
|
@@ -14,7 +14,7 @@ using labeling_result_t = typename index_dense_t::labeling_result_t;
|
|
|
14
14
|
using search_result_t = typename index_dense_t::search_result_t;
|
|
15
15
|
using shared_index_dense_t = std::shared_ptr<index_dense_t>;
|
|
16
16
|
|
|
17
|
-
static_assert(std::is_same<USearchKey, index_dense_t::
|
|
17
|
+
static_assert(std::is_same<USearchKey, index_dense_t::vector_key_t>::value, "Type mismatch between Objective-C and C++");
|
|
18
18
|
|
|
19
19
|
metric_kind_t to_native_metric(USearchMetric m) {
|
|
20
20
|
switch (m) {
|
|
@@ -33,6 +33,9 @@ metric_kind_t to_native_metric(USearchMetric m) {
|
|
|
33
33
|
case USearchMetricHaversine:
|
|
34
34
|
return metric_kind_t::haversine_k;
|
|
35
35
|
|
|
36
|
+
case USearchMetricDivergence:
|
|
37
|
+
return metric_kind_t::divergence_k;
|
|
38
|
+
|
|
36
39
|
case USearchMetricJaccard:
|
|
37
40
|
return metric_kind_t::jaccard_k;
|
|
38
41
|
|
package/package.json
CHANGED
package/pyproject.toml
CHANGED
|
@@ -8,9 +8,13 @@ addopts = ["-ra", "--showlocals", "--strict-markers", "--strict-config"]
|
|
|
8
8
|
xfail_strict = true
|
|
9
9
|
filterwarnings = ["error"]
|
|
10
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"
|
|
11
15
|
[tool.cibuildwheel]
|
|
12
|
-
test-requires = [
|
|
13
|
-
test-command = "
|
|
16
|
+
test-requires = []
|
|
17
|
+
test-command = ""
|
|
14
18
|
build-verbosity = 0
|
|
15
19
|
skip = ["*musllinux*", "*i686*", "pp*", "cp36-*", "cp312-*"]
|
|
16
20
|
|
|
@@ -18,22 +22,20 @@ skip = ["*musllinux*", "*i686*", "pp*", "cp36-*", "cp312-*"]
|
|
|
18
22
|
before-build = [
|
|
19
23
|
"rm -rf {project}/CMakeCache.txt {project}/build {project}/build_debug {project}/CMakeFiles.txt {project}/_deps {project}/.pytest_cache",
|
|
20
24
|
"mkdir -p build/usearch",
|
|
21
|
-
"git submodule update --init --recursive"
|
|
25
|
+
"git submodule update --init --recursive",
|
|
22
26
|
]
|
|
23
27
|
manylinux-x86_64-image = "manylinux_2_28"
|
|
24
28
|
manylinux-aarch64-image = "manylinux_2_28"
|
|
25
29
|
|
|
26
30
|
archs = ["x86_64", "aarch64"]
|
|
27
|
-
before-all = [
|
|
28
|
-
"yum install -y glibc-devel wget python3-devel"
|
|
29
|
-
]
|
|
31
|
+
before-all = ["yum install -y glibc-devel wget python3-devel"]
|
|
30
32
|
repair-wheel-command = "auditwheel repair --lib-sdir . -w {dest_dir} {wheel}"
|
|
31
33
|
|
|
32
34
|
[tool.cibuildwheel.macos]
|
|
33
35
|
before-build = [
|
|
34
36
|
"rm -rf {project}/CMakeCache.txt {project}/build {project}/build_debug {project}/CMakeFiles.txt {project}/_deps {project}/.pytest_cache",
|
|
35
37
|
"mkdir -p build/usearch",
|
|
36
|
-
"git submodule update --init --recursive"
|
|
38
|
+
"git submodule update --init --recursive",
|
|
37
39
|
]
|
|
38
40
|
archs = ["x86_64", "universal2", "arm64"]
|
|
39
41
|
repair-wheel-command = "delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel}"
|
|
@@ -43,7 +45,7 @@ repair-wheel-command = "delocate-wheel --require-archs {delocate_archs} -w {dest
|
|
|
43
45
|
before-build = [
|
|
44
46
|
"rd /s /q {project}\\CMakeCache.txt {project}\\build {project}\\build_debug {project}\\CMakeFiles.txt {project}\\_deps {project}\\.pytest_cache || echo Done",
|
|
45
47
|
"md build\\usearch",
|
|
46
|
-
"git submodule update --init --recursive"
|
|
48
|
+
"git submodule update --init --recursive",
|
|
47
49
|
]
|
|
48
50
|
archs = ["x86", "AMD64"]
|
|
49
51
|
skip = ["*win32*", "pp*", "cp36-*", "cp312-*"]
|
package/python/lib.cpp
CHANGED
|
@@ -38,7 +38,7 @@ using py_shape_t = py::array::ShapeContainer;
|
|
|
38
38
|
using metric_t = metric_punned_t;
|
|
39
39
|
using distance_t = distance_punned_t;
|
|
40
40
|
|
|
41
|
-
using dense_key_t = typename index_dense_t::
|
|
41
|
+
using dense_key_t = typename index_dense_t::vector_key_t;
|
|
42
42
|
using dense_add_result_t = typename index_dense_t::add_result_t;
|
|
43
43
|
using dense_search_result_t = typename index_dense_t::search_result_t;
|
|
44
44
|
using dense_labeling_result_t = typename index_dense_t::labeling_result_t;
|
|
@@ -48,7 +48,7 @@ using dense_clustering_result_t = typename index_dense_t::clustering_result_t;
|
|
|
48
48
|
using progress_func_t = std::function<bool(std::size_t /*processed*/, std::size_t /*total*/)>;
|
|
49
49
|
|
|
50
50
|
struct progress_t {
|
|
51
|
-
inline progress_t(nullptr_t = nullptr) : func_(&dummy_progress) {}
|
|
51
|
+
inline progress_t(std::nullptr_t = nullptr) : func_(&dummy_progress) {}
|
|
52
52
|
inline progress_t(progress_func_t const& func) : func_(func ? func : &dummy_progress) {}
|
|
53
53
|
inline bool operator()(std::size_t processed, std::size_t total) const noexcept { return func_(processed, total); }
|
|
54
54
|
|
|
@@ -864,6 +864,7 @@ PYBIND11_MODULE(compiled, m) {
|
|
|
864
864
|
.value("L2sq", metric_kind_t::l2sq_k)
|
|
865
865
|
|
|
866
866
|
.value("Haversine", metric_kind_t::haversine_k)
|
|
867
|
+
.value("Divergence", metric_kind_t::divergence_k)
|
|
867
868
|
.value("Pearson", metric_kind_t::pearson_k)
|
|
868
869
|
.value("Jaccard", metric_kind_t::jaccard_k)
|
|
869
870
|
.value("Hamming", metric_kind_t::hamming_k)
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
},
|
|
12
12
|
{
|
|
13
13
|
"cell_type": "code",
|
|
14
|
-
"execution_count":
|
|
14
|
+
"execution_count": 1,
|
|
15
15
|
"metadata": {},
|
|
16
16
|
"outputs": [],
|
|
17
17
|
"source": [
|
|
@@ -19,6 +19,28 @@
|
|
|
19
19
|
"import plotly.graph_objects as go"
|
|
20
20
|
]
|
|
21
21
|
},
|
|
22
|
+
{
|
|
23
|
+
"cell_type": "code",
|
|
24
|
+
"execution_count": 6,
|
|
25
|
+
"metadata": {},
|
|
26
|
+
"outputs": [
|
|
27
|
+
{
|
|
28
|
+
"data": {
|
|
29
|
+
"text/plain": [
|
|
30
|
+
"('auto', 'auto', 'auto')"
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
"execution_count": 6,
|
|
34
|
+
"metadata": {},
|
|
35
|
+
"output_type": "execute_result"
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
"source": [
|
|
39
|
+
"from usearch.index import Index\n",
|
|
40
|
+
"\n",
|
|
41
|
+
"Index(ndim=256, metric=\"cos\", dtype=\"f32\").hardware_acceleration, Index(ndim=256, metric=\"cos\", dtype=\"f16\").hardware_acceleration, Index(ndim=256, metric=\"cos\", dtype=\"i8\").hardware_acceleration"
|
|
42
|
+
]
|
|
43
|
+
},
|
|
22
44
|
{
|
|
23
45
|
"cell_type": "code",
|
|
24
46
|
"execution_count": null,
|
|
@@ -162,7 +184,7 @@
|
|
|
162
184
|
"name": "python",
|
|
163
185
|
"nbconvert_exporter": "python",
|
|
164
186
|
"pygments_lexer": "ipython3",
|
|
165
|
-
"version": "3.
|
|
187
|
+
"version": "3.11.5"
|
|
166
188
|
},
|
|
167
189
|
"orig_nbformat": 4
|
|
168
190
|
},
|
package/python/usearch/index.py
CHANGED
|
@@ -151,6 +151,7 @@ def _normalize_metric(metric) -> MetricKind:
|
|
|
151
151
|
"l2sq": MetricKind.L2sq,
|
|
152
152
|
"l2_sq": MetricKind.L2sq,
|
|
153
153
|
"haversine": MetricKind.Haversine,
|
|
154
|
+
"divergence": MetricKind.Divergence,
|
|
154
155
|
"pearson": MetricKind.Pearson,
|
|
155
156
|
"hamming": MetricKind.Hamming,
|
|
156
157
|
"tanimoto": MetricKind.Tanimoto,
|
|
@@ -573,7 +574,7 @@ class Index:
|
|
|
573
574
|
)
|
|
574
575
|
|
|
575
576
|
self.path = path
|
|
576
|
-
if path is not None:
|
|
577
|
+
if path is not None and os.path.exists(path):
|
|
577
578
|
if view:
|
|
578
579
|
self.view(path)
|
|
579
580
|
else:
|
|
@@ -873,7 +874,7 @@ class Index:
|
|
|
873
874
|
|
|
874
875
|
@property
|
|
875
876
|
def metric_kind(self) -> Union[MetricKind, CompiledMetric]:
|
|
876
|
-
return self._metric_jit if self._metric_jit
|
|
877
|
+
return self._metric_jit.kind if self._metric_jit else self._metric_kind
|
|
877
878
|
|
|
878
879
|
@property
|
|
879
880
|
def metric(self) -> Union[MetricKind, CompiledMetric]:
|
|
@@ -965,7 +966,11 @@ class Index:
|
|
|
965
966
|
if isinstance(path_or_buffer, bytes):
|
|
966
967
|
self._compiled.load_index_from_buffer(path_or_buffer, progress)
|
|
967
968
|
else:
|
|
968
|
-
|
|
969
|
+
path_or_buffer = os.fspath(path_or_buffer)
|
|
970
|
+
if os.path.exists(path_or_buffer):
|
|
971
|
+
self._compiled.load_index_from_path(path_or_buffer, progress)
|
|
972
|
+
else:
|
|
973
|
+
raise RuntimeError("Missing file!")
|
|
969
974
|
|
|
970
975
|
def view(
|
|
971
976
|
self,
|