usearch 2.8.3 → 2.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.vscode/settings.json +1 -0
- package/CITATION.cff +1 -1
- package/CONTRIBUTING.md +258 -6
- package/Cargo.toml +1 -1
- package/README.md +57 -53
- package/conanfile.py +1 -1
- package/cpp/README.md +89 -21
- package/csharp/DEV_SETUP.md +1 -1
- package/csharp/nuget/nuget-package.props +1 -1
- package/docs/{compilation.rst → contributing.rst} +2 -2
- package/docs/index.rst +1 -1
- package/include/usearch/index.hpp +1 -1
- package/include/usearch/index_dense.hpp +11 -7
- package/package.json +1 -1
- package/python/README.md +1 -1
- package/simsimd/CMakeLists.txt +1 -1
- package/simsimd/README.md +7 -1
- package/simsimd/include/simsimd/probability.h +24 -24
- package/simsimd/include/simsimd/types.h +8 -0
- package/simsimd/javascript/{test.js → test/simsimd.test.js} +15 -15
- package/simsimd/package.json +4 -8
- package/simsimd/setup.py +3 -0
- package/wasmer.toml +1 -1
- package/docs/compilation.md +0 -215
- package/simsimd/.clang-format +0 -10
- package/simsimd/.github/workflows/prerelease.yml +0 -89
- package/simsimd/.github/workflows/release.yml +0 -141
- package/simsimd/.github/workflows/update_version.sh +0 -5
- package/simsimd/.vscode/launch.json +0 -53
- package/simsimd/.vscode/settings.json +0 -114
- package/simsimd/.vscode/tasks.json +0 -23
- package/simsimd/go.mod +0 -3
- package/simsimd/golang/bench_test.go +0 -40
- package/simsimd/golang/simsimd.go +0 -47
- package/simsimd/golang/unit_test.go +0 -40
- package/simsimd/pyproject.toml +0 -42
- package/simsimd/python/bench.ipynb +0 -187
- package/simsimd/python/bench.py +0 -268
- package/simsimd/python/lib.c +0 -492
- package/simsimd/python/test.py +0 -195
package/csharp/DEV_SETUP.md
CHANGED
|
@@ -11,7 +11,7 @@ To obtain all libraries, download the artifacts generated by the GitHub workflow
|
|
|
11
11
|
|
|
12
12
|
To get a library for your current platform (Linux or Macos), execute: `./eng/build_lib.sh`.
|
|
13
13
|
|
|
14
|
-
For more details, refer to the [compilation guide](https://github.com/unum-cloud/usearch/blob/main/
|
|
14
|
+
For more details, refer to the [compilation guide](https://github.com/unum-cloud/usearch/blob/main/CONTRIBUTING.md).
|
|
15
15
|
|
|
16
16
|
# Build and Test
|
|
17
17
|
|
package/docs/index.rst
CHANGED
|
@@ -323,7 +323,7 @@ class index_dense_gt {
|
|
|
323
323
|
/// @brief Schema: input buffer, bytes in input buffer, output buffer.
|
|
324
324
|
using cast_t = std::function<bool(byte_t const*, std::size_t, byte_t*)>;
|
|
325
325
|
/// @brief Punned index.
|
|
326
|
-
using index_t = index_gt<
|
|
326
|
+
using index_t = index_gt< //
|
|
327
327
|
distance_t, vector_key_t, compressed_slot_t, //
|
|
328
328
|
dynamic_allocator_t, tape_allocator_t>;
|
|
329
329
|
using index_allocator_t = aligned_allocator_gt<index_t, 64>;
|
|
@@ -1512,10 +1512,14 @@ class index_dense_gt {
|
|
|
1512
1512
|
* @brief Implements clustering, classifying the given objects (vectors of member keys)
|
|
1513
1513
|
* into a given number of clusters.
|
|
1514
1514
|
*
|
|
1515
|
-
* @param[in] queries_begin Iterator
|
|
1516
|
-
* @param[in] queries_end
|
|
1515
|
+
* @param[in] queries_begin Iterator pointing to the first query.
|
|
1516
|
+
* @param[in] queries_end Iterator pointing to the last query.
|
|
1517
1517
|
* @param[in] executor Thread-pool to execute the job in parallel.
|
|
1518
1518
|
* @param[in] progress Callback to report the execution progress.
|
|
1519
|
+
* @param[in] config Configuration parameters for clustering.
|
|
1520
|
+
*
|
|
1521
|
+
* @param[out] cluster_keys Pointer to the array where the cluster keys will be exported.
|
|
1522
|
+
* @param[out] cluster_distances Pointer to the array where the distances to those centroids will be exported.
|
|
1519
1523
|
*/
|
|
1520
1524
|
template < //
|
|
1521
1525
|
typename queries_iterator_at, //
|
|
@@ -1526,7 +1530,7 @@ class index_dense_gt {
|
|
|
1526
1530
|
queries_iterator_at queries_begin, //
|
|
1527
1531
|
queries_iterator_at queries_end, //
|
|
1528
1532
|
index_dense_clustering_config_t config, //
|
|
1529
|
-
vector_key_t* cluster_keys,
|
|
1533
|
+
vector_key_t* cluster_keys, //
|
|
1530
1534
|
distance_t* cluster_distances, //
|
|
1531
1535
|
executor_at&& executor = executor_at{}, //
|
|
1532
1536
|
progress_at&& progress = progress_at{}) {
|
|
@@ -1715,7 +1719,7 @@ class index_dense_gt {
|
|
|
1715
1719
|
}
|
|
1716
1720
|
|
|
1717
1721
|
template <typename scalar_at>
|
|
1718
|
-
add_result_t add_(
|
|
1722
|
+
add_result_t add_( //
|
|
1719
1723
|
vector_key_t key, scalar_at const* vector, //
|
|
1720
1724
|
std::size_t thread, bool force_vector_copy, cast_t const& cast) {
|
|
1721
1725
|
|
|
@@ -1811,8 +1815,8 @@ class index_dense_gt {
|
|
|
1811
1815
|
}
|
|
1812
1816
|
|
|
1813
1817
|
template <typename scalar_at>
|
|
1814
|
-
aggregated_distances_t distance_between_(
|
|
1815
|
-
vector_key_t key, scalar_at const* vector,
|
|
1818
|
+
aggregated_distances_t distance_between_( //
|
|
1819
|
+
vector_key_t key, scalar_at const* vector, //
|
|
1816
1820
|
std::size_t thread, cast_t const& cast) const {
|
|
1817
1821
|
|
|
1818
1822
|
// Cast the vector, if needed for compatibility with `metric_`
|
package/package.json
CHANGED
package/python/README.md
CHANGED
package/simsimd/CMakeLists.txt
CHANGED
|
@@ -48,7 +48,7 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "^(Apple)?Clang$")
|
|
|
48
48
|
endif()
|
|
49
49
|
add_compile_options(-pedantic -ferror-limit=1)
|
|
50
50
|
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
|
51
|
-
add_compile_options(-march=native -pedantic -fmax-errors=1)
|
|
51
|
+
add_compile_options(-march=native -pedantic -fmax-errors=1 -Wno-tautological-constant-compare)
|
|
52
52
|
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM")
|
|
53
53
|
add_compile_options(-w -ferror-limit=1)
|
|
54
54
|
endif()
|
package/simsimd/README.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# SimSIMD 📏
|
|
2
2
|
|
|
3
|
+
<div>
|
|
4
|
+
<a href="https://pypi.org/project/simsimd/"> <img alt="PyPI - Downloads" src="https://img.shields.io/pypi/dm/simsimd?label=pypi%20downloads"> </a>
|
|
5
|
+
<a href="https://www.npmjs.com/package/simsimd"> <img alt="npm" src="https://img.shields.io/npm/dy/simsimd?label=npm%20dowloads"> </a>
|
|
6
|
+
<img alt="GitHub code size in bytes" src="https://img.shields.io/github/languages/code-size/ashvardanian/simsimd">
|
|
7
|
+
</div>
|
|
8
|
+
|
|
3
9
|
## Efficient Alternative to [`scipy.spatial.distance`][scipy] and [`numpy.inner`][numpy]
|
|
4
10
|
|
|
5
11
|
SimSIMD leverages SIMD intrinsics, capabilities that only select compilers effectively utilize. This framework supports conventional AVX2 instructions on x86, NEON on Arm, as well as __rare__ AVX-512 FP16 instructions on x86 and Scalable Vector Extensions (SVE) on Arm. Designed specifically for Machine Learning contexts, it's optimized for handling high-dimensional vector embeddings.
|
|
@@ -189,7 +195,7 @@ __To test and benchmark JavaScript bindings__:
|
|
|
189
195
|
```sh
|
|
190
196
|
npm install --dev
|
|
191
197
|
npm test
|
|
192
|
-
npm bench
|
|
198
|
+
npm run bench
|
|
193
199
|
```
|
|
194
200
|
|
|
195
201
|
__To test and benchmark GoLang bindings__:
|
|
@@ -52,17 +52,17 @@
|
|
|
52
52
|
extern "C" {
|
|
53
53
|
#endif
|
|
54
54
|
|
|
55
|
-
SIMSIMD_MAKE_KL(serial, f32, f32, SIMSIMD_IDENTIFY,
|
|
56
|
-
SIMSIMD_MAKE_JS(serial, f32, f32, SIMSIMD_IDENTIFY,
|
|
55
|
+
SIMSIMD_MAKE_KL(serial, f32, f32, SIMSIMD_IDENTIFY, SIMSIMD_F32_DIVISION_EPSILON) // simsimd_serial_f32_kl
|
|
56
|
+
SIMSIMD_MAKE_JS(serial, f32, f32, SIMSIMD_IDENTIFY, SIMSIMD_F32_DIVISION_EPSILON) // simsimd_serial_f32_js
|
|
57
57
|
|
|
58
|
-
SIMSIMD_MAKE_KL(serial, f16, f32, SIMSIMD_UNCOMPRESS_F16,
|
|
59
|
-
SIMSIMD_MAKE_JS(serial, f16, f32, SIMSIMD_UNCOMPRESS_F16,
|
|
58
|
+
SIMSIMD_MAKE_KL(serial, f16, f32, SIMSIMD_UNCOMPRESS_F16, SIMSIMD_F32_DIVISION_EPSILON) // simsimd_serial_f16_kl
|
|
59
|
+
SIMSIMD_MAKE_JS(serial, f16, f32, SIMSIMD_UNCOMPRESS_F16, SIMSIMD_F32_DIVISION_EPSILON) // simsimd_serial_f16_js
|
|
60
60
|
|
|
61
|
-
SIMSIMD_MAKE_KL(accurate, f32, f64, SIMSIMD_IDENTIFY,
|
|
62
|
-
SIMSIMD_MAKE_JS(accurate, f32, f64, SIMSIMD_IDENTIFY,
|
|
61
|
+
SIMSIMD_MAKE_KL(accurate, f32, f64, SIMSIMD_IDENTIFY, SIMSIMD_F32_DIVISION_EPSILON) // simsimd_accurate_f32_kl
|
|
62
|
+
SIMSIMD_MAKE_JS(accurate, f32, f64, SIMSIMD_IDENTIFY, SIMSIMD_F32_DIVISION_EPSILON) // simsimd_accurate_f32_js
|
|
63
63
|
|
|
64
|
-
SIMSIMD_MAKE_KL(accurate, f16, f64, SIMSIMD_UNCOMPRESS_F16,
|
|
65
|
-
SIMSIMD_MAKE_JS(accurate, f16, f64, SIMSIMD_UNCOMPRESS_F16,
|
|
64
|
+
SIMSIMD_MAKE_KL(accurate, f16, f64, SIMSIMD_UNCOMPRESS_F16, SIMSIMD_F32_DIVISION_EPSILON) // simsimd_accurate_f16_kl
|
|
65
|
+
SIMSIMD_MAKE_JS(accurate, f16, f64, SIMSIMD_UNCOMPRESS_F16, SIMSIMD_F32_DIVISION_EPSILON) // simsimd_accurate_f16_js
|
|
66
66
|
|
|
67
67
|
#if SIMSIMD_TARGET_ARM
|
|
68
68
|
#if SIMSIMD_TARGET_ARM_NEON
|
|
@@ -108,7 +108,7 @@ __attribute__((target("+simd"))) //
|
|
|
108
108
|
inline static simsimd_f32_t
|
|
109
109
|
simsimd_neon_f32_kl(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n) {
|
|
110
110
|
float32x4_t sum_vec = vdupq_n_f32(0);
|
|
111
|
-
simsimd_f32_t epsilon =
|
|
111
|
+
simsimd_f32_t epsilon = SIMSIMD_F32_DIVISION_EPSILON;
|
|
112
112
|
float32x4_t epsilon_vec = vdupq_n_f32(epsilon);
|
|
113
113
|
simsimd_size_t i = 0;
|
|
114
114
|
for (; i + 4 <= n; i += 4) {
|
|
@@ -129,7 +129,7 @@ simsimd_neon_f32_kl(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size
|
|
|
129
129
|
__attribute__((target("+simd"))) inline static simsimd_f32_t
|
|
130
130
|
simsimd_neon_f32_js(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n) {
|
|
131
131
|
float32x4_t sum_vec = vdupq_n_f32(0);
|
|
132
|
-
simsimd_f32_t epsilon =
|
|
132
|
+
simsimd_f32_t epsilon = SIMSIMD_F32_DIVISION_EPSILON;
|
|
133
133
|
float32x4_t epsilon_vec = vdupq_n_f32(epsilon);
|
|
134
134
|
simsimd_size_t i = 0;
|
|
135
135
|
for (; i + 4 <= n; i += 4) {
|
|
@@ -147,11 +147,11 @@ simsimd_neon_f32_js(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size
|
|
|
147
147
|
simsimd_f32_t log2_normalizer = 0.693147181f;
|
|
148
148
|
simsimd_f32_t sum = vaddvq_f32(sum_vec) * log2_normalizer;
|
|
149
149
|
for (; i < n; ++i) {
|
|
150
|
-
simsimd_f32_t mi = a[i] + b[i];
|
|
150
|
+
simsimd_f32_t mi = 0.5f * (a[i] + b[i]);
|
|
151
151
|
sum += a[i] * SIMSIMD_LOG((a[i] + epsilon) / (mi + epsilon));
|
|
152
152
|
sum += b[i] * SIMSIMD_LOG((b[i] + epsilon) / (mi + epsilon));
|
|
153
153
|
}
|
|
154
|
-
return sum
|
|
154
|
+
return sum;
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
/*
|
|
@@ -168,7 +168,7 @@ __attribute__((target("+simd+fp16"))) //
|
|
|
168
168
|
inline static simsimd_f32_t
|
|
169
169
|
simsimd_neon_f16_kl(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n) {
|
|
170
170
|
float32x4_t sum_vec = vdupq_n_f32(0);
|
|
171
|
-
simsimd_f32_t epsilon =
|
|
171
|
+
simsimd_f32_t epsilon = SIMSIMD_F32_DIVISION_EPSILON;
|
|
172
172
|
float32x4_t epsilon_vec = vdupq_n_f32(epsilon);
|
|
173
173
|
simsimd_size_t i = 0;
|
|
174
174
|
for (; i + 4 <= n; i += 4) {
|
|
@@ -191,7 +191,7 @@ __attribute__((target("+simd+fp16"))) //
|
|
|
191
191
|
inline static simsimd_f32_t
|
|
192
192
|
simsimd_neon_f16_js(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n) {
|
|
193
193
|
float32x4_t sum_vec = vdupq_n_f32(0);
|
|
194
|
-
simsimd_f32_t epsilon =
|
|
194
|
+
simsimd_f32_t epsilon = SIMSIMD_F32_DIVISION_EPSILON;
|
|
195
195
|
float32x4_t epsilon_vec = vdupq_n_f32(epsilon);
|
|
196
196
|
simsimd_size_t i = 0;
|
|
197
197
|
for (; i + 4 <= n; i += 4) {
|
|
@@ -211,11 +211,11 @@ simsimd_neon_f16_js(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size
|
|
|
211
211
|
for (; i < n; ++i) {
|
|
212
212
|
simsimd_f32_t ai = SIMSIMD_UNCOMPRESS_F16(a[i]);
|
|
213
213
|
simsimd_f32_t bi = SIMSIMD_UNCOMPRESS_F16(b[i]);
|
|
214
|
-
simsimd_f32_t mi = ai + bi;
|
|
214
|
+
simsimd_f32_t mi = 0.5f * (ai + bi);
|
|
215
215
|
sum += ai * SIMSIMD_LOG((ai + epsilon) / (mi + epsilon));
|
|
216
216
|
sum += bi * SIMSIMD_LOG((bi + epsilon) / (mi + epsilon));
|
|
217
217
|
}
|
|
218
|
-
return sum
|
|
218
|
+
return sum;
|
|
219
219
|
}
|
|
220
220
|
|
|
221
221
|
#endif // SIMSIMD_TARGET_ARM_NEON
|
|
@@ -268,7 +268,7 @@ __attribute__((target("avx2,f16c,fma"))) //
|
|
|
268
268
|
inline static simsimd_f32_t
|
|
269
269
|
simsimd_avx2_f16_kl(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n) {
|
|
270
270
|
__m256 sum_vec = _mm256_set1_ps(0);
|
|
271
|
-
simsimd_f32_t epsilon =
|
|
271
|
+
simsimd_f32_t epsilon = SIMSIMD_F32_DIVISION_EPSILON;
|
|
272
272
|
__m256 epsilon_vec = _mm256_set1_ps(epsilon);
|
|
273
273
|
simsimd_size_t i = 0;
|
|
274
274
|
for (; i + 8 <= n; i += 8) {
|
|
@@ -300,7 +300,7 @@ __attribute__((target("avx2,f16c,fma"))) //
|
|
|
300
300
|
inline static simsimd_f32_t
|
|
301
301
|
simsimd_avx2_f16_js(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n) {
|
|
302
302
|
__m256 sum_vec = _mm256_set1_ps(0);
|
|
303
|
-
simsimd_f32_t epsilon =
|
|
303
|
+
simsimd_f32_t epsilon = SIMSIMD_F32_DIVISION_EPSILON;
|
|
304
304
|
__m256 epsilon_vec = _mm256_set1_ps(epsilon);
|
|
305
305
|
simsimd_size_t i = 0;
|
|
306
306
|
for (; i + 8 <= n; i += 8) {
|
|
@@ -374,7 +374,7 @@ __attribute__((target("avx512f,avx512vl,bmi2"))) //
|
|
|
374
374
|
inline static simsimd_f32_t
|
|
375
375
|
simsimd_avx512_f32_kl(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n) {
|
|
376
376
|
__m512 sum_vec = _mm512_set1_ps(0);
|
|
377
|
-
simsimd_f32_t epsilon =
|
|
377
|
+
simsimd_f32_t epsilon = SIMSIMD_F32_DIVISION_EPSILON;
|
|
378
378
|
__m512 epsilon_vec = _mm512_set1_ps(epsilon);
|
|
379
379
|
__m512 a_vec, b_vec;
|
|
380
380
|
|
|
@@ -405,7 +405,7 @@ inline static simsimd_f32_t
|
|
|
405
405
|
simsimd_avx512_f32_js(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t n) {
|
|
406
406
|
__m512 sum_a_vec = _mm512_set1_ps(0);
|
|
407
407
|
__m512 sum_b_vec = _mm512_set1_ps(0);
|
|
408
|
-
simsimd_f32_t epsilon =
|
|
408
|
+
simsimd_f32_t epsilon = SIMSIMD_F32_DIVISION_EPSILON;
|
|
409
409
|
__m512 epsilon_vec = _mm512_set1_ps(epsilon);
|
|
410
410
|
__m512 a_vec, b_vec;
|
|
411
411
|
|
|
@@ -425,8 +425,8 @@ simsimd_avx512_f32_js_cycle:
|
|
|
425
425
|
__mmask16 nonzero_mask_b = _mm512_cmp_ps_mask(b_vec, epsilon_vec, _CMP_GE_OQ);
|
|
426
426
|
__mmask16 nonzero_mask = nonzero_mask_a & nonzero_mask_b;
|
|
427
427
|
__m512 m_recip_approx = _mm512_rcp14_ps(m_vec);
|
|
428
|
-
__m512 ratio_a_vec =
|
|
429
|
-
__m512 ratio_b_vec =
|
|
428
|
+
__m512 ratio_a_vec = _mm512_div_ps(a_vec, m_vec);
|
|
429
|
+
__m512 ratio_b_vec = _mm512_div_ps(b_vec, m_vec);
|
|
430
430
|
__m512 log_ratio_a_vec = simsimd_avx512_f32_log2(ratio_a_vec);
|
|
431
431
|
__m512 log_ratio_b_vec = simsimd_avx512_f32_log2(ratio_b_vec);
|
|
432
432
|
sum_a_vec = _mm512_maskz_fmadd_ps(nonzero_mask, a_vec, log_ratio_a_vec, sum_a_vec);
|
|
@@ -472,7 +472,7 @@ __attribute__((target("avx512f,avx512vl,avx512fp16,bmi2"))) //
|
|
|
472
472
|
inline static simsimd_f32_t
|
|
473
473
|
simsimd_avx512_f16_kl(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n) {
|
|
474
474
|
__m512h sum_vec = _mm512_set1_ph((_Float16)0);
|
|
475
|
-
__m512h epsilon_vec = _mm512_set1_ph((_Float16)
|
|
475
|
+
__m512h epsilon_vec = _mm512_set1_ph((_Float16)SIMSIMD_F16_DIVISION_EPSILON);
|
|
476
476
|
__m512h a_vec, b_vec;
|
|
477
477
|
|
|
478
478
|
simsimd_avx512_f16_kl_cycle:
|
|
@@ -502,7 +502,7 @@ inline static simsimd_f32_t
|
|
|
502
502
|
simsimd_avx512_f16_js(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n) {
|
|
503
503
|
__m512h sum_a_vec = _mm512_set1_ph((_Float16)0);
|
|
504
504
|
__m512h sum_b_vec = _mm512_set1_ph((_Float16)0);
|
|
505
|
-
__m512h epsilon_vec = _mm512_set1_ph((_Float16)
|
|
505
|
+
__m512h epsilon_vec = _mm512_set1_ph((_Float16)SIMSIMD_F16_DIVISION_EPSILON);
|
|
506
506
|
__m512h a_vec, b_vec;
|
|
507
507
|
|
|
508
508
|
simsimd_avx512_f16_js_cycle:
|
|
@@ -91,6 +91,14 @@
|
|
|
91
91
|
#define SIMSIMD_LOG(x) (logf(x))
|
|
92
92
|
#endif
|
|
93
93
|
|
|
94
|
+
#ifndef SIMSIMD_F32_DIVISION_EPSILON
|
|
95
|
+
#define SIMSIMD_F32_DIVISION_EPSILON 1e-7
|
|
96
|
+
#endif
|
|
97
|
+
|
|
98
|
+
#ifndef SIMSIMD_F16_DIVISION_EPSILON
|
|
99
|
+
#define SIMSIMD_F16_DIVISION_EPSILON 1e-3
|
|
100
|
+
#endif
|
|
101
|
+
|
|
94
102
|
#ifdef __cplusplus
|
|
95
103
|
extern "C" {
|
|
96
104
|
#endif
|
|
@@ -4,12 +4,6 @@ import assert from 'node:assert';
|
|
|
4
4
|
|
|
5
5
|
const simsimd = bindings('simsimd');
|
|
6
6
|
|
|
7
|
-
const f32Array1 = new Float32Array([1.0, 2.0, 3.0]);
|
|
8
|
-
const f32Array2 = new Float32Array([4.0, 5.0, 6.0]);
|
|
9
|
-
|
|
10
|
-
const u8Array1 = new Uint8Array([1, 2, 3]);
|
|
11
|
-
const u8Array2 = new Uint8Array([4, 5, 6]);
|
|
12
|
-
|
|
13
7
|
function assertAlmostEqual(actual, expected, tolerance = 1e-6) {
|
|
14
8
|
const lowerBound = expected - tolerance;
|
|
15
9
|
const upperBound = expected + tolerance;
|
|
@@ -17,20 +11,26 @@ function assertAlmostEqual(actual, expected, tolerance = 1e-6) {
|
|
|
17
11
|
}
|
|
18
12
|
|
|
19
13
|
test('Distance from itself', () => {
|
|
20
|
-
assertAlmostEqual(simsimd.sqeuclidean(f32Array1, f32Array1), 0.0, 0.01);
|
|
21
|
-
assertAlmostEqual(simsimd.cosine(f32Array1, f32Array1), 0.0, 0.01);
|
|
22
14
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
assertAlmostEqual(simsimd.
|
|
15
|
+
const f32s = new Float32Array([1.0, 2.0, 3.0]);
|
|
16
|
+
assertAlmostEqual(simsimd.sqeuclidean(f32s, f32s), 0.0, 0.01);
|
|
17
|
+
assertAlmostEqual(simsimd.cosine(f32s, f32s), 0.0, 0.01);
|
|
26
18
|
|
|
27
|
-
|
|
28
|
-
assertAlmostEqual(simsimd.
|
|
19
|
+
const f32sNormalized = new Float32Array([1.0 / Math.sqrt(14), 2.0 / Math.sqrt(14), 3.0 / Math.sqrt(14)]);
|
|
20
|
+
assertAlmostEqual(simsimd.inner(f32sNormalized, f32sNormalized), 0.0, 0.01);
|
|
29
21
|
|
|
30
|
-
|
|
31
|
-
assertAlmostEqual(simsimd.
|
|
22
|
+
const f32sDistribution = new Float32Array([1.0 / 6, 2.0 / 6, 3.0 / 6]);
|
|
23
|
+
assertAlmostEqual(simsimd.kullbackleibler(f32sDistribution, f32sDistribution), 0.0, 0.01);
|
|
24
|
+
assertAlmostEqual(simsimd.jensenshannon(f32sDistribution, f32sDistribution), 0.0, 0.01);
|
|
25
|
+
|
|
26
|
+
const u8s = new Uint8Array([1, 2, 3]);
|
|
27
|
+
assertAlmostEqual(simsimd.hamming(u8s, u8s), 0.0, 0.01);
|
|
28
|
+
assertAlmostEqual(simsimd.jaccard(u8s, u8s), 0.0, 0.01);
|
|
32
29
|
});
|
|
33
30
|
|
|
31
|
+
const f32Array1 = new Float32Array([1.0, 2.0, 3.0]);
|
|
32
|
+
const f32Array2 = new Float32Array([4.0, 5.0, 6.0]);
|
|
33
|
+
|
|
34
34
|
test('Squared Euclidean Distance', () => {
|
|
35
35
|
const result = simsimd.sqeuclidean(f32Array1, f32Array2);
|
|
36
36
|
assertAlmostEqual(result, 27.0, 0.01);
|
package/simsimd/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "simsimd",
|
|
3
|
-
"version": "3.3
|
|
3
|
+
"version": "3.5.3",
|
|
4
4
|
"description": "Vector Similarity Functions 3x-200x Faster than SciPy and NumPy",
|
|
5
5
|
"author": "Ash Vardanian",
|
|
6
6
|
"license": "Apache 2.0",
|
|
7
7
|
"main": "javascript/simsimd.js",
|
|
8
8
|
"type": "module",
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "node --test ./javascript/test",
|
|
11
|
+
"bench": "node ./javascript/bench.js"
|
|
12
12
|
},
|
|
13
13
|
"gypfile": true,
|
|
14
14
|
"engines": {
|
|
@@ -19,10 +19,6 @@
|
|
|
19
19
|
"bindings": "~1.2.1",
|
|
20
20
|
"node-addon-api": "^3.0.0"
|
|
21
21
|
},
|
|
22
|
-
"scripts": {
|
|
23
|
-
"test": "node --test ./javascript/test.js",
|
|
24
|
-
"bench": "node ./javascript/bench.js"
|
|
25
|
-
},
|
|
26
22
|
"devDependencies": {
|
|
27
23
|
"benchmark": "^2.1.4",
|
|
28
24
|
"mathjs": "^11.11.2",
|
package/simsimd/setup.py
CHANGED
|
@@ -27,6 +27,9 @@ if sys.platform == "linux":
|
|
|
27
27
|
compile_args.append("-fopenmp")
|
|
28
28
|
link_args.append("-lgomp")
|
|
29
29
|
|
|
30
|
+
# Add vectorized `logf` implementation from the `glibc`
|
|
31
|
+
link_args.append("-lm")
|
|
32
|
+
|
|
30
33
|
if sys.platform == "darwin":
|
|
31
34
|
compile_args.append("-std=c11")
|
|
32
35
|
compile_args.append("-O3")
|
package/wasmer.toml
CHANGED
package/docs/compilation.md
DELETED
|
@@ -1,215 +0,0 @@
|
|
|
1
|
-
# Compiling USearch
|
|
2
|
-
|
|
3
|
-
This document describes the workflow for advanced USearch users and enthusiasts willing to contribute to the project.
|
|
4
|
-
Before building the first time, please pull submodules.
|
|
5
|
-
|
|
6
|
-
```sh
|
|
7
|
-
git submodule update --init --recursive
|
|
8
|
-
```
|
|
9
|
-
|
|
10
|
-
## C++11
|
|
11
|
-
|
|
12
|
-
Linux:
|
|
13
|
-
|
|
14
|
-
```sh
|
|
15
|
-
sudo apt-get update
|
|
16
|
-
sudo apt-get install cmake build-essential libjemalloc-dev
|
|
17
|
-
cmake -B ./build_release \
|
|
18
|
-
-DCMAKE_BUILD_TYPE=Release \
|
|
19
|
-
-DUSEARCH_USE_OPENMP=1 \
|
|
20
|
-
-DUSEARCH_USE_SIMSIMD=1 \
|
|
21
|
-
-DUSEARCH_USE_JEMALLOC=1 \
|
|
22
|
-
-DUSEARCH_BUILD_TEST_CPP=1 \
|
|
23
|
-
-DUSEARCH_BUILD_BENCH_CPP=1 \
|
|
24
|
-
-DUSEARCH_BUILD_LIB_C=1 \
|
|
25
|
-
-DUSEARCH_BUILD_TEST_C=1 \
|
|
26
|
-
-DUSEARCH_USE_NATIVE_F16=1 \
|
|
27
|
-
&& \
|
|
28
|
-
make -C ./build_release -j
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
MacOS:
|
|
32
|
-
|
|
33
|
-
```sh
|
|
34
|
-
brew install libomp llvm
|
|
35
|
-
cmake -B ./build_release \
|
|
36
|
-
-DCMAKE_C_COMPILER="/opt/homebrew/opt/llvm/bin/clang" \
|
|
37
|
-
-DCMAKE_CXX_COMPILER="/opt/homebrew/opt/llvm/bin/clang++" \
|
|
38
|
-
-DUSEARCH_USE_OPENMP=1 \
|
|
39
|
-
-DUSEARCH_USE_SIMSIMD=1 \
|
|
40
|
-
-DUSEARCH_BUILD_BENCH_CPP=1 \
|
|
41
|
-
-DUSEARCH_BUILD_TEST_CPP=1 \
|
|
42
|
-
&& \
|
|
43
|
-
make -C ./build_release -j
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
Linting:
|
|
47
|
-
|
|
48
|
-
```sh
|
|
49
|
-
cppcheck --enable=all --force --suppress=cstyleCast --suppress=unusedFunction \
|
|
50
|
-
include/usearch/index.hpp \
|
|
51
|
-
include/index_dense.hpp \
|
|
52
|
-
include/index_plugins.hpp
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
Testing:
|
|
56
|
-
|
|
57
|
-
```sh
|
|
58
|
-
cmake -DUSEARCH_BUILD_TEST_CPP=1 -B ./build_debug
|
|
59
|
-
cmake --build ./build_debug --config Debug
|
|
60
|
-
./build_debug/test_cpp
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
## Python 3
|
|
64
|
-
|
|
65
|
-
Use PyTest to validate the build.
|
|
66
|
-
The `-s` option will disable capturing the logs.
|
|
67
|
-
The `-x` option will exit after first failure to simplify debugging.
|
|
68
|
-
|
|
69
|
-
```sh
|
|
70
|
-
pip install -e . && pytest python/scripts/ -s -x
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
Linting:
|
|
74
|
-
|
|
75
|
-
```sh
|
|
76
|
-
pip install ruff
|
|
77
|
-
ruff --format=github --select=E9,F63,F7,F82 --target-version=py37 python
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
Testing wheel builds locally:
|
|
81
|
-
|
|
82
|
-
```sh
|
|
83
|
-
pip install cibuildwheel
|
|
84
|
-
cibuildwheel --platform linux
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
## JavaScript
|
|
88
|
-
|
|
89
|
-
Node.JS:
|
|
90
|
-
|
|
91
|
-
```sh
|
|
92
|
-
npm install && node --test ./javascript/usearch.test.js
|
|
93
|
-
npm publish
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
WebAssembly:
|
|
97
|
-
|
|
98
|
-
```sh
|
|
99
|
-
emcmake cmake -B ./build -DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS} -s TOTAL_MEMORY=64MB" && emmake make -C ./build
|
|
100
|
-
node ./build/usearch.test.js
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
If you don't yet have `emcmake` installed:
|
|
104
|
-
|
|
105
|
-
```sh
|
|
106
|
-
git clone https://github.com/emscripten-core/emsdk.git && ./emsdk/emsdk install latest && ./emsdk/emsdk activate latest && source ./emsdk/emsdk_env.sh
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
## Rust
|
|
110
|
-
|
|
111
|
-
```sh
|
|
112
|
-
cargo test -p usearch
|
|
113
|
-
cargo publish
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
## Java
|
|
117
|
-
|
|
118
|
-
```sh
|
|
119
|
-
gradle clean build
|
|
120
|
-
java -cp . -Djava.library.path="$(pwd)/build/libs/usearch/shared" java/cloud/unum/usearch/Index.java
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
Or step by-step:
|
|
124
|
-
|
|
125
|
-
```sh
|
|
126
|
-
cs java/unum/cloud/usearch
|
|
127
|
-
javac -h . Index.java
|
|
128
|
-
|
|
129
|
-
# Ubuntu:
|
|
130
|
-
g++ -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux cloud_unum_usearch_Index.cpp -o cloud_unum_usearch_Index.o
|
|
131
|
-
g++ -shared -fPIC -o libusearch_c.so cloud_unum_usearch_Index.o -lc
|
|
132
|
-
|
|
133
|
-
# Windows
|
|
134
|
-
g++ -c -I%JAVA_HOME%\include -I%JAVA_HOME%\include\win32 cloud_unum_usearch_Index.cpp -o cloud_unum_usearch_Index.o
|
|
135
|
-
g++ -shared -o USearchJNI.dll cloud_unum_usearch_Index.o -Wl,--add-stdcall-alias
|
|
136
|
-
|
|
137
|
-
# MacOS
|
|
138
|
-
g++ -std=c++11 -c -fPIC \
|
|
139
|
-
-I../../../../include \
|
|
140
|
-
-I../../../../fp16/include \
|
|
141
|
-
-I../../../../simsimd/include \
|
|
142
|
-
-I${JAVA_HOME}/include -I${JAVA_HOME}/include/darwin cloud_unum_usearch_Index.cpp -o cloud_unum_usearch_Index.o
|
|
143
|
-
g++ -dynamiclib -o libusearch.dylib cloud_unum_usearch_Index.o -lc
|
|
144
|
-
# Run linking to that directory
|
|
145
|
-
java -cp . -Djava.library.path="$(pwd)/java/cloud/unum/usearch/" Index.java
|
|
146
|
-
java -cp . -Djava.library.path="$(pwd)/java" cloud.unum.usearch.Index
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
## Objective-C and Swift
|
|
150
|
-
|
|
151
|
-
```sh
|
|
152
|
-
swift build
|
|
153
|
-
swift test -v
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
## C 99
|
|
157
|
-
|
|
158
|
-
There are a few ways to compile the C 99 USearch SDK.
|
|
159
|
-
Using the Makefile, specifying the targets you need:
|
|
160
|
-
|
|
161
|
-
```sh
|
|
162
|
-
cmake -B ./build_release -DUSEARCH_BUILD_LIB_C=1 -DUSEARCH_BUILD_TEST_C=1 -DUSEARCH_USE_OPENMP=1 -DUSEARCH_USE_SIMSIMD=1
|
|
163
|
-
cmake --build ./build_release --config Release -j
|
|
164
|
-
./build_release/test_c
|
|
165
|
-
# On Windows:
|
|
166
|
-
.\build_release\test_c.exe
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
## GoLang
|
|
170
|
-
|
|
171
|
-
GoLang bindings are based on C.
|
|
172
|
-
So one should first compile the C library, link it with GoLang, and only then run tests.
|
|
173
|
-
|
|
174
|
-
```sh
|
|
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/
|
|
179
|
-
cd golang && go test -v ; cd ..
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
## Wolfram
|
|
183
|
-
|
|
184
|
-
```sh
|
|
185
|
-
brew install --cask wolfram-engine
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
## Docker
|
|
189
|
-
|
|
190
|
-
```sh
|
|
191
|
-
docker build -t unum/usearch . && docker run unum/usearch
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
For multi-architecture builds and publications:
|
|
195
|
-
|
|
196
|
-
```sh
|
|
197
|
-
version=$(cat VERSION)
|
|
198
|
-
docker buildx create --use &&
|
|
199
|
-
docker login &&
|
|
200
|
-
docker buildx build \
|
|
201
|
-
--platform "linux/amd64,linux/arm64" \
|
|
202
|
-
--build-arg version=$version \
|
|
203
|
-
--file Dockerfile \
|
|
204
|
-
--tag unum/usearch:$version \
|
|
205
|
-
--tag unum/usearch:latest \
|
|
206
|
-
--push .
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
## Sub-Modules
|
|
210
|
-
|
|
211
|
-
Extending metrics in SimSIMD:
|
|
212
|
-
|
|
213
|
-
```sh
|
|
214
|
-
git push --set-upstream https://github.com/ashvardanian/simsimd.git HEAD:main
|
|
215
|
-
```
|