usearch 2.7.6 → 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 +4 -1
- 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 +91 -24
- 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 +6 -6
- 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
|
@@ -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',
|
|
@@ -186,20 +199,6 @@ inline bool str_equals(char const* begin, std::size_t len, char const* other_beg
|
|
|
186
199
|
return len == other_len && std::strncmp(begin, other_begin, len) == 0;
|
|
187
200
|
}
|
|
188
201
|
|
|
189
|
-
inline char const* isa_name(simsimd_capability_t isa_kind) noexcept {
|
|
190
|
-
switch (isa_kind) {
|
|
191
|
-
case simsimd_cap_serial_k: return "serial";
|
|
192
|
-
case simsimd_cap_arm_neon_k: return "neon";
|
|
193
|
-
case simsimd_cap_arm_sve_k: return "sve";
|
|
194
|
-
case simsimd_cap_x86_avx2_k: return "avx2";
|
|
195
|
-
case simsimd_cap_x86_avx512_k: return "avx512";
|
|
196
|
-
case simsimd_cap_x86_avx2fp16_k: return "avx2+f16";
|
|
197
|
-
case simsimd_cap_x86_avx512fp16_k: return "avx512+f16";
|
|
198
|
-
case simsimd_cap_x86_avx512vpopcntdq_k: return "avx512+popcnt";
|
|
199
|
-
default: return "unknown";
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
202
|
inline std::size_t bits_per_scalar(scalar_kind_t scalar_kind) noexcept {
|
|
204
203
|
switch (scalar_kind) {
|
|
205
204
|
case scalar_kind_t::f64_k: return 64;
|
|
@@ -241,6 +240,7 @@ inline char const* metric_kind_name(metric_kind_t metric) noexcept {
|
|
|
241
240
|
case metric_kind_t::l2sq_k: return "l2sq";
|
|
242
241
|
case metric_kind_t::pearson_k: return "pearson";
|
|
243
242
|
case metric_kind_t::haversine_k: return "haversine";
|
|
243
|
+
case metric_kind_t::divergence_k: return "divergence";
|
|
244
244
|
case metric_kind_t::jaccard_k: return "jaccard";
|
|
245
245
|
case metric_kind_t::hamming_k: return "hamming";
|
|
246
246
|
case metric_kind_t::tanimoto_k: return "tanimoto";
|
|
@@ -277,6 +277,8 @@ inline expected_gt<metric_kind_t> metric_from_name(char const* name, std::size_t
|
|
|
277
277
|
parsed.result = metric_kind_t::cos_k;
|
|
278
278
|
} else if (str_equals(name, len, "haversine")) {
|
|
279
279
|
parsed.result = metric_kind_t::haversine_k;
|
|
280
|
+
} else if (str_equals(name, len, "divergence")) {
|
|
281
|
+
parsed.result = metric_kind_t::divergence_k;
|
|
280
282
|
} else if (str_equals(name, len, "pearson")) {
|
|
281
283
|
parsed.result = metric_kind_t::pearson_k;
|
|
282
284
|
} else if (str_equals(name, len, "hamming")) {
|
|
@@ -286,8 +288,8 @@ inline expected_gt<metric_kind_t> metric_from_name(char const* name, std::size_t
|
|
|
286
288
|
} else if (str_equals(name, len, "sorensen")) {
|
|
287
289
|
parsed.result = metric_kind_t::sorensen_k;
|
|
288
290
|
} else
|
|
289
|
-
parsed.failed(
|
|
290
|
-
|
|
291
|
+
parsed.failed("Unknown distance, choose: l2sq, ip, cos, haversine, divergence, jaccard, pearson, hamming, "
|
|
292
|
+
"tanimoto, sorensen");
|
|
291
293
|
return parsed;
|
|
292
294
|
}
|
|
293
295
|
|
|
@@ -570,7 +572,9 @@ class aligned_allocator_gt {
|
|
|
570
572
|
using size_type = std::size_t;
|
|
571
573
|
using pointer = element_at*;
|
|
572
574
|
using const_pointer = element_at const*;
|
|
573
|
-
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
|
+
};
|
|
574
578
|
|
|
575
579
|
constexpr std::size_t alignment() const { return alignment_ak; }
|
|
576
580
|
|
|
@@ -1180,6 +1184,32 @@ template <typename scalar_at = float, typename result_at = float> struct metric_
|
|
|
1180
1184
|
}
|
|
1181
1185
|
};
|
|
1182
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
|
+
|
|
1183
1213
|
struct cos_i8_t {
|
|
1184
1214
|
using scalar_t = i8_t;
|
|
1185
1215
|
using result_t = f32_t;
|
|
@@ -1283,7 +1313,10 @@ class metric_punned_t {
|
|
|
1283
1313
|
std::size_t dimensions_ = 0;
|
|
1284
1314
|
metric_kind_t metric_kind_ = metric_kind_t::unknown_k;
|
|
1285
1315
|
scalar_kind_t scalar_kind_ = scalar_kind_t::unknown_k;
|
|
1316
|
+
|
|
1317
|
+
#if USEARCH_USE_SIMSIMD
|
|
1286
1318
|
simsimd_capability_t isa_kind_ = simsimd_cap_serial_k;
|
|
1319
|
+
#endif
|
|
1287
1320
|
|
|
1288
1321
|
public:
|
|
1289
1322
|
/**
|
|
@@ -1303,7 +1336,7 @@ class metric_punned_t {
|
|
|
1303
1336
|
metric_kind_t metric_kind = metric_kind_t::l2sq_k, //
|
|
1304
1337
|
scalar_kind_t scalar_kind = scalar_kind_t::f32_k) noexcept
|
|
1305
1338
|
: raw_arg3_(dimensions), raw_arg4_(dimensions), dimensions_(dimensions), metric_kind_(metric_kind),
|
|
1306
|
-
scalar_kind_(scalar_kind)
|
|
1339
|
+
scalar_kind_(scalar_kind) {
|
|
1307
1340
|
|
|
1308
1341
|
#if USEARCH_USE_SIMSIMD
|
|
1309
1342
|
if (configure_with_simsimd())
|
|
@@ -1328,7 +1361,23 @@ class metric_punned_t {
|
|
|
1328
1361
|
inline std::size_t dimensions() const noexcept { return dimensions_; }
|
|
1329
1362
|
inline metric_kind_t metric_kind() const noexcept { return metric_kind_; }
|
|
1330
1363
|
inline scalar_kind_t scalar_kind() const noexcept { return scalar_kind_; }
|
|
1331
|
-
|
|
1364
|
+
|
|
1365
|
+
inline char const* isa_name() const noexcept {
|
|
1366
|
+
#if USEARCH_USE_SIMSIMD
|
|
1367
|
+
switch (isa_kind_) {
|
|
1368
|
+
case simsimd_cap_serial_k: return "serial";
|
|
1369
|
+
case simsimd_cap_arm_neon_k: return "neon";
|
|
1370
|
+
case simsimd_cap_arm_sve_k: return "sve";
|
|
1371
|
+
case simsimd_cap_x86_avx2_k: return "avx2";
|
|
1372
|
+
case simsimd_cap_x86_avx512_k: return "avx512";
|
|
1373
|
+
case simsimd_cap_x86_avx2fp16_k: return "avx2+f16";
|
|
1374
|
+
case simsimd_cap_x86_avx512fp16_k: return "avx512+f16";
|
|
1375
|
+
case simsimd_cap_x86_avx512vpopcntdq_k: return "avx512+popcnt";
|
|
1376
|
+
default: return "unknown";
|
|
1377
|
+
}
|
|
1378
|
+
#endif
|
|
1379
|
+
return "serial";
|
|
1380
|
+
}
|
|
1332
1381
|
|
|
1333
1382
|
inline std::size_t bytes_per_vector() const noexcept {
|
|
1334
1383
|
return divide_round_up<CHAR_BIT>(dimensions_ * bits_per_scalar(scalar_kind_));
|
|
@@ -1339,8 +1388,8 @@ class metric_punned_t {
|
|
|
1339
1388
|
}
|
|
1340
1389
|
|
|
1341
1390
|
private:
|
|
1342
|
-
bool configure_with_simsimd() noexcept {
|
|
1343
1391
|
#if USEARCH_USE_SIMSIMD
|
|
1392
|
+
bool configure_with_simsimd(simsimd_capability_t simd_caps) noexcept {
|
|
1344
1393
|
simsimd_metric_kind_t kind = simsimd_metric_unknown_k;
|
|
1345
1394
|
simsimd_datatype_t datatype = simsimd_datatype_unknown_k;
|
|
1346
1395
|
simsimd_capability_t allowed = simsimd_cap_any_k;
|
|
@@ -1350,6 +1399,7 @@ class metric_punned_t {
|
|
|
1350
1399
|
case metric_kind_t::l2sq_k: kind = simsimd_metric_l2sq_k; break;
|
|
1351
1400
|
case metric_kind_t::hamming_k: kind = simsimd_metric_hamming_k; break;
|
|
1352
1401
|
case metric_kind_t::jaccard_k: kind = simsimd_metric_jaccard_k; break;
|
|
1402
|
+
default: break;
|
|
1353
1403
|
}
|
|
1354
1404
|
switch (scalar_kind_) {
|
|
1355
1405
|
case scalar_kind_t::f32_k: datatype = simsimd_datatype_f32_k; break;
|
|
@@ -1357,20 +1407,25 @@ class metric_punned_t {
|
|
|
1357
1407
|
case scalar_kind_t::f16_k: datatype = simsimd_datatype_f16_k; break;
|
|
1358
1408
|
case scalar_kind_t::i8_k: datatype = simsimd_datatype_i8_k; break;
|
|
1359
1409
|
case scalar_kind_t::b1x8_k: datatype = simsimd_datatype_b8_k; break;
|
|
1410
|
+
default: break;
|
|
1360
1411
|
}
|
|
1361
1412
|
simsimd_metric_punned_t simd_metric = NULL;
|
|
1362
1413
|
simsimd_capability_t simd_kind = simsimd_cap_any_k;
|
|
1363
|
-
simsimd_find_metric_punned(kind, datatype,
|
|
1414
|
+
simsimd_find_metric_punned(kind, datatype, simd_caps, allowed, &simd_metric, &simd_kind);
|
|
1364
1415
|
if (simd_metric == nullptr)
|
|
1365
1416
|
return false;
|
|
1366
1417
|
|
|
1367
1418
|
raw_ptr_ = (punned_ptr_t)simd_metric;
|
|
1368
1419
|
isa_kind_ = simd_kind;
|
|
1369
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
|
+
}
|
|
1370
1426
|
#else
|
|
1371
|
-
|
|
1427
|
+
bool configure_with_simsimd() noexcept { return false; }
|
|
1372
1428
|
#endif
|
|
1373
|
-
}
|
|
1374
1429
|
|
|
1375
1430
|
void configure_with_auto_vectorized() noexcept {
|
|
1376
1431
|
switch (metric_kind_) {
|
|
@@ -1427,6 +1482,17 @@ class metric_punned_t {
|
|
|
1427
1482
|
}
|
|
1428
1483
|
break;
|
|
1429
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
|
+
}
|
|
1430
1496
|
case metric_kind_t::jaccard_k: // Equivalent to Tanimoto
|
|
1431
1497
|
case metric_kind_t::tanimoto_k:
|
|
1432
1498
|
raw_ptr_ = (punned_ptr_t)&equidimensional_<metric_tanimoto_gt<b1x8_t>>,
|
|
@@ -2113,7 +2179,8 @@ class flat_hash_multi_set_gt {
|
|
|
2113
2179
|
slot_ref_t slot = slot_ref(slot_index);
|
|
2114
2180
|
if ((~slot.header.populated & slot.mask) | (slot.header.deleted & slot.mask)) {
|
|
2115
2181
|
// Found an empty or deleted slot
|
|
2116
|
-
|
|
2182
|
+
populate_slot(slot, element);
|
|
2183
|
+
++populated_slots_;
|
|
2117
2184
|
return true;
|
|
2118
2185
|
}
|
|
2119
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/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)
|
|
@@ -918,7 +919,7 @@ PYBIND11_MODULE(compiled, m) {
|
|
|
918
919
|
m.def(
|
|
919
920
|
"hardware_acceleration",
|
|
920
921
|
[](scalar_kind_t scalar_kind, std::size_t dimensions, metric_kind_t metric_kind) -> py::str {
|
|
921
|
-
return
|
|
922
|
+
return metric_t(dimensions, metric_kind, scalar_kind).isa_name();
|
|
922
923
|
},
|
|
923
924
|
py::kw_only(), //
|
|
924
925
|
py::arg("dtype") = scalar_kind_t::f32_k, //
|
|
@@ -1087,9 +1088,8 @@ PYBIND11_MODULE(compiled, m) {
|
|
|
1087
1088
|
py::arg("metric_pointer") = 0 //
|
|
1088
1089
|
);
|
|
1089
1090
|
|
|
1090
|
-
i.def_property_readonly("hardware_acceleration",
|
|
1091
|
-
|
|
1092
|
-
});
|
|
1091
|
+
i.def_property_readonly("hardware_acceleration",
|
|
1092
|
+
[](dense_index_py_t const& index) -> py::str { return index.metric().isa_name(); });
|
|
1093
1093
|
|
|
1094
1094
|
i.def("contains_one", &dense_index_py_t::contains);
|
|
1095
1095
|
i.def("count_one", &dense_index_py_t::count);
|
|
@@ -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
|
},
|