usearch 2.9.1 → 2.9.2
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/CITATION.cff +1 -1
- package/CONTRIBUTING.md +10 -2
- package/Cargo.toml +1 -1
- package/README.md +12 -15
- package/VERSION +1 -1
- package/c/test.c +58 -50
- package/conanfile.py +1 -1
- package/include/usearch/index.hpp +1 -1
- package/include/usearch/index_plugins.hpp +20 -10
- package/javascript/types/usearch.d.ts.map +1 -1
- package/javascript/usearch.js +4 -1
- package/package.json +1 -1
- package/simsimd/CONTRIBUTING.md +88 -0
- package/simsimd/Cargo.lock +4 -3
- package/simsimd/Cargo.toml +10 -2
- package/simsimd/README.md +102 -60
- package/simsimd/include/simsimd/binary.h +44 -0
- package/simsimd/include/simsimd/complex.h +174 -0
- package/simsimd/include/simsimd/simsimd.h +18 -9
- package/simsimd/include/simsimd/spatial.h +128 -36
- package/simsimd/include/simsimd/types.h +3 -2
- package/simsimd/package-lock.json +5 -5
- package/simsimd/package.json +1 -1
- package/simsimd/rust/benches/native.rs +12 -9
- package/simsimd/rust/lib.c +32 -55
- package/simsimd/rust/lib.rs +374 -56
- package/stringzilla/CONTRIBUTING.md +17 -0
- package/stringzilla/Cargo.lock +1 -1
- package/stringzilla/Cargo.toml +1 -1
- package/stringzilla/README.md +175 -34
- package/stringzilla/VERSION +1 -1
- package/stringzilla/build.rs +77 -4
- package/stringzilla/c/lib.c +33 -0
- package/stringzilla/cli/README.md +30 -13
- package/stringzilla/cli/__init__.py +0 -0
- package/stringzilla/cli/split.py +66 -33
- package/stringzilla/cli/wc.py +101 -21
- package/stringzilla/include/stringzilla/experimental.h +122 -1
- package/stringzilla/include/stringzilla/stringzilla.h +262 -132
- package/stringzilla/include/stringzilla/stringzilla.hpp +13 -5
- package/stringzilla/package.json +1 -1
- package/stringzilla/rust/lib.rs +673 -162
- package/wasmer.toml +1 -1
|
@@ -194,11 +194,25 @@ simsimd_neon_f16_l2sq(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_si
|
|
|
194
194
|
float32x4_t diff_vec = vsubq_f32(a_vec, b_vec);
|
|
195
195
|
sum_vec = vfmaq_f32(sum_vec, diff_vec, diff_vec);
|
|
196
196
|
}
|
|
197
|
-
|
|
198
|
-
for
|
|
199
|
-
|
|
200
|
-
|
|
197
|
+
|
|
198
|
+
// In case the software emulation for `f16` scalars is enabled, the `simsimd_uncompress_f16`
|
|
199
|
+
// function will run. It is extremely slow, so even for the tail, let's combine serial
|
|
200
|
+
// loads and stores with vectorized math.
|
|
201
|
+
if (i < n) {
|
|
202
|
+
union {
|
|
203
|
+
float16x4_t f16_vec;
|
|
204
|
+
simsimd_f16_t f16[4];
|
|
205
|
+
} a_padded_tail, b_padded_tail;
|
|
206
|
+
simsimd_size_t j = 0;
|
|
207
|
+
for (; i < n; ++i, ++j)
|
|
208
|
+
a_padded_tail.f16[j] = a[i], b_padded_tail.f16[j] = b[i];
|
|
209
|
+
for (; j < 4; ++j)
|
|
210
|
+
a_padded_tail.f16[j] = 0, b_padded_tail.f16[j] = 0;
|
|
211
|
+
float32x4_t diff_vec = vsubq_f32(vcvt_f32_f16(a_padded_tail.f16_vec), vcvt_f32_f16(b_padded_tail.f16_vec));
|
|
212
|
+
sum_vec = vfmaq_f32(sum_vec, diff_vec, diff_vec);
|
|
201
213
|
}
|
|
214
|
+
|
|
215
|
+
simsimd_f32_t sum = vaddvq_f32(sum_vec);
|
|
202
216
|
return sum;
|
|
203
217
|
}
|
|
204
218
|
|
|
@@ -212,9 +226,23 @@ simsimd_neon_f16_ip(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size
|
|
|
212
226
|
float32x4_t b_vec = vcvt_f32_f16(vld1_f16((float16_t const*)b + i));
|
|
213
227
|
ab_vec = vfmaq_f32(ab_vec, a_vec, b_vec);
|
|
214
228
|
}
|
|
229
|
+
|
|
230
|
+
// In case the software emulation for `f16` scalars is enabled, the `simsimd_uncompress_f16`
|
|
231
|
+
// function will run. It is extremely slow, so even for the tail, let's combine serial
|
|
232
|
+
// loads and stores with vectorized math.
|
|
233
|
+
if (i < n) {
|
|
234
|
+
union {
|
|
235
|
+
float16x4_t f16_vec;
|
|
236
|
+
simsimd_f16_t f16[4];
|
|
237
|
+
} a_padded_tail, b_padded_tail;
|
|
238
|
+
simsimd_size_t j = 0;
|
|
239
|
+
for (; i < n; ++i, ++j)
|
|
240
|
+
a_padded_tail.f16[j] = a[i], b_padded_tail.f16[j] = b[i];
|
|
241
|
+
for (; j < 4; ++j)
|
|
242
|
+
a_padded_tail.f16[j] = 0, b_padded_tail.f16[j] = 0;
|
|
243
|
+
ab_vec = vfmaq_f32(ab_vec, vcvt_f32_f16(a_padded_tail.f16_vec), vcvt_f32_f16(b_padded_tail.f16_vec));
|
|
244
|
+
}
|
|
215
245
|
simsimd_f32_t ab = vaddvq_f32(ab_vec);
|
|
216
|
-
for (; i < n; ++i)
|
|
217
|
-
ab += SIMSIMD_UNCOMPRESS_F16(a[i]) * SIMSIMD_UNCOMPRESS_F16(b[i]);
|
|
218
246
|
return 1 - ab;
|
|
219
247
|
}
|
|
220
248
|
|
|
@@ -230,13 +258,29 @@ simsimd_neon_f16_cos(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_siz
|
|
|
230
258
|
a2_vec = vfmaq_f32(a2_vec, a_vec, a_vec);
|
|
231
259
|
b2_vec = vfmaq_f32(b2_vec, b_vec, b_vec);
|
|
232
260
|
}
|
|
233
|
-
|
|
234
|
-
for
|
|
235
|
-
|
|
236
|
-
|
|
261
|
+
|
|
262
|
+
// In case the software emulation for `f16` scalars is enabled, the `simsimd_uncompress_f16`
|
|
263
|
+
// function will run. It is extremely slow, so even for the tail, let's combine serial
|
|
264
|
+
// loads and stores with vectorized math.
|
|
265
|
+
if (i < n) {
|
|
266
|
+
union {
|
|
267
|
+
float16x4_t f16_vec;
|
|
268
|
+
simsimd_f16_t f16[4];
|
|
269
|
+
} a_padded_tail, b_padded_tail;
|
|
270
|
+
simsimd_size_t j = 0;
|
|
271
|
+
for (; i < n; ++i, ++j)
|
|
272
|
+
a_padded_tail.f16[j] = a[i], b_padded_tail.f16[j] = b[i];
|
|
273
|
+
for (; j < 4; ++j)
|
|
274
|
+
a_padded_tail.f16[j] = 0, b_padded_tail.f16[j] = 0;
|
|
275
|
+
float32x4_t a_vec = vcvt_f32_f16(a_padded_tail.f16_vec);
|
|
276
|
+
float32x4_t b_vec = vcvt_f32_f16(b_padded_tail.f16_vec);
|
|
277
|
+
ab_vec = vfmaq_f32(ab_vec, a_vec, b_vec);
|
|
278
|
+
a2_vec = vfmaq_f32(a2_vec, a_vec, a_vec);
|
|
279
|
+
b2_vec = vfmaq_f32(b2_vec, b_vec, b_vec);
|
|
237
280
|
}
|
|
238
281
|
|
|
239
282
|
// Avoid `simsimd_approximate_inverse_square_root` on Arm NEON
|
|
283
|
+
simsimd_f32_t ab = vaddvq_f32(ab_vec), a2 = vaddvq_f32(a2_vec), b2 = vaddvq_f32(b2_vec);
|
|
240
284
|
simsimd_f32_t a2_b2_arr[2] = {a2, b2};
|
|
241
285
|
float32x2_t a2_b2 = vld1_f32(a2_b2_arr);
|
|
242
286
|
a2_b2 = vrsqrte_f32(a2_b2);
|
|
@@ -582,18 +626,31 @@ simsimd_avx2_f16_l2sq(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_si
|
|
|
582
626
|
d2_vec = _mm256_fmadd_ps(d_vec, d_vec, d2_vec);
|
|
583
627
|
}
|
|
584
628
|
|
|
629
|
+
// In case the software emulation for `f16` scalars is enabled, the `simsimd_uncompress_f16`
|
|
630
|
+
// function will run. It is extremely slow, so even for the tail, let's combine serial
|
|
631
|
+
// loads and stores with vectorized math.
|
|
632
|
+
if (i < n) {
|
|
633
|
+
union {
|
|
634
|
+
__m128i f16_vec;
|
|
635
|
+
simsimd_f16_t f16[8];
|
|
636
|
+
} a_padded_tail, b_padded_tail;
|
|
637
|
+
simsimd_size_t j = 0;
|
|
638
|
+
for (; i < n; ++i, ++j)
|
|
639
|
+
a_padded_tail.f16[j] = a[i], b_padded_tail.f16[j] = b[i];
|
|
640
|
+
for (; j < 8; ++j)
|
|
641
|
+
a_padded_tail.f16[j] = 0, b_padded_tail.f16[j] = 0;
|
|
642
|
+
__m256 a_vec = _mm256_cvtph_ps(a_padded_tail.f16_vec);
|
|
643
|
+
__m256 b_vec = _mm256_cvtph_ps(b_padded_tail.f16_vec);
|
|
644
|
+
__m256 d_vec = _mm256_sub_ps(a_vec, b_vec);
|
|
645
|
+
d2_vec = _mm256_fmadd_ps(d_vec, d_vec, d2_vec);
|
|
646
|
+
}
|
|
647
|
+
|
|
585
648
|
d2_vec = _mm256_add_ps(_mm256_permute2f128_ps(d2_vec, d2_vec, 1), d2_vec);
|
|
586
649
|
d2_vec = _mm256_hadd_ps(d2_vec, d2_vec);
|
|
587
650
|
d2_vec = _mm256_hadd_ps(d2_vec, d2_vec);
|
|
588
651
|
|
|
589
652
|
simsimd_f32_t result;
|
|
590
653
|
_mm_store_ss(&result, _mm256_castps256_ps128(d2_vec));
|
|
591
|
-
|
|
592
|
-
// Accumulate the tail:
|
|
593
|
-
for (; i < n; ++i) {
|
|
594
|
-
simsimd_f32_t n = SIMSIMD_UNCOMPRESS_F16(a[i]) - SIMSIMD_UNCOMPRESS_F16(b[i]);
|
|
595
|
-
result += n * n;
|
|
596
|
-
}
|
|
597
654
|
return result;
|
|
598
655
|
}
|
|
599
656
|
|
|
@@ -608,18 +665,33 @@ simsimd_avx2_f16_ip(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size
|
|
|
608
665
|
ab_vec = _mm256_fmadd_ps(a_vec, b_vec, ab_vec);
|
|
609
666
|
}
|
|
610
667
|
|
|
668
|
+
// In case the software emulation for `f16` scalars is enabled, the `simsimd_uncompress_f16`
|
|
669
|
+
// function will run. It is extremely slow, so even for the tail, let's combine serial
|
|
670
|
+
// loads and stores with vectorized math.
|
|
671
|
+
if (i < n) {
|
|
672
|
+
union {
|
|
673
|
+
__m128i f16_vec;
|
|
674
|
+
simsimd_f16_t f16[8];
|
|
675
|
+
} a_padded_tail, b_padded_tail;
|
|
676
|
+
simsimd_size_t j = 0;
|
|
677
|
+
for (; i < n; ++i, ++j)
|
|
678
|
+
a_padded_tail.f16[j] = a[i], b_padded_tail.f16[j] = b[i];
|
|
679
|
+
for (; j < 8; ++j)
|
|
680
|
+
a_padded_tail.f16[j] = 0, b_padded_tail.f16[j] = 0;
|
|
681
|
+
__m256 a_vec = _mm256_cvtph_ps(a_padded_tail.f16_vec);
|
|
682
|
+
__m256 b_vec = _mm256_cvtph_ps(b_padded_tail.f16_vec);
|
|
683
|
+
ab_vec = _mm256_fmadd_ps(a_vec, b_vec, ab_vec);
|
|
684
|
+
}
|
|
685
|
+
|
|
611
686
|
ab_vec = _mm256_add_ps(_mm256_permute2f128_ps(ab_vec, ab_vec, 1), ab_vec);
|
|
612
687
|
ab_vec = _mm256_hadd_ps(ab_vec, ab_vec);
|
|
613
688
|
ab_vec = _mm256_hadd_ps(ab_vec, ab_vec);
|
|
614
689
|
|
|
615
690
|
simsimd_f32_t result;
|
|
616
691
|
_mm_store_ss(&result, _mm256_castps256_ps128(ab_vec));
|
|
617
|
-
|
|
618
|
-
// Accumulate the tail:
|
|
619
|
-
for (; i < n; ++i)
|
|
620
|
-
result += SIMSIMD_UNCOMPRESS_F16(a[i]) * SIMSIMD_UNCOMPRESS_F16(b[i]);
|
|
621
692
|
return 1 - result;
|
|
622
693
|
}
|
|
694
|
+
|
|
623
695
|
__attribute__((target("avx2,f16c,fma"))) //
|
|
624
696
|
inline static simsimd_f32_t
|
|
625
697
|
simsimd_avx2_f16_cos(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_size_t n) {
|
|
@@ -634,6 +706,27 @@ simsimd_avx2_f16_cos(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_siz
|
|
|
634
706
|
b2_vec = _mm256_fmadd_ps(b_vec, b_vec, b2_vec);
|
|
635
707
|
}
|
|
636
708
|
|
|
709
|
+
// In case the software emulation for `f16` scalars is enabled, the `simsimd_uncompress_f16`
|
|
710
|
+
// function will run. It is extremely slow, so even for the tail, let's combine serial
|
|
711
|
+
// loads and stores with vectorized math.
|
|
712
|
+
if (i < n) {
|
|
713
|
+
union {
|
|
714
|
+
__m128i f16_vec;
|
|
715
|
+
simsimd_f16_t f16[8];
|
|
716
|
+
} a_padded_tail, b_padded_tail;
|
|
717
|
+
simsimd_size_t j = 0;
|
|
718
|
+
for (; i < n; ++i, ++j)
|
|
719
|
+
a_padded_tail.f16[j] = a[i], b_padded_tail.f16[j] = b[i];
|
|
720
|
+
for (; j < 8; ++j)
|
|
721
|
+
a_padded_tail.f16[j] = 0, b_padded_tail.f16[j] = 0;
|
|
722
|
+
__m256 a_vec = _mm256_cvtph_ps(a_padded_tail.f16_vec);
|
|
723
|
+
__m256 b_vec = _mm256_cvtph_ps(b_padded_tail.f16_vec);
|
|
724
|
+
ab_vec = _mm256_fmadd_ps(a_vec, b_vec, ab_vec);
|
|
725
|
+
a2_vec = _mm256_fmadd_ps(a_vec, a_vec, a2_vec);
|
|
726
|
+
b2_vec = _mm256_fmadd_ps(b_vec, b_vec, b2_vec);
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
// Horizontal reductions:
|
|
637
730
|
ab_vec = _mm256_add_ps(_mm256_permute2f128_ps(ab_vec, ab_vec, 1), ab_vec);
|
|
638
731
|
ab_vec = _mm256_hadd_ps(ab_vec, ab_vec);
|
|
639
732
|
ab_vec = _mm256_hadd_ps(ab_vec, ab_vec);
|
|
@@ -651,12 +744,6 @@ simsimd_avx2_f16_cos(simsimd_f16_t const* a, simsimd_f16_t const* b, simsimd_siz
|
|
|
651
744
|
_mm_store_ss(&a2, _mm256_castps256_ps128(a2_vec));
|
|
652
745
|
_mm_store_ss(&b2, _mm256_castps256_ps128(b2_vec));
|
|
653
746
|
|
|
654
|
-
// Accumulate the tail:
|
|
655
|
-
for (; i < n; ++i) {
|
|
656
|
-
simsimd_f32_t ai = SIMSIMD_UNCOMPRESS_F16(a[i]), bi = SIMSIMD_UNCOMPRESS_F16(b[i]);
|
|
657
|
-
ab += ai * bi, a2 += ai * ai, b2 += bi * bi;
|
|
658
|
-
}
|
|
659
|
-
|
|
660
747
|
// Replace simsimd_approximate_inverse_square_root with `rsqrtss`
|
|
661
748
|
__m128 a2_sqrt_recip = _mm_rsqrt_ss(_mm_set_ss((float)a2));
|
|
662
749
|
__m128 b2_sqrt_recip = _mm_rsqrt_ss(_mm_set_ss((float)b2));
|
|
@@ -1037,19 +1124,24 @@ simsimd_avx512_i8_cos(simsimd_i8_t const* a, simsimd_i8_t const* b, simsimd_size
|
|
|
1037
1124
|
__m512i a_vec, b_vec;
|
|
1038
1125
|
|
|
1039
1126
|
simsimd_avx512_i8_cos_cycle:
|
|
1040
|
-
if (n <
|
|
1041
|
-
|
|
1042
|
-
a_vec =
|
|
1043
|
-
b_vec =
|
|
1127
|
+
if (n < 32) {
|
|
1128
|
+
__mmask32 mask = _bzhi_u32(0xFFFFFFFF, n);
|
|
1129
|
+
a_vec = _mm512_cvtepi8_epi16(_mm256_maskz_loadu_epi8(mask, a));
|
|
1130
|
+
b_vec = _mm512_cvtepi8_epi16(_mm256_maskz_loadu_epi8(mask, b));
|
|
1044
1131
|
n = 0;
|
|
1045
1132
|
} else {
|
|
1046
|
-
a_vec =
|
|
1047
|
-
b_vec =
|
|
1048
|
-
a +=
|
|
1133
|
+
a_vec = _mm512_cvtepi8_epi16(_mm256_loadu_epi8(a));
|
|
1134
|
+
b_vec = _mm512_cvtepi8_epi16(_mm256_loadu_epi8(b));
|
|
1135
|
+
a += 32, b += 32, n -= 32;
|
|
1049
1136
|
}
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1137
|
+
// Unfortunately we can't use the `_mm512_dpbusd_epi32` intrinsics here either,
|
|
1138
|
+
// as it's assymetric with respect to the sign of the input arguments:
|
|
1139
|
+
// Signed(ZeroExtend16(a.byte[4*j]) * SignExtend16(b.byte[4*j]))
|
|
1140
|
+
// So we have to use the `_mm512_dpwssd_epi32` intrinsics instead, upcasting
|
|
1141
|
+
// to 16-bit beforehand.
|
|
1142
|
+
ab_i32s_vec = _mm512_dpwssd_epi32(ab_i32s_vec, a_vec, b_vec);
|
|
1143
|
+
a2_i32s_vec = _mm512_dpwssd_epi32(a2_i32s_vec, a_vec, a_vec);
|
|
1144
|
+
b2_i32s_vec = _mm512_dpwssd_epi32(b2_i32s_vec, b_vec, b_vec);
|
|
1053
1145
|
if (n)
|
|
1054
1146
|
goto simsimd_avx512_i8_cos_cycle;
|
|
1055
1147
|
|
|
@@ -84,11 +84,11 @@
|
|
|
84
84
|
#endif
|
|
85
85
|
|
|
86
86
|
#ifndef SIMSIMD_F32_DIVISION_EPSILON
|
|
87
|
-
#define SIMSIMD_F32_DIVISION_EPSILON 1e-7
|
|
87
|
+
#define SIMSIMD_F32_DIVISION_EPSILON (1e-7)
|
|
88
88
|
#endif
|
|
89
89
|
|
|
90
90
|
#ifndef SIMSIMD_F16_DIVISION_EPSILON
|
|
91
|
-
#define SIMSIMD_F16_DIVISION_EPSILON 1e-3
|
|
91
|
+
#define SIMSIMD_F16_DIVISION_EPSILON (1e-3)
|
|
92
92
|
#endif
|
|
93
93
|
|
|
94
94
|
#ifdef __cplusplus
|
|
@@ -100,6 +100,7 @@ typedef float simsimd_f32_t;
|
|
|
100
100
|
typedef double simsimd_f64_t;
|
|
101
101
|
typedef signed char simsimd_i8_t;
|
|
102
102
|
typedef unsigned char simsimd_b8_t;
|
|
103
|
+
typedef unsigned long long simsimd_u64_t;
|
|
103
104
|
typedef unsigned long long simsimd_size_t;
|
|
104
105
|
|
|
105
106
|
#if !defined(SIMSIMD_NATIVE_F16) || SIMSIMD_NATIVE_F16
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "simsimd",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.8.1",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "simsimd",
|
|
9
|
-
"version": "3.
|
|
9
|
+
"version": "3.8.1",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "Apache 2.0",
|
|
12
12
|
"dependencies": {
|
|
@@ -627,9 +627,9 @@
|
|
|
627
627
|
"dev": true
|
|
628
628
|
},
|
|
629
629
|
"node_modules/ip": {
|
|
630
|
-
"version": "2.0.
|
|
631
|
-
"resolved": "https://registry.npmjs.org/ip/-/ip-2.0.
|
|
632
|
-
"integrity": "sha512-
|
|
630
|
+
"version": "2.0.1",
|
|
631
|
+
"resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz",
|
|
632
|
+
"integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==",
|
|
633
633
|
"dev": true
|
|
634
634
|
},
|
|
635
635
|
"node_modules/is-fullwidth-code-point": {
|
package/simsimd/package.json
CHANGED
|
@@ -10,18 +10,21 @@ pub(crate) fn cosine_similarity_cpu(a: &[f32], b: &[f32]) -> Option<f32> {
|
|
|
10
10
|
return None;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
let dot_product
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
let (dot_product, norm_a, norm_b) = a
|
|
14
|
+
.iter()
|
|
15
|
+
.zip(b)
|
|
16
|
+
.map(|(a, b)| (a * b, a * a, b * b))
|
|
17
|
+
.fold((0.0, 0.0, 0.0), |acc, x| {
|
|
18
|
+
(acc.0 + x.0, acc.1 + x.1, acc.2 + x.2)
|
|
19
|
+
});
|
|
16
20
|
|
|
17
21
|
Some(1.0 - (dot_product / (norm_a.sqrt() * norm_b.sqrt())))
|
|
18
22
|
}
|
|
19
23
|
|
|
20
|
-
pub(crate) fn squared_euclidean_cpu(a: &[f32], b: &[f32]) -> f32 {
|
|
21
|
-
|
|
24
|
+
pub(crate) fn squared_euclidean_cpu(a: &[f32], b: &[f32]) -> Option<f32> {
|
|
25
|
+
if a.len() != b.len() {
|
|
26
|
+
return None;
|
|
27
|
+
}
|
|
22
28
|
|
|
23
|
-
a.iter()
|
|
24
|
-
.zip(b.iter())
|
|
25
|
-
.map(|(x, y)| ((*x) - (*y)) * ((*x) - (*y)))
|
|
26
|
-
.fold(0.0, ::std::ops::Add::add)
|
|
29
|
+
Some(a.iter().zip(b).map(|(x, y)| (x - y).powi(2)).sum())
|
|
27
30
|
}
|
package/simsimd/rust/lib.c
CHANGED
|
@@ -7,62 +7,39 @@ simsimd_capability_t cached_capabilities(void) {
|
|
|
7
7
|
return static_capabilities;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
#define SIMSIMD_METRIC_DECLARATION(name, type) \
|
|
11
|
+
simsimd_f32_t name##_##type(simsimd_##type##_t const* a, simsimd_##type##_t const* b, simsimd_size_t d) { \
|
|
12
|
+
static simsimd_metric_punned_t metric = 0; \
|
|
13
|
+
if (metric == 0) { \
|
|
14
|
+
simsimd_capability_t used_capability; \
|
|
15
|
+
simsimd_find_metric_punned(simsimd_metric_##name##_k, simsimd_datatype_##type##_k, cached_capabilities(), \
|
|
16
|
+
simsimd_cap_any_k, &metric, &used_capability); \
|
|
17
|
+
} \
|
|
18
|
+
return metric(a, b, d, d); \
|
|
16
19
|
}
|
|
17
|
-
return metric(a, b, d, d);
|
|
18
|
-
}
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
21
|
+
// Spatial distances
|
|
22
|
+
SIMSIMD_METRIC_DECLARATION(cosine, i8)
|
|
23
|
+
SIMSIMD_METRIC_DECLARATION(cosine, f16)
|
|
24
|
+
SIMSIMD_METRIC_DECLARATION(cosine, f32)
|
|
25
|
+
SIMSIMD_METRIC_DECLARATION(cosine, f64)
|
|
26
|
+
SIMSIMD_METRIC_DECLARATION(inner, i8)
|
|
27
|
+
SIMSIMD_METRIC_DECLARATION(inner, f16)
|
|
28
|
+
SIMSIMD_METRIC_DECLARATION(inner, f32)
|
|
29
|
+
SIMSIMD_METRIC_DECLARATION(inner, f64)
|
|
30
|
+
SIMSIMD_METRIC_DECLARATION(sqeuclidean, i8)
|
|
31
|
+
SIMSIMD_METRIC_DECLARATION(sqeuclidean, f16)
|
|
32
|
+
SIMSIMD_METRIC_DECLARATION(sqeuclidean, f32)
|
|
33
|
+
SIMSIMD_METRIC_DECLARATION(sqeuclidean, f64)
|
|
29
34
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
simsimd_capability_t used_capability;
|
|
34
|
-
simsimd_find_metric_punned(simsimd_metric_inner_k, simsimd_datatype_i8_k, cached_capabilities(),
|
|
35
|
-
simsimd_cap_any_k, &metric, &used_capability);
|
|
36
|
-
}
|
|
37
|
-
return metric(a, b, d, d);
|
|
38
|
-
}
|
|
35
|
+
// Binary distances
|
|
36
|
+
SIMSIMD_METRIC_DECLARATION(hamming, b8)
|
|
37
|
+
SIMSIMD_METRIC_DECLARATION(jaccard, b8)
|
|
39
38
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
return metric(a, b, d, d);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
simsimd_f32_t sqeuclidean_i8(simsimd_i8_t const* a, simsimd_i8_t const* b, simsimd_size_t d) {
|
|
51
|
-
static simsimd_metric_punned_t metric = 0;
|
|
52
|
-
if (metric == 0) {
|
|
53
|
-
simsimd_capability_t used_capability;
|
|
54
|
-
simsimd_find_metric_punned(simsimd_metric_sqeuclidean_k, simsimd_datatype_i8_k, cached_capabilities(),
|
|
55
|
-
simsimd_cap_any_k, &metric, &used_capability);
|
|
56
|
-
}
|
|
57
|
-
return metric(a, b, d, d);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
simsimd_f32_t sqeuclidean_f32(simsimd_f32_t const* a, simsimd_f32_t const* b, simsimd_size_t d) {
|
|
61
|
-
static simsimd_metric_punned_t metric = 0;
|
|
62
|
-
if (metric == 0) {
|
|
63
|
-
simsimd_capability_t used_capability;
|
|
64
|
-
simsimd_find_metric_punned(simsimd_metric_sqeuclidean_k, simsimd_datatype_f32_k, cached_capabilities(),
|
|
65
|
-
simsimd_cap_any_k, &metric, &used_capability);
|
|
66
|
-
}
|
|
67
|
-
return metric(a, b, d, d);
|
|
68
|
-
}
|
|
39
|
+
// Probability distributions
|
|
40
|
+
SIMSIMD_METRIC_DECLARATION(kl, f16)
|
|
41
|
+
SIMSIMD_METRIC_DECLARATION(kl, f32)
|
|
42
|
+
SIMSIMD_METRIC_DECLARATION(kl, f64)
|
|
43
|
+
SIMSIMD_METRIC_DECLARATION(js, f16)
|
|
44
|
+
SIMSIMD_METRIC_DECLARATION(js, f32)
|
|
45
|
+
SIMSIMD_METRIC_DECLARATION(js, f64)
|