faiss 0.4.3 → 0.5.1

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 +10 -0
  3. data/README.md +2 -0
  4. data/ext/faiss/index.cpp +33 -6
  5. data/ext/faiss/index_binary.cpp +17 -4
  6. data/ext/faiss/kmeans.cpp +6 -6
  7. data/lib/faiss/version.rb +1 -1
  8. data/vendor/faiss/faiss/AutoTune.cpp +2 -3
  9. data/vendor/faiss/faiss/AutoTune.h +1 -1
  10. data/vendor/faiss/faiss/Clustering.cpp +2 -2
  11. data/vendor/faiss/faiss/Clustering.h +2 -2
  12. data/vendor/faiss/faiss/IVFlib.cpp +26 -51
  13. data/vendor/faiss/faiss/IVFlib.h +1 -1
  14. data/vendor/faiss/faiss/Index.cpp +11 -0
  15. data/vendor/faiss/faiss/Index.h +34 -11
  16. data/vendor/faiss/faiss/Index2Layer.cpp +1 -1
  17. data/vendor/faiss/faiss/Index2Layer.h +2 -2
  18. data/vendor/faiss/faiss/IndexAdditiveQuantizer.cpp +1 -0
  19. data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.cpp +9 -4
  20. data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.h +5 -1
  21. data/vendor/faiss/faiss/IndexBinary.h +7 -7
  22. data/vendor/faiss/faiss/IndexBinaryFromFloat.h +1 -1
  23. data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +8 -2
  24. data/vendor/faiss/faiss/IndexBinaryHNSW.h +1 -1
  25. data/vendor/faiss/faiss/IndexBinaryHash.cpp +3 -3
  26. data/vendor/faiss/faiss/IndexBinaryHash.h +5 -5
  27. data/vendor/faiss/faiss/IndexBinaryIVF.cpp +7 -6
  28. data/vendor/faiss/faiss/IndexFastScan.cpp +125 -49
  29. data/vendor/faiss/faiss/IndexFastScan.h +102 -7
  30. data/vendor/faiss/faiss/IndexFlat.cpp +374 -4
  31. data/vendor/faiss/faiss/IndexFlat.h +81 -1
  32. data/vendor/faiss/faiss/IndexHNSW.cpp +93 -2
  33. data/vendor/faiss/faiss/IndexHNSW.h +58 -2
  34. data/vendor/faiss/faiss/IndexIDMap.cpp +14 -13
  35. data/vendor/faiss/faiss/IndexIDMap.h +6 -6
  36. data/vendor/faiss/faiss/IndexIVF.cpp +1 -1
  37. data/vendor/faiss/faiss/IndexIVF.h +5 -5
  38. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +1 -1
  39. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.cpp +9 -3
  40. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.h +3 -1
  41. data/vendor/faiss/faiss/IndexIVFFastScan.cpp +176 -90
  42. data/vendor/faiss/faiss/IndexIVFFastScan.h +173 -18
  43. data/vendor/faiss/faiss/IndexIVFFlat.cpp +1 -0
  44. data/vendor/faiss/faiss/IndexIVFFlatPanorama.cpp +251 -0
  45. data/vendor/faiss/faiss/IndexIVFFlatPanorama.h +64 -0
  46. data/vendor/faiss/faiss/IndexIVFPQ.cpp +3 -1
  47. data/vendor/faiss/faiss/IndexIVFPQ.h +1 -1
  48. data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +134 -2
  49. data/vendor/faiss/faiss/IndexIVFPQFastScan.h +7 -1
  50. data/vendor/faiss/faiss/IndexIVFRaBitQ.cpp +99 -8
  51. data/vendor/faiss/faiss/IndexIVFRaBitQ.h +4 -1
  52. data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.cpp +828 -0
  53. data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.h +252 -0
  54. data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +1 -1
  55. data/vendor/faiss/faiss/IndexIVFSpectralHash.h +1 -1
  56. data/vendor/faiss/faiss/IndexNNDescent.cpp +1 -1
  57. data/vendor/faiss/faiss/IndexNSG.cpp +1 -1
  58. data/vendor/faiss/faiss/IndexNeuralNetCodec.h +1 -1
  59. data/vendor/faiss/faiss/IndexPQ.cpp +4 -1
  60. data/vendor/faiss/faiss/IndexPQ.h +1 -1
  61. data/vendor/faiss/faiss/IndexPQFastScan.cpp +6 -2
  62. data/vendor/faiss/faiss/IndexPQFastScan.h +5 -1
  63. data/vendor/faiss/faiss/IndexPreTransform.cpp +14 -0
  64. data/vendor/faiss/faiss/IndexPreTransform.h +9 -0
  65. data/vendor/faiss/faiss/IndexRaBitQ.cpp +96 -13
  66. data/vendor/faiss/faiss/IndexRaBitQ.h +11 -2
  67. data/vendor/faiss/faiss/IndexRaBitQFastScan.cpp +731 -0
  68. data/vendor/faiss/faiss/IndexRaBitQFastScan.h +175 -0
  69. data/vendor/faiss/faiss/IndexRefine.cpp +49 -0
  70. data/vendor/faiss/faiss/IndexRefine.h +17 -0
  71. data/vendor/faiss/faiss/IndexShards.cpp +1 -1
  72. data/vendor/faiss/faiss/MatrixStats.cpp +3 -3
  73. data/vendor/faiss/faiss/MetricType.h +1 -1
  74. data/vendor/faiss/faiss/VectorTransform.h +2 -2
  75. data/vendor/faiss/faiss/clone_index.cpp +5 -1
  76. data/vendor/faiss/faiss/gpu/GpuCloner.cpp +1 -1
  77. data/vendor/faiss/faiss/gpu/GpuClonerOptions.h +3 -1
  78. data/vendor/faiss/faiss/gpu/GpuIndex.h +11 -11
  79. data/vendor/faiss/faiss/gpu/GpuIndexBinaryCagra.h +1 -1
  80. data/vendor/faiss/faiss/gpu/GpuIndexBinaryFlat.h +1 -1
  81. data/vendor/faiss/faiss/gpu/GpuIndexCagra.h +11 -7
  82. data/vendor/faiss/faiss/gpu/StandardGpuResources.cpp +1 -1
  83. data/vendor/faiss/faiss/gpu/perf/IndexWrapper-inl.h +2 -0
  84. data/vendor/faiss/faiss/gpu/test/TestGpuIcmEncoder.cpp +7 -0
  85. data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFFlat.cpp +1 -1
  86. data/vendor/faiss/faiss/impl/AdditiveQuantizer.cpp +1 -1
  87. data/vendor/faiss/faiss/impl/AdditiveQuantizer.h +1 -1
  88. data/vendor/faiss/faiss/impl/AuxIndexStructures.cpp +2 -2
  89. data/vendor/faiss/faiss/impl/AuxIndexStructures.h +1 -1
  90. data/vendor/faiss/faiss/impl/CodePacker.h +2 -2
  91. data/vendor/faiss/faiss/impl/DistanceComputer.h +77 -6
  92. data/vendor/faiss/faiss/impl/FastScanDistancePostProcessing.h +53 -0
  93. data/vendor/faiss/faiss/impl/HNSW.cpp +295 -16
  94. data/vendor/faiss/faiss/impl/HNSW.h +35 -6
  95. data/vendor/faiss/faiss/impl/IDSelector.cpp +2 -2
  96. data/vendor/faiss/faiss/impl/IDSelector.h +4 -4
  97. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +4 -4
  98. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.h +1 -1
  99. data/vendor/faiss/faiss/impl/LookupTableScaler.h +1 -1
  100. data/vendor/faiss/faiss/impl/NNDescent.cpp +1 -1
  101. data/vendor/faiss/faiss/impl/NNDescent.h +2 -2
  102. data/vendor/faiss/faiss/impl/NSG.cpp +1 -1
  103. data/vendor/faiss/faiss/impl/Panorama.cpp +193 -0
  104. data/vendor/faiss/faiss/impl/Panorama.h +204 -0
  105. data/vendor/faiss/faiss/impl/PanoramaStats.cpp +33 -0
  106. data/vendor/faiss/faiss/impl/PanoramaStats.h +38 -0
  107. data/vendor/faiss/faiss/impl/PolysemousTraining.cpp +5 -5
  108. data/vendor/faiss/faiss/impl/ProductAdditiveQuantizer.cpp +1 -1
  109. data/vendor/faiss/faiss/impl/ProductAdditiveQuantizer.h +1 -1
  110. data/vendor/faiss/faiss/impl/ProductQuantizer-inl.h +2 -0
  111. data/vendor/faiss/faiss/impl/ProductQuantizer.h +1 -1
  112. data/vendor/faiss/faiss/impl/RaBitQStats.cpp +29 -0
  113. data/vendor/faiss/faiss/impl/RaBitQStats.h +56 -0
  114. data/vendor/faiss/faiss/impl/RaBitQUtils.cpp +294 -0
  115. data/vendor/faiss/faiss/impl/RaBitQUtils.h +330 -0
  116. data/vendor/faiss/faiss/impl/RaBitQuantizer.cpp +304 -223
  117. data/vendor/faiss/faiss/impl/RaBitQuantizer.h +72 -4
  118. data/vendor/faiss/faiss/impl/RaBitQuantizerMultiBit.cpp +362 -0
  119. data/vendor/faiss/faiss/impl/RaBitQuantizerMultiBit.h +112 -0
  120. data/vendor/faiss/faiss/impl/ResidualQuantizer.h +1 -1
  121. data/vendor/faiss/faiss/impl/ResultHandler.h +4 -4
  122. data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +7 -10
  123. data/vendor/faiss/faiss/impl/ScalarQuantizer.h +2 -4
  124. data/vendor/faiss/faiss/impl/ThreadedIndex-inl.h +7 -4
  125. data/vendor/faiss/faiss/impl/index_read.cpp +238 -10
  126. data/vendor/faiss/faiss/impl/index_write.cpp +212 -19
  127. data/vendor/faiss/faiss/impl/io.cpp +2 -2
  128. data/vendor/faiss/faiss/impl/io.h +4 -4
  129. data/vendor/faiss/faiss/impl/kmeans1d.cpp +1 -1
  130. data/vendor/faiss/faiss/impl/kmeans1d.h +1 -1
  131. data/vendor/faiss/faiss/impl/lattice_Zn.h +2 -2
  132. data/vendor/faiss/faiss/impl/mapped_io.cpp +2 -2
  133. data/vendor/faiss/faiss/impl/mapped_io.h +4 -3
  134. data/vendor/faiss/faiss/impl/maybe_owned_vector.h +8 -1
  135. data/vendor/faiss/faiss/impl/platform_macros.h +12 -0
  136. data/vendor/faiss/faiss/impl/pq4_fast_scan.cpp +30 -4
  137. data/vendor/faiss/faiss/impl/pq4_fast_scan.h +14 -8
  138. data/vendor/faiss/faiss/impl/pq4_fast_scan_search_qbs.cpp +5 -6
  139. data/vendor/faiss/faiss/impl/simd_result_handlers.h +55 -11
  140. data/vendor/faiss/faiss/impl/svs_io.cpp +86 -0
  141. data/vendor/faiss/faiss/impl/svs_io.h +67 -0
  142. data/vendor/faiss/faiss/impl/zerocopy_io.h +1 -1
  143. data/vendor/faiss/faiss/index_factory.cpp +217 -8
  144. data/vendor/faiss/faiss/index_factory.h +1 -1
  145. data/vendor/faiss/faiss/index_io.h +1 -1
  146. data/vendor/faiss/faiss/invlists/BlockInvertedLists.h +1 -1
  147. data/vendor/faiss/faiss/invlists/DirectMap.cpp +1 -1
  148. data/vendor/faiss/faiss/invlists/InvertedLists.cpp +115 -1
  149. data/vendor/faiss/faiss/invlists/InvertedLists.h +46 -0
  150. data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +1 -1
  151. data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.h +1 -1
  152. data/vendor/faiss/faiss/svs/IndexSVSFaissUtils.h +261 -0
  153. data/vendor/faiss/faiss/svs/IndexSVSFlat.cpp +117 -0
  154. data/vendor/faiss/faiss/svs/IndexSVSFlat.h +66 -0
  155. data/vendor/faiss/faiss/svs/IndexSVSVamana.cpp +245 -0
  156. data/vendor/faiss/faiss/svs/IndexSVSVamana.h +137 -0
  157. data/vendor/faiss/faiss/svs/IndexSVSVamanaLVQ.cpp +39 -0
  158. data/vendor/faiss/faiss/svs/IndexSVSVamanaLVQ.h +42 -0
  159. data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.cpp +149 -0
  160. data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.h +58 -0
  161. data/vendor/faiss/faiss/utils/AlignedTable.h +1 -1
  162. data/vendor/faiss/faiss/utils/Heap.cpp +2 -2
  163. data/vendor/faiss/faiss/utils/Heap.h +3 -3
  164. data/vendor/faiss/faiss/utils/NeuralNet.cpp +1 -1
  165. data/vendor/faiss/faiss/utils/NeuralNet.h +3 -3
  166. data/vendor/faiss/faiss/utils/approx_topk/approx_topk.h +2 -2
  167. data/vendor/faiss/faiss/utils/approx_topk/avx2-inl.h +2 -2
  168. data/vendor/faiss/faiss/utils/approx_topk/mode.h +1 -1
  169. data/vendor/faiss/faiss/utils/distances.cpp +0 -3
  170. data/vendor/faiss/faiss/utils/distances.h +2 -2
  171. data/vendor/faiss/faiss/utils/extra_distances-inl.h +3 -1
  172. data/vendor/faiss/faiss/utils/hamming-inl.h +2 -0
  173. data/vendor/faiss/faiss/utils/hamming.cpp +7 -6
  174. data/vendor/faiss/faiss/utils/hamming.h +1 -1
  175. data/vendor/faiss/faiss/utils/hamming_distance/common.h +1 -2
  176. data/vendor/faiss/faiss/utils/partitioning.cpp +5 -5
  177. data/vendor/faiss/faiss/utils/partitioning.h +2 -2
  178. data/vendor/faiss/faiss/utils/rabitq_simd.h +222 -336
  179. data/vendor/faiss/faiss/utils/random.cpp +1 -1
  180. data/vendor/faiss/faiss/utils/simdlib_avx2.h +1 -1
  181. data/vendor/faiss/faiss/utils/simdlib_avx512.h +1 -1
  182. data/vendor/faiss/faiss/utils/simdlib_neon.h +2 -2
  183. data/vendor/faiss/faiss/utils/transpose/transpose-avx512-inl.h +1 -1
  184. data/vendor/faiss/faiss/utils/utils.cpp +9 -2
  185. data/vendor/faiss/faiss/utils/utils.h +2 -2
  186. metadata +29 -1
@@ -27,11 +27,13 @@
27
27
  #include <faiss/IndexIVFAdditiveQuantizer.h>
28
28
  #include <faiss/IndexIVFAdditiveQuantizerFastScan.h>
29
29
  #include <faiss/IndexIVFFlat.h>
30
+ #include <faiss/IndexIVFFlatPanorama.h>
30
31
  #include <faiss/IndexIVFIndependentQuantizer.h>
31
32
  #include <faiss/IndexIVFPQ.h>
32
33
  #include <faiss/IndexIVFPQFastScan.h>
33
34
  #include <faiss/IndexIVFPQR.h>
34
35
  #include <faiss/IndexIVFRaBitQ.h>
36
+ #include <faiss/IndexIVFRaBitQFastScan.h>
35
37
  #include <faiss/IndexIVFSpectralHash.h>
36
38
  #include <faiss/IndexLSH.h>
37
39
  #include <faiss/IndexLattice.h>
@@ -41,8 +43,16 @@
41
43
  #include <faiss/IndexPQFastScan.h>
42
44
  #include <faiss/IndexPreTransform.h>
43
45
  #include <faiss/IndexRaBitQ.h>
46
+ #include <faiss/IndexRaBitQFastScan.h>
44
47
  #include <faiss/IndexRefine.h>
45
48
  #include <faiss/IndexRowwiseMinMax.h>
49
+ #ifdef FAISS_ENABLE_SVS
50
+ #include <faiss/impl/svs_io.h>
51
+ #include <faiss/svs/IndexSVSFlat.h>
52
+ #include <faiss/svs/IndexSVSVamana.h>
53
+ #include <faiss/svs/IndexSVSVamanaLVQ.h>
54
+ #include <faiss/svs/IndexSVSVamanaLeanVec.h>
55
+ #endif
46
56
  #include <faiss/IndexScalarQuantizer.h>
47
57
  #include <faiss/MetaIndexes.h>
48
58
  #include <faiss/VectorTransform.h>
@@ -68,7 +78,7 @@
68
78
  * or deprecated fields), the fourcc can be replaced. New code should
69
79
  * be able to read the old fourcc and fill in new classes.
70
80
  *
71
- * TODO: in this file, the read functions that encouter errors may
81
+ * TODO: in this file, the read functions that encounter errors may
72
82
  * leak memory.
73
83
  **************************************************************/
74
84
 
@@ -245,6 +255,33 @@ void write_InvertedLists(const InvertedLists* ils, IOWriter* f) {
245
255
  if (ils == nullptr) {
246
256
  uint32_t h = fourcc("il00");
247
257
  WRITE1(h);
258
+ } else if (
259
+ const auto& ailp =
260
+ dynamic_cast<const ArrayInvertedListsPanorama*>(ils)) {
261
+ uint32_t h = fourcc("ilpn");
262
+ WRITE1(h);
263
+ WRITE1(ailp->nlist);
264
+ WRITE1(ailp->code_size);
265
+ WRITE1(ailp->n_levels);
266
+ uint32_t list_type = fourcc("full");
267
+ WRITE1(list_type);
268
+ std::vector<size_t> sizes;
269
+ sizes.reserve(ailp->nlist);
270
+ for (size_t i = 0; i < ailp->nlist; i++) {
271
+ sizes.push_back(ailp->ids[i].size());
272
+ }
273
+ WRITEVECTOR(sizes);
274
+
275
+ // Write codes, ids, and cum_sums
276
+ for (size_t i = 0; i < ailp->nlist; i++) {
277
+ size_t n = ailp->ids[i].size();
278
+ if (n > 0) {
279
+ WRITEANDCHECK(ailp->codes[i].data(), ailp->codes[i].size());
280
+ WRITEANDCHECK(ailp->ids[i].data(), n);
281
+ WRITEANDCHECK(
282
+ ailp->cum_sums[i].data(), ailp->cum_sums[i].size());
283
+ }
284
+ }
248
285
  } else if (
249
286
  const auto& ails = dynamic_cast<const ArrayInvertedLists*>(ils)) {
250
287
  uint32_t h = fourcc("ilar");
@@ -366,11 +403,17 @@ static void write_NNDescent(const NNDescent* nnd, IOWriter* f) {
366
403
  WRITEVECTOR(nnd->final_graph);
367
404
  }
368
405
 
369
- static void write_RaBitQuantizer(const RaBitQuantizer* rabitq, IOWriter* f) {
370
- // don't care about rabitq->centroid
406
+ // Write RaBitQuantizer for 1-bit format (backward compatible)
407
+ static void write_RaBitQuantizer(
408
+ const RaBitQuantizer* rabitq,
409
+ IOWriter* f,
410
+ bool multi_bit = true) {
371
411
  WRITE1(rabitq->d);
372
412
  WRITE1(rabitq->code_size);
373
413
  WRITE1(rabitq->metric_type);
414
+ if (multi_bit) {
415
+ WRITE1(rabitq->nb_bits);
416
+ }
374
417
  }
375
418
 
376
419
  static void write_direct_map(const DirectMap* dm, IOWriter* f) {
@@ -402,6 +445,18 @@ void write_index(const Index* idx, IOWriter* f, int io_flags) {
402
445
  // eg. for a storage component of HNSW that is set to nullptr
403
446
  uint32_t h = fourcc("null");
404
447
  WRITE1(h);
448
+ } else if (
449
+ const IndexFlatL2Panorama* idxpan =
450
+ dynamic_cast<const IndexFlatL2Panorama*>(idx)) {
451
+ uint32_t h = fourcc("IxFP");
452
+ WRITE1(h);
453
+ WRITE1(idxpan->d);
454
+ WRITE1(idxpan->n_levels);
455
+ WRITE1(idxpan->batch_size);
456
+ WRITE1(idxpan->ntotal);
457
+ WRITE1(idxpan->is_trained);
458
+ WRITEVECTOR(idxpan->codes);
459
+ WRITEVECTOR(idxpan->cum_sums);
405
460
  } else if (const IndexFlat* idxf = dynamic_cast<const IndexFlat*>(idx)) {
406
461
  uint32_t h =
407
462
  fourcc(idxf->metric_type == METRIC_INNER_PRODUCT ? "IxFI"
@@ -638,6 +693,14 @@ void write_index(const Index* idx, IOWriter* f, int io_flags) {
638
693
  WRITEVECTOR(tab);
639
694
  }
640
695
  write_InvertedLists(ivfl->invlists, f);
696
+ } else if (
697
+ const IndexIVFFlatPanorama* ivfp =
698
+ dynamic_cast<const IndexIVFFlatPanorama*>(idx)) {
699
+ uint32_t h = fourcc("IwPn");
700
+ WRITE1(h);
701
+ write_ivf_header(ivfp, f);
702
+ WRITE1(ivfp->n_levels);
703
+ write_InvertedLists(ivfp->invlists, f);
641
704
  } else if (
642
705
  const IndexIVFFlat* ivfl_2 =
643
706
  dynamic_cast<const IndexIVFFlat*>(idx)) {
@@ -752,7 +815,9 @@ void write_index(const Index* idx, IOWriter* f, int io_flags) {
752
815
  write_ProductQuantizer(&imiq->pq, f);
753
816
  } else if (
754
817
  const IndexRefine* idxrf = dynamic_cast<const IndexRefine*>(idx)) {
755
- uint32_t h = fourcc("IxRF");
818
+ bool is_pano =
819
+ dynamic_cast<const IndexRefinePanorama*>(idxrf) != nullptr;
820
+ uint32_t h = is_pano ? fourcc("IxRP") : fourcc("IxRF");
756
821
  WRITE1(h);
757
822
  write_index_header(idxrf, f);
758
823
  write_index(idxrf->base_index, f);
@@ -768,15 +833,23 @@ void write_index(const Index* idx, IOWriter* f, int io_flags) {
768
833
  write_index(idxmap->index, f);
769
834
  WRITEVECTOR(idxmap->id_map);
770
835
  } else if (const IndexHNSW* idxhnsw = dynamic_cast<const IndexHNSW*>(idx)) {
771
- uint32_t h = dynamic_cast<const IndexHNSWFlat*>(idx) ? fourcc("IHNf")
772
- : dynamic_cast<const IndexHNSWPQ*>(idx) ? fourcc("IHNp")
773
- : dynamic_cast<const IndexHNSWSQ*>(idx) ? fourcc("IHNs")
774
- : dynamic_cast<const IndexHNSW2Level*>(idx) ? fourcc("IHN2")
775
- : dynamic_cast<const IndexHNSWCagra*>(idx) ? fourcc("IHc2")
776
- : 0;
836
+ uint32_t h = dynamic_cast<const IndexHNSWFlatPanorama*>(idx)
837
+ ? fourcc("IHfP")
838
+ : dynamic_cast<const IndexHNSWFlat*>(idx) ? fourcc("IHNf")
839
+ : dynamic_cast<const IndexHNSWPQ*>(idx) ? fourcc("IHNp")
840
+ : dynamic_cast<const IndexHNSWSQ*>(idx) ? fourcc("IHNs")
841
+ : dynamic_cast<const IndexHNSW2Level*>(idx) ? fourcc("IHN2")
842
+ : dynamic_cast<const IndexHNSWCagra*>(idx) ? fourcc("IHc2")
843
+ : 0;
777
844
  FAISS_THROW_IF_NOT(h != 0);
778
845
  WRITE1(h);
779
846
  write_index_header(idxhnsw, f);
847
+ if (h == fourcc("IHfP")) {
848
+ auto idx_panorama =
849
+ dynamic_cast<const IndexHNSWFlatPanorama*>(idxhnsw);
850
+ WRITE1(idx_panorama->num_panorama_levels);
851
+ WRITEVECTOR(idx_panorama->cum_sums);
852
+ }
780
853
  if (h == fourcc("IHc2")) {
781
854
  WRITE1(idxhnsw->keep_max_size_level0);
782
855
  auto idx_hnsw_cagra = dynamic_cast<const IndexHNSWCagra*>(idxhnsw);
@@ -848,7 +921,7 @@ void write_index(const Index* idx, IOWriter* f, int io_flags) {
848
921
  } else if (
849
922
  const IndexRowwiseMinMax* imm =
850
923
  dynamic_cast<const IndexRowwiseMinMax*>(idx)) {
851
- // IndexRowwiseMinmaxFloat
924
+ // IndexRowwiseMinMaxFloat
852
925
  uint32_t h = fourcc("IRMf");
853
926
  WRITE1(h);
854
927
  write_index_header(imm, f);
@@ -856,31 +929,151 @@ void write_index(const Index* idx, IOWriter* f, int io_flags) {
856
929
  } else if (
857
930
  const IndexRowwiseMinMaxFP16* imm_2 =
858
931
  dynamic_cast<const IndexRowwiseMinMaxFP16*>(idx)) {
859
- // IndexRowwiseMinmaxHalf
932
+ // IndexRowwiseMinMaxHalf
860
933
  uint32_t h = fourcc("IRMh");
861
934
  WRITE1(h);
862
935
  write_index_header(imm_2, f);
863
936
  write_index(imm_2->index, f);
864
937
  } else if (
865
- const IndexRaBitQ* idxq = dynamic_cast<const IndexRaBitQ*>(idx)) {
866
- uint32_t h = fourcc("Ixrq");
938
+ const IndexRaBitQFastScan* idxqfs =
939
+ dynamic_cast<const IndexRaBitQFastScan*>(idx)) {
940
+ uint32_t h = fourcc("Irfs");
867
941
  WRITE1(h);
868
942
  write_index_header(idx, f);
869
- write_RaBitQuantizer(&idxq->rabitq, f);
943
+ write_RaBitQuantizer(&idxqfs->rabitq, f);
944
+ WRITEVECTOR(idxqfs->center);
945
+ WRITE1(idxqfs->qb);
946
+ WRITEVECTOR(idxqfs->flat_storage);
947
+ WRITE1(idxqfs->bbs);
948
+ WRITE1(idxqfs->ntotal2);
949
+ WRITE1(idxqfs->M2);
950
+ WRITE1(idxqfs->code_size);
951
+ WRITEVECTOR(idxqfs->codes);
952
+ } else if (
953
+ const IndexRaBitQ* idxq = dynamic_cast<const IndexRaBitQ*>(idx)) {
954
+ // Use different fourcc codes for 1-bit vs multi-bit
955
+ if (idxq->rabitq.nb_bits == 1) {
956
+ uint32_t h = fourcc("Ixrq"); // 1-bit (backward compatible)
957
+ WRITE1(h);
958
+ write_index_header(idx, f);
959
+ write_RaBitQuantizer(&idxq->rabitq, f, false);
960
+ } else {
961
+ uint32_t h = fourcc("Ixrr"); // multi-bit (new format)
962
+ WRITE1(h);
963
+ write_index_header(idx, f);
964
+ write_RaBitQuantizer(&idxq->rabitq, f, true);
965
+ }
870
966
  WRITEVECTOR(idxq->codes);
871
967
  WRITEVECTOR(idxq->center);
872
968
  WRITE1(idxq->qb);
873
969
  } else if (
874
970
  const IndexIVFRaBitQ* ivrq =
875
971
  dynamic_cast<const IndexIVFRaBitQ*>(idx)) {
876
- uint32_t h = fourcc("Iwrq");
877
- WRITE1(h);
878
- write_ivf_header(ivrq, f);
879
- write_RaBitQuantizer(&ivrq->rabitq, f);
972
+ // Use different fourcc codes for 1-bit vs multi-bit
973
+ if (ivrq->rabitq.nb_bits == 1) {
974
+ uint32_t h = fourcc("Iwrq"); // 1-bit (backward compatible)
975
+ WRITE1(h);
976
+ write_ivf_header(ivrq, f);
977
+ write_RaBitQuantizer(&ivrq->rabitq, f, false);
978
+ } else {
979
+ uint32_t h = fourcc("Iwrr"); // multi-bit (new format)
980
+ WRITE1(h);
981
+ write_ivf_header(ivrq, f);
982
+ write_RaBitQuantizer(&ivrq->rabitq, f, true);
983
+ }
880
984
  WRITE1(ivrq->code_size);
881
985
  WRITE1(ivrq->by_residual);
882
986
  WRITE1(ivrq->qb);
883
987
  write_InvertedLists(ivrq->invlists, f);
988
+ }
989
+ #ifdef FAISS_ENABLE_SVS
990
+ else if (
991
+ const IndexSVSVamana* svs =
992
+ dynamic_cast<const IndexSVSVamana*>(idx)) {
993
+ uint32_t h;
994
+ auto* lvq = dynamic_cast<const IndexSVSVamanaLVQ*>(svs);
995
+ auto* lean = dynamic_cast<const IndexSVSVamanaLeanVec*>(svs);
996
+ if (lvq != nullptr) {
997
+ h = fourcc("ILVQ"); // LVQ
998
+ } else if (lean != nullptr) {
999
+ h = fourcc("ISVL"); // LeanVec
1000
+ } else {
1001
+ h = fourcc("ISVD"); // uncompressed
1002
+ }
1003
+
1004
+ WRITE1(h);
1005
+ write_index_header(svs, f);
1006
+ WRITE1(svs->graph_max_degree);
1007
+ WRITE1(svs->alpha);
1008
+ WRITE1(svs->search_window_size);
1009
+ WRITE1(svs->search_buffer_capacity);
1010
+ WRITE1(svs->construction_window_size);
1011
+ WRITE1(svs->max_candidate_pool_size);
1012
+ WRITE1(svs->prune_to);
1013
+ WRITE1(svs->use_full_search_history);
1014
+ WRITE1(svs->storage_kind);
1015
+
1016
+ if (lean != nullptr) {
1017
+ WRITE1(lean->leanvec_d);
1018
+ }
1019
+
1020
+ bool initialized = (svs->impl != nullptr);
1021
+ WRITE1(initialized);
1022
+ if (initialized) {
1023
+ faiss::BufferedIOWriter bwr(f);
1024
+ faiss::svs_io::WriterStreambuf wbuf(&bwr);
1025
+ std::ostream os(&wbuf);
1026
+ svs->serialize_impl(os);
1027
+ os.flush();
1028
+ }
1029
+
1030
+ if (lean != nullptr) {
1031
+ // Store training data info
1032
+ bool trained = (lean->training_data != nullptr);
1033
+ WRITE1(trained);
1034
+ if (trained) {
1035
+ faiss::BufferedIOWriter bwr(f);
1036
+ faiss::svs_io::WriterStreambuf wbuf(&bwr);
1037
+ std::ostream os(&wbuf);
1038
+ lean->serialize_training_data(os);
1039
+ os.flush();
1040
+ }
1041
+ }
1042
+ } else if (
1043
+ const IndexSVSFlat* svs = dynamic_cast<const IndexSVSFlat*>(idx)) {
1044
+ uint32_t h = fourcc("ISVF");
1045
+ WRITE1(h);
1046
+ write_index_header(idx, f);
1047
+
1048
+ bool initialized = (svs->impl != nullptr);
1049
+ WRITE1(initialized);
1050
+ if (initialized) {
1051
+ // Wrap SVS I/O and stream to IOWriter
1052
+ faiss::BufferedIOWriter bwr(f);
1053
+ faiss::svs_io::WriterStreambuf wbuf(&bwr);
1054
+ std::ostream os(&wbuf);
1055
+ svs->serialize_impl(os);
1056
+ os.flush();
1057
+ }
1058
+ }
1059
+ #endif // FAISS_ENABLE_SVS
1060
+ else if (
1061
+ const IndexIVFRaBitQFastScan* ivrqfs =
1062
+ dynamic_cast<const IndexIVFRaBitQFastScan*>(idx)) {
1063
+ uint32_t h = fourcc("Iwrf");
1064
+ WRITE1(h);
1065
+ write_ivf_header(ivrqfs, f);
1066
+ write_RaBitQuantizer(&ivrqfs->rabitq, f);
1067
+ WRITE1(ivrqfs->by_residual);
1068
+ WRITE1(ivrqfs->code_size);
1069
+ WRITE1(ivrqfs->bbs);
1070
+ WRITE1(ivrqfs->qbs2);
1071
+ WRITE1(ivrqfs->M2);
1072
+ WRITE1(ivrqfs->implem);
1073
+ WRITE1(ivrqfs->qb);
1074
+ WRITE1(ivrqfs->centered);
1075
+ WRITEVECTOR(ivrqfs->flat_storage);
1076
+ write_InvertedLists(ivrqfs->invlists, f);
884
1077
  } else {
885
1078
  FAISS_THROW_MSG("don't know how to serialize this type of index");
886
1079
  }
@@ -74,7 +74,7 @@ FileIOReader::FileIOReader(const char* fname) {
74
74
  FileIOReader::~FileIOReader() {
75
75
  if (need_close) {
76
76
  int ret = fclose(f);
77
- if (ret != 0) { // we cannot raise and exception in the destructor
77
+ if (ret != 0) { // we cannot raise an exception in the destructor
78
78
  fprintf(stderr,
79
79
  "file %s close error: %s",
80
80
  name.c_str(),
@@ -109,7 +109,7 @@ FileIOWriter::~FileIOWriter() {
109
109
  if (need_close) {
110
110
  int ret = fclose(f);
111
111
  if (ret != 0) {
112
- // we cannot raise and exception in the destructor
112
+ // we cannot raise an exception in the destructor
113
113
  fprintf(stderr,
114
114
  "file %s close error: %s",
115
115
  name.c_str(),
@@ -65,9 +65,9 @@ struct FileIOReader : IOReader {
65
65
  FILE* f = nullptr;
66
66
  bool need_close = false;
67
67
 
68
- FileIOReader(FILE* rf);
68
+ explicit FileIOReader(FILE* rf);
69
69
 
70
- FileIOReader(const char* fname);
70
+ explicit FileIOReader(const char* fname);
71
71
 
72
72
  ~FileIOReader() override;
73
73
 
@@ -80,9 +80,9 @@ struct FileIOWriter : IOWriter {
80
80
  FILE* f = nullptr;
81
81
  bool need_close = false;
82
82
 
83
- FileIOWriter(FILE* wf);
83
+ explicit FileIOWriter(FILE* wf);
84
84
 
85
- FileIOWriter(const char* fname);
85
+ explicit FileIOWriter(const char* fname);
86
86
 
87
87
  ~FileIOWriter() override;
88
88
 
@@ -141,7 +141,7 @@ void smawk(
141
141
  namespace {
142
142
 
143
143
  class CostCalculator {
144
- // The reuslt would be inaccurate if we use float
144
+ // The result would be inaccurate if we use float
145
145
  std::vector<double> cumsum;
146
146
  std::vector<double> cumsum2;
147
147
 
@@ -41,7 +41,7 @@ void smawk(
41
41
  * @param n input array length
42
42
  * @param nclusters number of clusters
43
43
  * @param centroids output centroids, size nclusters
44
- * @return imbalancce factor
44
+ * @return imbalance factor
45
45
  */
46
46
  double kmeans1d(const float* x, size_t n, size_t nclusters, float* centroids);
47
47
 
@@ -26,7 +26,7 @@ struct ZnSphereSearch {
26
26
  int dimS, r2;
27
27
  int natom;
28
28
 
29
- /// size dim * ntatom
29
+ /// size dim * natom
30
30
  std::vector<float> voc;
31
31
 
32
32
  ZnSphereSearch(int dim, int r2);
@@ -138,7 +138,7 @@ struct ZnSphereCodec : ZnSphereSearch, EnumeratedVectors {
138
138
  *
139
139
  * Uses a recursive decomposition on the dimensions to encode
140
140
  * centroids found by the ZnSphereSearch. The codes are *not*
141
- * compatible with the ones of ZnSpehreCodec
141
+ * compatible with the ones of ZnSphereCodec
142
142
  */
143
143
  struct ZnSphereCodecRec : EnumeratedVectors {
144
144
  int r2;
@@ -33,7 +33,7 @@ struct MmappedFileMappingOwner::PImpl {
33
33
  void* ptr = nullptr;
34
34
  size_t ptr_size = 0;
35
35
 
36
- PImpl(const std::string& filename) {
36
+ explicit PImpl(const std::string& filename) {
37
37
  auto f = std::unique_ptr<FILE, decltype(&fclose)>(
38
38
  fopen(filename.c_str(), "r"), &fclose);
39
39
  FAISS_THROW_IF_NOT_FMT(
@@ -64,7 +64,7 @@ struct MmappedFileMappingOwner::PImpl {
64
64
  ptr_size = filesize;
65
65
  }
66
66
 
67
- PImpl(FILE* f) {
67
+ explicit PImpl(FILE* f) {
68
68
  // get the size
69
69
  struct stat s;
70
70
  int status = fstat(fileno(f), &s);
@@ -18,8 +18,8 @@ namespace faiss {
18
18
 
19
19
  // holds a memory-mapped region over a file
20
20
  struct MmappedFileMappingOwner : public MaybeOwnedVectorOwner {
21
- MmappedFileMappingOwner(const std::string& filename);
22
- MmappedFileMappingOwner(FILE* f);
21
+ explicit MmappedFileMappingOwner(const std::string& filename);
22
+ explicit MmappedFileMappingOwner(FILE* f);
23
23
  ~MmappedFileMappingOwner();
24
24
 
25
25
  void* data() const;
@@ -37,7 +37,8 @@ struct MappedFileIOReader : IOReader {
37
37
 
38
38
  size_t pos = 0;
39
39
 
40
- MappedFileIOReader(const std::shared_ptr<MmappedFileMappingOwner>& owner);
40
+ explicit MappedFileIOReader(
41
+ const std::shared_ptr<MmappedFileMappingOwner>& owner);
41
42
 
42
43
  // perform a copy
43
44
  size_t operator()(void* ptr, size_t size, size_t nitems) override;
@@ -51,7 +51,7 @@ struct MaybeOwnedVector {
51
51
  size_t c_size = 0;
52
52
 
53
53
  MaybeOwnedVector() = default;
54
- MaybeOwnedVector(const size_t initial_size) {
54
+ explicit MaybeOwnedVector(const size_t initial_size) {
55
55
  is_owned = true;
56
56
 
57
57
  owned_data.resize(initial_size);
@@ -295,9 +295,16 @@ struct is_maybe_owned_vector : std::false_type {};
295
295
  template <typename T>
296
296
  struct is_maybe_owned_vector<MaybeOwnedVector<T>> : std::true_type {};
297
297
 
298
+ // guard with c++-17 (maybe, it is available somewhere in
299
+ // faiss/impl/platform.h?).
300
+ // This allows headers to be included in c++11 code.
301
+ #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L)
302
+
298
303
  template <typename T>
299
304
  inline constexpr bool is_maybe_owned_vector_v = is_maybe_owned_vector<T>::value;
300
305
 
306
+ #endif
307
+
301
308
  template <typename T>
302
309
  bool operator==(
303
310
  const MaybeOwnedVector<T>& lhs,
@@ -107,6 +107,12 @@ inline int __builtin_clzll(uint64_t x) {
107
107
 
108
108
  #define FAISS_ALWAYS_INLINE __forceinline
109
109
 
110
+ // MSVC uses pragma pack instead of __attribute__((packed))
111
+ // Use FAISS_PACK_STRUCTS_BEGIN/END to wrap packed structure definitions
112
+ #define FAISS_PACKED
113
+ #define FAISS_PACK_STRUCTS_BEGIN __pragma(pack(push, 1))
114
+ #define FAISS_PACK_STRUCTS_END __pragma(pack(pop))
115
+
110
116
  #else
111
117
  /*******************************************************
112
118
  * Linux and OSX
@@ -119,10 +125,16 @@ inline int __builtin_clzll(uint64_t x) {
119
125
  // windows
120
126
  #ifdef SWIG
121
127
  #define ALIGNED(x)
128
+ #define FAISS_PACKED
122
129
  #else
123
130
  #define ALIGNED(x) __attribute__((aligned(x)))
131
+ #define FAISS_PACKED __attribute__((packed))
124
132
  #endif
125
133
 
134
+ // On non-Windows, FAISS_PACKED handles packing, so these are no-ops
135
+ #define FAISS_PACK_STRUCTS_BEGIN
136
+ #define FAISS_PACK_STRUCTS_END
137
+
126
138
  #define FAISS_ALWAYS_INLINE __attribute__((always_inline)) inline
127
139
 
128
140
  #endif
@@ -49,7 +49,19 @@ void pq4_pack_codes(
49
49
  size_t nb,
50
50
  size_t bbs,
51
51
  size_t nsq,
52
- uint8_t* blocks) {
52
+ uint8_t* blocks,
53
+ size_t code_stride) {
54
+ // Determine stride: use custom if provided, otherwise use legacy
55
+ // calculation
56
+ size_t actual_stride = (code_stride == 0) ? (M + 1) / 2 : code_stride;
57
+
58
+ // Input validation for custom stride
59
+ if (code_stride != 0) {
60
+ FAISS_THROW_IF_NOT_MSG(
61
+ code_stride >= (M + 1) / 2,
62
+ "Custom stride must be >= minimum code size");
63
+ }
64
+
53
65
  FAISS_THROW_IF_NOT(bbs % 32 == 0);
54
66
  FAISS_THROW_IF_NOT(nb % bbs == 0);
55
67
  FAISS_THROW_IF_NOT(nsq % 2 == 0);
@@ -72,7 +84,8 @@ void pq4_pack_codes(
72
84
  for (size_t i = 0; i < bbs; i += 32) {
73
85
  std::array<uint8_t, 32> c, c0, c1;
74
86
  get_matrix_column(
75
- codes, ntotal, (M + 1) / 2, i0 + i, sq / 2, c);
87
+ codes, ntotal, actual_stride, i0 + i, sq / 2, c);
88
+
76
89
  for (int j = 0; j < 32; j++) {
77
90
  c0[j] = c[j] & 15;
78
91
  c1[j] = c[j] >> 4;
@@ -97,7 +110,19 @@ void pq4_pack_codes_range(
97
110
  size_t i1,
98
111
  size_t bbs,
99
112
  size_t nsq,
100
- uint8_t* blocks) {
113
+ uint8_t* blocks,
114
+ size_t code_stride) {
115
+ // Determine stride: use custom if provided, otherwise use legacy
116
+ // calculation
117
+ size_t actual_stride = (code_stride == 0) ? (M + 1) / 2 : code_stride;
118
+
119
+ // Input validation for custom stride
120
+ if (code_stride != 0) {
121
+ FAISS_THROW_IF_NOT_MSG(
122
+ code_stride >= (M + 1) / 2,
123
+ "Custom stride must be >= minimum code size");
124
+ }
125
+
101
126
  #ifdef FAISS_BIG_ENDIAN
102
127
  const uint8_t perm0[16] = {
103
128
  8, 0, 9, 1, 10, 2, 11, 3, 12, 4, 13, 5, 14, 6, 15, 7};
@@ -117,7 +142,8 @@ void pq4_pack_codes_range(
117
142
  for (size_t i = 0; i < bbs; i += 32) {
118
143
  std::array<uint8_t, 32> c, c0, c1;
119
144
  get_matrix_column(
120
- codes, i1 - i0, (M + 1) / 2, i_base + i, sq / 2, c);
145
+ codes, i1 - i0, actual_stride, i_base + i, sq / 2, c);
146
+
121
147
  for (int j = 0; j < 32; j++) {
122
148
  c0[j] = c[j] & 15;
123
149
  c1[j] = c[j] >> 4;
@@ -34,9 +34,11 @@ struct SIMDResultHandler;
34
34
  * @param ntotal number of input codes
35
35
  * @param nb output number of codes (ntotal rounded up to a multiple of
36
36
  * bbs)
37
- * @param nsq number of sub-quantizers (=M rounded up to a muliple of 2)
37
+ * @param nsq number of sub-quantizers (=M rounded up to a multiple of 2)
38
38
  * @param bbs size of database blocks (multiple of 32)
39
39
  * @param blocks output array, size nb * nsq / 2.
40
+ * @param code_stride optional stride between consecutive codes (0 = use
41
+ default (M + 1) / 2)
40
42
  */
41
43
  void pq4_pack_codes(
42
44
  const uint8_t* codes,
@@ -45,7 +47,8 @@ void pq4_pack_codes(
45
47
  size_t nb,
46
48
  size_t bbs,
47
49
  size_t nsq,
48
- uint8_t* blocks);
50
+ uint8_t* blocks,
51
+ size_t code_stride = 0);
49
52
 
50
53
  /** Same as pack_codes but write in a given range of the output,
51
54
  * leaving the rest untouched. Assumes allocated entries are 0 on input.
@@ -54,6 +57,8 @@ void pq4_pack_codes(
54
57
  * @param i0 first output code to write
55
58
  * @param i1 last output code to write
56
59
  * @param blocks output array, size at least ceil(i1 / bbs) * bbs * nsq / 2
60
+ * @param code_stride optional stride between consecutive codes (0 = use
61
+ * default (M + 1) / 2)
57
62
  */
58
63
  void pq4_pack_codes_range(
59
64
  const uint8_t* codes,
@@ -62,7 +67,8 @@ void pq4_pack_codes_range(
62
67
  size_t i1,
63
68
  size_t bbs,
64
69
  size_t nsq,
65
- uint8_t* blocks);
70
+ uint8_t* blocks,
71
+ size_t code_stride = 0);
66
72
 
67
73
  /** get a single element from a packed codes table
68
74
  *
@@ -104,7 +110,7 @@ struct CodePackerPQ4 : CodePacker {
104
110
  /** Pack Look-up table for consumption by the kernel.
105
111
  *
106
112
  * @param nq number of queries
107
- * @param nsq number of sub-quantizers (muliple of 2)
113
+ * @param nsq number of sub-quantizers (multiple of 2)
108
114
  * @param src input array, size (nq, 16)
109
115
  * @param dest output array, size (nq, 16)
110
116
  */
@@ -115,7 +121,7 @@ void pq4_pack_LUT(int nq, int nsq, const uint8_t* src, uint8_t* dest);
115
121
  * @param nq number of queries
116
122
  * @param nb number of database elements
117
123
  * @param bbs size of database blocks (multiple of 32)
118
- * @param nsq number of sub-quantizers (muliple of 2)
124
+ * @param nsq number of sub-quantizers (multiple of 2)
119
125
  * @param codes packed codes array
120
126
  * @param LUT packed look-up table
121
127
  * @param scaler scaler to scale the encoded norm
@@ -154,7 +160,7 @@ int pq4_preferred_qbs(int nq);
154
160
  *
155
161
  * @param qbs 4-bit encoded number of query blocks, the total number of
156
162
  * queries handled (nq) is deduced from it
157
- * @param nsq number of sub-quantizers (muliple of 2)
163
+ * @param nsq number of sub-quantizers (multiple of 2)
158
164
  * @param src input array, size (nq, 16)
159
165
  * @param dest output array, size (nq, 16)
160
166
  * @return nq
@@ -173,11 +179,11 @@ int pq4_pack_LUT_qbs_q_map(
173
179
  /** Run accumulation loop.
174
180
  *
175
181
  * @param qbs 4-bit encoded number of queries
176
- * @param nb number of database codes (mutliple of bbs)
182
+ * @param nb number of database codes (multiple of bbs)
177
183
  * @param nsq number of sub-quantizers
178
184
  * @param codes encoded database vectors (packed)
179
185
  * @param LUT look-up table (packed)
180
- * @param res call-back for the resutls
186
+ * @param res call-back for the results
181
187
  * @param scaler scaler to scale the encoded norm
182
188
  */
183
189
  void pq4_accumulate_loop_qbs(