faiss 0.6.1 → 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 (186) 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/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 +10 -12
  12. data/vendor/faiss/faiss/IndexBinaryHash.cpp +5 -9
  13. data/vendor/faiss/faiss/IndexBinaryIVF.cpp +5 -7
  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 +177 -148
  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 +19 -8
  22. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +3 -3
  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 +6 -5
  28. data/vendor/faiss/faiss/IndexIVFFlatPanorama.cpp +3 -3
  29. data/vendor/faiss/faiss/IndexIVFIndependentQuantizer.cpp +1 -1
  30. data/vendor/faiss/faiss/IndexIVFPQ.cpp +42 -25
  31. data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +0 -1
  32. data/vendor/faiss/faiss/IndexIVFPQR.cpp +2 -3
  33. data/vendor/faiss/faiss/IndexIVFRaBitQ.cpp +23 -62
  34. data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.cpp +180 -76
  35. data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.h +5 -4
  36. data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +8 -6
  37. data/vendor/faiss/faiss/IndexLSH.cpp +2 -3
  38. data/vendor/faiss/faiss/IndexLattice.cpp +5 -0
  39. data/vendor/faiss/faiss/IndexNNDescent.cpp +10 -3
  40. data/vendor/faiss/faiss/IndexNSG.cpp +8 -4
  41. data/vendor/faiss/faiss/IndexPQ.cpp +6 -8
  42. data/vendor/faiss/faiss/IndexPreTransform.cpp +15 -0
  43. data/vendor/faiss/faiss/IndexRaBitQ.cpp +2 -2
  44. data/vendor/faiss/faiss/IndexRaBitQFastScan.cpp +1 -2
  45. data/vendor/faiss/faiss/IndexRaBitQFastScan.h +5 -1
  46. data/vendor/faiss/faiss/IndexRefine.cpp +30 -1
  47. data/vendor/faiss/faiss/IndexReplicas.cpp +1 -2
  48. data/vendor/faiss/faiss/IndexScalarQuantizer.cpp +68 -6
  49. data/vendor/faiss/faiss/IndexScalarQuantizer.h +10 -0
  50. data/vendor/faiss/faiss/IndexShards.cpp +2 -2
  51. data/vendor/faiss/faiss/IndexShardsIVF.cpp +2 -2
  52. data/vendor/faiss/faiss/MetaIndexes.cpp +2 -4
  53. data/vendor/faiss/faiss/SuperKMeans.cpp +256 -240
  54. data/vendor/faiss/faiss/SuperKMeans.h +30 -0
  55. data/vendor/faiss/faiss/VectorTransform.cpp +33 -2
  56. data/vendor/faiss/faiss/clone_index.cpp +5 -0
  57. data/vendor/faiss/faiss/cppcontrib/SaDecodeKernels.h +1 -1
  58. data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-neon-inl.h +902 -12
  59. data/vendor/faiss/faiss/cppcontrib/sa_decode/PQ-neon-inl.h +702 -10
  60. data/vendor/faiss/faiss/factory_tools.cpp +51 -4
  61. data/vendor/faiss/faiss/gpu/GpuCloner.cpp +11 -11
  62. data/vendor/faiss/faiss/gpu/GpuIndex.h +34 -11
  63. data/vendor/faiss/faiss/gpu/GpuIndexCagra.h +47 -0
  64. data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +17 -0
  65. data/vendor/faiss/faiss/gpu/GpuIndexIVFScalarQuantizer.h +16 -0
  66. data/vendor/faiss/faiss/gpu/GpuResources.h +3 -2
  67. data/vendor/faiss/faiss/gpu/StandardGpuResources.cpp +11 -12
  68. data/vendor/faiss/faiss/gpu/StandardGpuResources.h +3 -3
  69. data/vendor/faiss/faiss/gpu/perf/PerfClustering.cpp +1 -1
  70. data/vendor/faiss/faiss/gpu/perf/PerfIVFPQAdd.cpp +2 -2
  71. data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFScalarQuantizer.cpp +180 -0
  72. data/vendor/faiss/faiss/gpu_metal/MetalDistance.h +87 -0
  73. data/vendor/faiss/faiss/gpu_metal/MetalIndex.h +7 -0
  74. data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFFlat.h +177 -0
  75. data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFPQ.h +88 -0
  76. data/vendor/faiss/faiss/gpu_metal/MetalKernels.h +48 -3
  77. data/vendor/faiss/faiss/gpu_metal/MetalPythonBridge.h +45 -0
  78. data/vendor/faiss/faiss/gpu_metal/impl/MetalIVFFlat.h +193 -0
  79. data/vendor/faiss/faiss/gpu_metal/impl/MetalIVFPQ.h +134 -0
  80. data/vendor/faiss/faiss/impl/ClusteringInitialization.cpp +2 -2
  81. data/vendor/faiss/faiss/impl/DistanceComputer.h +34 -0
  82. data/vendor/faiss/faiss/impl/EDENQuantizer.h +119 -0
  83. data/vendor/faiss/faiss/impl/HNSW.cpp +658 -344
  84. data/vendor/faiss/faiss/impl/HNSW.h +51 -13
  85. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +2 -2
  86. data/vendor/faiss/faiss/impl/NSG.cpp +18 -12
  87. data/vendor/faiss/faiss/impl/Panorama.h +20 -7
  88. data/vendor/faiss/faiss/impl/PolysemousTraining.cpp +152 -84
  89. data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +59 -24
  90. data/vendor/faiss/faiss/impl/RaBitQUtils.cpp +45 -37
  91. data/vendor/faiss/faiss/impl/RaBitQUtils.h +35 -0
  92. data/vendor/faiss/faiss/impl/RaBitQuantizer.cpp +175 -68
  93. data/vendor/faiss/faiss/impl/RaBitQuantizer.h +19 -0
  94. data/vendor/faiss/faiss/impl/RaBitQuantizerMultiBit.cpp +2 -11
  95. data/vendor/faiss/faiss/impl/ResultHandler.h +26 -31
  96. data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +522 -58
  97. data/vendor/faiss/faiss/impl/ScalarQuantizer.h +70 -0
  98. data/vendor/faiss/faiss/impl/ThreadedIndex-inl.h +2 -2
  99. data/vendor/faiss/faiss/impl/VisitedTable.cpp +33 -13
  100. data/vendor/faiss/faiss/impl/VisitedTable.h +88 -33
  101. data/vendor/faiss/faiss/impl/binary_hamming/IndexBinaryIVF_impl.h +1 -1
  102. data/vendor/faiss/faiss/impl/binary_hamming/avx2.cpp +4 -4
  103. data/vendor/faiss/faiss/impl/fast_scan/dispatching.h +38 -3
  104. data/vendor/faiss/faiss/impl/hnsw/LockVector.cpp +1 -1
  105. data/vendor/faiss/faiss/impl/hnsw/MinimaxHeap.cpp +35 -43
  106. data/vendor/faiss/faiss/impl/hnsw/MinimaxHeap.h +64 -15
  107. data/vendor/faiss/faiss/impl/hnsw/avx2.cpp +86 -40
  108. data/vendor/faiss/faiss/impl/hnsw/avx512.cpp +81 -50
  109. data/vendor/faiss/faiss/impl/index_read.cpp +476 -75
  110. data/vendor/faiss/faiss/impl/index_write.cpp +56 -4
  111. data/vendor/faiss/faiss/impl/io_macros.h +25 -0
  112. data/vendor/faiss/faiss/impl/lattice_Zn.cpp +8 -9
  113. data/vendor/faiss/faiss/impl/platform_macros.h +15 -9
  114. data/vendor/faiss/faiss/impl/polysemous_training/avx512.cpp +284 -0
  115. data/vendor/faiss/faiss/impl/polysemous_training/dispatch.h +115 -0
  116. data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQ_QueryTables.cpp +0 -1
  117. data/vendor/faiss/faiss/impl/pq_code_distance/PQDistanceComputer_impl.h +26 -15
  118. data/vendor/faiss/faiss/impl/pq_code_distance/avx2.cpp +6 -4
  119. data/vendor/faiss/faiss/impl/pq_code_distance/avx512.cpp +2 -0
  120. data/vendor/faiss/faiss/impl/pq_code_distance/neon.cpp +2 -0
  121. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-generic.cpp +20 -0
  122. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-inl.h +36 -0
  123. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-sve.cpp +5 -0
  124. data/vendor/faiss/faiss/impl/pq_code_distance/pq_scan_impl.h +105 -0
  125. data/vendor/faiss/faiss/impl/pq_code_distance/rvv.cpp +2 -0
  126. data/vendor/faiss/faiss/impl/result_handler/ResultHandler.cpp +195 -0
  127. data/vendor/faiss/faiss/impl/result_handler/avx2.cpp +133 -0
  128. data/vendor/faiss/faiss/impl/result_handler/avx512.cpp +281 -0
  129. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx2.cpp +72 -0
  130. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx512.cpp +228 -0
  131. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer.cpp +882 -0
  132. data/vendor/faiss/faiss/impl/scalar_quantizer/distance_computers.h +6 -0
  133. data/vendor/faiss/faiss/impl/scalar_quantizer/quantizers.h +336 -26
  134. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx2.cpp +331 -32
  135. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-impl.h +553 -0
  136. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-spr.cpp +558 -0
  137. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512.cpp +284 -45
  138. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-dispatch.h +502 -3
  139. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-neon.cpp +157 -32
  140. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-rvv.cpp +26 -0
  141. data/vendor/faiss/faiss/impl/simd_dispatch.h +86 -8
  142. data/vendor/faiss/faiss/index_factory.cpp +37 -7
  143. data/vendor/faiss/faiss/index_io.h +16 -0
  144. data/vendor/faiss/faiss/invlists/DirectMap.cpp +5 -2
  145. data/vendor/faiss/faiss/invlists/InvertedLists.cpp +15 -15
  146. data/vendor/faiss/faiss/invlists/InvertedLists.h +2 -2
  147. data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +19 -4
  148. data/vendor/faiss/faiss/python/python_callbacks.cpp +3 -1
  149. data/vendor/faiss/faiss/svs/IndexSVSFaissUtils.h +60 -0
  150. data/vendor/faiss/faiss/svs/IndexSVSFlat.cpp +26 -1
  151. data/vendor/faiss/faiss/svs/IndexSVSFlat.h +13 -0
  152. data/vendor/faiss/faiss/svs/IndexSVSIVF.cpp +1 -1
  153. data/vendor/faiss/faiss/svs/IndexSVSIVFLeanVec.cpp +1 -1
  154. data/vendor/faiss/faiss/svs/IndexSVSVamana.cpp +150 -23
  155. data/vendor/faiss/faiss/svs/IndexSVSVamana.h +30 -7
  156. data/vendor/faiss/faiss/svs/IndexSVSVamanaLVQ.cpp +3 -2
  157. data/vendor/faiss/faiss/svs/IndexSVSVamanaLVQ.h +2 -1
  158. data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.cpp +65 -25
  159. data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.h +3 -2
  160. data/vendor/faiss/faiss/utils/approx_topk_hamming/approx_topk_hamming.h +1 -1
  161. data/vendor/faiss/faiss/utils/bf16.h +34 -0
  162. data/vendor/faiss/faiss/utils/distances.cpp +14 -2
  163. data/vendor/faiss/faiss/utils/distances_simd.cpp +4 -4
  164. data/vendor/faiss/faiss/utils/extra_distances.cpp +4 -14
  165. data/vendor/faiss/faiss/utils/extra_distances.h +1 -2
  166. data/vendor/faiss/faiss/utils/hamming.cpp +9 -9
  167. data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx2.cpp +2 -1
  168. data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512_spr.cpp +15 -0
  169. data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-avx512.h +6 -30
  170. data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-avx512_spr.h +171 -0
  171. data/vendor/faiss/faiss/utils/partitioning.cpp +0 -2
  172. data/vendor/faiss/faiss/utils/quantize_lut.cpp +29 -8
  173. data/vendor/faiss/faiss/utils/rabitq_simd.h +202 -0
  174. data/vendor/faiss/faiss/utils/simd_impl/distances_avx2.cpp +0 -1
  175. data/vendor/faiss/faiss/utils/simd_impl/distances_avx512.cpp +263 -15
  176. data/vendor/faiss/faiss/utils/simd_impl/distances_rvv.cpp +160 -18
  177. data/vendor/faiss/faiss/utils/simd_impl/partitioning_simdlib256.h +14 -68
  178. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx2.cpp +245 -0
  179. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512.cpp +273 -0
  180. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512_spr.cpp +435 -0
  181. data/vendor/faiss/faiss/utils/simd_impl/rabitq_neon.cpp +11 -0
  182. data/vendor/faiss/faiss/utils/simd_impl/rabitq_rvv.cpp +143 -6
  183. data/vendor/faiss/faiss/utils/simd_levels.cpp +56 -2
  184. data/vendor/faiss/faiss/utils/simd_levels.h +14 -0
  185. data/vendor/faiss/faiss/utils/utils.cpp +9 -27
  186. metadata +27 -2
@@ -77,6 +77,12 @@ struct DCTemplate<Quantizer, Similarity, SIMDLevel::NONE> : SQDistanceComputer {
77
77
  template <class Similarity, SIMDLevel SL>
78
78
  struct DistanceComputerByte : SQDistanceComputer {};
79
79
 
80
+ // Byte-domain distance computer for QT_8bit_direct_signed (storage is
81
+ // value+128). Only specialized for AVX512_SPR; other levels fall back to
82
+ // the float-domain DCTemplate path via the dispatch logic.
83
+ template <class Similarity, SIMDLevel SL>
84
+ struct DistanceComputerByteSigned : SQDistanceComputer {};
85
+
80
86
  template <class Similarity>
81
87
  struct DistanceComputerByte<Similarity, SIMDLevel::NONE> : SQDistanceComputer {
82
88
  using Sim = Similarity;
@@ -7,14 +7,44 @@
7
7
 
8
8
  #pragma once
9
9
 
10
+ #include <cmath>
11
+
12
+ // Hack for MSVC
13
+ #ifndef M_PI
14
+ #define M_PI 3.14159265358979323846
15
+ #endif
16
+
10
17
  #include <algorithm>
18
+ #include <cstring>
11
19
 
12
20
  #include <faiss/impl/FaissAssert.h>
21
+ #include <faiss/impl/RaBitQUtils.h>
13
22
  #include <faiss/impl/ScalarQuantizer.h>
23
+ #include <faiss/impl/platform_macros.h>
14
24
  #include <faiss/impl/simdlib/simdlib_dispatch.h>
15
25
  #include <faiss/utils/bf16.h>
26
+ #include <faiss/utils/distances.h>
16
27
  #include <faiss/utils/fp16.h>
28
+ #include <faiss/utils/random.h>
17
29
  #include <faiss/utils/simd_levels.h>
30
+ #include <faiss/utils/utils.h>
31
+
32
+ extern "C" {
33
+ int sgemm_(
34
+ const char* transa,
35
+ const char* transb,
36
+ int* m,
37
+ int* n,
38
+ int* k,
39
+ const float* alpha,
40
+ const float* a,
41
+ int* lda,
42
+ const float* b,
43
+ int* ldb,
44
+ float* beta,
45
+ float* c,
46
+ int* ldc);
47
+ }
18
48
 
19
49
  namespace faiss {
20
50
 
@@ -117,14 +147,13 @@ struct QuantizerTemplate<
117
147
  };
118
148
 
119
149
  /*******************************************************************
120
- * TurboQuant MSE quantizer
150
+ * Lloyd-Max scalar quantizer
121
151
  *******************************************************************/
122
152
  template <int NBits, SIMDLevel SL>
123
- struct QuantizerTurboQuantMSE;
153
+ struct QuantizerLloydMax;
124
154
 
125
155
  template <int NBits>
126
- struct QuantizerTurboQuantMSE<NBits, SIMDLevel::NONE>
127
- : ScalarQuantizer::SQuantizer {
156
+ struct QuantizerLloydMax<NBits, SIMDLevel::NONE> : ScalarQuantizer::SQuantizer {
128
157
  static_assert(NBits >= 1 && NBits <= 8);
129
158
 
130
159
  static constexpr size_t kCentroidsCount = size_t(1) << NBits;
@@ -135,22 +164,21 @@ struct QuantizerTurboQuantMSE<NBits, SIMDLevel::NONE>
135
164
  const float* centroids;
136
165
  const float* boundaries;
137
166
 
138
- QuantizerTurboQuantMSE(size_t d_in, const std::vector<float>& trained)
167
+ QuantizerLloydMax(size_t d_in, const std::vector<float>& trained)
139
168
  : d(d_in), centroids(nullptr), boundaries(nullptr) {
140
169
  FAISS_THROW_IF_NOT(trained.size() == 2 * kCentroidsCount - 1);
141
170
  centroids = trained.data();
142
171
  boundaries = trained.data() + kCentroidsCount;
143
172
  }
144
173
 
145
- FAISS_ALWAYS_INLINE uint8_t select_index(float x) const {
174
+ uint8_t select_index(float x) const {
146
175
  return static_cast<uint8_t>(
147
176
  std::upper_bound(
148
177
  boundaries, boundaries + (kCentroidsCount - 1), x) -
149
178
  boundaries);
150
179
  }
151
180
 
152
- FAISS_ALWAYS_INLINE void encode_index(uint8_t idx, uint8_t* code, size_t i)
153
- const {
181
+ void encode_index(uint8_t idx, uint8_t* code, size_t i) const {
154
182
  const size_t bit_offset = i * NBits;
155
183
  const size_t byte_offset = bit_offset >> 3;
156
184
  const size_t bit_shift = bit_offset & 7;
@@ -162,8 +190,7 @@ struct QuantizerTurboQuantMSE<NBits, SIMDLevel::NONE>
162
190
  }
163
191
  }
164
192
 
165
- FAISS_ALWAYS_INLINE uint8_t
166
- decode_index(const uint8_t* code, size_t i) const {
193
+ uint8_t decode_index(const uint8_t* code, size_t i) const {
167
194
  const size_t bit_offset = i * NBits;
168
195
  const size_t byte_offset = bit_offset >> 3;
169
196
  const size_t bit_shift = bit_offset & 7;
@@ -175,31 +202,31 @@ struct QuantizerTurboQuantMSE<NBits, SIMDLevel::NONE>
175
202
  return static_cast<uint8_t>((packed >> bit_shift) & kIndexMask);
176
203
  }
177
204
 
178
- void encode_vector(const float* x, uint8_t* code) const final {
205
+ void encode_vector(const float* x, uint8_t* code) const override {
179
206
  for (size_t i = 0; i < d; i++) {
180
207
  encode_index(select_index(x[i]), code, i);
181
208
  }
182
209
  }
183
210
 
184
- void decode_vector(const uint8_t* code, float* x) const final {
211
+ void decode_vector(const uint8_t* code, float* x) const override {
185
212
  for (size_t i = 0; i < d; i++) {
186
213
  x[i] = centroids[decode_index(code, i)];
187
214
  }
188
215
  }
189
216
 
190
- FAISS_ALWAYS_INLINE float reconstruct_component(
191
- const uint8_t* code,
192
- size_t i) const {
217
+ float reconstruct_component(const uint8_t* code, size_t i) const {
193
218
  return centroids[decode_index(code, i)];
194
219
  }
195
220
  };
196
221
 
197
222
  template <int NBits, SIMDLevel SL>
198
- struct QuantizerTurboQuantMSE : QuantizerTurboQuantMSE<NBits, SIMDLevel::NONE> {
199
- using QuantizerTurboQuantMSE<NBits, SIMDLevel::NONE>::
200
- QuantizerTurboQuantMSE;
223
+ struct QuantizerLloydMax : QuantizerLloydMax<NBits, SIMDLevel::NONE> {
224
+ using QuantizerLloydMax<NBits, SIMDLevel::NONE>::QuantizerLloydMax;
201
225
  };
202
226
 
227
+ template <int NBits, SIMDLevel SL>
228
+ using QuantizerTurboQuantMSE = QuantizerLloydMax<NBits, SL>;
229
+
203
230
  /*******************************************************************
204
231
  * FP16 quantizer
205
232
  *******************************************************************/
@@ -252,16 +279,12 @@ struct QuantizerBF16<SIMDLevel::NONE> : ScalarQuantizer::SQuantizer {
252
279
  QuantizerBF16(size_t d_in, const std::vector<float>& /* unused */)
253
280
  : d(d_in) {}
254
281
 
255
- void encode_vector(const float* x, uint8_t* code) const final {
256
- for (size_t i = 0; i < d; i++) {
257
- ((uint16_t*)code)[i] = encode_bf16(x[i]);
258
- }
282
+ void encode_vector(const float* x, uint8_t* code) const override {
283
+ encode_bf16_simd(x, (uint16_t*)code, d);
259
284
  }
260
285
 
261
- void decode_vector(const uint8_t* code, float* x) const final {
262
- for (size_t i = 0; i < d; i++) {
263
- x[i] = decode_bf16(((uint16_t*)code)[i]);
264
- }
286
+ void decode_vector(const uint8_t* code, float* x) const override {
287
+ decode_bf16_simd((const uint16_t*)code, x, d);
265
288
  }
266
289
 
267
290
  FAISS_ALWAYS_INLINE float reconstruct_component(
@@ -276,6 +299,11 @@ struct QuantizerBF16 : QuantizerBF16<SIMDLevel::NONE> {
276
299
  using QuantizerBF16<SIMDLevel::NONE>::QuantizerBF16;
277
300
  };
278
301
 
302
+ template <>
303
+ struct QuantizerBF16<SIMDLevel::AVX512>;
304
+ template <>
305
+ struct QuantizerBF16<SIMDLevel::AVX512_SPR>;
306
+
279
307
  /*******************************************************************
280
308
  * 8bit_direct quantizer
281
309
  *******************************************************************/
@@ -355,6 +383,288 @@ struct Quantizer8bitDirectSigned : Quantizer8bitDirectSigned<SIMDLevel::NONE> {
355
383
  using Quantizer8bitDirectSigned<SIMDLevel::NONE>::Quantizer8bitDirectSigned;
356
384
  };
357
385
 
386
+ /*******************************************************************
387
+ * Full TurboQuant (MSE + QJL) quantizer
388
+ *
389
+ * NBits = total bits per dimension (2-5).
390
+ * MSE bits = NBits - 1, QJL bits = 1.
391
+ *
392
+ * Trained vector layout:
393
+ * [centroids (k floats), boundaries (k-1 floats),
394
+ * seed_lo (float), seed_hi (float), qjl_type (float)]
395
+ * where k = 2^(NBits-1).
396
+ *******************************************************************/
397
+
398
+ FAISS_PACK_STRUCTS_BEGIN
399
+ struct SQTurboQFactors {
400
+ float norm = 0;
401
+ float gamma = 0;
402
+ };
403
+ FAISS_PACK_STRUCTS_END
404
+
405
+ template <int NBits, SIMDLevel SL>
406
+ struct QuantizerTurboQuantFull;
407
+
408
+ template <int NBits>
409
+ struct QuantizerTurboQuantFull<NBits, SIMDLevel::NONE>
410
+ : ScalarQuantizer::SQuantizer {
411
+ static_assert(NBits >= 2 && NBits <= 5);
412
+
413
+ static constexpr int kMSEBits = NBits - 1;
414
+ static constexpr size_t kCentroidsCount = size_t(1) << kMSEBits;
415
+
416
+ const size_t d;
417
+ const float* centroids;
418
+ const float* boundaries;
419
+
420
+ // QJL projection type: 0 = FWHT, 2 = Random Rotation
421
+ uint8_t qjl_type;
422
+
423
+ // FWHT state (qjl_type == 0)
424
+ size_t padded_d;
425
+ std::vector<float> fwht_signs;
426
+
427
+ // Random Rotation state (qjl_type == 2)
428
+ std::vector<float> rr_matrix; // d x d orthogonal matrix (row-major)
429
+
430
+ size_t mse_plane_bytes; // bytes for one bit-plane of d bits
431
+ size_t mse_total_bytes; // kMSEBits * mse_plane_bytes
432
+ size_t qjl_plane_bytes;
433
+
434
+ QuantizerTurboQuantFull(size_t d_in, const std::vector<float>& trained)
435
+ : d(d_in),
436
+ centroids(trained.data()),
437
+ boundaries(trained.data() + kCentroidsCount) {
438
+ // trained = [centroids(k), boundaries(k-1), seed_lo, seed_hi, qjl_type]
439
+ size_t k = kCentroidsCount;
440
+ FAISS_THROW_IF_NOT(trained.size() == 2 * k - 1 + 3);
441
+
442
+ mse_plane_bytes = (d + 7) / 8;
443
+ mse_total_bytes = kMSEBits * mse_plane_bytes;
444
+ qjl_plane_bytes = (d + 7) / 8;
445
+
446
+ // Extract seed from trained
447
+ uint64_t seed = ScalarQuantizer::TurboQuantRefine::unpack_seed(
448
+ trained[2 * k - 1], trained[2 * k]);
449
+ qjl_type = static_cast<uint8_t>(trained[2 * k + 1]);
450
+
451
+ if (qjl_type == 0) {
452
+ // FWHT mode
453
+ padded_d = 1;
454
+ while (padded_d < d) {
455
+ padded_d <<= 1;
456
+ }
457
+ fwht_signs.resize(padded_d);
458
+ RandomGenerator rng(seed);
459
+ for (size_t i = 0; i < padded_d; i++) {
460
+ fwht_signs[i] = (rng.rand_int(2) == 0) ? 1.0f : -1.0f;
461
+ }
462
+ } else {
463
+ // Random Rotation mode
464
+ padded_d = d; // no padding needed for dense multiply
465
+ rr_matrix.resize(d * d);
466
+ float_randn(rr_matrix.data(), d * d, static_cast<int64_t>(seed));
467
+ matrix_qr(
468
+ static_cast<int>(d), static_cast<int>(d), rr_matrix.data());
469
+ }
470
+ }
471
+
472
+ void fwht_inplace(float* x, size_t n) const {
473
+ for (size_t h = 1; h < n; h <<= 1) {
474
+ for (size_t i = 0; i < n; i += h << 1) {
475
+ for (size_t j = i; j < i + h; j++) {
476
+ float a = x[j];
477
+ float b = x[j + h];
478
+ x[j] = a + b;
479
+ x[j + h] = a - b;
480
+ }
481
+ }
482
+ }
483
+ }
484
+
485
+ /// Forward QJL projection: residual -> projected (d outputs)
486
+ void project_forward(const float* residual, float* out) const {
487
+ if (qjl_type == 0) {
488
+ std::vector<float> fwht_buf(padded_d);
489
+ for (size_t j = 0; j < d; j++) {
490
+ fwht_buf[j] = residual[j] * fwht_signs[j];
491
+ }
492
+ for (size_t j = d; j < padded_d; j++) {
493
+ fwht_buf[j] = 0.0f;
494
+ }
495
+ fwht_inplace(fwht_buf.data(), padded_d);
496
+ for (size_t j = 0; j < d; j++) {
497
+ out[j] = fwht_buf[j];
498
+ }
499
+ } else {
500
+ rr_forward(residual, out);
501
+ }
502
+ }
503
+
504
+ /// Inverse QJL projection: signs_buf -> reconstructed (d outputs)
505
+ void project_inverse(float* signs_buf, float* out) const {
506
+ if (qjl_type == 0) {
507
+ fwht_inplace(signs_buf, padded_d);
508
+ for (size_t j = 0; j < d; j++) {
509
+ out[j] = signs_buf[j] * fwht_signs[j];
510
+ }
511
+ } else {
512
+ rr_inverse(signs_buf, out);
513
+ }
514
+ }
515
+
516
+ void rr_forward(const float* x, float* out) const {
517
+ float alpha = 1.0f;
518
+ float beta = 0.0f;
519
+ int di = static_cast<int>(d);
520
+ int one = 1;
521
+ sgemm_("T",
522
+ "N",
523
+ &di,
524
+ &one,
525
+ &di,
526
+ &alpha,
527
+ rr_matrix.data(),
528
+ &di,
529
+ x,
530
+ &di,
531
+ &beta,
532
+ out,
533
+ &di);
534
+ }
535
+
536
+ void rr_inverse(const float* x, float* out) const {
537
+ float alpha = 1.0f;
538
+ float beta = 0.0f;
539
+ int di = static_cast<int>(d);
540
+ int one = 1;
541
+ sgemm_("N",
542
+ "N",
543
+ &di,
544
+ &one,
545
+ &di,
546
+ &alpha,
547
+ rr_matrix.data(),
548
+ &di,
549
+ x,
550
+ &di,
551
+ &beta,
552
+ out,
553
+ &di);
554
+ }
555
+
556
+ /// Store MSE index for dimension j using BIT-PLANE layout.
557
+ /// Plane p stores bit p of every dimension's index.
558
+ void store_mse_index(uint8_t idx, uint8_t* code, size_t j) const {
559
+ for (int p = 0; p < kMSEBits; p++) {
560
+ if (idx & (1 << p)) {
561
+ code[p * mse_plane_bytes + j / 8] |= (1 << (j % 8));
562
+ }
563
+ }
564
+ }
565
+
566
+ /// Load MSE index for dimension j from BIT-PLANE layout.
567
+ uint8_t load_mse_index(const uint8_t* code, size_t j) const {
568
+ uint8_t idx = 0;
569
+ for (int p = 0; p < kMSEBits; p++) {
570
+ if (code[p * mse_plane_bytes + j / 8] & (1 << (j % 8))) {
571
+ idx |= (1 << p);
572
+ }
573
+ }
574
+ return idx;
575
+ }
576
+
577
+ void encode_vector(const float* x, uint8_t* code) const final {
578
+ float sqrt_d = std::sqrt(static_cast<float>(d));
579
+ float inv_sqrt_d = 1.0f / sqrt_d;
580
+
581
+ float x_norm = std::sqrt(fvec_norm_L2sqr(x, d));
582
+ if (x_norm < 1e-30f) {
583
+ x_norm = 1e-30f;
584
+ }
585
+
586
+ // MSE quantize in scaled space + compute residual
587
+ std::vector<float> residual(padded_d);
588
+ for (size_t j = 0; j < d; j++) {
589
+ float v = x[j] / x_norm; // unit-normalized
590
+ float val = v * sqrt_d; // scaled for MSE lookup
591
+ uint8_t idx = static_cast<uint8_t>(
592
+ std::upper_bound(
593
+ boundaries,
594
+ boundaries + (kCentroidsCount - 1),
595
+ val) -
596
+ boundaries);
597
+ store_mse_index(idx, code, j);
598
+ residual[j] = v - centroids[idx] * inv_sqrt_d;
599
+ }
600
+
601
+ // QJL: project residual, take signs
602
+ std::vector<float> proj(d);
603
+ project_forward(residual.data(), proj.data());
604
+
605
+ uint8_t* qjl_code = code + mse_total_bytes;
606
+ for (size_t j = 0; j < d; j++) {
607
+ if (proj[j] > 0.0f) {
608
+ rabitq_utils::set_bit_standard(qjl_code, j);
609
+ }
610
+ }
611
+
612
+ // Store per-vector factors
613
+ float gamma = std::sqrt(fvec_norm_L2sqr(residual.data(), d));
614
+ auto* factors = reinterpret_cast<SQTurboQFactors*>(
615
+ code + mse_total_bytes + qjl_plane_bytes);
616
+ factors->norm = x_norm;
617
+ factors->gamma = gamma;
618
+ }
619
+
620
+ void decode_vector(const uint8_t* code, float* x) const final {
621
+ float inv_sqrt_d = 1.0f / std::sqrt(static_cast<float>(d));
622
+ float inv_sqrt_pd = 1.0f / std::sqrt(static_cast<float>(padded_d));
623
+
624
+ const auto* factors = reinterpret_cast<const SQTurboQFactors*>(
625
+ code + mse_total_bytes + qjl_plane_bytes);
626
+
627
+ // MSE reconstruction
628
+ for (size_t j = 0; j < d; j++) {
629
+ uint8_t idx = load_mse_index(code, j);
630
+ x[j] = centroids[idx] * inv_sqrt_d;
631
+ }
632
+
633
+ // QJL reconstruction: coeff * gamma * S^T * signs
634
+ const uint8_t* qjl_code = code + mse_total_bytes;
635
+ float coeff =
636
+ std::sqrt(M_PI / 2.0f) / static_cast<float>(d) * factors->gamma;
637
+
638
+ std::vector<float> signs_buf(padded_d);
639
+ for (size_t j = 0; j < d; j++) {
640
+ signs_buf[j] = rabitq_utils::extract_bit_standard(qjl_code, j)
641
+ ? inv_sqrt_pd
642
+ : -inv_sqrt_pd;
643
+ }
644
+ for (size_t j = d; j < padded_d; j++) {
645
+ signs_buf[j] = 0.0f;
646
+ }
647
+
648
+ std::vector<float> reconstructed(d);
649
+ project_inverse(signs_buf.data(), reconstructed.data());
650
+ for (size_t j = 0; j < d; j++) {
651
+ x[j] += coeff * reconstructed[j];
652
+ }
653
+
654
+ // Scale by norm
655
+ for (size_t j = 0; j < d; j++) {
656
+ x[j] *= factors->norm;
657
+ }
658
+ }
659
+ };
660
+
661
+ template <int NBits, SIMDLevel SL>
662
+ struct QuantizerTurboQuantFull
663
+ : QuantizerTurboQuantFull<NBits, SIMDLevel::NONE> {
664
+ using QuantizerTurboQuantFull<NBits, SIMDLevel::NONE>::
665
+ QuantizerTurboQuantFull;
666
+ };
667
+
358
668
  /*******************************************************************
359
669
  * Selection function
360
670
  *******************************************************************/