usearch 2.2.0 → 2.3.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.
@@ -45,6 +45,9 @@
45
45
  #endif
46
46
  #endif
47
47
 
48
+ #undef SIMSIMD_TARGET_X86
49
+ #undef SIMSIMD_TARGET_X86_AVX2
50
+ #undef SIMSIMD_TARGET_X86_AVX512
48
51
  #define SIMSIMD_TARGET_X86 0
49
52
  #define SIMSIMD_TARGET_X86_AVX2 0
50
53
  #define SIMSIMD_TARGET_X86_AVX512 0
@@ -71,6 +74,9 @@
71
74
  #endif
72
75
  #endif
73
76
 
77
+ #undef SIMSIMD_TARGET_ARM
78
+ #undef SIMSIMD_TARGET_ARM_NEON
79
+ #undef SIMSIMD_TARGET_ARM_SVE
74
80
  #define SIMSIMD_TARGET_ARM 0
75
81
  #define SIMSIMD_TARGET_ARM_NEON 0
76
82
  #define SIMSIMD_TARGET_ARM_SVE 0
@@ -143,7 +149,7 @@ simsimd_cos_f32_sve(simsimd_f32_t const* a, simsimd_f32_t const* b, size_t d) {
143
149
  simsimd_f32_t ab = svaddv_f32(svptrue_b32(), ab_vec);
144
150
  simsimd_f32_t a2 = svaddv_f32(svptrue_b32(), a2_vec);
145
151
  simsimd_f32_t b2 = svaddv_f32(svptrue_b32(), b2_vec);
146
- return 1 - ab / (sqrt(a2) * sqrt(b2));
152
+ return 1 - ab / (sqrtf(a2) * sqrtf(b2));
147
153
  }
148
154
 
149
155
  __attribute__((target("+sve"))) inline static simsimd_f32_t //
@@ -184,7 +190,7 @@ simsimd_cos_f16_sve(simsimd_f16_t const* a_enum, simsimd_f16_t const* b_enum, si
184
190
  simsimd_f16_t ab = svaddv_f16(svptrue_b16(), ab_vec);
185
191
  simsimd_f16_t a2 = svaddv_f16(svptrue_b16(), a2_vec);
186
192
  simsimd_f16_t b2 = svaddv_f16(svptrue_b16(), b2_vec);
187
- return 1 - ab / (sqrt(a2) * sqrt(b2));
193
+ return 1 - ab / (sqrtf(a2) * sqrtf(b2));
188
194
  }
189
195
 
190
196
  __attribute__((target("+sve+fp16"))) inline static simsimd_f32_t //
@@ -235,6 +241,18 @@ simsimd_dot_f32x4_neon(simsimd_f32_t const* a, simsimd_f32_t const* b, size_t d)
235
241
  return 1 - vaddvq_f32(ab_vec);
236
242
  }
237
243
 
244
+ __attribute__((target("+simd+fp16"))) inline static simsimd_f32_t //
245
+ simsimd_dot_f16x4_neon(simsimd_f16_t const* a, simsimd_f16_t const* b, size_t d) {
246
+
247
+ float32x4_t ab_vec = vdupq_n_f32(0);
248
+ for (size_t i = 0; i != d; i += 4) {
249
+ float32x4_t a_vec = vcvt_f32_f16(vld1_f16((float16_t const*)a + i));
250
+ float32x4_t b_vec = vcvt_f32_f16(vld1_f16((float16_t const*)b + i));
251
+ ab_vec = vfmaq_f32(ab_vec, a_vec, b_vec);
252
+ }
253
+ return 1 - vaddvq_f32(ab_vec);
254
+ }
255
+
238
256
  __attribute__((target("+simd+fp16"))) inline static simsimd_f32_t //
239
257
  simsimd_cos_f16x4_neon(simsimd_f16_t const* a, simsimd_f16_t const* b, size_t d) {
240
258
 
@@ -252,7 +270,7 @@ simsimd_cos_f16x4_neon(simsimd_f16_t const* a, simsimd_f16_t const* b, size_t d)
252
270
  simsimd_f32_t ab = vaddvq_f32(ab_vec);
253
271
  simsimd_f32_t a2 = vaddvq_f32(a2_vec);
254
272
  simsimd_f32_t b2 = vaddvq_f32(b2_vec);
255
- return 1 - ab / (sqrt(a2) * sqrt(b2));
273
+ return 1 - ab / (sqrtf(a2) * sqrtf(b2));
256
274
  }
257
275
 
258
276
  __attribute__((target("+simd"))) inline static simsimd_f32_t //
@@ -290,7 +308,7 @@ simsimd_cos_i8x16_neon(int8_t const* a, int8_t const* b, size_t d) {
290
308
  int32_t a2 = vget_lane_s32(vpadd_s32(a2_part, a2_part), 0);
291
309
  int32x2_t b2_part = vadd_s32(vget_high_s32(b2_vec), vget_low_s32(b2_vec));
292
310
  int32_t b2 = vget_lane_s32(vpadd_s32(b2_part, b2_part), 0);
293
- return 1 - ab / (sqrt(a2) * sqrt(b2));
311
+ return 1 - ab / (sqrtf(a2) * sqrtf(b2));
294
312
  }
295
313
 
296
314
  __attribute__((target("+simd"))) inline static simsimd_f32_t //
@@ -327,7 +345,7 @@ simsimd_cos_f32x4_neon(simsimd_f32_t const* a, simsimd_f32_t const* b, size_t d)
327
345
  simsimd_f32_t ab = vaddvq_f32(ab_vec);
328
346
  simsimd_f32_t a2 = vaddvq_f32(a2_vec);
329
347
  simsimd_f32_t b2 = vaddvq_f32(b2_vec);
330
- return 1 - ab / (sqrt(a2) * sqrt(b2));
348
+ return 1 - ab / (sqrtf(a2) * sqrtf(b2));
331
349
  }
332
350
 
333
351
  __attribute__((target("+sve"))) inline static simsimd_f32_t //
@@ -385,7 +403,7 @@ simsimd_cos_f32x4_avx2(simsimd_f32_t const* a, simsimd_f32_t const* b, size_t d)
385
403
  union simsimd_f32i32_t ab_union = {_mm_cvtsi128_si32(_mm_castps_si128(ab_vec))};
386
404
  union simsimd_f32i32_t a2_union = {_mm_cvtsi128_si32(_mm_castps_si128(a2_vec))};
387
405
  union simsimd_f32i32_t b2_union = {_mm_cvtsi128_si32(_mm_castps_si128(b2_vec))};
388
- return 1 - ab_union.f / (sqrt(a2_union.f) * sqrt(b2_union.f));
406
+ return 1 - ab_union.f / (sqrtf(a2_union.f) * sqrtf(b2_union.f));
389
407
  }
390
408
 
391
409
  __attribute__((target("avx2"))) //
@@ -407,16 +425,17 @@ __attribute__((target("avx2"))) //
407
425
  __attribute__((target("f16c"))) //
408
426
  __attribute__((target("fma"))) inline static simsimd_f32_t //
409
427
  simsimd_dot_f16x8_avx2(simsimd_f16_t const* a, simsimd_f16_t const* b, size_t d) {
410
- __m128 ab_vec = _mm_set1_ps(0);
428
+ __m256 ab_vec = _mm256_set1_ps(0);
411
429
  for (size_t i = 0; i != d; i += 8) {
412
- __m128 a_vec = _mm_cvtph_ps(_mm_loadu_si128((__m128i const*)(a + i)));
413
- __m128 b_vec = _mm_cvtph_ps(_mm_loadu_si128((__m128i const*)(b + i)));
414
- ab_vec = _mm_fmadd_ps(a_vec, b_vec, ab_vec);
430
+ __m256 a_vec = _mm256_cvtph_ps(_mm_loadu_si128((__m128i const*)(a + i)));
431
+ __m256 b_vec = _mm256_cvtph_ps(_mm_loadu_si128((__m128i const*)(b + i)));
432
+ ab_vec = _mm256_fmadd_ps(a_vec, b_vec, ab_vec);
415
433
  }
416
- ab_vec = _mm_hadd_ps(ab_vec, ab_vec);
417
- ab_vec = _mm_hadd_ps(ab_vec, ab_vec);
434
+ ab_vec = _mm256_add_ps(_mm256_permute2f128_ps(ab_vec, ab_vec, 0x81), ab_vec);
435
+ ab_vec = _mm256_hadd_ps(ab_vec, ab_vec);
436
+ ab_vec = _mm256_hadd_ps(ab_vec, ab_vec);
418
437
  float result[1];
419
- _mm_store_ss(result, ab_vec);
438
+ _mm_store_ss(result, _mm256_castps256_ps128(ab_vec));
420
439
  return 1 - result[0];
421
440
  }
422
441
 
@@ -424,47 +443,94 @@ __attribute__((target("avx2"))) //
424
443
  __attribute__((target("f16c"))) //
425
444
  __attribute__((target("fma"))) inline static simsimd_f32_t //
426
445
  simsimd_cos_f16x8_avx2(simsimd_f16_t const* a, simsimd_f16_t const* b, size_t d) {
427
- __m128 ab_vec = _mm_set1_ps(0);
428
- __m128 a2_vec = _mm_set1_ps(0);
429
- __m128 b2_vec = _mm_set1_ps(0);
446
+ __m256 ab_vec = _mm256_set1_ps(0);
447
+ __m256 a2_vec = _mm256_set1_ps(0);
448
+ __m256 b2_vec = _mm256_set1_ps(0);
430
449
  for (size_t i = 0; i != d; i += 8) {
431
- __m128 a_vec = _mm_cvtph_ps(_mm_loadu_si128((__m128i const*)(a + i)));
432
- __m128 b_vec = _mm_cvtph_ps(_mm_loadu_si128((__m128i const*)(b + i)));
433
- ab_vec = _mm_fmadd_ps(a_vec, b_vec, ab_vec);
434
- a2_vec = _mm_fmadd_ps(a_vec, a_vec, a2_vec);
435
- b2_vec = _mm_fmadd_ps(b_vec, b_vec, b2_vec);
450
+ __m256 a_vec = _mm256_cvtph_ps(_mm_loadu_si128((__m128i const*)(a + i)));
451
+ __m256 b_vec = _mm256_cvtph_ps(_mm_loadu_si128((__m128i const*)(b + i)));
452
+ ab_vec = _mm256_fmadd_ps(a_vec, b_vec, ab_vec);
453
+ a2_vec = _mm256_fmadd_ps(a_vec, a_vec, a2_vec);
454
+ b2_vec = _mm256_fmadd_ps(b_vec, b_vec, b2_vec);
436
455
  }
437
- ab_vec = _mm_hadd_ps(ab_vec, ab_vec);
438
- ab_vec = _mm_hadd_ps(ab_vec, ab_vec);
439
- a2_vec = _mm_hadd_ps(a2_vec, a2_vec);
440
- a2_vec = _mm_hadd_ps(a2_vec, a2_vec);
441
- b2_vec = _mm_hadd_ps(b2_vec, b2_vec);
442
- b2_vec = _mm_hadd_ps(b2_vec, b2_vec);
456
+ ab_vec = _mm256_add_ps(_mm256_permute2f128_ps(ab_vec, ab_vec, 0x81), ab_vec);
457
+ ab_vec = _mm256_hadd_ps(ab_vec, ab_vec);
458
+ ab_vec = _mm256_hadd_ps(ab_vec, ab_vec);
459
+ a2_vec = _mm256_add_ps(_mm256_permute2f128_ps(a2_vec, a2_vec, 0x81), a2_vec);
460
+ a2_vec = _mm256_hadd_ps(a2_vec, a2_vec);
461
+ a2_vec = _mm256_hadd_ps(a2_vec, a2_vec);
462
+ b2_vec = _mm256_add_ps(_mm256_permute2f128_ps(b2_vec, b2_vec, 0x81), b2_vec);
463
+ b2_vec = _mm256_hadd_ps(b2_vec, b2_vec);
464
+ b2_vec = _mm256_hadd_ps(b2_vec, b2_vec);
443
465
  float ab_result[1], a2_result[1], b2_result[1];
444
- _mm_store_ss(ab_result, ab_vec);
445
- _mm_store_ss(a2_result, a2_vec);
446
- _mm_store_ss(b2_result, b2_vec);
447
- return 1 - ab_result[0] / (sqrt(a2_result[0]) * sqrt(b2_result[0]));
466
+ _mm_store_ss(ab_result, _mm256_castps256_ps128(ab_vec));
467
+ _mm_store_ss(a2_result, _mm256_castps256_ps128(a2_vec));
468
+ _mm_store_ss(b2_result, _mm256_castps256_ps128(b2_vec));
469
+ return 1 - ab_result[0] / (sqrtf(a2_result[0]) * sqrtf(b2_result[0]));
448
470
  }
449
471
 
450
472
  __attribute__((target("avx2"))) //
451
473
  __attribute__((target("f16c"))) //
452
474
  __attribute__((target("fma"))) inline static simsimd_f32_t //
453
475
  simsimd_l2sq_f16x8_avx2(simsimd_f16_t const* a, simsimd_f16_t const* b, size_t d) {
454
- __m128 sum_vec = _mm_set1_ps(0);
476
+ __m256 sum_vec = _mm256_set1_ps(0);
455
477
  for (size_t i = 0; i != d; i += 8) {
456
- __m128 a_vec = _mm_cvtph_ps(_mm_loadu_si128((__m128i const*)(a + i)));
457
- __m128 b_vec = _mm_cvtph_ps(_mm_loadu_si128((__m128i const*)(b + i)));
458
- __m128 diff_vec = _mm_sub_ps(a_vec, b_vec);
459
- sum_vec = _mm_fmadd_ps(diff_vec, diff_vec, sum_vec);
478
+ __m256 a_vec = _mm256_cvtph_ps(_mm_loadu_si128((__m128i const*)(a + i)));
479
+ __m256 b_vec = _mm256_cvtph_ps(_mm_loadu_si128((__m128i const*)(b + i)));
480
+ __m256 diff_vec = _mm256_sub_ps(a_vec, b_vec);
481
+ sum_vec = _mm256_fmadd_ps(diff_vec, diff_vec, sum_vec);
460
482
  }
461
- sum_vec = _mm_hadd_ps(sum_vec, sum_vec);
462
- sum_vec = _mm_hadd_ps(sum_vec, sum_vec);
483
+ sum_vec = _mm256_add_ps(_mm256_permute2f128_ps(sum_vec, sum_vec, 0x81), sum_vec);
484
+ sum_vec = _mm256_hadd_ps(sum_vec, sum_vec);
485
+ sum_vec = _mm256_hadd_ps(sum_vec, sum_vec);
463
486
  float result[1];
464
- _mm_store_ss(result, sum_vec);
487
+ _mm_store_ss(result, _mm256_castps256_ps128(sum_vec));
465
488
  return result[0];
466
489
  }
467
490
 
491
+ __attribute__((target("avx2"))) //
492
+ inline static simsimd_f32_t
493
+ simsimd_cos_i8x32_avx2(int8_t const* a, int8_t const* b, size_t d) {
494
+
495
+ __m256i ab_vec = _mm256_setzero_si256();
496
+ __m256i a2_vec = _mm256_setzero_si256();
497
+ __m256i b2_vec = _mm256_setzero_si256();
498
+
499
+ for (size_t i = 0; i != d; i += 32) {
500
+ __m256i a_vec = _mm256_loadu_si256((__m256i const*)(a + i));
501
+ __m256i b_vec = _mm256_loadu_si256((__m256i const*)(b + i));
502
+
503
+ // Multiply and add packed 8-bit integers
504
+ __m256i ab_part_vec = _mm256_maddubs_epi16(a_vec, b_vec);
505
+ __m256i a2_part_vec = _mm256_maddubs_epi16(a_vec, a_vec);
506
+ __m256i b2_part_vec = _mm256_maddubs_epi16(b_vec, b_vec);
507
+
508
+ ab_vec = _mm256_add_epi32(ab_vec, ab_part_vec);
509
+ a2_vec = _mm256_add_epi32(a2_vec, a2_part_vec);
510
+ b2_vec = _mm256_add_epi32(b2_vec, b2_part_vec);
511
+ }
512
+
513
+ // Horizontal sum across the 256-bit register
514
+ __m128i ab_low = _mm256_extracti128_si256(ab_vec, 0);
515
+ __m128i ab_high = _mm256_extracti128_si256(ab_vec, 1);
516
+ __m128i ab_sum = _mm_add_epi32(ab_low, ab_high);
517
+
518
+ __m128i a2_low = _mm256_extracti128_si256(a2_vec, 0);
519
+ __m128i a2_high = _mm256_extracti128_si256(a2_vec, 1);
520
+ __m128i a2_sum = _mm_add_epi32(a2_low, a2_high);
521
+
522
+ __m128i b2_low = _mm256_extracti128_si256(b2_vec, 0);
523
+ __m128i b2_high = _mm256_extracti128_si256(b2_vec, 1);
524
+ __m128i b2_sum = _mm_add_epi32(b2_low, b2_high);
525
+
526
+ // Further reduce to a single sum for each vector
527
+ int ab = _mm_extract_epi32(_mm_hadd_epi32(_mm_hadd_epi32(ab_sum, ab_sum), ab_sum), 0);
528
+ int a2 = _mm_extract_epi32(_mm_hadd_epi32(_mm_hadd_epi32(a2_sum, a2_sum), a2_sum), 0);
529
+ int b2 = _mm_extract_epi32(_mm_hadd_epi32(_mm_hadd_epi32(b2_sum, b2_sum), b2_sum), 0);
530
+
531
+ return 1 - ab / (sqrtf(a2) * sqrtf(b2));
532
+ }
533
+
468
534
  #endif // SIMSIMD_TARGET_X86_AVX2
469
535
 
470
536
  #if SIMSIMD_TARGET_X86_AVX512
@@ -498,7 +564,7 @@ simsimd_cos_f16x16_avx512(simsimd_f16_t const* a, simsimd_f16_t const* b, size_t
498
564
  simsimd_f32_t ab = _mm512_reduce_add_ps(ab_vec);
499
565
  simsimd_f32_t a2 = _mm512_reduce_add_ps(a2_vec);
500
566
  simsimd_f32_t b2 = _mm512_reduce_add_ps(b2_vec);
501
- return 1 - ab / (sqrt(a2) * sqrt(b2));
567
+ return 1 - ab / (sqrtf(a2) * sqrtf(b2));
502
568
  }
503
569
 
504
570
  __attribute__((target("avx512fp16"))) //
package/wasmer.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name="unum/usearch"
3
- version="2.2.0"
3
+ version="2.3.0"
4
4
  description="Smaller & Faster Single-File Vector Search Engine from Unum"
5
5
  license="Apache-2.0"
6
6
  readme="README.md"