faiss 0.6.2 → 0.6.3

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 (144) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -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/IVFlib.cpp +14 -3
  7. data/vendor/faiss/faiss/Index.h +2 -2
  8. data/vendor/faiss/faiss/IndexAdditiveQuantizer.cpp +9 -10
  9. data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.cpp +2 -3
  10. data/vendor/faiss/faiss/IndexBinaryFromFloat.cpp +1 -2
  11. data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +4 -5
  12. data/vendor/faiss/faiss/IndexBinaryHash.cpp +5 -9
  13. data/vendor/faiss/faiss/IndexBinaryIVF.cpp +2 -4
  14. data/vendor/faiss/faiss/IndexEDEN.cpp +273 -0
  15. data/vendor/faiss/faiss/IndexEDEN.h +57 -0
  16. data/vendor/faiss/faiss/IndexFastScan.cpp +15 -4
  17. data/vendor/faiss/faiss/IndexFlat.cpp +13 -50
  18. data/vendor/faiss/faiss/IndexHNSW.cpp +10 -11
  19. data/vendor/faiss/faiss/IndexIDMap.cpp +16 -3
  20. data/vendor/faiss/faiss/IndexIDMap.h +2 -0
  21. data/vendor/faiss/faiss/IndexIVF.cpp +17 -6
  22. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +1 -1
  23. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.cpp +3 -4
  24. data/vendor/faiss/faiss/IndexIVFEDEN.cpp +302 -0
  25. data/vendor/faiss/faiss/IndexIVFEDEN.h +70 -0
  26. data/vendor/faiss/faiss/IndexIVFFastScan.cpp +5 -6
  27. data/vendor/faiss/faiss/IndexIVFFlat.cpp +3 -4
  28. data/vendor/faiss/faiss/IndexIVFIndependentQuantizer.cpp +1 -1
  29. data/vendor/faiss/faiss/IndexIVFPQ.cpp +40 -22
  30. data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +0 -1
  31. data/vendor/faiss/faiss/IndexIVFRaBitQ.cpp +19 -49
  32. data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.cpp +180 -76
  33. data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.h +5 -4
  34. data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +8 -6
  35. data/vendor/faiss/faiss/IndexLSH.cpp +2 -3
  36. data/vendor/faiss/faiss/IndexLattice.cpp +5 -0
  37. data/vendor/faiss/faiss/IndexNNDescent.cpp +9 -2
  38. data/vendor/faiss/faiss/IndexNSG.cpp +7 -2
  39. data/vendor/faiss/faiss/IndexPQ.cpp +6 -8
  40. data/vendor/faiss/faiss/IndexPreTransform.cpp +15 -0
  41. data/vendor/faiss/faiss/IndexRaBitQ.cpp +2 -2
  42. data/vendor/faiss/faiss/IndexRaBitQFastScan.cpp +1 -2
  43. data/vendor/faiss/faiss/IndexRaBitQFastScan.h +5 -1
  44. data/vendor/faiss/faiss/IndexRefine.cpp +30 -1
  45. data/vendor/faiss/faiss/IndexReplicas.cpp +1 -2
  46. data/vendor/faiss/faiss/IndexShards.cpp +2 -2
  47. data/vendor/faiss/faiss/IndexShardsIVF.cpp +2 -2
  48. data/vendor/faiss/faiss/MetaIndexes.cpp +2 -4
  49. data/vendor/faiss/faiss/SuperKMeans.cpp +256 -240
  50. data/vendor/faiss/faiss/SuperKMeans.h +30 -0
  51. data/vendor/faiss/faiss/VectorTransform.cpp +33 -2
  52. data/vendor/faiss/faiss/clone_index.cpp +5 -0
  53. data/vendor/faiss/faiss/factory_tools.cpp +47 -4
  54. data/vendor/faiss/faiss/gpu/GpuCloner.cpp +11 -11
  55. data/vendor/faiss/faiss/gpu/GpuIndex.h +34 -11
  56. data/vendor/faiss/faiss/gpu/GpuIndexCagra.h +47 -0
  57. data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +17 -0
  58. data/vendor/faiss/faiss/gpu/GpuIndexIVFScalarQuantizer.h +16 -0
  59. data/vendor/faiss/faiss/gpu/perf/PerfClustering.cpp +1 -1
  60. data/vendor/faiss/faiss/gpu/perf/PerfIVFPQAdd.cpp +2 -2
  61. data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFScalarQuantizer.cpp +180 -0
  62. data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFFlat.h +1 -5
  63. data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFPQ.h +88 -0
  64. data/vendor/faiss/faiss/gpu_metal/impl/MetalIVFPQ.h +134 -0
  65. data/vendor/faiss/faiss/impl/ClusteringInitialization.cpp +2 -2
  66. data/vendor/faiss/faiss/impl/DistanceComputer.h +34 -0
  67. data/vendor/faiss/faiss/impl/EDENQuantizer.h +119 -0
  68. data/vendor/faiss/faiss/impl/HNSW.cpp +109 -152
  69. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +2 -2
  70. data/vendor/faiss/faiss/impl/NSG.cpp +3 -1
  71. data/vendor/faiss/faiss/impl/Panorama.h +9 -7
  72. data/vendor/faiss/faiss/impl/PolysemousTraining.cpp +152 -84
  73. data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +34 -22
  74. data/vendor/faiss/faiss/impl/RaBitQUtils.cpp +44 -36
  75. data/vendor/faiss/faiss/impl/RaBitQUtils.h +35 -0
  76. data/vendor/faiss/faiss/impl/RaBitQuantizer.cpp +168 -67
  77. data/vendor/faiss/faiss/impl/RaBitQuantizer.h +19 -0
  78. data/vendor/faiss/faiss/impl/RaBitQuantizerMultiBit.cpp +2 -11
  79. data/vendor/faiss/faiss/impl/ResultHandler.h +25 -31
  80. data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +258 -57
  81. data/vendor/faiss/faiss/impl/ScalarQuantizer.h +20 -0
  82. data/vendor/faiss/faiss/impl/ThreadedIndex-inl.h +2 -2
  83. data/vendor/faiss/faiss/impl/VisitedTable.cpp +22 -2
  84. data/vendor/faiss/faiss/impl/VisitedTable.h +20 -0
  85. data/vendor/faiss/faiss/impl/binary_hamming/IndexBinaryIVF_impl.h +1 -1
  86. data/vendor/faiss/faiss/impl/binary_hamming/avx2.cpp +4 -4
  87. data/vendor/faiss/faiss/impl/fast_scan/dispatching.h +35 -2
  88. data/vendor/faiss/faiss/impl/hnsw/LockVector.cpp +1 -1
  89. data/vendor/faiss/faiss/impl/index_read.cpp +376 -36
  90. data/vendor/faiss/faiss/impl/index_write.cpp +55 -4
  91. data/vendor/faiss/faiss/impl/lattice_Zn.cpp +8 -9
  92. data/vendor/faiss/faiss/impl/platform_macros.h +3 -1
  93. data/vendor/faiss/faiss/impl/polysemous_training/avx512.cpp +284 -0
  94. data/vendor/faiss/faiss/impl/polysemous_training/dispatch.h +115 -0
  95. data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQ_QueryTables.cpp +0 -1
  96. data/vendor/faiss/faiss/impl/pq_code_distance/PQDistanceComputer_impl.h +26 -15
  97. data/vendor/faiss/faiss/impl/pq_code_distance/avx2.cpp +4 -4
  98. data/vendor/faiss/faiss/impl/result_handler/ResultHandler.cpp +195 -0
  99. data/vendor/faiss/faiss/impl/result_handler/avx2.cpp +133 -0
  100. data/vendor/faiss/faiss/impl/result_handler/avx512.cpp +281 -0
  101. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx2.cpp +72 -0
  102. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx512.cpp +228 -0
  103. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer.cpp +882 -0
  104. data/vendor/faiss/faiss/impl/scalar_quantizer/quantizers.h +9 -8
  105. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx2.cpp +85 -23
  106. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-impl.h +30 -30
  107. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-spr.cpp +4 -5
  108. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512.cpp +101 -34
  109. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-dispatch.h +136 -0
  110. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-neon.cpp +16 -16
  111. data/vendor/faiss/faiss/impl/simd_dispatch.h +30 -9
  112. data/vendor/faiss/faiss/index_factory.cpp +32 -6
  113. data/vendor/faiss/faiss/invlists/DirectMap.cpp +1 -1
  114. data/vendor/faiss/faiss/invlists/InvertedLists.cpp +2 -2
  115. data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +19 -4
  116. data/vendor/faiss/faiss/python/python_callbacks.cpp +3 -1
  117. data/vendor/faiss/faiss/svs/IndexSVSFaissUtils.h +60 -0
  118. data/vendor/faiss/faiss/svs/IndexSVSFlat.cpp +26 -1
  119. data/vendor/faiss/faiss/svs/IndexSVSFlat.h +13 -0
  120. data/vendor/faiss/faiss/svs/IndexSVSIVF.cpp +1 -1
  121. data/vendor/faiss/faiss/svs/IndexSVSIVFLeanVec.cpp +1 -1
  122. data/vendor/faiss/faiss/svs/IndexSVSVamana.cpp +31 -1
  123. data/vendor/faiss/faiss/svs/IndexSVSVamana.h +15 -2
  124. data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.cpp +1 -2
  125. data/vendor/faiss/faiss/utils/approx_topk_hamming/approx_topk_hamming.h +1 -1
  126. data/vendor/faiss/faiss/utils/distances.cpp +14 -2
  127. data/vendor/faiss/faiss/utils/distances_simd.cpp +4 -3
  128. data/vendor/faiss/faiss/utils/extra_distances.cpp +4 -14
  129. data/vendor/faiss/faiss/utils/extra_distances.h +1 -2
  130. data/vendor/faiss/faiss/utils/hamming.cpp +1 -1
  131. data/vendor/faiss/faiss/utils/quantize_lut.cpp +29 -8
  132. data/vendor/faiss/faiss/utils/rabitq_simd.h +202 -0
  133. data/vendor/faiss/faiss/utils/simd_impl/distances_avx2.cpp +0 -1
  134. data/vendor/faiss/faiss/utils/simd_impl/distances_avx512.cpp +263 -15
  135. data/vendor/faiss/faiss/utils/simd_impl/distances_rvv.cpp +160 -18
  136. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx2.cpp +245 -0
  137. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512.cpp +273 -0
  138. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512_spr.cpp +92 -0
  139. data/vendor/faiss/faiss/utils/simd_impl/rabitq_neon.cpp +11 -0
  140. data/vendor/faiss/faiss/utils/simd_impl/rabitq_rvv.cpp +143 -6
  141. data/vendor/faiss/faiss/utils/simd_levels.cpp +44 -0
  142. data/vendor/faiss/faiss/utils/simd_levels.h +14 -0
  143. data/vendor/faiss/faiss/utils/utils.cpp +9 -27
  144. metadata +16 -1
@@ -5,19 +5,107 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
+ // -*- c++ -*-
9
+
8
10
  #include <faiss/utils/rabitq_simd.h>
9
11
 
10
12
  #ifdef COMPILE_SIMD_RISCV_RVV
11
13
 
14
+ #include <riscv_vector.h>
15
+
12
16
  namespace faiss::rabitq {
13
17
 
18
+ // SWAR per-byte popcount over a u8m4 group: each output byte holds the
19
+ // population count (0..8) of the corresponding input byte.
20
+ static inline vuint8m4_t popcount_u8m4(vuint8m4_t v, size_t vl) {
21
+ vuint8m4_t t = __riscv_vsrl_vx_u8m4(v, 1, vl);
22
+ t = __riscv_vand_vx_u8m4(t, 0x55, vl);
23
+ v = __riscv_vsub_vv_u8m4(v, t, vl);
24
+ t = __riscv_vsrl_vx_u8m4(v, 2, vl);
25
+ t = __riscv_vand_vx_u8m4(t, 0x33, vl);
26
+ v = __riscv_vand_vx_u8m4(v, 0x33, vl);
27
+ v = __riscv_vadd_vv_u8m4(v, t, vl);
28
+ t = __riscv_vsrl_vx_u8m4(v, 4, vl);
29
+ v = __riscv_vadd_vv_u8m4(v, t, vl);
30
+ return __riscv_vand_vx_u8m4(v, 0x0F, vl);
31
+ }
32
+
33
+ // Shared body for bitwise_{and,xor}_dot_product. @p combine applies the
34
+ // per-element bit op (AND or XOR) between the data and query bit-planes; the
35
+ // popcount of the result for query bit-plane j is weighted by 2^j.
36
+ template <typename Op>
37
+ static inline uint64_t bitwise_dot_product_rvv(
38
+ const uint8_t* query,
39
+ const uint8_t* data,
40
+ size_t size,
41
+ size_t qb,
42
+ Op combine) {
43
+ size_t vlmax = __riscv_vsetvlmax_e16m8();
44
+ vuint16m8_t acc = __riscv_vmv_v_x_u16m8(0, vlmax);
45
+ size_t i = 0;
46
+ while (i < size) {
47
+ size_t vl = __riscv_vsetvl_e8m4(size - i);
48
+ vuint8m4_t vx = __riscv_vle8_v_u8m4(data + i, vl);
49
+ for (size_t j = 0; j < qb; j++) {
50
+ vuint8m4_t vq = __riscv_vle8_v_u8m4(query + j * size + i, vl);
51
+ vuint8m4_t vp = popcount_u8m4(combine(vx, vq, vl), vl);
52
+ vuint16m8_t vw = __riscv_vzext_vf2_u16m8(vp, vl);
53
+ vw = __riscv_vsll_vx_u16m8(vw, j, vl);
54
+ acc = __riscv_vadd_vv_u16m8_tu(acc, acc, vw, vl);
55
+ }
56
+ i += vl;
57
+ }
58
+ vuint32m1_t red = __riscv_vmv_v_x_u32m1(0, 1);
59
+ red = __riscv_vwredsumu_vs_u16m8_u32m1(acc, red, vlmax);
60
+ return __riscv_vmv_x_s_u32m1_u32(red);
61
+ }
62
+
14
63
  template <>
15
64
  uint64_t bitwise_and_dot_product<SIMDLevel::RISCV_RVV>(
16
65
  const uint8_t* query,
17
66
  const uint8_t* data,
18
67
  size_t size,
19
68
  size_t qb) {
20
- return bitwise_and_dot_product<SIMDLevel::NONE>(query, data, size, qb);
69
+ return bitwise_dot_product_rvv(
70
+ query, data, size, qb, [](vuint8m4_t a, vuint8m4_t b, size_t vl) {
71
+ return __riscv_vand_vv_u8m4(a, b, vl);
72
+ });
73
+ }
74
+
75
+ template <>
76
+ BitwiseAndDotProductResult bitwise_and_dot_product_with_popcount<
77
+ SIMDLevel::RISCV_RVV>(
78
+ const uint8_t* query,
79
+ const uint8_t* data,
80
+ size_t size,
81
+ size_t qb) {
82
+ // Fused single pass over @p data: reuse each loaded data group for both the
83
+ // doc-side popcount and the qb AND-dot bit-planes, mirroring the separate
84
+ // popcount<RVV> and bitwise_and_dot_product<RVV> kernels above.
85
+ size_t vlmax = __riscv_vsetvlmax_e16m8();
86
+ vuint16m8_t dot_acc = __riscv_vmv_v_x_u16m8(0, vlmax);
87
+ vuint16m8_t pop_acc = __riscv_vmv_v_x_u16m8(0, vlmax);
88
+ size_t i = 0;
89
+ while (i < size) {
90
+ size_t vl = __riscv_vsetvl_e8m4(size - i);
91
+ vuint8m4_t vx = __riscv_vle8_v_u8m4(data + i, vl);
92
+ vuint16m8_t vxp = __riscv_vzext_vf2_u16m8(popcount_u8m4(vx, vl), vl);
93
+ pop_acc = __riscv_vadd_vv_u16m8_tu(pop_acc, pop_acc, vxp, vl);
94
+ for (size_t j = 0; j < qb; j++) {
95
+ vuint8m4_t vq = __riscv_vle8_v_u8m4(query + j * size + i, vl);
96
+ vuint8m4_t vp = popcount_u8m4(__riscv_vand_vv_u8m4(vx, vq, vl), vl);
97
+ vuint16m8_t vw = __riscv_vzext_vf2_u16m8(vp, vl);
98
+ vw = __riscv_vsll_vx_u16m8(vw, j, vl);
99
+ dot_acc = __riscv_vadd_vv_u16m8_tu(dot_acc, dot_acc, vw, vl);
100
+ }
101
+ i += vl;
102
+ }
103
+ vuint32m1_t dot_red = __riscv_vmv_v_x_u32m1(0, 1);
104
+ dot_red = __riscv_vwredsumu_vs_u16m8_u32m1(dot_acc, dot_red, vlmax);
105
+ vuint32m1_t pop_red = __riscv_vmv_v_x_u32m1(0, 1);
106
+ pop_red = __riscv_vwredsumu_vs_u16m8_u32m1(pop_acc, pop_red, vlmax);
107
+ return {__riscv_vmv_x_s_u32m1_u32(dot_red),
108
+ __riscv_vmv_x_s_u32m1_u32(pop_red)};
21
109
  }
22
110
 
23
111
  template <>
@@ -26,28 +114,77 @@ uint64_t bitwise_xor_dot_product<SIMDLevel::RISCV_RVV>(
26
114
  const uint8_t* data,
27
115
  size_t size,
28
116
  size_t qb) {
29
- return bitwise_xor_dot_product<SIMDLevel::NONE>(query, data, size, qb);
117
+ return bitwise_dot_product_rvv(
118
+ query, data, size, qb, [](vuint8m4_t a, vuint8m4_t b, size_t vl) {
119
+ return __riscv_vxor_vv_u8m4(a, b, vl);
120
+ });
30
121
  }
31
122
 
32
123
  template <>
33
124
  uint64_t popcount<SIMDLevel::RISCV_RVV>(const uint8_t* data, size_t size) {
34
- return popcount<SIMDLevel::NONE>(data, size);
125
+ size_t vlmax = __riscv_vsetvlmax_e16m8();
126
+ vuint16m8_t acc = __riscv_vmv_v_x_u16m8(0, vlmax);
127
+ size_t i = 0;
128
+ while (i < size) {
129
+ size_t vl = __riscv_vsetvl_e8m4(size - i);
130
+ vuint8m4_t v = popcount_u8m4(__riscv_vle8_v_u8m4(data + i, vl), vl);
131
+ vuint16m8_t vw = __riscv_vzext_vf2_u16m8(v, vl);
132
+ acc = __riscv_vadd_vv_u16m8_tu(acc, acc, vw, vl);
133
+ i += vl;
134
+ }
135
+ vuint32m1_t red = __riscv_vmv_v_x_u32m1(0, 1);
136
+ red = __riscv_vwredsumu_vs_u16m8_u32m1(acc, red, vlmax);
137
+ return __riscv_vmv_x_s_u32m1_u32(red);
35
138
  }
36
139
 
37
140
  } // namespace faiss::rabitq
38
141
 
39
142
  namespace faiss::rabitq::multibit {
40
143
 
144
+ static float ip_1exbit_rvv(
145
+ const uint8_t* __restrict sign_bits,
146
+ const uint8_t* __restrict ex_code,
147
+ const float* __restrict rotated_q,
148
+ size_t d,
149
+ float cb) {
150
+ size_t vlmax = __riscv_vsetvlmax_e32m8();
151
+ vfloat32m8_t acc = __riscv_vfmv_v_f_f32m8(0.0f, vlmax);
152
+ size_t i = 0;
153
+ while (i < d) {
154
+ size_t vl = __riscv_vsetvl_e32m8(d - i);
155
+ vbool4_t sb = __riscv_vlm_v_b4(sign_bits + i / 8, vl);
156
+ vbool4_t eb = __riscv_vlm_v_b4(ex_code + i / 8, vl);
157
+ vfloat32m8_t recon = __riscv_vfmv_v_f_f32m8(cb, vl);
158
+ recon = __riscv_vfadd_vf_f32m8_mu(sb, recon, recon, 2.0f, vl);
159
+ recon = __riscv_vfadd_vf_f32m8_mu(eb, recon, recon, 1.0f, vl);
160
+ vfloat32m8_t rq = __riscv_vle32_v_f32m8(rotated_q + i, vl);
161
+ acc = __riscv_vfmacc_vv_f32m8_tu(acc, rq, recon, vl);
162
+ i += vl;
163
+ }
164
+ vfloat32m1_t sum = __riscv_vfmv_s_f_f32m1(0.0f, 1);
165
+ sum = __riscv_vfredusum_vs_f32m8_f32m1(acc, sum, vlmax);
166
+ return __riscv_vfmv_f_s_f32m1_f32(sum);
167
+ }
168
+
169
+ // no-tree-vectorize keeps the ex_bits >= 2 tail on the existing scalar
170
+ // ip_scalar without GCC turning its 64-bit memcpy window into a vluxei64 gather
171
+ // at unaligned addresses, which SIGBUSes on strict-align RVV cores (SpacemiT
172
+ // X60).
41
173
  template <>
42
- float compute_inner_product<SIMDLevel::RISCV_RVV>(
174
+ __attribute__((optimize("no-tree-vectorize", "no-tree-slp-vectorize"))) float
175
+ compute_inner_product<SIMDLevel::RISCV_RVV>(
43
176
  const uint8_t* __restrict sign_bits,
44
177
  const uint8_t* __restrict ex_code,
45
178
  const float* __restrict rotated_q,
46
179
  size_t d,
47
180
  size_t ex_bits,
48
181
  float cb) {
49
- return compute_inner_product<SIMDLevel::NONE>(
50
- sign_bits, ex_code, rotated_q, d, ex_bits, cb);
182
+ if (ex_bits == 1) {
183
+ return ip_1exbit_rvv(sign_bits, ex_code, rotated_q, d, cb);
184
+ }
185
+ // ex_bits >= 2 needs strided bit-plane extraction (PEXT on x86); RVV has no
186
+ // cheap equivalent without Zvbb, so reuse the scalar kernel.
187
+ return ip_scalar(sign_bits, ex_code, rotated_q, 0, d, ex_bits, cb);
51
188
  }
52
189
 
53
190
  } // namespace faiss::rabitq::multibit
@@ -20,6 +20,10 @@ SIMDLevel SIMDConfig::level = SIMDLevel::NONE;
20
20
  // Bitmask of supported SIMD levels (1 << SIMDLevel)
21
21
  uint64_t SIMDConfig::supported_simd_levels = 0;
22
22
 
23
+ // Microarchitecture flags (x86). Default false; set by
24
+ // detect_x86_uarch_flags() at load time.
25
+ bool SIMDConfig::avx512_split = false;
26
+
23
27
  // ARM SVE runtime detection
24
28
  #if defined(__aarch64__) || defined(_M_ARM64)
25
29
 
@@ -53,6 +57,43 @@ static bool has_sve() {
53
57
  }
54
58
  #endif
55
59
 
60
+ // Detect x86 microarchitecture flags used for kernel routing. Uses raw
61
+ // cpuid so it is safe to run on any CPU regardless of compiled SIMD level.
62
+ #if defined(__x86_64__)
63
+ namespace {
64
+ void detect_x86_uarch_flags() {
65
+ unsigned int eax, ebx, ecx, edx;
66
+
67
+ // Vendor string (CPUID.0): "AuthenticAMD" is EBX="Auth", EDX="enti",
68
+ // ECX="cAMD".
69
+ eax = 0;
70
+ ecx = 0;
71
+ asm volatile("cpuid"
72
+ : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
73
+ : "a"(eax), "c"(ecx));
74
+ const bool is_amd =
75
+ ebx == 0x68747541u && edx == 0x69746e65u && ecx == 0x444d4163u;
76
+
77
+ // Family/model (CPUID.1 EAX).
78
+ eax = 1;
79
+ ecx = 0;
80
+ asm volatile("cpuid"
81
+ : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
82
+ : "a"(eax), "c"(ecx));
83
+ const unsigned int base_family = (eax >> 8) & 0xfu;
84
+ const unsigned int display_family =
85
+ base_family + (base_family == 0xfu ? ((eax >> 20) & 0xffu) : 0u);
86
+ // AMD Zen 4 / Zen 4c (Bergamo) is family 0x19 and splits AVX-512.
87
+ // (Zen 5, family 0x1A, has a native 512-bit datapath and is excluded.)
88
+ SIMDConfig::avx512_split = is_amd && display_family == 0x19u;
89
+ }
90
+ } // namespace
91
+ #else
92
+ namespace {
93
+ void detect_x86_uarch_flags() {}
94
+ } // namespace
95
+ #endif
96
+
56
97
  #ifdef FAISS_ENABLE_DD
57
98
 
58
99
  // =============================================================================
@@ -101,6 +142,8 @@ bool SIMDConfig::is_simd_level_available(SIMDLevel l) {
101
142
  SIMDLevel SIMDConfig::auto_detect_simd_level() {
102
143
  SIMDLevel detected_level = SIMDLevel::NONE;
103
144
 
145
+ detect_x86_uarch_flags();
146
+
104
147
  #if defined(__x86_64__) && \
105
148
  (defined(COMPILE_SIMD_AVX2) || defined(COMPILE_SIMD_AVX512))
106
149
  unsigned int eax, ebx, ecx, edx;
@@ -264,6 +307,7 @@ bool SIMDConfig::is_simd_level_available(SIMDLevel l) {
264
307
  }
265
308
 
266
309
  SIMDLevel SIMDConfig::auto_detect_simd_level() {
310
+ detect_x86_uarch_flags();
267
311
  // In static mode, return the compiled-in level
268
312
  #if defined(COMPILE_SIMD_AVX512_SPR)
269
313
  return SIMDLevel::AVX512_SPR;
@@ -161,8 +161,22 @@ struct FAISS_API SIMDConfig {
161
161
  /// Returns bitmask of supported SIMD levels (1 << SIMDLevel).
162
162
  static uint64_t supported_simd_levels;
163
163
 
164
+ /// CPU implements AVX-512 by splitting over a 256-bit datapath
165
+ /// (AMD Zen 4 / Zen 4c "Bergamo", family 0x19). On such CPUs 512-bit
166
+ /// ops give no throughput gain, so the fast-scan QBS path prefers the
167
+ /// 256-bit kernel.
168
+ static bool avx512_split;
169
+
164
170
  static SIMDLevel auto_detect_simd_level();
165
171
 
172
+ static constexpr bool has_dynamic_dispatch() {
173
+ #ifdef FAISS_ENABLE_DD
174
+ return true;
175
+ #else
176
+ return false;
177
+ #endif
178
+ }
179
+
166
180
  SIMDConfig(const char** faiss_simd_level_env = nullptr);
167
181
 
168
182
  /// Set the SIMD level. Throws FaissException if level is not supported.
@@ -30,6 +30,7 @@
30
30
  #include <algorithm>
31
31
  #include <set>
32
32
  #include <type_traits>
33
+ #include <unordered_set>
33
34
  #include <vector>
34
35
 
35
36
  #include <faiss/impl/AuxIndexStructures.h>
@@ -362,39 +363,20 @@ size_t ranklist_intersection_size(
362
363
  const int64_t* v2_in) {
363
364
  if (k2 > k1)
364
365
  return ranklist_intersection_size(k2, v2_in, k1, v1);
365
- int64_t* v2 = new int64_t[k2];
366
- memcpy(v2, v2_in, sizeof(int64_t) * k2);
367
- std::sort(v2, v2 + k2);
368
- { // de-dup v2
369
- int64_t prev = -1;
370
- size_t wp = 0;
371
- for (size_t i = 0; i < k2; i++) {
372
- if (v2[i] != prev) {
373
- v2[wp++] = prev = v2[i];
374
- }
366
+ // erase-on-hit avoids double-counting; negatives are padding, not IDs
367
+ std::unordered_set<int64_t> remaining;
368
+ remaining.reserve(k2);
369
+ for (size_t i = 0; i < k2; i++) {
370
+ if (v2_in[i] >= 0) {
371
+ remaining.insert(v2_in[i]);
375
372
  }
376
- k2 = wp;
377
373
  }
378
- const int64_t seen_flag = int64_t{1} << 60;
379
374
  size_t count = 0;
380
375
  for (size_t i = 0; i < k1; i++) {
381
- int64_t q = v1[i];
382
- size_t i0 = 0, i1 = k2;
383
- while (i0 + 1 < i1) {
384
- size_t imed = (i1 + i0) / 2;
385
- int64_t piv = v2[imed] & ~seen_flag;
386
- if (piv <= q)
387
- i0 = imed;
388
- else
389
- i1 = imed;
390
- }
391
- if (v2[i0] == q) {
376
+ if (remaining.erase(v1[i]) != 0) {
392
377
  count++;
393
- v2[i0] |= seen_flag;
394
378
  }
395
379
  }
396
- delete[] v2;
397
-
398
380
  return count;
399
381
  }
400
382
 
@@ -462,7 +444,7 @@ uint64_t ivec_checksum(size_t n, const int32_t* assigned) {
462
444
  uint64_t bvec_checksum(size_t n, const uint8_t* a) {
463
445
  uint64_t cs = ivec_checksum(n / 4, (const int32_t*)a);
464
446
  for (size_t i = n / 4 * 4; i < n; i++) {
465
- cs = cs * 65713 + a[n] * 1686049;
447
+ cs = cs * 65713 + a[i] * 1686049;
466
448
  }
467
449
  return cs;
468
450
  }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: faiss
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.2
4
+ version: 0.6.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
@@ -85,6 +85,8 @@ files:
85
85
  - vendor/faiss/faiss/IndexBinaryHash.h
86
86
  - vendor/faiss/faiss/IndexBinaryIVF.cpp
87
87
  - vendor/faiss/faiss/IndexBinaryIVF.h
88
+ - vendor/faiss/faiss/IndexEDEN.cpp
89
+ - vendor/faiss/faiss/IndexEDEN.h
88
90
  - vendor/faiss/faiss/IndexFastScan.cpp
89
91
  - vendor/faiss/faiss/IndexFastScan.h
90
92
  - vendor/faiss/faiss/IndexFlat.cpp
@@ -101,6 +103,8 @@ files:
101
103
  - vendor/faiss/faiss/IndexIVFAdditiveQuantizer.h
102
104
  - vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.cpp
103
105
  - vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.h
106
+ - vendor/faiss/faiss/IndexIVFEDEN.cpp
107
+ - vendor/faiss/faiss/IndexIVFEDEN.h
104
108
  - vendor/faiss/faiss/IndexIVFFastScan.cpp
105
109
  - vendor/faiss/faiss/IndexIVFFastScan.h
106
110
  - vendor/faiss/faiss/IndexIVFFlat.cpp
@@ -238,11 +242,13 @@ files:
238
242
  - vendor/faiss/faiss/gpu_metal/MetalIndex.h
239
243
  - vendor/faiss/faiss/gpu_metal/MetalIndexFlat.h
240
244
  - vendor/faiss/faiss/gpu_metal/MetalIndexIVFFlat.h
245
+ - vendor/faiss/faiss/gpu_metal/MetalIndexIVFPQ.h
241
246
  - vendor/faiss/faiss/gpu_metal/MetalKernels.h
242
247
  - vendor/faiss/faiss/gpu_metal/MetalPythonBridge.h
243
248
  - vendor/faiss/faiss/gpu_metal/MetalResources.h
244
249
  - vendor/faiss/faiss/gpu_metal/StandardMetalResources.h
245
250
  - vendor/faiss/faiss/gpu_metal/impl/MetalIVFFlat.h
251
+ - vendor/faiss/faiss/gpu_metal/impl/MetalIVFPQ.h
246
252
  - vendor/faiss/faiss/impl/AdSampling.cpp
247
253
  - vendor/faiss/faiss/impl/AdSampling.h
248
254
  - vendor/faiss/faiss/impl/AdditiveQuantizer.cpp
@@ -258,6 +264,7 @@ files:
258
264
  - vendor/faiss/faiss/impl/CodePackerRaBitQ.cpp
259
265
  - vendor/faiss/faiss/impl/CodePackerRaBitQ.h
260
266
  - vendor/faiss/faiss/impl/DistanceComputer.h
267
+ - vendor/faiss/faiss/impl/EDENQuantizer.h
261
268
  - vendor/faiss/faiss/impl/FaissAssert.h
262
269
  - vendor/faiss/faiss/impl/FaissException.cpp
263
270
  - vendor/faiss/faiss/impl/FaissException.h
@@ -356,6 +363,8 @@ files:
356
363
  - vendor/faiss/faiss/impl/mapped_io.h
357
364
  - vendor/faiss/faiss/impl/maybe_owned_vector.h
358
365
  - vendor/faiss/faiss/impl/platform_macros.h
366
+ - vendor/faiss/faiss/impl/polysemous_training/avx512.cpp
367
+ - vendor/faiss/faiss/impl/polysemous_training/dispatch.h
359
368
  - vendor/faiss/faiss/impl/pq_code_distance/IVFPQScanner_impl.h
360
369
  - vendor/faiss/faiss/impl/pq_code_distance/IVFPQ_QueryTables.cpp
361
370
  - vendor/faiss/faiss/impl/pq_code_distance/IVFPQ_QueryTables.h
@@ -373,6 +382,12 @@ files:
373
382
  - vendor/faiss/faiss/impl/pq_code_distance/rvv.cpp
374
383
  - vendor/faiss/faiss/impl/residual_quantizer_encode_steps.cpp
375
384
  - vendor/faiss/faiss/impl/residual_quantizer_encode_steps.h
385
+ - vendor/faiss/faiss/impl/result_handler/ResultHandler.cpp
386
+ - vendor/faiss/faiss/impl/result_handler/avx2.cpp
387
+ - vendor/faiss/faiss/impl/result_handler/avx512.cpp
388
+ - vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx2.cpp
389
+ - vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx512.cpp
390
+ - vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer.cpp
376
391
  - vendor/faiss/faiss/impl/scalar_quantizer/codecs.h
377
392
  - vendor/faiss/faiss/impl/scalar_quantizer/distance_computers.h
378
393
  - vendor/faiss/faiss/impl/scalar_quantizer/quantizers.h