faiss 0.6.2 → 0.6.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.
Files changed (178) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/lib/faiss/version.rb +1 -1
  4. data/vendor/faiss/faiss/AutoTune.cpp +3 -1
  5. data/vendor/faiss/faiss/Clustering.cpp +9 -1
  6. data/vendor/faiss/faiss/Clustering.h +8 -0
  7. data/vendor/faiss/faiss/IVFlib.cpp +14 -3
  8. data/vendor/faiss/faiss/Index.h +2 -2
  9. data/vendor/faiss/faiss/IndexAdditiveQuantizer.cpp +9 -10
  10. data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.cpp +2 -3
  11. data/vendor/faiss/faiss/IndexBinaryFromFloat.cpp +24 -4
  12. data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +16 -145
  13. data/vendor/faiss/faiss/IndexBinaryHNSW.h +0 -6
  14. data/vendor/faiss/faiss/IndexBinaryHash.cpp +5 -9
  15. data/vendor/faiss/faiss/IndexBinaryIVF.cpp +8 -18
  16. data/vendor/faiss/faiss/IndexBinaryIVF.h +8 -1
  17. data/vendor/faiss/faiss/IndexEDEN.cpp +273 -0
  18. data/vendor/faiss/faiss/IndexEDEN.h +57 -0
  19. data/vendor/faiss/faiss/IndexFastScan.cpp +15 -4
  20. data/vendor/faiss/faiss/IndexFlat.cpp +21 -54
  21. data/vendor/faiss/faiss/IndexFlat.h +2 -2
  22. data/vendor/faiss/faiss/IndexHNSW.cpp +311 -102
  23. data/vendor/faiss/faiss/IndexHNSW.h +31 -7
  24. data/vendor/faiss/faiss/IndexIDMap.cpp +26 -8
  25. data/vendor/faiss/faiss/IndexIDMap.h +2 -0
  26. data/vendor/faiss/faiss/IndexIVF.cpp +36 -10
  27. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +1 -1
  28. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.cpp +3 -4
  29. data/vendor/faiss/faiss/IndexIVFEDEN.cpp +302 -0
  30. data/vendor/faiss/faiss/IndexIVFEDEN.h +70 -0
  31. data/vendor/faiss/faiss/IndexIVFFastScan.cpp +5 -6
  32. data/vendor/faiss/faiss/IndexIVFFlat.cpp +3 -4
  33. data/vendor/faiss/faiss/IndexIVFIndependentQuantizer.cpp +1 -1
  34. data/vendor/faiss/faiss/IndexIVFPQ.cpp +49 -23
  35. data/vendor/faiss/faiss/IndexIVFPQ.h +11 -0
  36. data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +0 -1
  37. data/vendor/faiss/faiss/IndexIVFRaBitQ.cpp +19 -49
  38. data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.cpp +180 -76
  39. data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.h +5 -4
  40. data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +8 -6
  41. data/vendor/faiss/faiss/IndexLSH.cpp +2 -3
  42. data/vendor/faiss/faiss/IndexLattice.cpp +5 -0
  43. data/vendor/faiss/faiss/IndexNNDescent.cpp +9 -2
  44. data/vendor/faiss/faiss/IndexNSG.cpp +7 -2
  45. data/vendor/faiss/faiss/IndexPQ.cpp +6 -8
  46. data/vendor/faiss/faiss/IndexPreTransform.cpp +15 -0
  47. data/vendor/faiss/faiss/IndexRaBitQ.cpp +2 -2
  48. data/vendor/faiss/faiss/IndexRaBitQFastScan.cpp +1 -2
  49. data/vendor/faiss/faiss/IndexRaBitQFastScan.h +5 -1
  50. data/vendor/faiss/faiss/IndexRefine.cpp +30 -1
  51. data/vendor/faiss/faiss/IndexReplicas.cpp +1 -2
  52. data/vendor/faiss/faiss/IndexShards.cpp +5 -5
  53. data/vendor/faiss/faiss/IndexShardsIVF.cpp +6 -5
  54. data/vendor/faiss/faiss/MetaIndexes.cpp +2 -4
  55. data/vendor/faiss/faiss/SuperKMeans.cpp +286 -247
  56. data/vendor/faiss/faiss/SuperKMeans.h +33 -2
  57. data/vendor/faiss/faiss/VectorTransform.cpp +71 -2
  58. data/vendor/faiss/faiss/VectorTransform.h +3 -0
  59. data/vendor/faiss/faiss/clone_index.cpp +8 -0
  60. data/vendor/faiss/faiss/factory_tools.cpp +47 -4
  61. data/vendor/faiss/faiss/gpu/GpuCloner.cpp +11 -11
  62. data/vendor/faiss/faiss/gpu/GpuClonerOptions.h +1 -5
  63. data/vendor/faiss/faiss/gpu/GpuDistance.h +2 -5
  64. data/vendor/faiss/faiss/gpu/GpuIndex.h +38 -16
  65. data/vendor/faiss/faiss/gpu/GpuIndexCagra.h +71 -1
  66. data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +17 -0
  67. data/vendor/faiss/faiss/gpu/GpuIndexIVFScalarQuantizer.h +16 -0
  68. data/vendor/faiss/faiss/gpu/perf/PerfClustering.cpp +1 -1
  69. data/vendor/faiss/faiss/gpu/perf/PerfIVFPQAdd.cpp +2 -2
  70. data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFScalarQuantizer.cpp +180 -0
  71. data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFFlat.h +1 -5
  72. data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFPQ.h +88 -0
  73. data/vendor/faiss/faiss/gpu_metal/impl/MetalIVFPQ.h +134 -0
  74. data/vendor/faiss/faiss/impl/AdditiveQuantizer.cpp +1 -1
  75. data/vendor/faiss/faiss/impl/ClusteringInitialization.cpp +7 -4
  76. data/vendor/faiss/faiss/impl/DistanceComputer.h +34 -0
  77. data/vendor/faiss/faiss/impl/EDENQuantizer.h +119 -0
  78. data/vendor/faiss/faiss/impl/HNSW.cpp +528 -267
  79. data/vendor/faiss/faiss/impl/HNSW.h +46 -7
  80. data/vendor/faiss/faiss/impl/IDSelector.h +44 -0
  81. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +2 -2
  82. data/vendor/faiss/faiss/impl/NNDescent.cpp +10 -3
  83. data/vendor/faiss/faiss/impl/NSG.cpp +3 -1
  84. data/vendor/faiss/faiss/impl/Panorama.h +20 -9
  85. data/vendor/faiss/faiss/impl/PolysemousTraining.cpp +152 -84
  86. data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +38 -26
  87. data/vendor/faiss/faiss/impl/RaBitQUtils.cpp +45 -37
  88. data/vendor/faiss/faiss/impl/RaBitQUtils.h +35 -0
  89. data/vendor/faiss/faiss/impl/RaBitQuantizer.cpp +239 -72
  90. data/vendor/faiss/faiss/impl/RaBitQuantizer.h +66 -4
  91. data/vendor/faiss/faiss/impl/RaBitQuantizerMultiBit.cpp +4 -13
  92. data/vendor/faiss/faiss/impl/ResultHandler.h +34 -34
  93. data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +287 -84
  94. data/vendor/faiss/faiss/impl/ScalarQuantizer.h +26 -10
  95. data/vendor/faiss/faiss/impl/ThreadedIndex-inl.h +2 -2
  96. data/vendor/faiss/faiss/impl/VisitedTable.cpp +22 -2
  97. data/vendor/faiss/faiss/impl/VisitedTable.h +20 -0
  98. data/vendor/faiss/faiss/impl/binary_hamming/IndexBinaryIVF_impl.h +90 -14
  99. data/vendor/faiss/faiss/impl/binary_hamming/avx2.cpp +4 -4
  100. data/vendor/faiss/faiss/impl/expanded_scanners.h +5 -1
  101. data/vendor/faiss/faiss/impl/fast_scan/decompose_qbs.h +1 -0
  102. data/vendor/faiss/faiss/impl/fast_scan/dispatching.h +35 -2
  103. data/vendor/faiss/faiss/impl/hnsw/LockVector.cpp +1 -1
  104. data/vendor/faiss/faiss/impl/index_read.cpp +491 -50
  105. data/vendor/faiss/faiss/impl/index_write.cpp +86 -30
  106. data/vendor/faiss/faiss/impl/lattice_Zn.cpp +8 -9
  107. data/vendor/faiss/faiss/impl/platform_macros.h +3 -1
  108. data/vendor/faiss/faiss/impl/polysemous_training/avx512.cpp +284 -0
  109. data/vendor/faiss/faiss/impl/polysemous_training/dispatch.h +115 -0
  110. data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQScanner_impl.h +73 -39
  111. data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQ_QueryTables.cpp +0 -1
  112. data/vendor/faiss/faiss/impl/pq_code_distance/PQDistanceComputer_impl.h +26 -15
  113. data/vendor/faiss/faiss/impl/pq_code_distance/avx2.cpp +4 -4
  114. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-generic.cpp +4 -4
  115. data/vendor/faiss/faiss/impl/result_handler/ResultHandler.cpp +195 -0
  116. data/vendor/faiss/faiss/impl/result_handler/avx2.cpp +133 -0
  117. data/vendor/faiss/faiss/impl/result_handler/avx512.cpp +281 -0
  118. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx2.cpp +72 -0
  119. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx512.cpp +228 -0
  120. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer.cpp +887 -0
  121. data/vendor/faiss/faiss/impl/scalar_quantizer/distance_computers.h +2 -2
  122. data/vendor/faiss/faiss/impl/scalar_quantizer/quantizers.h +9 -8
  123. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx2.cpp +90 -24
  124. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-impl.h +30 -30
  125. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-spr.cpp +4 -5
  126. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512.cpp +101 -34
  127. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-dispatch.h +169 -13
  128. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-neon.cpp +125 -26
  129. data/vendor/faiss/faiss/impl/simd_dispatch.h +70 -31
  130. data/vendor/faiss/faiss/index_factory.cpp +40 -7
  131. data/vendor/faiss/faiss/invlists/DirectMap.cpp +1 -1
  132. data/vendor/faiss/faiss/invlists/InvertedLists.cpp +9 -6
  133. data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +29 -8
  134. data/vendor/faiss/faiss/python/python_callbacks.cpp +3 -1
  135. data/vendor/faiss/faiss/svs/IndexSVSFaissUtils.h +60 -0
  136. data/vendor/faiss/faiss/svs/IndexSVSFlat.cpp +26 -1
  137. data/vendor/faiss/faiss/svs/IndexSVSFlat.h +13 -0
  138. data/vendor/faiss/faiss/svs/IndexSVSIVF.cpp +1 -1
  139. data/vendor/faiss/faiss/svs/IndexSVSIVFLeanVec.cpp +1 -1
  140. data/vendor/faiss/faiss/svs/IndexSVSVamana.cpp +47 -5
  141. data/vendor/faiss/faiss/svs/IndexSVSVamana.h +23 -3
  142. data/vendor/faiss/faiss/svs/IndexSVSVamanaLVQ.cpp +4 -2
  143. data/vendor/faiss/faiss/svs/IndexSVSVamanaLVQ.h +2 -1
  144. data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.cpp +10 -4
  145. data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.h +2 -1
  146. data/vendor/faiss/faiss/utils/approx_topk_hamming/approx_topk_hamming.h +1 -1
  147. data/vendor/faiss/faiss/utils/distances.cpp +30 -11
  148. data/vendor/faiss/faiss/utils/distances_dispatch.h +30 -24
  149. data/vendor/faiss/faiss/utils/distances_fused/distances_fused.cpp +1 -1
  150. data/vendor/faiss/faiss/utils/distances_simd.cpp +4 -3
  151. data/vendor/faiss/faiss/utils/extra_distances.cpp +4 -14
  152. data/vendor/faiss/faiss/utils/extra_distances.h +1 -2
  153. data/vendor/faiss/faiss/utils/hamming.cpp +16 -10
  154. data/vendor/faiss/faiss/utils/hamming.h +10 -1
  155. data/vendor/faiss/faiss/utils/hamming_distance/common.h +14 -3
  156. data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512_vpopcnt.cpp +24 -0
  157. data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-avx512.h +1 -1
  158. data/vendor/faiss/faiss/utils/hamming_distance/{hamming_computer-avx512_spr.h → hamming_computer-avx512_vpopcnt.h} +85 -24
  159. data/vendor/faiss/faiss/utils/hamming_distance/hamming_impl.h +141 -0
  160. data/vendor/faiss/faiss/utils/quantize_lut.cpp +29 -8
  161. data/vendor/faiss/faiss/utils/rabitq_simd.h +202 -0
  162. data/vendor/faiss/faiss/utils/simd_impl/distances_arm_sve.cpp +194 -30
  163. data/vendor/faiss/faiss/utils/simd_impl/distances_avx2.cpp +0 -1
  164. data/vendor/faiss/faiss/utils/simd_impl/distances_avx512.cpp +263 -15
  165. data/vendor/faiss/faiss/utils/simd_impl/distances_rvv.cpp +198 -18
  166. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx2.cpp +245 -0
  167. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512.cpp +330 -40
  168. data/vendor/faiss/faiss/utils/simd_impl/{rabitq_avx512_spr.cpp → rabitq_avx512_vpopcnt.cpp} +112 -23
  169. data/vendor/faiss/faiss/utils/simd_impl/rabitq_neon.cpp +11 -0
  170. data/vendor/faiss/faiss/utils/simd_impl/rabitq_rvv.cpp +143 -6
  171. data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_dispatch.h +2 -7
  172. data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels.h +6 -1
  173. data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels_sve.cpp +34 -0
  174. data/vendor/faiss/faiss/utils/simd_levels.cpp +196 -47
  175. data/vendor/faiss/faiss/utils/simd_levels.h +33 -8
  176. data/vendor/faiss/faiss/utils/utils.cpp +9 -27
  177. metadata +21 -5
  178. data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512_spr.cpp +0 -15
@@ -12,12 +12,58 @@
12
12
  #ifdef COMPILE_SIMD_RISCV_RVV
13
13
 
14
14
  #include <faiss/utils/extra_distances.h>
15
+ #include <riscv_vector.h>
15
16
 
16
17
  namespace faiss {
17
18
 
19
+ template <typename Vec, typename Reduce>
20
+ static inline float rvv_reduce(
21
+ Vec value,
22
+ size_t vl,
23
+ float identity,
24
+ Reduce reduce) {
25
+ vfloat32m1_t init = __riscv_vfmv_s_f_f32m1(identity, 1);
26
+ vfloat32m1_t result = reduce(value, init, vl);
27
+ return __riscv_vfmv_f_s_f32m1_f32(result);
28
+ }
29
+
30
+ static inline size_t rvv_argmin(const float* values, size_t n) {
31
+ size_t vlmax = __riscv_vsetvlmax_e32m8();
32
+ vfloat32m8_t vmin = __riscv_vfmv_v_f_f32m8(__builtin_inff(), vlmax);
33
+ size_t i = 0;
34
+ while (i < n) {
35
+ size_t vl = __riscv_vsetvl_e32m8(n - i);
36
+ vfloat32m8_t vd = __riscv_vle32_v_f32m8(values + i, vl);
37
+ vmin = __riscv_vfmin_vv_f32m8_tu(vmin, vmin, vd, vl);
38
+ i += vl;
39
+ }
40
+ float min_val = rvv_reduce(
41
+ vmin, vlmax, __builtin_inff(), __riscv_vfredmin_vs_f32m8_f32m1);
42
+ i = 0;
43
+ while (i < n) {
44
+ size_t vl = __riscv_vsetvl_e32m8(n - i);
45
+ vfloat32m8_t vd = __riscv_vle32_v_f32m8(values + i, vl);
46
+ long j = __riscv_vfirst_m_b4(
47
+ __riscv_vmfeq_vf_f32m8_b4(vd, min_val, vl), vl);
48
+ if (j >= 0)
49
+ return i + static_cast<size_t>(j);
50
+ i += vl;
51
+ }
52
+ return n;
53
+ }
54
+
18
55
  template <>
19
56
  float fvec_norm_L2sqr<SIMDLevel::RISCV_RVV>(const float* x, size_t d) {
20
- return fvec_norm_L2sqr<SIMDLevel::NONE>(x, d);
57
+ size_t vlmax = __riscv_vsetvlmax_e32m8();
58
+ vfloat32m8_t acc = __riscv_vfmv_v_f_f32m8(0.0f, vlmax);
59
+ size_t i = 0;
60
+ while (i < d) {
61
+ size_t vl = __riscv_vsetvl_e32m8(d - i);
62
+ vfloat32m8_t vx = __riscv_vle32_v_f32m8(x + i, vl);
63
+ acc = __riscv_vfmacc_vv_f32m8_tu(acc, vx, vx, vl);
64
+ i += vl;
65
+ }
66
+ return rvv_reduce(acc, vlmax, 0.0f, __riscv_vfredusum_vs_f32m8_f32m1);
21
67
  }
22
68
 
23
69
  template <>
@@ -25,7 +71,18 @@ float fvec_L2sqr<SIMDLevel::RISCV_RVV>(
25
71
  const float* x,
26
72
  const float* y,
27
73
  size_t d) {
28
- return fvec_L2sqr<SIMDLevel::NONE>(x, y, d);
74
+ size_t vlmax = __riscv_vsetvlmax_e32m8();
75
+ vfloat32m8_t acc = __riscv_vfmv_v_f_f32m8(0.0f, vlmax);
76
+ size_t i = 0;
77
+ while (i < d) {
78
+ size_t vl = __riscv_vsetvl_e32m8(d - i);
79
+ vfloat32m8_t vx = __riscv_vle32_v_f32m8(x + i, vl);
80
+ vfloat32m8_t vy = __riscv_vle32_v_f32m8(y + i, vl);
81
+ vx = __riscv_vfsub_vv_f32m8(vx, vy, vl);
82
+ acc = __riscv_vfmacc_vv_f32m8_tu(acc, vx, vx, vl);
83
+ i += vl;
84
+ }
85
+ return rvv_reduce(acc, vlmax, 0.0f, __riscv_vfredusum_vs_f32m8_f32m1);
29
86
  }
30
87
 
31
88
  template <>
@@ -33,12 +90,34 @@ float fvec_inner_product<SIMDLevel::RISCV_RVV>(
33
90
  const float* x,
34
91
  const float* y,
35
92
  size_t d) {
36
- return fvec_inner_product<SIMDLevel::NONE>(x, y, d);
93
+ size_t vlmax = __riscv_vsetvlmax_e32m8();
94
+ vfloat32m8_t acc = __riscv_vfmv_v_f_f32m8(0.0f, vlmax);
95
+ size_t i = 0;
96
+ while (i < d) {
97
+ size_t vl = __riscv_vsetvl_e32m8(d - i);
98
+ vfloat32m8_t vx = __riscv_vle32_v_f32m8(x + i, vl);
99
+ vfloat32m8_t vy = __riscv_vle32_v_f32m8(y + i, vl);
100
+ acc = __riscv_vfmacc_vv_f32m8_tu(acc, vx, vy, vl);
101
+ i += vl;
102
+ }
103
+ return rvv_reduce(acc, vlmax, 0.0f, __riscv_vfredusum_vs_f32m8_f32m1);
37
104
  }
38
105
 
39
106
  template <>
40
107
  float fvec_L1<SIMDLevel::RISCV_RVV>(const float* x, const float* y, size_t d) {
41
- return fvec_L1<SIMDLevel::NONE>(x, y, d);
108
+ size_t vlmax = __riscv_vsetvlmax_e32m8();
109
+ vfloat32m8_t acc = __riscv_vfmv_v_f_f32m8(0.0f, vlmax);
110
+ size_t i = 0;
111
+ while (i < d) {
112
+ size_t vl = __riscv_vsetvl_e32m8(d - i);
113
+ vfloat32m8_t vx = __riscv_vle32_v_f32m8(x + i, vl);
114
+ vfloat32m8_t vy = __riscv_vle32_v_f32m8(y + i, vl);
115
+ vx = __riscv_vfsub_vv_f32m8(vx, vy, vl);
116
+ vx = __riscv_vfsgnjx_vv_f32m8(vx, vx, vl);
117
+ acc = __riscv_vfadd_vv_f32m8_tu(acc, acc, vx, vl);
118
+ i += vl;
119
+ }
120
+ return rvv_reduce(acc, vlmax, 0.0f, __riscv_vfredusum_vs_f32m8_f32m1);
42
121
  }
43
122
 
44
123
  template <>
@@ -46,7 +125,19 @@ float fvec_Linf<SIMDLevel::RISCV_RVV>(
46
125
  const float* x,
47
126
  const float* y,
48
127
  size_t d) {
49
- return fvec_Linf<SIMDLevel::NONE>(x, y, d);
128
+ size_t vlmax = __riscv_vsetvlmax_e32m8();
129
+ vfloat32m8_t vmax = __riscv_vfmv_v_f_f32m8(0.0f, vlmax);
130
+ size_t i = 0;
131
+ while (i < d) {
132
+ size_t vl = __riscv_vsetvl_e32m8(d - i);
133
+ vfloat32m8_t vx = __riscv_vle32_v_f32m8(x + i, vl);
134
+ vfloat32m8_t vy = __riscv_vle32_v_f32m8(y + i, vl);
135
+ vx = __riscv_vfsub_vv_f32m8(vx, vy, vl);
136
+ vx = __riscv_vfsgnjx_vv_f32m8(vx, vx, vl);
137
+ vmax = __riscv_vfmax_vv_f32m8_tu(vmax, vmax, vx, vl);
138
+ i += vl;
139
+ }
140
+ return rvv_reduce(vmax, vlmax, 0.0f, __riscv_vfredmax_vs_f32m8_f32m1);
50
141
  }
51
142
 
52
143
  template <>
@@ -61,8 +152,29 @@ void fvec_inner_product_batch_4<SIMDLevel::RISCV_RVV>(
61
152
  float& dis1,
62
153
  float& dis2,
63
154
  float& dis3) {
64
- fvec_inner_product_batch_4<SIMDLevel::NONE>(
65
- x, y0, y1, y2, y3, d, dis0, dis1, dis2, dis3);
155
+ size_t vlmax = __riscv_vsetvlmax_e32m4();
156
+ vfloat32m4_t vacc0 = __riscv_vfmv_v_f_f32m4(0.0f, vlmax);
157
+ vfloat32m4_t vacc1 = __riscv_vfmv_v_f_f32m4(0.0f, vlmax);
158
+ vfloat32m4_t vacc2 = __riscv_vfmv_v_f_f32m4(0.0f, vlmax);
159
+ vfloat32m4_t vacc3 = __riscv_vfmv_v_f_f32m4(0.0f, vlmax);
160
+ size_t i = 0;
161
+ while (i < d) {
162
+ size_t vl = __riscv_vsetvl_e32m4(d - i);
163
+ vfloat32m4_t vx = __riscv_vle32_v_f32m4(x + i, vl);
164
+ vfloat32m4_t vy = __riscv_vle32_v_f32m4(y0 + i, vl);
165
+ vacc0 = __riscv_vfmacc_vv_f32m4_tu(vacc0, vx, vy, vl);
166
+ vy = __riscv_vle32_v_f32m4(y1 + i, vl);
167
+ vacc1 = __riscv_vfmacc_vv_f32m4_tu(vacc1, vx, vy, vl);
168
+ vy = __riscv_vle32_v_f32m4(y2 + i, vl);
169
+ vacc2 = __riscv_vfmacc_vv_f32m4_tu(vacc2, vx, vy, vl);
170
+ vy = __riscv_vle32_v_f32m4(y3 + i, vl);
171
+ vacc3 = __riscv_vfmacc_vv_f32m4_tu(vacc3, vx, vy, vl);
172
+ i += vl;
173
+ }
174
+ dis0 = rvv_reduce(vacc0, vlmax, 0.0f, __riscv_vfredusum_vs_f32m4_f32m1);
175
+ dis1 = rvv_reduce(vacc1, vlmax, 0.0f, __riscv_vfredusum_vs_f32m4_f32m1);
176
+ dis2 = rvv_reduce(vacc2, vlmax, 0.0f, __riscv_vfredusum_vs_f32m4_f32m1);
177
+ dis3 = rvv_reduce(vacc3, vlmax, 0.0f, __riscv_vfredusum_vs_f32m4_f32m1);
66
178
  }
67
179
 
68
180
  template <>
@@ -77,8 +189,33 @@ void fvec_L2sqr_batch_4<SIMDLevel::RISCV_RVV>(
77
189
  float& dis1,
78
190
  float& dis2,
79
191
  float& dis3) {
80
- fvec_L2sqr_batch_4<SIMDLevel::NONE>(
81
- x, y0, y1, y2, y3, d, dis0, dis1, dis2, dis3);
192
+ size_t vlmax = __riscv_vsetvlmax_e32m4();
193
+ vfloat32m4_t vacc0 = __riscv_vfmv_v_f_f32m4(0.0f, vlmax);
194
+ vfloat32m4_t vacc1 = __riscv_vfmv_v_f_f32m4(0.0f, vlmax);
195
+ vfloat32m4_t vacc2 = __riscv_vfmv_v_f_f32m4(0.0f, vlmax);
196
+ vfloat32m4_t vacc3 = __riscv_vfmv_v_f_f32m4(0.0f, vlmax);
197
+ size_t i = 0;
198
+ while (i < d) {
199
+ size_t vl = __riscv_vsetvl_e32m4(d - i);
200
+ vfloat32m4_t vx = __riscv_vle32_v_f32m4(x + i, vl);
201
+ vfloat32m4_t vy = __riscv_vle32_v_f32m4(y0 + i, vl);
202
+ vy = __riscv_vfsub_vv_f32m4(vx, vy, vl);
203
+ vacc0 = __riscv_vfmacc_vv_f32m4_tu(vacc0, vy, vy, vl);
204
+ vy = __riscv_vle32_v_f32m4(y1 + i, vl);
205
+ vy = __riscv_vfsub_vv_f32m4(vx, vy, vl);
206
+ vacc1 = __riscv_vfmacc_vv_f32m4_tu(vacc1, vy, vy, vl);
207
+ vy = __riscv_vle32_v_f32m4(y2 + i, vl);
208
+ vy = __riscv_vfsub_vv_f32m4(vx, vy, vl);
209
+ vacc2 = __riscv_vfmacc_vv_f32m4_tu(vacc2, vy, vy, vl);
210
+ vy = __riscv_vle32_v_f32m4(y3 + i, vl);
211
+ vy = __riscv_vfsub_vv_f32m4(vx, vy, vl);
212
+ vacc3 = __riscv_vfmacc_vv_f32m4_tu(vacc3, vy, vy, vl);
213
+ i += vl;
214
+ }
215
+ dis0 = rvv_reduce(vacc0, vlmax, 0.0f, __riscv_vfredusum_vs_f32m4_f32m1);
216
+ dis1 = rvv_reduce(vacc1, vlmax, 0.0f, __riscv_vfredusum_vs_f32m4_f32m1);
217
+ dis2 = rvv_reduce(vacc2, vlmax, 0.0f, __riscv_vfredusum_vs_f32m4_f32m1);
218
+ dis3 = rvv_reduce(vacc3, vlmax, 0.0f, __riscv_vfredusum_vs_f32m4_f32m1);
82
219
  }
83
220
 
84
221
  template <>
@@ -90,8 +227,32 @@ void fvec_L2sqr_ny_transposed<SIMDLevel::RISCV_RVV>(
90
227
  size_t d,
91
228
  size_t d_offset,
92
229
  size_t ny) {
93
- fvec_L2sqr_ny_transposed<SIMDLevel::NONE>(
94
- dis, x, y, y_sqlen, d, d_offset, ny);
230
+ size_t vlmax = __riscv_vsetvlmax_e32m8();
231
+ vfloat32m8_t acc = __riscv_vfmv_v_f_f32m8(0.0f, vlmax);
232
+ size_t i = 0;
233
+ while (i < d) {
234
+ size_t vl = __riscv_vsetvl_e32m8(d - i);
235
+ vfloat32m8_t vx = __riscv_vle32_v_f32m8(x + i, vl);
236
+ acc = __riscv_vfmacc_vv_f32m8_tu(acc, vx, vx, vl);
237
+ i += vl;
238
+ }
239
+ float x_sqlen =
240
+ rvv_reduce(acc, vlmax, 0.0f, __riscv_vfredusum_vs_f32m8_f32m1);
241
+ i = 0;
242
+ while (i < ny) {
243
+ size_t vl = __riscv_vsetvl_e32m8(ny - i);
244
+ acc = __riscv_vfmv_v_f_f32m8(0.0f, vl);
245
+ for (size_t j = 0; j < d; j++) {
246
+ vfloat32m8_t vy = __riscv_vle32_v_f32m8(y + j * d_offset + i, vl);
247
+ acc = __riscv_vfmacc_vf_f32m8(acc, x[j], vy, vl);
248
+ }
249
+ vfloat32m8_t vres = __riscv_vle32_v_f32m8(y_sqlen + i, vl);
250
+ vres = __riscv_vfadd_vf_f32m8(vres, x_sqlen, vl);
251
+ acc = __riscv_vfmul_vf_f32m8(acc, 2.0f, vl);
252
+ vres = __riscv_vfsub_vv_f32m8(vres, acc, vl);
253
+ __riscv_vse32_v_f32m8(dis + i, vres, vl);
254
+ i += vl;
255
+ }
95
256
  }
96
257
 
97
258
  template <>
@@ -101,7 +262,10 @@ void fvec_inner_products_ny<SIMDLevel::RISCV_RVV>(
101
262
  const float* y,
102
263
  size_t d,
103
264
  size_t ny) {
104
- fvec_inner_products_ny<SIMDLevel::NONE>(ip, x, y, d, ny);
265
+ for (size_t i = 0; i < ny; i++) {
266
+ ip[i] = fvec_inner_product<SIMDLevel::RISCV_RVV>(x, y, d);
267
+ y += d;
268
+ }
105
269
  }
106
270
 
107
271
  template <>
@@ -111,7 +275,10 @@ void fvec_L2sqr_ny<SIMDLevel::RISCV_RVV>(
111
275
  const float* y,
112
276
  size_t d,
113
277
  size_t ny) {
114
- fvec_L2sqr_ny<SIMDLevel::NONE>(dis, x, y, d, ny);
278
+ for (size_t i = 0; i < ny; i++) {
279
+ dis[i] = fvec_L2sqr<SIMDLevel::RISCV_RVV>(x, y, d);
280
+ y += d;
281
+ }
115
282
  }
116
283
 
117
284
  template <>
@@ -121,8 +288,9 @@ size_t fvec_L2sqr_ny_nearest<SIMDLevel::RISCV_RVV>(
121
288
  const float* y,
122
289
  size_t d,
123
290
  size_t ny) {
124
- return fvec_L2sqr_ny_nearest<SIMDLevel::NONE>(
125
- distances_tmp_buffer, x, y, d, ny);
291
+ fvec_L2sqr_ny<SIMDLevel::RISCV_RVV>(distances_tmp_buffer, x, y, d, ny);
292
+ const size_t j = rvv_argmin(distances_tmp_buffer, ny);
293
+ return j < ny ? j : 0;
126
294
  }
127
295
 
128
296
  template <>
@@ -134,8 +302,10 @@ size_t fvec_L2sqr_ny_nearest_y_transposed<SIMDLevel::RISCV_RVV>(
134
302
  size_t d,
135
303
  size_t d_offset,
136
304
  size_t ny) {
137
- return fvec_L2sqr_ny_nearest_y_transposed<SIMDLevel::NONE>(
305
+ fvec_L2sqr_ny_transposed<SIMDLevel::RISCV_RVV>(
138
306
  distances_tmp_buffer, x, y, y_sqlen, d, d_offset, ny);
307
+ const size_t j = rvv_argmin(distances_tmp_buffer, ny);
308
+ return j < ny ? j : 0;
139
309
  }
140
310
 
141
311
  template <>
@@ -145,7 +315,15 @@ void fvec_madd<SIMDLevel::RISCV_RVV>(
145
315
  float bf,
146
316
  const float* b,
147
317
  float* c) {
148
- fvec_madd<SIMDLevel::NONE>(n, a, bf, b, c);
318
+ size_t i = 0;
319
+ while (i < n) {
320
+ size_t vl = __riscv_vsetvl_e32m8(n - i);
321
+ vfloat32m8_t va = __riscv_vle32_v_f32m8(a + i, vl);
322
+ vfloat32m8_t vb = __riscv_vle32_v_f32m8(b + i, vl);
323
+ va = __riscv_vfmacc_vf_f32m8(va, bf, vb, vl);
324
+ __riscv_vse32_v_f32m8(c + i, va, vl);
325
+ i += vl;
326
+ }
149
327
  }
150
328
 
151
329
  template <>
@@ -155,7 +333,9 @@ int fvec_madd_and_argmin<SIMDLevel::RISCV_RVV>(
155
333
  float bf,
156
334
  const float* b,
157
335
  float* c) {
158
- return fvec_madd_and_argmin<SIMDLevel::NONE>(n, a, bf, b, c);
336
+ fvec_madd<SIMDLevel::RISCV_RVV>(n, a, bf, b, c);
337
+ const size_t j = rvv_argmin(c, n);
338
+ return j < n ? static_cast<int>(j) : -1;
159
339
  }
160
340
 
161
341
  #define DEFINE_VECTOR_DISTANCE_RVV_FALLBACK(metric) \
@@ -9,6 +9,7 @@
9
9
 
10
10
  #include <faiss/utils/rabitq_simd.h>
11
11
  #include <immintrin.h>
12
+ #include <limits>
12
13
 
13
14
  namespace faiss::rabitq {
14
15
 
@@ -82,8 +83,161 @@ inline uint64_t reduce_add_128(__m128i v) {
82
83
  return lanes[0] + lanes[1];
83
84
  }
84
85
 
86
+ inline float reduce_min_256(__m256 v) {
87
+ __m128 x =
88
+ _mm_min_ps(_mm256_castps256_ps128(v), _mm256_extractf128_ps(v, 1));
89
+ x = _mm_min_ps(x, _mm_movehl_ps(x, x));
90
+ x = _mm_min_ss(x, _mm_shuffle_ps(x, x, 1));
91
+ return _mm_cvtss_f32(x);
92
+ }
93
+
94
+ inline float reduce_max_256(__m256 v) {
95
+ __m128 x =
96
+ _mm_max_ps(_mm256_castps256_ps128(v), _mm256_extractf128_ps(v, 1));
97
+ x = _mm_max_ps(x, _mm_movehl_ps(x, x));
98
+ x = _mm_max_ss(x, _mm_shuffle_ps(x, x, 1));
99
+ return _mm_cvtss_f32(x);
100
+ }
101
+
102
+ inline __m256i round_nonnegative_ps_to_i32(__m256 x) {
103
+ return _mm256_cvttps_epi32(_mm256_add_ps(x, _mm256_set1_ps(0.5f)));
104
+ }
105
+
106
+ inline void store_i32_as_u8_8(__m256i values, uint8_t* out) {
107
+ const __m128i packed16 = _mm_packus_epi32(
108
+ _mm256_castsi256_si128(values),
109
+ _mm256_extracti128_si256(values, 1));
110
+ const __m128i packed8 = _mm_packus_epi16(packed16, _mm_setzero_si128());
111
+ _mm_storel_epi64(reinterpret_cast<__m128i*>(out), packed8);
112
+ }
113
+
114
+ inline void accumulate_i32_as_i64(
115
+ __m256i values,
116
+ __m256i& low_acc,
117
+ __m256i& high_acc) {
118
+ low_acc = _mm256_add_epi64(
119
+ low_acc, _mm256_cvtepi32_epi64(_mm256_castsi256_si128(values)));
120
+ high_acc = _mm256_add_epi64(
121
+ high_acc,
122
+ _mm256_cvtepi32_epi64(_mm256_extracti128_si256(values, 1)));
123
+ }
124
+
85
125
  } // namespace
86
126
 
127
+ template <>
128
+ void lut_minmax_16<SIMDLevel::AVX2>(const float* tab, float& mn, float& mx) {
129
+ const __m256 lo = _mm256_loadu_ps(tab);
130
+ const __m256 hi = _mm256_loadu_ps(tab + 8);
131
+ const __m256 min_vec = _mm256_min_ps(lo, hi);
132
+ const __m256 max_vec = _mm256_max_ps(lo, hi);
133
+ mn = reduce_min_256(min_vec);
134
+ mx = reduce_max_256(max_vec);
135
+ }
136
+
137
+ template <>
138
+ void minmax_values<SIMDLevel::AVX2>(
139
+ const float* values,
140
+ size_t n,
141
+ float& mn,
142
+ float& mx) {
143
+ if (n == 0) {
144
+ return;
145
+ }
146
+
147
+ size_t i = 0;
148
+ __m256 min_vec = _mm256_set1_ps(std::numeric_limits<float>::max());
149
+ __m256 max_vec = _mm256_set1_ps(std::numeric_limits<float>::lowest());
150
+ for (; i + 8 <= n; i += 8) {
151
+ const __m256 values_vec = _mm256_loadu_ps(values + i);
152
+ min_vec = _mm256_min_ps(min_vec, values_vec);
153
+ max_vec = _mm256_max_ps(max_vec, values_vec);
154
+ }
155
+
156
+ mn = reduce_min_256(min_vec);
157
+ mx = reduce_max_256(max_vec);
158
+ for (; i < n; i++) {
159
+ mn = std::min(mn, values[i]);
160
+ mx = std::max(mx, values[i]);
161
+ }
162
+ }
163
+
164
+ template <>
165
+ void lut_quantize_16_to_uint8<SIMDLevel::AVX2>(
166
+ const float* tab,
167
+ float mn,
168
+ float a,
169
+ uint8_t* out) {
170
+ const __m256 a_vec = _mm256_set1_ps(a);
171
+ const __m256 mn_times_a_vec = _mm256_set1_ps(mn * a);
172
+ const __m256i zero = _mm256_setzero_si256();
173
+ for (size_t i = 0; i < 16; i += 8) {
174
+ const __m256 values = _mm256_loadu_ps(tab + i);
175
+ const __m256 scaled = _mm256_fmsub_ps(values, a_vec, mn_times_a_vec);
176
+ const __m256i rounded =
177
+ _mm256_max_epi32(round_nonnegative_ps_to_i32(scaled), zero);
178
+ store_i32_as_u8_8(rounded, out + i);
179
+ }
180
+ }
181
+
182
+ template <>
183
+ void quantize_query_values<SIMDLevel::AVX2>(
184
+ const float* rq,
185
+ size_t d,
186
+ float v_min,
187
+ float inv_delta,
188
+ uint8_t max_code,
189
+ bool centered,
190
+ uint8_t* rqq,
191
+ size_t& sum_qq,
192
+ int64_t& sum2_signed_odd_int) {
193
+ const __m256 inv_delta_vec = _mm256_set1_ps(inv_delta);
194
+ const __m256 v_min_times_inv_delta_vec = _mm256_set1_ps(v_min * inv_delta);
195
+ const __m256 zero = _mm256_setzero_ps();
196
+ const __m256 max_code_ps = _mm256_set1_ps(max_code);
197
+ const __m256i max_code_i32 = _mm256_set1_epi32(max_code);
198
+ const __m256i two = _mm256_set1_epi32(2);
199
+ __m256i sum_acc_lo = _mm256_setzero_si256();
200
+ __m256i sum_acc_hi = _mm256_setzero_si256();
201
+ __m256i sq_acc_lo = _mm256_setzero_si256();
202
+ __m256i sq_acc_hi = _mm256_setzero_si256();
203
+
204
+ size_t i = 0;
205
+ for (; i + 8 <= d; i += 8) {
206
+ const __m256 values = _mm256_loadu_ps(rq + i);
207
+ __m256 scaled = _mm256_fmsub_ps(
208
+ values, inv_delta_vec, v_min_times_inv_delta_vec);
209
+ scaled = _mm256_min_ps(_mm256_max_ps(scaled, zero), max_code_ps);
210
+ const __m256i rounded = round_nonnegative_ps_to_i32(scaled);
211
+ accumulate_i32_as_i64(rounded, sum_acc_lo, sum_acc_hi);
212
+
213
+ if (centered) {
214
+ const __m256i signed_odd = _mm256_sub_epi32(
215
+ _mm256_mullo_epi32(rounded, two), max_code_i32);
216
+ const __m256i signed_odd_sqr =
217
+ _mm256_mullo_epi32(signed_odd, signed_odd);
218
+ accumulate_i32_as_i64(signed_odd_sqr, sq_acc_lo, sq_acc_hi);
219
+ }
220
+ store_i32_as_u8_8(rounded, rqq + i);
221
+ }
222
+
223
+ sum_qq += reduce_add_256(sum_acc_lo) + reduce_add_256(sum_acc_hi);
224
+ if (centered) {
225
+ sum2_signed_odd_int +=
226
+ reduce_add_256(sq_acc_lo) + reduce_add_256(sq_acc_hi);
227
+ }
228
+
229
+ for (; i < d; i++) {
230
+ const uint8_t v_qq = round_clamped_byte_scalar(
231
+ (rq[i] - v_min) * inv_delta, max_code);
232
+ rqq[i] = v_qq;
233
+ sum_qq += v_qq;
234
+ if (centered) {
235
+ const int64_t signed_odd_int = int64_t(v_qq) * 2 - max_code;
236
+ sum2_signed_odd_int += signed_odd_int * signed_odd_int;
237
+ }
238
+ }
239
+ }
240
+
87
241
  template <>
88
242
  uint64_t bitwise_and_dot_product<SIMDLevel::AVX2>(
89
243
  const uint8_t* query,
@@ -137,6 +291,69 @@ uint64_t bitwise_and_dot_product<SIMDLevel::AVX2>(
137
291
  return sum;
138
292
  }
139
293
 
294
+ template <>
295
+ BitwiseAndDotProductResult bitwise_and_dot_product_with_popcount<
296
+ SIMDLevel::AVX2>(
297
+ const uint8_t* query,
298
+ const uint8_t* data,
299
+ size_t size,
300
+ size_t qb) {
301
+ uint64_t dot_product = 0;
302
+ uint64_t popcount_sum = 0;
303
+ size_t offset = 0;
304
+ if (size_t step = 256 / 8; offset + step <= size) {
305
+ __m256i dot_256 = _mm256_setzero_si256();
306
+ __m256i pop_256 = _mm256_setzero_si256();
307
+ for (; offset + step <= size; offset += step) {
308
+ __m256i v_x = _mm256_loadu_si256((const __m256i*)(data + offset));
309
+ pop_256 = _mm256_add_epi64(pop_256, popcount_256(v_x));
310
+ for (int j = 0; j < qb; j++) {
311
+ __m256i v_q = _mm256_loadu_si256(
312
+ (const __m256i*)(query + j * size + offset));
313
+ __m256i v_and = _mm256_and_si256(v_q, v_x);
314
+ __m256i v_popcnt = popcount_256(v_and);
315
+ __m256i v_shifted = _mm256_slli_epi64(v_popcnt, j);
316
+ dot_256 = _mm256_add_epi64(dot_256, v_shifted);
317
+ }
318
+ }
319
+ dot_product += reduce_add_256(dot_256);
320
+ popcount_sum += reduce_add_256(pop_256);
321
+ }
322
+ __m128i dot_128 = _mm_setzero_si128();
323
+ __m128i pop_128 = _mm_setzero_si128();
324
+ for (size_t step = 128 / 8; offset + step <= size; offset += step) {
325
+ __m128i v_x = _mm_loadu_si128((const __m128i*)(data + offset));
326
+ pop_128 = _mm_add_epi64(pop_128, popcount_128(v_x));
327
+ for (int j = 0; j < qb; j++) {
328
+ __m128i v_q = _mm_loadu_si128(
329
+ (const __m128i*)(query + j * size + offset));
330
+ __m128i v_and = _mm_and_si128(v_q, v_x);
331
+ __m128i v_popcnt = popcount_128(v_and);
332
+ __m128i v_shifted = _mm_slli_epi64(v_popcnt, j);
333
+ dot_128 = _mm_add_epi64(dot_128, v_shifted);
334
+ }
335
+ }
336
+ dot_product += reduce_add_128(dot_128);
337
+ popcount_sum += reduce_add_128(pop_128);
338
+ for (size_t step = 64 / 8; offset + step <= size; offset += step) {
339
+ const uint64_t yv = *(const uint64_t*)(data + offset);
340
+ popcount_sum += popcount64(yv);
341
+ for (int j = 0; j < qb; j++) {
342
+ const uint64_t qv = *(const uint64_t*)(query + j * size + offset);
343
+ dot_product += popcount64(qv & yv) << j;
344
+ }
345
+ }
346
+ for (; offset < size; ++offset) {
347
+ const uint8_t yv = *(data + offset);
348
+ popcount_sum += popcount32(yv);
349
+ for (int j = 0; j < qb; j++) {
350
+ const uint8_t qv = *(query + j * size + offset);
351
+ dot_product += popcount32(qv & yv) << j;
352
+ }
353
+ }
354
+ return {dot_product, popcount_sum};
355
+ }
356
+
140
357
  template <>
141
358
  uint64_t bitwise_xor_dot_product<SIMDLevel::AVX2>(
142
359
  const uint8_t* query,
@@ -220,6 +437,34 @@ uint64_t popcount<SIMDLevel::AVX2>(const uint8_t* data, size_t size) {
220
437
  return sum;
221
438
  }
222
439
 
440
+ template <>
441
+ void rearrange_bit_planes<SIMDLevel::AVX2>(
442
+ const uint8_t* rotated_qq,
443
+ size_t d,
444
+ size_t qb,
445
+ uint8_t* out) {
446
+ const size_t offset = (d + 7) / 8;
447
+ memset(out, 0, offset * qb);
448
+ const size_t nchunks = d / 32;
449
+ for (size_t chunk = 0; chunk < nchunks; chunk++) {
450
+ __m256i vals =
451
+ _mm256_loadu_si256((const __m256i*)(rotated_qq + chunk * 32));
452
+ for (size_t iv = 0; iv < qb; iv++) {
453
+ __m256i mask = _mm256_set1_epi8(static_cast<char>(1 << iv));
454
+ __m256i bits =
455
+ _mm256_cmpeq_epi8(_mm256_and_si256(vals, mask), mask);
456
+ uint32_t packed = static_cast<uint32_t>(_mm256_movemask_epi8(bits));
457
+ memcpy(&out[iv * offset + chunk * 4], &packed, 4);
458
+ }
459
+ }
460
+ for (size_t idim = nchunks * 32; idim < d; idim++) {
461
+ for (size_t iv = 0; iv < qb; iv++) {
462
+ const bool bit = ((rotated_qq[idim] & (1 << iv)) != 0);
463
+ out[iv * offset + idim / 8] |= bit ? (1 << (idim % 8)) : 0;
464
+ }
465
+ }
466
+ }
467
+
223
468
  } // namespace faiss::rabitq
224
469
 
225
470
  namespace faiss::rabitq::multibit {