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
@@ -147,14 +147,13 @@ struct QuantizerTemplate<
147
147
  };
148
148
 
149
149
  /*******************************************************************
150
- * TurboQuant MSE quantizer
150
+ * Lloyd-Max scalar quantizer
151
151
  *******************************************************************/
152
152
  template <int NBits, SIMDLevel SL>
153
- struct QuantizerTurboQuantMSE;
153
+ struct QuantizerLloydMax;
154
154
 
155
155
  template <int NBits>
156
- struct QuantizerTurboQuantMSE<NBits, SIMDLevel::NONE>
157
- : ScalarQuantizer::SQuantizer {
156
+ struct QuantizerLloydMax<NBits, SIMDLevel::NONE> : ScalarQuantizer::SQuantizer {
158
157
  static_assert(NBits >= 1 && NBits <= 8);
159
158
 
160
159
  static constexpr size_t kCentroidsCount = size_t(1) << NBits;
@@ -165,7 +164,7 @@ struct QuantizerTurboQuantMSE<NBits, SIMDLevel::NONE>
165
164
  const float* centroids;
166
165
  const float* boundaries;
167
166
 
168
- QuantizerTurboQuantMSE(size_t d_in, const std::vector<float>& trained)
167
+ QuantizerLloydMax(size_t d_in, const std::vector<float>& trained)
169
168
  : d(d_in), centroids(nullptr), boundaries(nullptr) {
170
169
  FAISS_THROW_IF_NOT(trained.size() == 2 * kCentroidsCount - 1);
171
170
  centroids = trained.data();
@@ -221,11 +220,13 @@ struct QuantizerTurboQuantMSE<NBits, SIMDLevel::NONE>
221
220
  };
222
221
 
223
222
  template <int NBits, SIMDLevel SL>
224
- struct QuantizerTurboQuantMSE : QuantizerTurboQuantMSE<NBits, SIMDLevel::NONE> {
225
- using QuantizerTurboQuantMSE<NBits, SIMDLevel::NONE>::
226
- QuantizerTurboQuantMSE;
223
+ struct QuantizerLloydMax : QuantizerLloydMax<NBits, SIMDLevel::NONE> {
224
+ using QuantizerLloydMax<NBits, SIMDLevel::NONE>::QuantizerLloydMax;
227
225
  };
228
226
 
227
+ template <int NBits, SIMDLevel SL>
228
+ using QuantizerTurboQuantMSE = QuantizerLloydMax<NBits, SL>;
229
+
229
230
  /*******************************************************************
230
231
  * FP16 quantizer
231
232
  *******************************************************************/
@@ -232,7 +232,7 @@ struct QuantizerTemplate<
232
232
  };
233
233
 
234
234
  /**********************************************************
235
- * TurboQuant MSE quantizer
235
+ * Lloyd-Max scalar quantizer
236
236
  **********************************************************/
237
237
 
238
238
  // 1-bit MSE: boundary is always at centroids midpoint.
@@ -240,11 +240,11 @@ struct QuantizerTemplate<
240
240
  // Decode: gather 8 centroids via index unpack.
241
241
  // NOLINTNEXTLINE(facebook-hte-MisplacedTemplateSpecialization,facebook-hte-ShadowingClass)
242
242
  template <>
243
- struct QuantizerTurboQuantMSE<1, SIMDLevel::AVX2>
244
- : QuantizerTurboQuantMSE<1, SIMDLevel::NONE> {
245
- using Base = QuantizerTurboQuantMSE<1, SIMDLevel::NONE>;
243
+ struct QuantizerLloydMax<1, SIMDLevel::AVX2>
244
+ : QuantizerLloydMax<1, SIMDLevel::NONE> {
245
+ using Base = QuantizerLloydMax<1, SIMDLevel::NONE>;
246
246
 
247
- QuantizerTurboQuantMSE(size_t d, const std::vector<float>& trained)
247
+ QuantizerLloydMax(size_t d, const std::vector<float>& trained)
248
248
  : Base(d, trained) {
249
249
  assert(d % 8 == 0);
250
250
  }
@@ -279,11 +279,11 @@ struct QuantizerTurboQuantMSE<1, SIMDLevel::AVX2>
279
279
  // Decode: gather via index unpack.
280
280
  // NOLINTNEXTLINE(facebook-hte-MisplacedTemplateSpecialization,facebook-hte-ShadowingClass)
281
281
  template <>
282
- struct QuantizerTurboQuantMSE<2, SIMDLevel::AVX2>
283
- : QuantizerTurboQuantMSE<2, SIMDLevel::NONE> {
284
- using Base = QuantizerTurboQuantMSE<2, SIMDLevel::NONE>;
282
+ struct QuantizerLloydMax<2, SIMDLevel::AVX2>
283
+ : QuantizerLloydMax<2, SIMDLevel::NONE> {
284
+ using Base = QuantizerLloydMax<2, SIMDLevel::NONE>;
285
285
 
286
- QuantizerTurboQuantMSE(size_t d, const std::vector<float>& trained)
286
+ QuantizerLloydMax(size_t d, const std::vector<float>& trained)
287
287
  : Base(d, trained) {
288
288
  assert(d % 8 == 0);
289
289
  }
@@ -334,15 +334,15 @@ struct QuantizerTurboQuantMSE<2, SIMDLevel::AVX2>
334
334
  }
335
335
  };
336
336
 
337
- // 3-bit and 4-bit MSE: use branchless comparison chain for encode.
337
+ // 3-bit and 4-bit Lloyd-Max: use branchless comparison chain for encode.
338
338
  // k boundaries → idx = sum of k-1 comparisons.
339
- #define DEFINE_TQMSE_AVX2_MULTIBIT(NBITS, UNPACK_EXPR) \
339
+ #define DEFINE_LLOYD_MAX_AVX2_MULTIBIT(NBITS, UNPACK_EXPR) \
340
340
  template <> \
341
- struct QuantizerTurboQuantMSE<NBITS, SIMDLevel::AVX2> \
342
- : QuantizerTurboQuantMSE<NBITS, SIMDLevel::NONE> { \
343
- using Base = QuantizerTurboQuantMSE<NBITS, SIMDLevel::NONE>; \
341
+ struct QuantizerLloydMax<NBITS, SIMDLevel::AVX2> \
342
+ : QuantizerLloydMax<NBITS, SIMDLevel::NONE> { \
343
+ using Base = QuantizerLloydMax<NBITS, SIMDLevel::NONE>; \
344
344
  \
345
- QuantizerTurboQuantMSE(size_t d, const std::vector<float>& trained) \
345
+ QuantizerLloydMax(size_t d, const std::vector<float>& trained) \
346
346
  : Base(d, trained) { \
347
347
  assert(d % 8 == 0); \
348
348
  } \
@@ -362,18 +362,18 @@ struct QuantizerTurboQuantMSE<2, SIMDLevel::AVX2>
362
362
  } \
363
363
  }
364
364
 
365
- DEFINE_TQMSE_AVX2_MULTIBIT(3, unpack_8x3bit_to_u32(code, i));
366
- DEFINE_TQMSE_AVX2_MULTIBIT(4, unpack_8x4bit_to_u32(code, i));
365
+ DEFINE_LLOYD_MAX_AVX2_MULTIBIT(3, unpack_8x3bit_to_u32(code, i));
366
+ DEFINE_LLOYD_MAX_AVX2_MULTIBIT(4, unpack_8x4bit_to_u32(code, i));
367
367
 
368
- #undef DEFINE_TQMSE_AVX2_MULTIBIT
368
+ #undef DEFINE_LLOYD_MAX_AVX2_MULTIBIT
369
369
 
370
- // 8-bit MSE: indices are raw bytes, no bit packing.
370
+ // 8-bit Lloyd-Max: indices are raw bytes, no bit packing.
371
371
  template <>
372
- struct QuantizerTurboQuantMSE<8, SIMDLevel::AVX2>
373
- : QuantizerTurboQuantMSE<8, SIMDLevel::NONE> {
374
- using Base = QuantizerTurboQuantMSE<8, SIMDLevel::NONE>;
372
+ struct QuantizerLloydMax<8, SIMDLevel::AVX2>
373
+ : QuantizerLloydMax<8, SIMDLevel::NONE> {
374
+ using Base = QuantizerLloydMax<8, SIMDLevel::NONE>;
375
375
 
376
- QuantizerTurboQuantMSE(size_t d, const std::vector<float>& trained)
376
+ QuantizerLloydMax(size_t d, const std::vector<float>& trained)
377
377
  : Base(d, trained) {
378
378
  assert(d % 8 == 0);
379
379
  }
@@ -787,6 +787,68 @@ struct DistanceComputerByte<Similarity, SIMDLevel::AVX2> : SQDistanceComputer {
787
787
  }
788
788
  };
789
789
 
790
+ template <class Similarity>
791
+ struct DistanceComputerByteSigned<Similarity, SIMDLevel::AVX2>
792
+ : SQDistanceComputer {
793
+ using Sim = Similarity;
794
+
795
+ int d;
796
+ std::vector<uint8_t> tmp;
797
+
798
+ DistanceComputerByteSigned(int d, const std::vector<float>&)
799
+ : d(d), tmp(d) {}
800
+
801
+ int compute_code_distance(const uint8_t* code1, const uint8_t* code2)
802
+ const {
803
+ // codes store value + 128. madd_epi16 is signed, so IP unbiases the
804
+ // bytes before multiplying; for L2 the +128 cancels in the difference.
805
+ // Only dispatched for d % 16 == 0, so the loop needs no tail.
806
+ __m256i accu = _mm256_setzero_si256();
807
+ for (int i = 0; i < d; i += 16) {
808
+ __m256i c1 = _mm256_cvtepu8_epi16(
809
+ _mm_loadu_si128((const __m128i*)(code1 + i)));
810
+ __m256i c2 = _mm256_cvtepu8_epi16(
811
+ _mm_loadu_si128((const __m128i*)(code2 + i)));
812
+ __m256i prod32;
813
+ if (Sim::metric_type == METRIC_INNER_PRODUCT) {
814
+ const __m256i bias = _mm256_set1_epi16(128);
815
+ c1 = _mm256_sub_epi16(c1, bias);
816
+ c2 = _mm256_sub_epi16(c2, bias);
817
+ prod32 = _mm256_madd_epi16(c1, c2);
818
+ } else {
819
+ __m256i diff = _mm256_sub_epi16(c1, c2);
820
+ prod32 = _mm256_madd_epi16(diff, diff);
821
+ }
822
+ accu = _mm256_add_epi32(accu, prod32);
823
+ }
824
+ __m128i sum = _mm256_extractf128_si256(accu, 0);
825
+ sum = _mm_add_epi32(sum, _mm256_extractf128_si256(accu, 1));
826
+ sum = _mm_hadd_epi32(sum, sum);
827
+ sum = _mm_hadd_epi32(sum, sum);
828
+ return _mm_cvtsi128_si32(sum);
829
+ }
830
+
831
+ void set_query(const float* x) final {
832
+ for (int i = 0; i < d; i++) {
833
+ tmp[i] = uint8_t(int(x[i]) + 128);
834
+ }
835
+ }
836
+
837
+ int compute_distance(const float* x, const uint8_t* code) {
838
+ set_query(x);
839
+ return compute_code_distance(tmp.data(), code);
840
+ }
841
+
842
+ float symmetric_dis(idx_t i, idx_t j) override {
843
+ return compute_code_distance(
844
+ codes + i * code_size, codes + j * code_size);
845
+ }
846
+
847
+ float query_to_code(const uint8_t* code) const final {
848
+ return compute_code_distance(tmp.data(), code);
849
+ }
850
+ };
851
+
790
852
  /**********************************************************
791
853
  * TurboQuant masked_sum AVX2 specialization
792
854
  **********************************************************/
@@ -241,41 +241,41 @@ struct QuantizerTemplate<
241
241
  };
242
242
 
243
243
  /**********************************************************
244
- * TurboQuant MSE quantizer
244
+ * Lloyd-Max scalar quantizer
245
245
  **********************************************************/
246
246
 
247
- #define DEFINE_TQMSE_AVX512_SPECIALIZATION(NBITS, INDEX_EXPR) \
248
- template <> \
249
- struct QuantizerTurboQuantMSE<NBITS, SIMDLevel::AVX512> \
250
- : QuantizerTurboQuantMSE<NBITS, SIMDLevel::NONE> { \
251
- using Base = QuantizerTurboQuantMSE<NBITS, SIMDLevel::NONE>; \
252
- \
253
- QuantizerTurboQuantMSE(size_t d, const std::vector<float>& trained) \
254
- : Base(d, trained) { \
255
- assert(d % 16 == 0); \
256
- } \
257
- \
258
- FAISS_ALWAYS_INLINE simd16float32 \
259
- reconstruct_16_components(const uint8_t* code, int i) const { \
260
- const __m512i indices = (INDEX_EXPR); \
261
- return simd16float32(_mm512_i32gather_ps( \
262
- indices, this->centroids, sizeof(float))); \
263
- } \
264
- }
265
-
266
- DEFINE_TQMSE_AVX512_SPECIALIZATION(1, unpack_16x1bit_to_u32(code, i));
267
- DEFINE_TQMSE_AVX512_SPECIALIZATION(2, unpack_16x2bit_to_u32(code, i));
268
- DEFINE_TQMSE_AVX512_SPECIALIZATION(3, unpack_16x3bit_to_u32(code, i));
269
- DEFINE_TQMSE_AVX512_SPECIALIZATION(4, unpack_16x4bit_to_u32(code, i));
270
-
271
- #undef DEFINE_TQMSE_AVX512_SPECIALIZATION
247
+ #define DEFINE_LLOYD_MAX_AVX512_SPECIALIZATION(NBITS, INDEX_EXPR) \
248
+ template <> \
249
+ struct QuantizerLloydMax<NBITS, SIMDLevel::AVX512> \
250
+ : QuantizerLloydMax<NBITS, SIMDLevel::NONE> { \
251
+ using Base = QuantizerLloydMax<NBITS, SIMDLevel::NONE>; \
252
+ \
253
+ QuantizerLloydMax(size_t d, const std::vector<float>& trained) \
254
+ : Base(d, trained) { \
255
+ assert(d % 16 == 0); \
256
+ } \
257
+ \
258
+ FAISS_ALWAYS_INLINE simd16float32 \
259
+ reconstruct_16_components(const uint8_t* code, int i) const { \
260
+ const __m512i indices = (INDEX_EXPR); \
261
+ return simd16float32(_mm512_i32gather_ps( \
262
+ indices, this->centroids, sizeof(float))); \
263
+ } \
264
+ }
265
+
266
+ DEFINE_LLOYD_MAX_AVX512_SPECIALIZATION(1, unpack_16x1bit_to_u32(code, i));
267
+ DEFINE_LLOYD_MAX_AVX512_SPECIALIZATION(2, unpack_16x2bit_to_u32(code, i));
268
+ DEFINE_LLOYD_MAX_AVX512_SPECIALIZATION(3, unpack_16x3bit_to_u32(code, i));
269
+ DEFINE_LLOYD_MAX_AVX512_SPECIALIZATION(4, unpack_16x4bit_to_u32(code, i));
270
+
271
+ #undef DEFINE_LLOYD_MAX_AVX512_SPECIALIZATION
272
272
 
273
273
  template <>
274
- struct QuantizerTurboQuantMSE<8, SIMDLevel::AVX512>
275
- : QuantizerTurboQuantMSE<8, SIMDLevel::NONE> {
276
- using Base = QuantizerTurboQuantMSE<8, SIMDLevel::NONE>;
274
+ struct QuantizerLloydMax<8, SIMDLevel::AVX512>
275
+ : QuantizerLloydMax<8, SIMDLevel::NONE> {
276
+ using Base = QuantizerLloydMax<8, SIMDLevel::NONE>;
277
277
 
278
- QuantizerTurboQuantMSE(size_t d, const std::vector<float>& trained)
278
+ QuantizerLloydMax(size_t d, const std::vector<float>& trained)
279
279
  : Base(d, trained) {
280
280
  assert(d % 16 == 0);
281
281
  }
@@ -100,14 +100,13 @@ struct Quantizer8bitDirectSigned<SIMDLevel::AVX512_SPR>
100
100
  };
101
101
 
102
102
  /**********************************************************
103
- * TurboQuant MSE inherit AVX512 implementations
103
+ * Lloyd-Max scalar quantizer - inherit AVX512 implementations
104
104
  **********************************************************/
105
105
 
106
106
  template <int NBits>
107
- struct QuantizerTurboQuantMSE<NBits, SIMDLevel::AVX512_SPR>
108
- : QuantizerTurboQuantMSE<NBits, SIMDLevel::AVX512> {
109
- using QuantizerTurboQuantMSE<NBits, SIMDLevel::AVX512>::
110
- QuantizerTurboQuantMSE;
107
+ struct QuantizerLloydMax<NBits, SIMDLevel::AVX512_SPR>
108
+ : QuantizerLloydMax<NBits, SIMDLevel::AVX512> {
109
+ using QuantizerLloydMax<NBits, SIMDLevel::AVX512>::QuantizerLloydMax;
111
110
  };
112
111
 
113
112
  /**********************************************************
@@ -250,16 +250,16 @@ struct QuantizerTemplate<
250
250
  };
251
251
 
252
252
  /**********************************************************
253
- * TurboQuant MSE quantizer
253
+ * Lloyd-Max scalar quantizer
254
254
  **********************************************************/
255
255
 
256
- // 1-bit MSE AVX512: 16 comparisons → 2 bytes via mask compare.
256
+ // 1-bit Lloyd-Max AVX512: 16 comparisons → 2 bytes via mask compare.
257
257
  template <>
258
- struct QuantizerTurboQuantMSE<1, SIMDLevel::AVX512>
259
- : QuantizerTurboQuantMSE<1, SIMDLevel::NONE> {
260
- using Base = QuantizerTurboQuantMSE<1, SIMDLevel::NONE>;
258
+ struct QuantizerLloydMax<1, SIMDLevel::AVX512>
259
+ : QuantizerLloydMax<1, SIMDLevel::NONE> {
260
+ using Base = QuantizerLloydMax<1, SIMDLevel::NONE>;
261
261
 
262
- QuantizerTurboQuantMSE(size_t d, const std::vector<float>& trained)
262
+ QuantizerLloydMax(size_t d, const std::vector<float>& trained)
263
263
  : Base(d, trained) {
264
264
  assert(d % 16 == 0);
265
265
  }
@@ -291,14 +291,14 @@ struct QuantizerTurboQuantMSE<1, SIMDLevel::AVX512>
291
291
  }
292
292
  };
293
293
 
294
- // 2-4 bit MSE AVX512: decode via gather, encode stays scalar.
295
- #define DEFINE_TQMSE_AVX512_MULTIBIT(NBITS, UNPACK_EXPR) \
294
+ // 2-4 bit Lloyd-Max AVX512: decode via gather, encode stays scalar.
295
+ #define DEFINE_LLOYD_MAX_AVX512_MULTIBIT(NBITS, UNPACK_EXPR) \
296
296
  template <> \
297
- struct QuantizerTurboQuantMSE<NBITS, SIMDLevel::AVX512> \
298
- : QuantizerTurboQuantMSE<NBITS, SIMDLevel::NONE> { \
299
- using Base = QuantizerTurboQuantMSE<NBITS, SIMDLevel::NONE>; \
297
+ struct QuantizerLloydMax<NBITS, SIMDLevel::AVX512> \
298
+ : QuantizerLloydMax<NBITS, SIMDLevel::NONE> { \
299
+ using Base = QuantizerLloydMax<NBITS, SIMDLevel::NONE>; \
300
300
  \
301
- QuantizerTurboQuantMSE(size_t d, const std::vector<float>& trained) \
301
+ QuantizerLloydMax(size_t d, const std::vector<float>& trained) \
302
302
  : Base(d, trained) { \
303
303
  assert(d % 16 == 0); \
304
304
  } \
@@ -318,19 +318,19 @@ struct QuantizerTurboQuantMSE<1, SIMDLevel::AVX512>
318
318
  } \
319
319
  }
320
320
 
321
- DEFINE_TQMSE_AVX512_MULTIBIT(2, unpack_16x2bit_to_u32(code, i));
322
- DEFINE_TQMSE_AVX512_MULTIBIT(3, unpack_16x3bit_to_u32(code, i));
323
- DEFINE_TQMSE_AVX512_MULTIBIT(4, unpack_16x4bit_to_u32(code, i));
321
+ DEFINE_LLOYD_MAX_AVX512_MULTIBIT(2, unpack_16x2bit_to_u32(code, i));
322
+ DEFINE_LLOYD_MAX_AVX512_MULTIBIT(3, unpack_16x3bit_to_u32(code, i));
323
+ DEFINE_LLOYD_MAX_AVX512_MULTIBIT(4, unpack_16x4bit_to_u32(code, i));
324
324
 
325
- #undef DEFINE_TQMSE_AVX512_MULTIBIT
325
+ #undef DEFINE_LLOYD_MAX_AVX512_MULTIBIT
326
326
 
327
- // 8-bit MSE AVX512
327
+ // 8-bit Lloyd-Max AVX512
328
328
  template <>
329
- struct QuantizerTurboQuantMSE<8, SIMDLevel::AVX512>
330
- : QuantizerTurboQuantMSE<8, SIMDLevel::NONE> {
331
- using Base = QuantizerTurboQuantMSE<8, SIMDLevel::NONE>;
329
+ struct QuantizerLloydMax<8, SIMDLevel::AVX512>
330
+ : QuantizerLloydMax<8, SIMDLevel::NONE> {
331
+ using Base = QuantizerLloydMax<8, SIMDLevel::NONE>;
332
332
 
333
- QuantizerTurboQuantMSE(size_t d, const std::vector<float>& trained)
333
+ QuantizerLloydMax(size_t d, const std::vector<float>& trained)
334
334
  : Base(d, trained) {
335
335
  assert(d % 16 == 0);
336
336
  }
@@ -677,24 +677,36 @@ struct DistanceComputerByte<Similarity, SIMDLevel::AVX512>
677
677
 
678
678
  int compute_code_distance(const uint8_t* code1, const uint8_t* code2)
679
679
  const {
680
- // compute 16 lanes of 32-bit products (16-bytes) at once for
680
+ // compute 32 lanes of 16-bit products (32-bytes) at once for
681
681
  // the supported metrics
682
682
  __m512i accu = _mm512_setzero_si512();
683
- constexpr int kLanes = 16;
684
- for (int i = 0; i < d; i += kLanes) {
685
- __m128i c1 = _mm_loadu_si128((__m128i*)(code1 + i));
686
- __m128i c2 = _mm_loadu_si128((__m128i*)(code2 + i));
687
- __m512i c1i = _mm512_cvtepu8_epi32(c1);
688
- __m512i c2i = _mm512_cvtepu8_epi32(c2);
689
-
690
- __m512i v;
683
+ constexpr int kLanes = 32;
684
+ int i = 0;
685
+ for (; i + kLanes <= d; i += kLanes) {
686
+ __m256i c1 = _mm256_loadu_epi8(code1 + i);
687
+ __m256i c2 = _mm256_loadu_epi8(code2 + i);
688
+ __m512i c1i16 = _mm512_cvtepu8_epi16(c1);
689
+ __m512i c2i16 = _mm512_cvtepu8_epi16(c2);
691
690
  if (Sim::metric_type == METRIC_INNER_PRODUCT) {
692
- v = _mm512_mullo_epi32(c1i, c2i);
691
+ accu = _mm512_add_epi32(accu, _mm512_madd_epi16(c1i16, c2i16));
693
692
  } else {
694
- __m512i diff = _mm512_sub_epi32(c1i, c2i);
695
- v = _mm512_mullo_epi32(diff, diff);
693
+ __m512i diff = _mm512_sub_epi16(c1i16, c2i16);
694
+ accu = _mm512_add_epi32(accu, _mm512_madd_epi16(diff, diff));
695
+ }
696
+ }
697
+ // tail handling for dimensions not divisible by 32
698
+ if (i < d) {
699
+ __mmask32 mask = (__mmask32)((1ULL << (d - i)) - 1ULL);
700
+ __m256i c1 = _mm256_maskz_loadu_epi8(mask, code1 + i);
701
+ __m256i c2 = _mm256_maskz_loadu_epi8(mask, code2 + i);
702
+ __m512i c1i16 = _mm512_cvtepu8_epi16(c1);
703
+ __m512i c2i16 = _mm512_cvtepu8_epi16(c2);
704
+ if (Sim::metric_type == METRIC_INNER_PRODUCT) {
705
+ accu = _mm512_add_epi32(accu, _mm512_madd_epi16(c1i16, c2i16));
706
+ } else {
707
+ __m512i diff = _mm512_sub_epi16(c1i16, c2i16);
708
+ accu = _mm512_add_epi32(accu, _mm512_madd_epi16(diff, diff));
696
709
  }
697
- accu = _mm512_add_epi32(accu, v);
698
710
  }
699
711
  return _mm512_reduce_add_epi32(accu);
700
712
  }
@@ -720,6 +732,61 @@ struct DistanceComputerByte<Similarity, SIMDLevel::AVX512>
720
732
  }
721
733
  };
722
734
 
735
+ template <class Similarity>
736
+ struct DistanceComputerByteSigned<Similarity, SIMDLevel::AVX512>
737
+ : SQDistanceComputer {
738
+ using Sim = Similarity;
739
+
740
+ int d;
741
+ std::vector<uint8_t> tmp;
742
+
743
+ DistanceComputerByteSigned(int d, const std::vector<float>&)
744
+ : d(d), tmp(d) {}
745
+
746
+ int compute_code_distance(const uint8_t* code1, const uint8_t* code2)
747
+ const {
748
+ // codes store value + 128. madd_epi16 is signed, so IP unbiases the
749
+ // bytes before multiplying; for L2 the +128 cancels in the difference.
750
+ // Only dispatched for d % 32 == 0, so the loop needs no tail.
751
+ __m512i accu = _mm512_setzero_si512();
752
+ constexpr int kLanes = 32;
753
+ for (int i = 0; i + kLanes <= d; i += kLanes) {
754
+ __m512i c1 = _mm512_cvtepu8_epi16(_mm256_loadu_epi8(code1 + i));
755
+ __m512i c2 = _mm512_cvtepu8_epi16(_mm256_loadu_epi8(code2 + i));
756
+ if (Sim::metric_type == METRIC_INNER_PRODUCT) {
757
+ const __m512i bias = _mm512_set1_epi16(128);
758
+ c1 = _mm512_sub_epi16(c1, bias);
759
+ c2 = _mm512_sub_epi16(c2, bias);
760
+ accu = _mm512_add_epi32(accu, _mm512_madd_epi16(c1, c2));
761
+ } else {
762
+ __m512i diff = _mm512_sub_epi16(c1, c2);
763
+ accu = _mm512_add_epi32(accu, _mm512_madd_epi16(diff, diff));
764
+ }
765
+ }
766
+ return _mm512_reduce_add_epi32(accu);
767
+ }
768
+
769
+ void set_query(const float* x) final {
770
+ for (int i = 0; i < d; i++) {
771
+ tmp[i] = uint8_t(int(x[i]) + 128);
772
+ }
773
+ }
774
+
775
+ int compute_distance(const float* x, const uint8_t* code) {
776
+ set_query(x);
777
+ return compute_code_distance(tmp.data(), code);
778
+ }
779
+
780
+ float symmetric_dis(idx_t i, idx_t j) override {
781
+ return compute_code_distance(
782
+ codes + i * code_size, codes + j * code_size);
783
+ }
784
+
785
+ float query_to_code(const uint8_t* code) const final {
786
+ return compute_code_distance(tmp.data(), code);
787
+ }
788
+ };
789
+
723
790
  /**********************************************************
724
791
  * TurboQuant masked_sum AVX512 specialization
725
792
  **********************************************************/
@@ -416,6 +416,34 @@ ScalarQuantizer::SQuantizer* sq_select_quantizer<THE_LEVEL_TO_DISPATCH>(
416
416
  return new QuantizerTurboQuantMSE<4, SL>(d, trained);
417
417
  case ScalarQuantizer::QT_8bit_tqmse:
418
418
  return new QuantizerTurboQuantMSE<8, SL>(d, trained);
419
+ case ScalarQuantizer::QT_1bit_eden:
420
+ return new QuantizerLloydMax<1, SL>(d, trained);
421
+ case ScalarQuantizer::QT_2bit_eden:
422
+ return new QuantizerLloydMax<2, SL>(d, trained);
423
+ case ScalarQuantizer::QT_3bit_eden:
424
+ return new QuantizerLloydMax<3, SL>(d, trained);
425
+ case ScalarQuantizer::QT_4bit_eden:
426
+ return new QuantizerLloydMax<4, SL>(d, trained);
427
+ case ScalarQuantizer::QT_5bit_eden:
428
+ if constexpr (SL != SIMDLevel::NONE) {
429
+ return nullptr;
430
+ } else {
431
+ return new QuantizerLloydMax<5, SL>(d, trained);
432
+ }
433
+ case ScalarQuantizer::QT_6bit_eden:
434
+ if constexpr (SL != SIMDLevel::NONE) {
435
+ return nullptr;
436
+ } else {
437
+ return new QuantizerLloydMax<6, SL>(d, trained);
438
+ }
439
+ case ScalarQuantizer::QT_7bit_eden:
440
+ if constexpr (SL != SIMDLevel::NONE) {
441
+ return nullptr;
442
+ } else {
443
+ return new QuantizerLloydMax<7, SL>(d, trained);
444
+ }
445
+ case ScalarQuantizer::QT_8bit_eden:
446
+ return new QuantizerLloydMax<8, SL>(d, trained);
419
447
  case ScalarQuantizer::QT_2bit_tq:
420
448
  return new QuantizerTurboQuantFull<2, SL>(d, trained);
421
449
  case ScalarQuantizer::QT_3bit_tq:
@@ -518,6 +546,16 @@ SQDistanceComputer* select_distance_computer_body(
518
546
  return new DistanceComputerByteSigned<Sim, SL2>(
519
547
  static_cast<int>(d), trained);
520
548
  }
549
+ } else if constexpr (SL2 == SIMDLevel::AVX512) {
550
+ if (d % 32 == 0) {
551
+ return new DistanceComputerByteSigned<Sim, SL2>(
552
+ static_cast<int>(d), trained);
553
+ }
554
+ } else if constexpr (SL2 == SIMDLevel::AVX2) {
555
+ if (d % 16 == 0) {
556
+ return new DistanceComputerByteSigned<Sim, SL2>(
557
+ static_cast<int>(d), trained);
558
+ }
521
559
  }
522
560
  return new DCTemplate<Quantizer8bitDirectSigned<SL2>, Sim, SL2>(
523
561
  d, trained);
@@ -539,6 +577,42 @@ SQDistanceComputer* select_distance_computer_body(
539
577
  case ScalarQuantizer::QT_8bit_tqmse:
540
578
  return new DCTemplate<QuantizerTurboQuantMSE<8, SL2>, Sim, SL2>(
541
579
  d, trained);
580
+ case ScalarQuantizer::QT_1bit_eden:
581
+ return new DCTemplate<QuantizerLloydMax<1, SL2>, Sim, SL2>(
582
+ d, trained);
583
+ case ScalarQuantizer::QT_2bit_eden:
584
+ return new DCTemplate<QuantizerLloydMax<2, SL2>, Sim, SL2>(
585
+ d, trained);
586
+ case ScalarQuantizer::QT_3bit_eden:
587
+ return new DCTemplate<QuantizerLloydMax<3, SL2>, Sim, SL2>(
588
+ d, trained);
589
+ case ScalarQuantizer::QT_4bit_eden:
590
+ return new DCTemplate<QuantizerLloydMax<4, SL2>, Sim, SL2>(
591
+ d, trained);
592
+ case ScalarQuantizer::QT_5bit_eden:
593
+ if constexpr (SL2 != SIMDLevel::NONE) {
594
+ return nullptr;
595
+ } else {
596
+ return new DCTemplate<QuantizerLloydMax<5, SL2>, Sim, SL2>(
597
+ d, trained);
598
+ }
599
+ case ScalarQuantizer::QT_6bit_eden:
600
+ if constexpr (SL2 != SIMDLevel::NONE) {
601
+ return nullptr;
602
+ } else {
603
+ return new DCTemplate<QuantizerLloydMax<6, SL2>, Sim, SL2>(
604
+ d, trained);
605
+ }
606
+ case ScalarQuantizer::QT_7bit_eden:
607
+ if constexpr (SL2 != SIMDLevel::NONE) {
608
+ return nullptr;
609
+ } else {
610
+ return new DCTemplate<QuantizerLloydMax<7, SL2>, Sim, SL2>(
611
+ d, trained);
612
+ }
613
+ case ScalarQuantizer::QT_8bit_eden:
614
+ return new DCTemplate<QuantizerLloydMax<8, SL2>, Sim, SL2>(
615
+ d, trained);
542
616
  case ScalarQuantizer::QT_2bit_tq:
543
617
  // FRICTION: bypasses DCTemplate entirely — custom DC
544
618
  // that doesn't fit the Quantizer+Similarity decomposition
@@ -686,6 +760,16 @@ InvertedListScanner* sq_select_InvertedListScanner<THE_LEVEL_TO_DISPATCH>(
686
760
  return scan.template operator()<
687
761
  DistanceComputerByteSigned<Similarity, SL2>>();
688
762
  }
763
+ } else if constexpr (SL2 == SIMDLevel::AVX512) {
764
+ if (d % 32 == 0) {
765
+ return scan.template operator()<
766
+ DistanceComputerByteSigned<Similarity, SL2>>();
767
+ }
768
+ } else if constexpr (SL2 == SIMDLevel::AVX2) {
769
+ if (d % 16 == 0) {
770
+ return scan.template operator()<
771
+ DistanceComputerByteSigned<Similarity, SL2>>();
772
+ }
689
773
  }
690
774
  return scan.template operator()<DCTemplate<
691
775
  Quantizer8bitDirectSigned<SL2>,
@@ -719,6 +803,58 @@ InvertedListScanner* sq_select_InvertedListScanner<THE_LEVEL_TO_DISPATCH>(
719
803
  QuantizerTurboQuantMSE<8, SL2>,
720
804
  Similarity,
721
805
  SL2>>();
806
+ case ScalarQuantizer::QT_1bit_eden:
807
+ return scan.template operator()<DCTemplate<
808
+ QuantizerLloydMax<1, SL2>,
809
+ Similarity,
810
+ SL2>>();
811
+ case ScalarQuantizer::QT_2bit_eden:
812
+ return scan.template operator()<DCTemplate<
813
+ QuantizerLloydMax<2, SL2>,
814
+ Similarity,
815
+ SL2>>();
816
+ case ScalarQuantizer::QT_3bit_eden:
817
+ return scan.template operator()<DCTemplate<
818
+ QuantizerLloydMax<3, SL2>,
819
+ Similarity,
820
+ SL2>>();
821
+ case ScalarQuantizer::QT_4bit_eden:
822
+ return scan.template operator()<DCTemplate<
823
+ QuantizerLloydMax<4, SL2>,
824
+ Similarity,
825
+ SL2>>();
826
+ case ScalarQuantizer::QT_5bit_eden:
827
+ if constexpr (SL2 != SIMDLevel::NONE) {
828
+ return nullptr;
829
+ } else {
830
+ return scan.template operator()<DCTemplate<
831
+ QuantizerLloydMax<5, SL2>,
832
+ Similarity,
833
+ SL2>>();
834
+ }
835
+ case ScalarQuantizer::QT_6bit_eden:
836
+ if constexpr (SL2 != SIMDLevel::NONE) {
837
+ return nullptr;
838
+ } else {
839
+ return scan.template operator()<DCTemplate<
840
+ QuantizerLloydMax<6, SL2>,
841
+ Similarity,
842
+ SL2>>();
843
+ }
844
+ case ScalarQuantizer::QT_7bit_eden:
845
+ if constexpr (SL2 != SIMDLevel::NONE) {
846
+ return nullptr;
847
+ } else {
848
+ return scan.template operator()<DCTemplate<
849
+ QuantizerLloydMax<7, SL2>,
850
+ Similarity,
851
+ SL2>>();
852
+ }
853
+ case ScalarQuantizer::QT_8bit_eden:
854
+ return scan.template operator()<DCTemplate<
855
+ QuantizerLloydMax<8, SL2>,
856
+ Similarity,
857
+ SL2>>();
722
858
  case ScalarQuantizer::QT_2bit_tq:
723
859
  return scan.template
724
860
  operator()<DCTurboQuantFull<2, Similarity, SL2>>();