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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3f9b24e9b85c954d799a4c19009626bcd90b5071a0b05136a182030920150b5a
4
- data.tar.gz: 1fe65e3ee60d8f77471b8dc6dc77354d7d7f9e7a81a4c12be909ca3ac75fcea1
3
+ metadata.gz: 0ab0ef0079ca7056c6d303b95882757645a81bee9b4c13862f4337dbec1b105a
4
+ data.tar.gz: d61339d723153ed333a6719001de98fa1742606334684b0f7db26f26ad001b09
5
5
  SHA512:
6
- metadata.gz: 277f548905897091a697479e256a79d2e2f9c56647be54921ea5fd6caec6381966dd859b58cdc0d09fb9da5670ef9a7248dd5ba487e50eef58f315e96d952986
7
- data.tar.gz: 3a837ec44d583d6256f3490da8c6e17eec7e2a3854f4721826f6d03c4949e95163f6d67c70d7626d1b520a4b406fee9a3449b3d8fc7fbdd29fe5ff78dffd2e99
6
+ metadata.gz: 20ce33982905751c82f05241b94ca500b241ac15f18245e8e14dad29d2fe5f162c7d4fe4e5441e92f79e06eb9519538831fa2c857050e6b3ea8ad5d0b8e63366
7
+ data.tar.gz: cfd073d25d3067488fdde88e06c5c68eeec6840ea57b9e6222129f4594279a27148b62361bcbd0dcc57727053acd35e4f202558adef03de648d0c8179f05ce07
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 0.6.3 (2026-08-03)
2
+
3
+ - Updated Faiss to 1.15.0
4
+
1
5
  ## 0.6.2 (2026-06-13)
2
6
 
3
7
  - Updated Faiss to 1.14.3
data/lib/faiss/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Faiss
2
- VERSION = "0.6.2"
2
+ VERSION = "0.6.3"
3
3
  end
@@ -45,6 +45,8 @@ void AutoTuneCriterion::set_groundtruth(
45
45
  gt_D.resize(nq * gt_nnn_in);
46
46
  memcpy(gt_D.data(), gt_D_in, sizeof(gt_D[0]) * nq * gt_nnn_in);
47
47
  }
48
+ FAISS_THROW_IF_NOT_MSG(
49
+ gt_I_in != nullptr, "set_groundtruth: gt_I must be non-null");
48
50
  gt_I.resize(nq * gt_nnn_in);
49
51
  memcpy(gt_I.data(), gt_I_in, sizeof(gt_I[0]) * nq * gt_nnn_in);
50
52
  }
@@ -148,7 +150,7 @@ bool OperatingPoints::add(
148
150
  }
149
151
  // remove non-optimal points from array
150
152
  for (size_t i = a.size() - 1; i > 0; --i) {
151
- if (a[i].t < a[i - 1].t) {
153
+ if (a[i].t <= a[i - 1].t) {
152
154
  a.erase(a.begin() + (i - 1));
153
155
  }
154
156
  }
@@ -367,7 +367,7 @@ void Clustering::train_encoded(
367
367
  ? std::numeric_limits<double>::max()
368
368
  : std::abs(prev_obj - obj) / std::abs(prev_obj);
369
369
 
370
- if (change >= 0 && change <= early_stop_threshold) {
370
+ if (change <= early_stop_threshold) {
371
371
  if (verbose) {
372
372
  printf("\n Converged at iteration %d: "
373
373
  "objective did not change\n",
@@ -439,6 +439,14 @@ float kmeans_clustering(
439
439
  size_t k,
440
440
  const float* x,
441
441
  float* centroids) {
442
+ FAISS_THROW_IF_NOT_FMT(
443
+ d <= static_cast<size_t>(std::numeric_limits<int>::max()),
444
+ "kmeans_clustering: d=%zu exceeds INT_MAX",
445
+ d);
446
+ FAISS_THROW_IF_NOT_FMT(
447
+ k <= static_cast<size_t>(std::numeric_limits<int>::max()),
448
+ "kmeans_clustering: k=%zu exceeds INT_MAX",
449
+ k);
442
450
  Clustering clus(static_cast<int>(d), static_cast<int>(k));
443
451
  clus.verbose = d * n * k > (size_t(1) << 30);
444
452
  // display logs if > 1Gflop per iteration
@@ -592,8 +592,12 @@ void handle_ivf(
592
592
  static_cast<faiss::IndexIVF*>(faiss::clone_index(clone));
593
593
  if (generate_ids) {
594
594
  // Assume the quantizer does not natively support add_with_ids.
595
- sharded_index->quantizer =
596
- new IndexIDMap2(sharded_index->quantizer);
595
+ // The IDMap wraps the cloned quantizer; own_fields makes it delete
596
+ // that quantizer when sharded_index (which owns the IDMap) is
597
+ // freed.
598
+ auto* id_quantizer = new IndexIDMap2(sharded_index->quantizer);
599
+ id_quantizer->own_fields = true;
600
+ sharded_index->quantizer = id_quantizer;
597
601
  sharded_index->quantizer->add_with_ids(
598
602
  sharded_centroids[i].size() / index->quantizer->d,
599
603
  sharded_centroids[i].data(),
@@ -615,6 +619,7 @@ void handle_ivf(
615
619
  faiss::write_index(sharded_index, fname);
616
620
  delete sharded_index;
617
621
  }
622
+ delete clone;
618
623
  }
619
624
 
620
625
  void handle_binary_ivf(
@@ -650,8 +655,13 @@ void handle_binary_ivf(
650
655
  faiss::clone_binary_index(clone));
651
656
  if (generate_ids) {
652
657
  // Assume the quantizer does not natively support add_with_ids.
653
- sharded_index->quantizer =
658
+ // The IDMap wraps the cloned quantizer; own_fields makes it delete
659
+ // that quantizer when sharded_index (which owns the IDMap) is
660
+ // freed.
661
+ auto* id_quantizer =
654
662
  new IndexBinaryIDMap2(sharded_index->quantizer);
663
+ id_quantizer->own_fields = true;
664
+ sharded_index->quantizer = id_quantizer;
655
665
  sharded_index->quantizer->add_with_ids(
656
666
  sharded_centroids[i].size() / reconstruction_size,
657
667
  sharded_centroids[i].data(),
@@ -673,6 +683,7 @@ void handle_binary_ivf(
673
683
  faiss::write_index_binary(sharded_index, fname);
674
684
  delete sharded_index;
675
685
  }
686
+ delete clone;
676
687
  }
677
688
 
678
689
  template <typename IndexType>
@@ -16,8 +16,8 @@
16
16
  #include <cstdio>
17
17
 
18
18
  #define FAISS_VERSION_MAJOR 1
19
- #define FAISS_VERSION_MINOR 14
20
- #define FAISS_VERSION_PATCH 3
19
+ #define FAISS_VERSION_MINOR 15
20
+ #define FAISS_VERSION_PATCH 0
21
21
 
22
22
  // Macro to combine the version components into a single string
23
23
  #ifndef FAISS_STRINGIFY
@@ -58,8 +58,8 @@ struct AQDistanceComputerDecompress : FlatCodesDistanceComputer {
58
58
  }
59
59
 
60
60
  float symmetric_dis(idx_t i, idx_t j) final {
61
- aq.decode(codes + i * d, tmp.data(), 1);
62
- aq.decode(codes + j * d, tmp.data() + d, 1);
61
+ aq.decode(codes + i * code_size, tmp.data(), 1);
62
+ aq.decode(codes + j * code_size, tmp.data() + d, 1);
63
63
  return vd(tmp.data(), tmp.data() + d);
64
64
  }
65
65
 
@@ -79,7 +79,8 @@ struct AQDistanceComputerLUT : FlatCodesDistanceComputer {
79
79
 
80
80
  explicit AQDistanceComputerLUT(const IndexAdditiveQuantizer& iaq)
81
81
  : FlatCodesDistanceComputer(iaq.codes.data(), iaq.code_size),
82
- LUT(iaq.aq->total_codebook_size + iaq.d * 2),
82
+ LUT(iaq.aq->total_codebook_size // Storage for LUT.
83
+ + size_t(iaq.d) * 2), // tmp storage for symmetric distance.
83
84
  aq(*iaq.aq),
84
85
  d(iaq.d) {}
85
86
 
@@ -96,9 +97,9 @@ struct AQDistanceComputerLUT : FlatCodesDistanceComputer {
96
97
  }
97
98
 
98
99
  float symmetric_dis(idx_t i, idx_t j) final {
99
- float* tmp = LUT.data();
100
- aq.decode(codes + i * d, tmp, 1);
101
- aq.decode(codes + j * d, tmp + d, 1);
100
+ float* tmp = LUT.data() + aq.total_codebook_size;
101
+ aq.decode(codes + i * code_size, tmp, 1);
102
+ aq.decode(codes + j * code_size, tmp + d, 1);
102
103
  return fvec_L2sqr(tmp, tmp + d, d);
103
104
  }
104
105
 
@@ -234,8 +235,7 @@ void IndexAdditiveQuantizer::search(
234
235
  float* distances,
235
236
  idx_t* labels,
236
237
  const SearchParameters* params) const {
237
- FAISS_THROW_IF_NOT_MSG(
238
- !params, "search params not supported for this index");
238
+ FAISS_THROW_IF_MSG(params, "search params not supported for this index");
239
239
 
240
240
  if (aq->search_type == AdditiveQuantizer::ST_decompress) {
241
241
  with_VectorDistance(d, metric_type, metric_arg, [&](auto vd) {
@@ -458,8 +458,7 @@ void AdditiveCoarseQuantizer::search(
458
458
  float* distances,
459
459
  idx_t* labels,
460
460
  const SearchParameters* params) const {
461
- FAISS_THROW_IF_NOT_MSG(
462
- !params, "search params not supported for this index");
461
+ FAISS_THROW_IF_MSG(params, "search params not supported for this index");
463
462
 
464
463
  if (metric_type == METRIC_INNER_PRODUCT) {
465
464
  aq->knn_centroids_inner_product(n, x, k, distances, labels);
@@ -36,7 +36,7 @@ void IndexAdditiveQuantizerFastScan::init(
36
36
  MetricType metric,
37
37
  int bbs_) {
38
38
  FAISS_THROW_IF_NOT(aq_init != nullptr);
39
- FAISS_THROW_IF_NOT(!aq_init->nbits.empty());
39
+ FAISS_THROW_IF_MSG(aq_init->nbits.empty(), "nbits must not be empty");
40
40
  FAISS_THROW_IF_NOT(aq_init->nbits[0] == 4);
41
41
  if (metric == METRIC_INNER_PRODUCT) {
42
42
  FAISS_THROW_IF_NOT_MSG(
@@ -192,8 +192,7 @@ void IndexAdditiveQuantizerFastScan::search(
192
192
  float* distances,
193
193
  idx_t* labels,
194
194
  const SearchParameters* params) const {
195
- FAISS_THROW_IF_NOT_MSG(
196
- !params, "search params not supported for this index");
195
+ FAISS_THROW_IF_MSG(params, "search params not supported for this index");
197
196
  FAISS_THROW_IF_NOT(k > 0);
198
197
  bool rescale = (rescale_norm && norm_scale > 1 && metric_type == METRIC_L2);
199
198
  if (!rescale) {
@@ -55,8 +55,7 @@ void IndexBinaryFromFloat::search(
55
55
  int32_t* distances,
56
56
  idx_t* labels,
57
57
  const SearchParameters* params) const {
58
- FAISS_THROW_IF_NOT_MSG(
59
- !params, "search params not supported for this index");
58
+ FAISS_THROW_IF_MSG(params, "search params not supported for this index");
60
59
  FAISS_THROW_IF_NOT(k > 0);
61
60
 
62
61
  constexpr idx_t bs = 32768;
@@ -24,7 +24,6 @@
24
24
  #include <faiss/impl/ResultHandler.h>
25
25
  #include <faiss/impl/VisitedTable.h>
26
26
  #include <faiss/utils/Heap.h>
27
- #include <faiss/utils/hamming.h>
28
27
  #include <faiss/utils/random.h>
29
28
 
30
29
  #include <faiss/impl/simd_dispatch.h>
@@ -293,8 +292,8 @@ void IndexBinaryHNSW::reconstruct(idx_t key, uint8_t* recons) const {
293
292
 
294
293
  DistanceComputer* IndexBinaryHNSW::get_distance_computer() const {
295
294
  IndexBinaryFlat* flat_storage = dynamic_cast<IndexBinaryFlat*>(storage);
296
- FAISS_THROW_IF_NOT_MSG(
297
- flat_storage != nullptr,
295
+ FAISS_THROW_IF_MSG(
296
+ flat_storage == nullptr,
298
297
  "IndexBinaryHNSW requires IndexBinaryFlat storage");
299
298
  return with_simd_level([&]<SIMDLevel SL>() {
300
299
  return make_binary_hnsw_distance_computer_fixSL<SL>(
@@ -317,8 +316,8 @@ IndexBinaryHNSWCagra::IndexBinaryHNSWCagra(int d_, int M)
317
316
  }
318
317
 
319
318
  void IndexBinaryHNSWCagra::add(idx_t n, const uint8_t* x) {
320
- FAISS_THROW_IF_NOT_MSG(
321
- !base_level_only,
319
+ FAISS_THROW_IF_MSG(
320
+ base_level_only,
322
321
  "Cannot add vectors when base_level_only is set to True");
323
322
 
324
323
  IndexBinaryHNSW::add(n, x);
@@ -27,7 +27,7 @@
27
27
  // NOLINTNEXTLINE(facebook-hte-InlineHeader)
28
28
  // NOLINTNEXTLINE(facebook-hte-InlineHeader)
29
29
  #include <faiss/impl/binary_hamming/IndexBinaryHash_impl.h>
30
- #include <faiss/utils/hamming_distance/hamming_computer-generic.h>
30
+ #include <faiss/utils/hamming_distance/hamming_computer-generic.h> // IWYU pragma: keep
31
31
  #undef THE_SIMD_LEVEL
32
32
 
33
33
  namespace faiss {
@@ -83,8 +83,7 @@ void IndexBinaryHash::range_search(
83
83
  int radius,
84
84
  RangeSearchResult* result,
85
85
  const SearchParameters* params) const {
86
- FAISS_THROW_IF_NOT_MSG(
87
- !params, "search params not supported for this index");
86
+ FAISS_THROW_IF_MSG(params, "search params not supported for this index");
88
87
  size_t nlist = 0, ndis = 0, n0 = 0;
89
88
 
90
89
  #pragma omp parallel if (n > 100) reduction(+ : ndis, n0, nlist)
@@ -116,8 +115,7 @@ void IndexBinaryHash::search(
116
115
  int32_t* distances,
117
116
  idx_t* labels,
118
117
  const SearchParameters* params) const {
119
- FAISS_THROW_IF_NOT_MSG(
120
- !params, "search params not supported for this index");
118
+ FAISS_THROW_IF_MSG(params, "search params not supported for this index");
121
119
  FAISS_THROW_IF_NOT(k > 0);
122
120
 
123
121
  using HeapForL2 = CMax<int32_t, idx_t>;
@@ -216,8 +214,7 @@ void IndexBinaryMultiHash::range_search(
216
214
  int radius,
217
215
  RangeSearchResult* result,
218
216
  const SearchParameters* params) const {
219
- FAISS_THROW_IF_NOT_MSG(
220
- !params, "search params not supported for this index");
217
+ FAISS_THROW_IF_MSG(params, "search params not supported for this index");
221
218
  size_t nlist = 0, ndis = 0, n0 = 0;
222
219
 
223
220
  #pragma omp parallel if (n > 100) reduction(+ : ndis, n0, nlist)
@@ -249,8 +246,7 @@ void IndexBinaryMultiHash::search(
249
246
  int32_t* distances,
250
247
  idx_t* labels,
251
248
  const SearchParameters* params) const {
252
- FAISS_THROW_IF_NOT_MSG(
253
- !params, "search params not supported for this index");
249
+ FAISS_THROW_IF_MSG(params, "search params not supported for this index");
254
250
  FAISS_THROW_IF_NOT(k > 0);
255
251
 
256
252
  using HeapForL2 = CMax<int32_t, idx_t>;
@@ -206,8 +206,7 @@ void IndexBinaryIVF::search_and_reconstruct(
206
206
  idx_t* __restrict labels,
207
207
  uint8_t* __restrict recons,
208
208
  const SearchParameters* params) const {
209
- FAISS_THROW_IF_NOT_MSG(
210
- !params, "search params not supported for this index");
209
+ FAISS_THROW_IF_MSG(params, "search params not supported for this index");
211
210
  const size_t nprobe_2 = std::min(nlist, this->nprobe);
212
211
  FAISS_THROW_IF_NOT(k > 0);
213
212
  FAISS_THROW_IF_NOT(nprobe_2 > 0);
@@ -524,8 +523,7 @@ void IndexBinaryIVF::range_search(
524
523
  int radius,
525
524
  RangeSearchResult* __restrict res,
526
525
  const SearchParameters* params) const {
527
- FAISS_THROW_IF_NOT_MSG(
528
- !params, "search params not supported for this index");
526
+ FAISS_THROW_IF_MSG(params, "search params not supported for this index");
529
527
  const size_t nprobe_2 = std::min(nlist, this->nprobe);
530
528
  std::unique_ptr<idx_t[]> idx(new idx_t[n * nprobe_2]);
531
529
  std::unique_ptr<int32_t[]> coarse_dis(new int32_t[n * nprobe_2]);
@@ -0,0 +1,273 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ #include <faiss/IndexEDEN.h>
9
+
10
+ #include <faiss/impl/FaissAssert.h>
11
+ #include <faiss/impl/ResultHandler.h>
12
+ #include <memory>
13
+
14
+ namespace faiss {
15
+
16
+ IndexEDEN::IndexEDEN() = default;
17
+
18
+ IndexEDEN::IndexEDEN(
19
+ idx_t d_in,
20
+ MetricType metric,
21
+ uint8_t nb_bits_in,
22
+ EDENScaleType scale_type_in)
23
+ : IndexFlatCodes(0, d_in, metric),
24
+ sq(d_in, eden_utils::quantizer_type_for_bits(nb_bits_in)),
25
+ scale_type(scale_type_in) {
26
+ FAISS_THROW_IF_NOT_MSG(
27
+ scale_type == EDENScaleType_UNBIASED ||
28
+ scale_type == EDENScaleType_BIASED,
29
+ "invalid EDEN scale type");
30
+ sq.train(0, nullptr);
31
+ code_size = eden_utils::code_size(d, sq.bits);
32
+ is_trained = false;
33
+ }
34
+
35
+ void IndexEDEN::train(idx_t n, const float* x) {
36
+ std::vector<float> centroid(d, 0.0f);
37
+ for (idx_t i = 0; i < n; i++) {
38
+ for (size_t j = 0; j < static_cast<size_t>(d); j++) {
39
+ centroid[j] += x[i * d + j];
40
+ }
41
+ }
42
+
43
+ if (n != 0) {
44
+ for (size_t j = 0; j < static_cast<size_t>(d); j++) {
45
+ centroid[j] /= static_cast<float>(n);
46
+ }
47
+ }
48
+
49
+ center = std::move(centroid);
50
+ sq.train(n, x);
51
+ is_trained = true;
52
+ }
53
+
54
+ void IndexEDEN::sa_encode(idx_t n, const float* x, uint8_t* bytes) const {
55
+ FAISS_THROW_IF_NOT(is_trained);
56
+ eden_utils::compute_codes(
57
+ sq, metric_type, scale_type, x, bytes, n, center.data());
58
+ }
59
+
60
+ void IndexEDEN::sa_decode(idx_t n, const uint8_t* bytes, float* x) const {
61
+ FAISS_THROW_IF_NOT(is_trained);
62
+ eden_utils::decode(sq, bytes, x, n, center.data());
63
+ }
64
+
65
+ FlatCodesDistanceComputer* IndexEDEN::get_FlatCodesDistanceComputer() const {
66
+ FlatCodesDistanceComputer* dc =
67
+ eden_utils::get_distance_computer(sq, metric_type, center.data());
68
+ dc->code_size = code_size;
69
+ dc->codes = codes.data();
70
+ return dc;
71
+ }
72
+
73
+ namespace {
74
+
75
+ bool use_eden_batch_scan(size_t d, size_t nb_bits) {
76
+ const size_t values_per_byte = 8 / nb_bits;
77
+ const size_t num_bytes = (d + values_per_byte - 1) / values_per_byte;
78
+ if (nb_bits == 1) {
79
+ return num_bytes >= 32;
80
+ }
81
+ if (nb_bits == 2) {
82
+ return num_bytes >= 16;
83
+ }
84
+ if (nb_bits == 4) {
85
+ return num_bytes >= 128;
86
+ }
87
+ return false;
88
+ }
89
+
90
+ struct Run_search_with_eden_dc {
91
+ using T = void;
92
+
93
+ template <class BlockResultHandler>
94
+ void f(BlockResultHandler& res, const IndexEDEN* index, const float* xq) {
95
+ const size_t ntotal = index->ntotal;
96
+ using SingleResultHandler =
97
+ typename BlockResultHandler::SingleResultHandler;
98
+ const int d = index->d;
99
+ const bool use_batch_scan = use_eden_batch_scan(d, index->sq.bits);
100
+
101
+ #pragma omp parallel
102
+ {
103
+ std::unique_ptr<EDENFlatCodesDistanceComputer> dc(
104
+ eden_utils::get_distance_computer(
105
+ index->sq,
106
+ index->metric_type,
107
+ index->center.data()));
108
+ dc->code_size = index->code_size;
109
+ dc->codes = index->codes.data();
110
+ SingleResultHandler resi(res);
111
+
112
+ #pragma omp for
113
+ for (int64_t q = 0; q < static_cast<int64_t>(res.nq); q++) {
114
+ resi.begin(q);
115
+ dc->set_query(xq + d * q);
116
+
117
+ if (use_batch_scan) {
118
+ size_t i = 0;
119
+ for (; i + 16 <= ntotal; i += 16) {
120
+ bool keep[16];
121
+ bool keep_all = true;
122
+ for (size_t j = 0; j < 16; j++) {
123
+ keep[j] = res.is_in_selection(i + j);
124
+ keep_all &= keep[j];
125
+ }
126
+
127
+ if (keep_all) {
128
+ float dis[16];
129
+ dc->consecutive_distances_batch_16(i, dis);
130
+ for (size_t j = 0; j < 16; j++) {
131
+ resi.add_result(dis[j], i + j);
132
+ }
133
+ } else {
134
+ for (size_t j = 0; j < 16; j++) {
135
+ if (keep[j]) {
136
+ resi.add_result((*dc)(i + j), i + j);
137
+ }
138
+ }
139
+ }
140
+ }
141
+ for (; i + 8 <= ntotal; i += 8) {
142
+ const bool keep0 = res.is_in_selection(i);
143
+ const bool keep1 = res.is_in_selection(i + 1);
144
+ const bool keep2 = res.is_in_selection(i + 2);
145
+ const bool keep3 = res.is_in_selection(i + 3);
146
+ const bool keep4 = res.is_in_selection(i + 4);
147
+ const bool keep5 = res.is_in_selection(i + 5);
148
+ const bool keep6 = res.is_in_selection(i + 6);
149
+ const bool keep7 = res.is_in_selection(i + 7);
150
+ if (keep0 && keep1 && keep2 && keep3 && keep4 &&
151
+ keep5 && keep6 && keep7) {
152
+ float dis[8];
153
+ dc->consecutive_distances_batch_8(i, dis);
154
+ resi.add_result(dis[0], i);
155
+ resi.add_result(dis[1], i + 1);
156
+ resi.add_result(dis[2], i + 2);
157
+ resi.add_result(dis[3], i + 3);
158
+ resi.add_result(dis[4], i + 4);
159
+ resi.add_result(dis[5], i + 5);
160
+ resi.add_result(dis[6], i + 6);
161
+ resi.add_result(dis[7], i + 7);
162
+ } else {
163
+ if (keep0) {
164
+ resi.add_result((*dc)(i), i);
165
+ }
166
+ if (keep1) {
167
+ resi.add_result((*dc)(i + 1), i + 1);
168
+ }
169
+ if (keep2) {
170
+ resi.add_result((*dc)(i + 2), i + 2);
171
+ }
172
+ if (keep3) {
173
+ resi.add_result((*dc)(i + 3), i + 3);
174
+ }
175
+ if (keep4) {
176
+ resi.add_result((*dc)(i + 4), i + 4);
177
+ }
178
+ if (keep5) {
179
+ resi.add_result((*dc)(i + 5), i + 5);
180
+ }
181
+ if (keep6) {
182
+ resi.add_result((*dc)(i + 6), i + 6);
183
+ }
184
+ if (keep7) {
185
+ resi.add_result((*dc)(i + 7), i + 7);
186
+ }
187
+ }
188
+ }
189
+ for (; i + 4 <= ntotal; i += 4) {
190
+ const bool keep0 = res.is_in_selection(i);
191
+ const bool keep1 = res.is_in_selection(i + 1);
192
+ const bool keep2 = res.is_in_selection(i + 2);
193
+ const bool keep3 = res.is_in_selection(i + 3);
194
+ if (keep0 && keep1 && keep2 && keep3) {
195
+ float dis0;
196
+ float dis1;
197
+ float dis2;
198
+ float dis3;
199
+ dc->distances_batch_4(
200
+ i,
201
+ i + 1,
202
+ i + 2,
203
+ i + 3,
204
+ dis0,
205
+ dis1,
206
+ dis2,
207
+ dis3);
208
+ resi.add_result(dis0, i);
209
+ resi.add_result(dis1, i + 1);
210
+ resi.add_result(dis2, i + 2);
211
+ resi.add_result(dis3, i + 3);
212
+ } else {
213
+ if (keep0) {
214
+ resi.add_result((*dc)(i), i);
215
+ }
216
+ if (keep1) {
217
+ resi.add_result((*dc)(i + 1), i + 1);
218
+ }
219
+ if (keep2) {
220
+ resi.add_result((*dc)(i + 2), i + 2);
221
+ }
222
+ if (keep3) {
223
+ resi.add_result((*dc)(i + 3), i + 3);
224
+ }
225
+ }
226
+ }
227
+ for (; i < ntotal; i++) {
228
+ if (res.is_in_selection(i)) {
229
+ resi.add_result((*dc)(i), i);
230
+ }
231
+ }
232
+ } else {
233
+ for (size_t i = 0; i < ntotal; i++) {
234
+ if (res.is_in_selection(i)) {
235
+ resi.add_result((*dc)(i), i);
236
+ }
237
+ }
238
+ }
239
+
240
+ resi.end();
241
+ }
242
+ }
243
+ }
244
+ };
245
+
246
+ } // namespace
247
+
248
+ void IndexEDEN::search(
249
+ idx_t n,
250
+ const float* x,
251
+ idx_t k,
252
+ float* distances,
253
+ idx_t* labels,
254
+ const SearchParameters* params) const {
255
+ FAISS_THROW_IF_NOT(is_trained);
256
+ const IDSelector* sel = params != nullptr ? params->sel : nullptr;
257
+ Run_search_with_eden_dc r;
258
+ dispatch_knn_ResultHandler(
259
+ n, distances, labels, k, metric_type, sel, r, this, x);
260
+ }
261
+
262
+ void IndexEDEN::range_search(
263
+ idx_t /*n*/,
264
+ const float* x,
265
+ float radius,
266
+ RangeSearchResult* result,
267
+ const SearchParameters* params) const {
268
+ const IDSelector* sel = params != nullptr ? params->sel : nullptr;
269
+ Run_search_with_eden_dc r;
270
+ dispatch_range_ResultHandler(result, radius, metric_type, sel, r, this, x);
271
+ }
272
+
273
+ } // namespace faiss
@@ -0,0 +1,57 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ #pragma once
9
+
10
+ #include <faiss/IndexFlatCodes.h>
11
+ #include <faiss/impl/EDENQuantizer.h>
12
+
13
+ namespace faiss {
14
+
15
+ struct IndexEDEN : IndexFlatCodes {
16
+ ScalarQuantizer sq;
17
+ EDENScaleType scale_type = EDENScaleType_UNBIASED;
18
+
19
+ // Center of all training points. Random rotation, if desired, is expected
20
+ // to be supplied externally via IndexPreTransform.
21
+ std::vector<float> center;
22
+
23
+ IndexEDEN();
24
+
25
+ // Factory strings: EDEN, EDEN<n>, EDENBIASED, EDEN<n>BIASED.
26
+ // <n> is the Lloyd-Max bit budget, 1..8. The default is EDEN's original
27
+ // unbiased scale; the BIASED suffix selects the MSE-minimizing scale.
28
+ explicit IndexEDEN(
29
+ idx_t d,
30
+ MetricType metric = METRIC_L2,
31
+ uint8_t nb_bits = 1,
32
+ EDENScaleType scale_type = EDENScaleType_UNBIASED);
33
+
34
+ void train(idx_t n, const float* x) override;
35
+
36
+ void sa_encode(idx_t n, const float* x, uint8_t* bytes) const override;
37
+ void sa_decode(idx_t n, const uint8_t* bytes, float* x) const override;
38
+
39
+ FlatCodesDistanceComputer* get_FlatCodesDistanceComputer() const override;
40
+
41
+ void search(
42
+ idx_t n,
43
+ const float* x,
44
+ idx_t k,
45
+ float* distances,
46
+ idx_t* labels,
47
+ const SearchParameters* params = nullptr) const override;
48
+
49
+ void range_search(
50
+ idx_t n,
51
+ const float* x,
52
+ float radius,
53
+ RangeSearchResult* result,
54
+ const SearchParameters* params = nullptr) const override;
55
+ };
56
+
57
+ } // namespace faiss