usearch 2.15.0 → 2.15.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/README.md +1 -1
- package/include/usearch/index.hpp +1 -1
- package/include/usearch/index_plugins.hpp +63 -8
- package/javascript/README.md +2 -1
- package/javascript/usearch.test.js +2 -2
- package/package.json +1 -1
- package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
- package/prebuilds/linux-arm64/usearch.node +0 -0
- package/prebuilds/linux-x64/usearch.node +0 -0
package/README.md
CHANGED
|
@@ -139,6 +139,9 @@ enum class scalar_kind_t : std::uint8_t {
|
|
|
139
139
|
i8_k = 23,
|
|
140
140
|
};
|
|
141
141
|
|
|
142
|
+
/**
|
|
143
|
+
* @brief Maps a scalar type to its corresponding scalar_kind_t enumeration value.
|
|
144
|
+
*/
|
|
142
145
|
template <typename scalar_at> scalar_kind_t scalar_kind() noexcept {
|
|
143
146
|
if (std::is_same<scalar_at, b1x8_t>())
|
|
144
147
|
return scalar_kind_t::b1x8_k;
|
|
@@ -175,22 +178,43 @@ template <typename scalar_at> scalar_kind_t scalar_kind() noexcept {
|
|
|
175
178
|
return scalar_kind_t::unknown_k;
|
|
176
179
|
}
|
|
177
180
|
|
|
181
|
+
/**
|
|
182
|
+
* @brief Converts an angle from degrees to radians.
|
|
183
|
+
*/
|
|
178
184
|
template <typename at> at angle_to_radians(at angle) noexcept { return angle * at(3.14159265358979323846) / at(180); }
|
|
179
185
|
|
|
186
|
+
/**
|
|
187
|
+
* @brief Readability helper to compute the square of a given value.
|
|
188
|
+
*/
|
|
180
189
|
template <typename at> at square(at value) noexcept { return value * value; }
|
|
181
190
|
|
|
191
|
+
/**
|
|
192
|
+
* @brief Clamps a value between a lower and upper bound using a custom comparator. Similar to `std::clamp`.
|
|
193
|
+
* https://en.cppreference.com/w/cpp/algorithm/clamp
|
|
194
|
+
*/
|
|
182
195
|
template <typename at, typename compare_at> inline at clamp(at v, at lo, at hi, compare_at comp) noexcept {
|
|
183
196
|
return comp(v, lo) ? lo : comp(hi, v) ? hi : v;
|
|
184
197
|
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* @brief Clamps a value between a lower and upper bound. Similar to `std::clamp`.
|
|
201
|
+
* https://en.cppreference.com/w/cpp/algorithm/clamp
|
|
202
|
+
*/
|
|
185
203
|
template <typename at> inline at clamp(at v, at lo, at hi) noexcept {
|
|
186
204
|
return usearch::clamp(v, lo, hi, std::less<at>{});
|
|
187
205
|
}
|
|
188
206
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
207
|
+
/**
|
|
208
|
+
* @brief Compares two strings for equality, given a length for the first string.
|
|
209
|
+
*/
|
|
210
|
+
inline bool str_equals(char const* first_begin, std::size_t first_len, char const* second_begin) noexcept {
|
|
211
|
+
std::size_t second_len = std::strlen(second_begin);
|
|
212
|
+
return first_len == second_len && std::strncmp(first_begin, second_begin, first_len) == 0;
|
|
192
213
|
}
|
|
193
214
|
|
|
215
|
+
/**
|
|
216
|
+
* @brief Returns the number of bits required to represent a scalar type.
|
|
217
|
+
*/
|
|
194
218
|
inline std::size_t bits_per_scalar(scalar_kind_t scalar_kind) noexcept {
|
|
195
219
|
switch (scalar_kind) {
|
|
196
220
|
case scalar_kind_t::uuid_k: return 128;
|
|
@@ -213,6 +237,10 @@ inline std::size_t bits_per_scalar(scalar_kind_t scalar_kind) noexcept {
|
|
|
213
237
|
}
|
|
214
238
|
}
|
|
215
239
|
|
|
240
|
+
/**
|
|
241
|
+
* @brief Returns the number of bits in a scalar word for a given scalar type.
|
|
242
|
+
* Equivalent to `bits_per_scalar` for types that are not bit-packed.
|
|
243
|
+
*/
|
|
216
244
|
inline std::size_t bits_per_scalar_word(scalar_kind_t scalar_kind) noexcept {
|
|
217
245
|
switch (scalar_kind) {
|
|
218
246
|
case scalar_kind_t::uuid_k: return 128;
|
|
@@ -235,6 +263,9 @@ inline std::size_t bits_per_scalar_word(scalar_kind_t scalar_kind) noexcept {
|
|
|
235
263
|
}
|
|
236
264
|
}
|
|
237
265
|
|
|
266
|
+
/**
|
|
267
|
+
* @brief Returns the string name of a given scalar type.
|
|
268
|
+
*/
|
|
238
269
|
inline char const* scalar_kind_name(scalar_kind_t scalar_kind) noexcept {
|
|
239
270
|
switch (scalar_kind) {
|
|
240
271
|
case scalar_kind_t::uuid_k: return "uuid";
|
|
@@ -257,6 +288,9 @@ inline char const* scalar_kind_name(scalar_kind_t scalar_kind) noexcept {
|
|
|
257
288
|
}
|
|
258
289
|
}
|
|
259
290
|
|
|
291
|
+
/**
|
|
292
|
+
* @brief Returns the string name of a given distance metric.
|
|
293
|
+
*/
|
|
260
294
|
inline char const* metric_kind_name(metric_kind_t metric) noexcept {
|
|
261
295
|
switch (metric) {
|
|
262
296
|
case metric_kind_t::unknown_k: return "unknown";
|
|
@@ -273,6 +307,10 @@ inline char const* metric_kind_name(metric_kind_t metric) noexcept {
|
|
|
273
307
|
default: return "";
|
|
274
308
|
}
|
|
275
309
|
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* @brief Parses a string to identify the corresponding `scalar_kind_t` enumeration value.
|
|
313
|
+
*/
|
|
276
314
|
inline expected_gt<scalar_kind_t> scalar_kind_from_name(char const* name, std::size_t len) {
|
|
277
315
|
expected_gt<scalar_kind_t> parsed;
|
|
278
316
|
if (str_equals(name, len, "f32"))
|
|
@@ -292,10 +330,16 @@ inline expected_gt<scalar_kind_t> scalar_kind_from_name(char const* name, std::s
|
|
|
292
330
|
return parsed;
|
|
293
331
|
}
|
|
294
332
|
|
|
333
|
+
/**
|
|
334
|
+
* @brief Parses a string to identify the corresponding `scalar_kind_t` enumeration value.
|
|
335
|
+
*/
|
|
295
336
|
inline expected_gt<scalar_kind_t> scalar_kind_from_name(char const* name) {
|
|
296
337
|
return scalar_kind_from_name(name, std::strlen(name));
|
|
297
338
|
}
|
|
298
339
|
|
|
340
|
+
/**
|
|
341
|
+
* @brief Parses a string to identify the corresponding `metric_kind_t` enumeration value.
|
|
342
|
+
*/
|
|
299
343
|
inline expected_gt<metric_kind_t> metric_from_name(char const* name, std::size_t len) {
|
|
300
344
|
expected_gt<metric_kind_t> parsed;
|
|
301
345
|
if (str_equals(name, len, "l2sq") || str_equals(name, len, "euclidean_sq")) {
|
|
@@ -321,6 +365,10 @@ inline expected_gt<metric_kind_t> metric_from_name(char const* name, std::size_t
|
|
|
321
365
|
"tanimoto, sorensen");
|
|
322
366
|
return parsed;
|
|
323
367
|
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* @brief Parses a string to identify the corresponding `metric_kind_t` enumeration value.
|
|
371
|
+
*/
|
|
324
372
|
inline expected_gt<metric_kind_t> metric_from_name(char const* name) {
|
|
325
373
|
return metric_from_name(name, std::strlen(name));
|
|
326
374
|
}
|
|
@@ -417,7 +465,7 @@ class f16_bits_t {
|
|
|
417
465
|
inline f16_bits_t(float v) noexcept : uint16_(f32_to_f16(v)) {}
|
|
418
466
|
inline f16_bits_t(double v) noexcept : uint16_(f32_to_f16(static_cast<float>(v))) {}
|
|
419
467
|
|
|
420
|
-
inline bool operator<(const
|
|
468
|
+
inline bool operator<(f16_bits_t const& other) const noexcept { return float(*this) < float(other); }
|
|
421
469
|
|
|
422
470
|
inline f16_bits_t operator+(f16_bits_t other) const noexcept { return {float(*this) + float(other)}; }
|
|
423
471
|
inline f16_bits_t operator-(f16_bits_t other) const noexcept { return {float(*this) - float(other)}; }
|
|
@@ -1419,7 +1467,10 @@ template <typename scalar_at = float, typename result_at = float> struct metric_
|
|
|
1419
1467
|
}
|
|
1420
1468
|
};
|
|
1421
1469
|
|
|
1422
|
-
|
|
1470
|
+
/**
|
|
1471
|
+
* @brief Cosine (Angular) distance for signed 8-bit integers using 16-bit intermediates.
|
|
1472
|
+
*/
|
|
1473
|
+
struct metric_cos_i8_t {
|
|
1423
1474
|
using scalar_t = i8_t;
|
|
1424
1475
|
using result_t = f32_t;
|
|
1425
1476
|
|
|
@@ -1445,7 +1496,11 @@ struct cos_i8_t {
|
|
|
1445
1496
|
}
|
|
1446
1497
|
};
|
|
1447
1498
|
|
|
1448
|
-
|
|
1499
|
+
/**
|
|
1500
|
+
* @brief Squared Euclidean (L2) distance for signed 8-bit integers using 16-bit intermediates.
|
|
1501
|
+
* Square root is avoided at the end, as it won't affect the ordering.
|
|
1502
|
+
*/
|
|
1503
|
+
struct metric_l2sq_i8_t {
|
|
1449
1504
|
using scalar_t = i8_t;
|
|
1450
1505
|
using result_t = f32_t;
|
|
1451
1506
|
|
|
@@ -1775,7 +1830,7 @@ class metric_punned_t {
|
|
|
1775
1830
|
case metric_kind_t::cos_k: {
|
|
1776
1831
|
switch (scalar_kind_) {
|
|
1777
1832
|
case scalar_kind_t::bf16_k: metric_ptr_ = (uptr_t)&equidimensional_<metric_cos_gt<bf16_t, f32_t>>; break;
|
|
1778
|
-
case scalar_kind_t::i8_k: metric_ptr_ = (uptr_t)&equidimensional_<
|
|
1833
|
+
case scalar_kind_t::i8_k: metric_ptr_ = (uptr_t)&equidimensional_<metric_cos_i8_t>; break;
|
|
1779
1834
|
case scalar_kind_t::f16_k: metric_ptr_ = (uptr_t)&equidimensional_<metric_cos_gt<f16_t, f32_t>>; break;
|
|
1780
1835
|
case scalar_kind_t::f32_k: metric_ptr_ = (uptr_t)&equidimensional_<metric_cos_gt<f32_t>>; break;
|
|
1781
1836
|
case scalar_kind_t::f64_k: metric_ptr_ = (uptr_t)&equidimensional_<metric_cos_gt<f64_t>>; break;
|
|
@@ -1786,7 +1841,7 @@ class metric_punned_t {
|
|
|
1786
1841
|
case metric_kind_t::l2sq_k: {
|
|
1787
1842
|
switch (scalar_kind_) {
|
|
1788
1843
|
case scalar_kind_t::bf16_k: metric_ptr_ = (uptr_t)&equidimensional_<metric_l2sq_gt<bf16_t, f32_t>>; break;
|
|
1789
|
-
case scalar_kind_t::i8_k: metric_ptr_ = (uptr_t)&equidimensional_<
|
|
1844
|
+
case scalar_kind_t::i8_k: metric_ptr_ = (uptr_t)&equidimensional_<metric_l2sq_i8_t>; break;
|
|
1790
1845
|
case scalar_kind_t::f16_k: metric_ptr_ = (uptr_t)&equidimensional_<metric_l2sq_gt<f16_t, f32_t>>; break;
|
|
1791
1846
|
case scalar_kind_t::f32_k: metric_ptr_ = (uptr_t)&equidimensional_<metric_l2sq_gt<f32_t>>; break;
|
|
1792
1847
|
case scalar_kind_t::f64_k: metric_ptr_ = (uptr_t)&equidimensional_<metric_l2sq_gt<f64_t>>; break;
|
package/javascript/README.md
CHANGED
|
@@ -21,8 +21,9 @@ wasmer install unum/usearch
|
|
|
21
21
|
Create an index, add vectors, and perform searches with ease:
|
|
22
22
|
|
|
23
23
|
```js
|
|
24
|
+
const assert = require('node:assert');
|
|
24
25
|
const usearch = require('usearch');
|
|
25
|
-
const index = new usearch.Index({ metric: '
|
|
26
|
+
const index = new usearch.Index({ metric: 'l2sq', connectivity: 16, dimensions: 3 });
|
|
26
27
|
index.add(42n, new Float32Array([0.2, 0.6, 0.4]));
|
|
27
28
|
const results = index.search(new Float32Array([0.2, 0.6, 0.4]), 10);
|
|
28
29
|
|
|
@@ -47,13 +47,13 @@ test('Batch operations', () => {
|
|
|
47
47
|
});
|
|
48
48
|
|
|
49
49
|
test("Expected results", () => {
|
|
50
|
-
|
|
50
|
+
const index = new usearch.Index({
|
|
51
51
|
metric: "l2sq",
|
|
52
52
|
connectivity: 16,
|
|
53
53
|
dimensions: 3,
|
|
54
54
|
});
|
|
55
55
|
index.add(42n, new Float32Array([0.2, 0.6, 0.4]));
|
|
56
|
-
|
|
56
|
+
const results = index.search(new Float32Array([0.2, 0.6, 0.4]), 10);
|
|
57
57
|
|
|
58
58
|
assert.equal(index.size(), 1);
|
|
59
59
|
assert.deepEqual(results.keys, new BigUint64Array([42n]));
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|