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
@@ -107,7 +107,7 @@ void IndexPQ::search(
107
107
  if (iparams) {
108
108
  params = dynamic_cast<const SearchParametersPQ*>(iparams);
109
109
  FAISS_THROW_IF_NOT_MSG(params, "invalid search params");
110
- FAISS_THROW_IF_NOT_MSG(!params->sel, "selector not supported");
110
+ FAISS_THROW_IF_MSG(params->sel, "selector not supported");
111
111
  param_search_type = params->search_type;
112
112
  }
113
113
 
@@ -459,7 +459,7 @@ struct SortedArray {
459
459
 
460
460
  void init(const T* x_2) {
461
461
  this->x = x_2;
462
- FAISS_THROW_IF_NOT(!perm.empty());
462
+ FAISS_THROW_IF_MSG(perm.empty(), "permutation array must not be empty");
463
463
  for (int n = 0; n < N; n++) {
464
464
  perm[n] = n;
465
465
  }
@@ -543,7 +543,7 @@ struct SemiSortedArray {
543
543
 
544
544
  void init(const T* x_2) {
545
545
  this->x = x_2;
546
- FAISS_THROW_IF_NOT(!perm.empty());
546
+ FAISS_THROW_IF_MSG(perm.empty(), "permutation array must not be empty");
547
547
  for (int n = 0; n < N; n++) {
548
548
  perm[n] = n;
549
549
  }
@@ -665,7 +665,7 @@ struct MinSumK {
665
665
 
666
666
  void mark_seen(int64_t i) {
667
667
  if (use_seen) {
668
- FAISS_THROW_IF_NOT(!seen.empty());
668
+ FAISS_THROW_IF_MSG(seen.empty(), "seen bitmap must not be empty");
669
669
  seen[i >> 3] |= 1 << (i & 7);
670
670
  }
671
671
  }
@@ -795,8 +795,7 @@ void MultiIndexQuantizer::search(
795
795
  float* distances,
796
796
  idx_t* labels,
797
797
  const SearchParameters* params) const {
798
- FAISS_THROW_IF_NOT_MSG(
799
- !params, "search params not supported for this index");
798
+ FAISS_THROW_IF_MSG(params, "search params not supported for this index");
800
799
  if (n == 0) {
801
800
  return;
802
801
  }
@@ -943,8 +942,7 @@ void MultiIndexQuantizer2::search(
943
942
  float* distances,
944
943
  idx_t* labels,
945
944
  const SearchParameters* params) const {
946
- FAISS_THROW_IF_NOT_MSG(
947
- !params, "search params not supported for this index");
945
+ FAISS_THROW_IF_MSG(params, "search params not supported for this index");
948
946
 
949
947
  if (n == 0) {
950
948
  return;
@@ -229,6 +229,7 @@ size_t IndexPreTransform::remove_ids(const IDSelector& sel) {
229
229
  }
230
230
 
231
231
  void IndexPreTransform::reconstruct(idx_t key, float* recons) const {
232
+ FAISS_THROW_IF_NOT_MSG(index, "IndexPreTransform: null sub-index");
232
233
  float* x = chain.empty() ? recons : new float[index->d];
233
234
  std::unique_ptr<float[]> del(recons == x ? nullptr : x);
234
235
  // Initial reconstruction
@@ -239,6 +240,7 @@ void IndexPreTransform::reconstruct(idx_t key, float* recons) const {
239
240
  }
240
241
 
241
242
  void IndexPreTransform::reconstruct_n(idx_t i0, idx_t ni, float* recons) const {
243
+ FAISS_THROW_IF_NOT_MSG(index, "IndexPreTransform: null sub-index");
242
244
  float* x = chain.empty() ? recons : new float[ni * index->d];
243
245
  std::unique_ptr<float[]> del(recons == x ? nullptr : x);
244
246
  // Initial reconstruction
@@ -345,6 +347,19 @@ struct PreTransformDistanceComputer : DistanceComputer {
345
347
  float operator()(idx_t i) override {
346
348
  return (*sub_dc)(i);
347
349
  }
350
+
351
+ void distances_batch_4(
352
+ const idx_t idx0,
353
+ const idx_t idx1,
354
+ const idx_t idx2,
355
+ const idx_t idx3,
356
+ float& dis0,
357
+ float& dis1,
358
+ float& dis2,
359
+ float& dis3) override {
360
+ sub_dc->distances_batch_4(
361
+ idx0, idx1, idx2, idx3, dis0, dis1, dis2, dis3);
362
+ }
348
363
  };
349
364
 
350
365
  } // anonymous namespace
@@ -122,8 +122,8 @@ struct Run_search_with_dc_res {
122
122
  // RaBitQuantizer.cpp for details.
123
123
  auto* dc = dynamic_cast<RaBitQDistanceComputer*>(
124
124
  dc_base.get());
125
- FAISS_THROW_IF_NOT_MSG(
126
- dc != nullptr,
125
+ FAISS_THROW_IF_MSG(
126
+ dc == nullptr,
127
127
  "Failed to cast to RaBitQDistanceComputer for two-stage search");
128
128
 
129
129
  bool is_similarity =
@@ -512,8 +512,7 @@ void IndexRaBitQFastScan::search(
512
512
  float* distances,
513
513
  idx_t* labels,
514
514
  const SearchParameters* params) const {
515
- FAISS_THROW_IF_NOT_MSG(
516
- !params, "search params not supported for this index");
515
+ FAISS_THROW_IF_MSG(params, "search params not supported for this index");
517
516
 
518
517
  // Create query factors array on stack - memory managed by caller
519
518
  std::vector<rabitq_utils::QueryFactorsData> query_factors_storage(n);
@@ -209,8 +209,12 @@ struct RaBitQHeapHandler
209
209
  : 0;
210
210
 
211
211
  const size_t block_idx = base_db_idx / rabitq_index->bbs;
212
+ // aux_base points at this 32-lane sub-block's factors: the bbs block
213
+ // base plus the loop-invariant intra-block offset
214
+ // ((base_db_idx % bbs)). Only the per-element i term varies below.
212
215
  const uint8_t* aux_base = rabitq_index->codes.get() +
213
- block_idx * full_block_size + packed_block_size;
216
+ block_idx * full_block_size + packed_block_size +
217
+ (base_db_idx % rabitq_index->bbs) * storage_size;
214
218
 
215
219
  for (size_t i = 0; i < max_vectors; i++) {
216
220
  const size_t db_idx = base_db_idx + i;
@@ -156,7 +156,17 @@ void IndexRefine::range_search(
156
156
  SearchParameters* base_index_params =
157
157
  (params != nullptr) ? params->base_index_params : nullptr;
158
158
 
159
- base_index->range_search(n, x, radius, result, base_index_params);
159
+ const float kf = (params != nullptr) ? params->k_factor : this->k_factor;
160
+
161
+ const bool is_similarity = is_similarity_metric(metric_type);
162
+
163
+ // Scale the base_index search radius by k_factor. Results are filtered to
164
+ // the exact radius below, so this only affects recall, not correctness; it
165
+ // is up to the user to pick a k_factor that widens the base search for
166
+ // their metric.
167
+ const float base_radius = radius * kf;
168
+
169
+ base_index->range_search(n, x, base_radius, result, base_index_params);
160
170
 
161
171
  #pragma omp parallel if (n > 1)
162
172
  {
@@ -177,6 +187,25 @@ void IndexRefine::range_search(
177
187
  }
178
188
  }
179
189
  }
190
+
191
+ // Exact filtering done here, as base index's approximations
192
+ // can fall outside the specified exact radius.
193
+ const std::vector<size_t> prev_lims(result->lims, result->lims + n + 1);
194
+ size_t wp = 0;
195
+ for (idx_t i = 0; i < n; i++) {
196
+ for (size_t j = prev_lims[i]; j < prev_lims[i + 1]; j++) {
197
+ const float dis = result->distances[j];
198
+ const bool within = is_similarity
199
+ ? CMin<float, idx_t>::cmp(radius, dis)
200
+ : CMax<float, idx_t>::cmp(radius, dis);
201
+ if (within) {
202
+ result->labels[wp] = result->labels[j];
203
+ result->distances[wp] = result->distances[j];
204
+ wp++;
205
+ }
206
+ }
207
+ result->lims[i + 1] = wp;
208
+ }
180
209
  }
181
210
 
182
211
  void IndexRefine::reconstruct(idx_t key, float* recons) const {
@@ -127,8 +127,7 @@ void IndexReplicasTemplate<IndexT>::search(
127
127
  distance_t* distances,
128
128
  idx_t* labels,
129
129
  const SearchParameters* params) const {
130
- FAISS_THROW_IF_NOT_MSG(
131
- !params, "search params not supported for this index");
130
+ FAISS_THROW_IF_MSG(params, "search params not supported for this index");
132
131
  FAISS_THROW_IF_NOT(k > 0);
133
132
  FAISS_THROW_IF_NOT_MSG(this->count() > 0, "no replicas in index");
134
133
 
@@ -14,6 +14,9 @@
14
14
 
15
15
  #include <omp.h>
16
16
 
17
+ #include <faiss/impl/ResultHandler.h>
18
+ #include <faiss/impl/expanded_scanners.h>
19
+
17
20
  #include <faiss/impl/FaissAssert.h>
18
21
  #include <faiss/impl/IDSelector.h>
19
22
  #include <faiss/impl/ScalarQuantizer.h>
@@ -137,6 +140,9 @@ IndexIVFScalarQuantizer::IndexIVFScalarQuantizer(
137
140
  by_residual = false;
138
141
  is_trained = true; // no training needed
139
142
  }
143
+ if (ScalarQuantizer::TurboQuantRefine::is_turboq_full(qtype)) {
144
+ by_residual = false;
145
+ }
140
146
  }
141
147
 
142
148
  IndexIVFScalarQuantizer::IndexIVFScalarQuantizer() : IndexIVF() {
@@ -330,9 +336,65 @@ void IndexIVFScalarQuantizer::add_core(
330
336
  InvertedListScanner* IndexIVFScalarQuantizer::get_InvertedListScanner(
331
337
  bool store_pairs,
332
338
  const IDSelector* sel,
333
- const IVFSearchParameters*) const {
334
- return sq.select_InvertedListScanner(
335
- metric_type, quantizer, store_pairs, sel, by_residual);
339
+ const IVFSearchParameters* search_params) const {
340
+ if (!ScalarQuantizer::TurboQuantRefine::is_turboq_full(sq.qtype)) {
341
+ return sq.select_InvertedListScanner(
342
+ metric_type, quantizer, store_pairs, sel, by_residual);
343
+ }
344
+
345
+ // TurboQ full types: create a TQ-specific scanner that supports
346
+ // search params (qb, int_qjl) and pre-screening.
347
+ uint8_t tq_qb = 0;
348
+ bool tq_int_qjl = false;
349
+ if (auto* tp = dynamic_cast<const IVFSQTurboQSearchParameters*>(
350
+ search_params)) {
351
+ tq_qb = tp->qb;
352
+ tq_int_qjl = tp->int_qjl;
353
+ }
354
+ using TurboQDC = ScalarQuantizer::TurboQuantRefine::DistanceComputer;
355
+ auto* dc = static_cast<TurboQDC*>(sq.get_distance_computer(metric_type));
356
+ dc->configure(tq_qb, tq_int_qjl);
357
+
358
+ struct TQScanner : InvertedListScanner {
359
+ std::unique_ptr<TurboQDC> dc;
360
+
361
+ explicit TQScanner(
362
+ TurboQDC* dc_in,
363
+ bool store_pairs_in,
364
+ const IDSelector* sel_in,
365
+ bool keep_max_in)
366
+ : InvertedListScanner(store_pairs_in, sel_in), dc(dc_in) {
367
+ this->keep_max = keep_max_in;
368
+ }
369
+
370
+ void set_query(const float* query) override {
371
+ dc->set_query(query);
372
+ }
373
+
374
+ void set_list(idx_t list_no_in, float) override {
375
+ this->list_no = list_no_in;
376
+ }
377
+
378
+ float distance_to_code(const uint8_t* code) const final {
379
+ return dc->distance_to_code(code);
380
+ }
381
+
382
+ size_t scan_codes(
383
+ size_t list_size,
384
+ const uint8_t* codes,
385
+ const idx_t* ids,
386
+ ResultHandler& handler) const override {
387
+ dc->set_prescreen_threshold(&handler.threshold, !keep_max);
388
+ size_t nup = run_scan_codes(*this, list_size, codes, ids, handler);
389
+ dc->clear_prescreen_threshold();
390
+ return nup;
391
+ }
392
+ };
393
+
394
+ auto* scanner = new TQScanner(
395
+ dc, store_pairs, sel, is_similarity_metric(metric_type));
396
+ scanner->code_size = code_size;
397
+ return scanner;
336
398
  }
337
399
 
338
400
  void IndexIVFScalarQuantizer::reconstruct_from_offset(
@@ -344,18 +406,18 @@ void IndexIVFScalarQuantizer::reconstruct_from_offset(
344
406
  quantizer->reconstruct(list_no, recons);
345
407
  return;
346
408
  }
347
- const uint8_t* code = invlists->get_single_code(list_no, offset);
409
+ InvertedLists::ScopedCodes sc(invlists, list_no, offset);
348
410
 
349
411
  if (by_residual) {
350
412
  std::vector<float> centroid(d);
351
413
  quantizer->reconstruct(list_no, centroid.data());
352
414
 
353
- sq.decode(code, recons, 1);
415
+ sq.decode(sc.get(), recons, 1);
354
416
  for (int i = 0; i < d; ++i) {
355
417
  recons[i] += centroid[i];
356
418
  }
357
419
  } else {
358
- sq.decode(code, recons, 1);
420
+ sq.decode(sc.get(), recons, 1);
359
421
  }
360
422
  }
361
423
 
@@ -63,6 +63,16 @@ struct IndexScalarQuantizer : IndexFlatCodes {
63
63
  * distances are computed.
64
64
  */
65
65
 
66
+ /// Search parameters for TurboQuant full types (QT_*_tq).
67
+ struct IVFSQTurboQSearchParameters : IVFSearchParameters {
68
+ /// Query quantization bits for integer MSE pre-screening.
69
+ /// 0 = float path (default), 1-8 = integer popcount path.
70
+ uint8_t qb = 0;
71
+
72
+ /// Also use integer popcount for QJL stage (requires qb > 0).
73
+ bool int_qjl = false;
74
+ };
75
+
66
76
  struct IndexIVFScalarQuantizer : IndexIVF {
67
77
  ScalarQuantizer sq;
68
78
 
@@ -143,8 +143,8 @@ void IndexShardsTemplate<IndexT>::add_with_ids(
143
143
  "request them to be shifted");
144
144
 
145
145
  if (successive_ids) {
146
- FAISS_THROW_IF_NOT_MSG(
147
- !xids,
146
+ FAISS_THROW_IF_MSG(
147
+ xids,
148
148
  "It makes no sense to pass in ids and "
149
149
  "request them to be shifted");
150
150
  FAISS_THROW_IF_NOT_MSG(
@@ -106,8 +106,8 @@ void IndexShardsIVF::add_with_ids(
106
106
  "request them to be shifted");
107
107
 
108
108
  if (successive_ids) {
109
- FAISS_THROW_IF_NOT_MSG(
110
- !xids,
109
+ FAISS_THROW_IF_MSG(
110
+ xids,
111
111
  "It makes no sense to pass in ids and "
112
112
  "request them to be shifted");
113
113
  FAISS_THROW_IF_NOT_MSG(
@@ -63,8 +63,7 @@ void IndexSplitVectors::search(
63
63
  float* distances,
64
64
  idx_t* labels,
65
65
  const SearchParameters* params) const {
66
- FAISS_THROW_IF_NOT_MSG(
67
- !params, "search params not supported for this index");
66
+ FAISS_THROW_IF_MSG(params, "search params not supported for this index");
68
67
  FAISS_THROW_IF_NOT_MSG(k == 1, "search implemented only for k=1");
69
68
  FAISS_THROW_IF_NOT_MSG(
70
69
  sum_d == d, "not enough indexes compared to # dimensions");
@@ -187,8 +186,7 @@ void IndexRandom::search(
187
186
  float* distances,
188
187
  idx_t* labels,
189
188
  const SearchParameters* params) const {
190
- FAISS_THROW_IF_NOT_MSG(
191
- !params, "search params not supported for this index");
189
+ FAISS_THROW_IF_MSG(params, "search params not supported for this index");
192
190
  FAISS_THROW_IF_NOT(k <= ntotal);
193
191
  #pragma omp parallel for if (n > 1000)
194
192
  for (idx_t i = 0; i < n; i++) {