faiss 0.6.2 → 0.6.4

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 (178) 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/Clustering.h +8 -0
  7. data/vendor/faiss/faiss/IVFlib.cpp +14 -3
  8. data/vendor/faiss/faiss/Index.h +2 -2
  9. data/vendor/faiss/faiss/IndexAdditiveQuantizer.cpp +9 -10
  10. data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.cpp +2 -3
  11. data/vendor/faiss/faiss/IndexBinaryFromFloat.cpp +24 -4
  12. data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +16 -145
  13. data/vendor/faiss/faiss/IndexBinaryHNSW.h +0 -6
  14. data/vendor/faiss/faiss/IndexBinaryHash.cpp +5 -9
  15. data/vendor/faiss/faiss/IndexBinaryIVF.cpp +8 -18
  16. data/vendor/faiss/faiss/IndexBinaryIVF.h +8 -1
  17. data/vendor/faiss/faiss/IndexEDEN.cpp +273 -0
  18. data/vendor/faiss/faiss/IndexEDEN.h +57 -0
  19. data/vendor/faiss/faiss/IndexFastScan.cpp +15 -4
  20. data/vendor/faiss/faiss/IndexFlat.cpp +21 -54
  21. data/vendor/faiss/faiss/IndexFlat.h +2 -2
  22. data/vendor/faiss/faiss/IndexHNSW.cpp +311 -102
  23. data/vendor/faiss/faiss/IndexHNSW.h +31 -7
  24. data/vendor/faiss/faiss/IndexIDMap.cpp +26 -8
  25. data/vendor/faiss/faiss/IndexIDMap.h +2 -0
  26. data/vendor/faiss/faiss/IndexIVF.cpp +36 -10
  27. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +1 -1
  28. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.cpp +3 -4
  29. data/vendor/faiss/faiss/IndexIVFEDEN.cpp +302 -0
  30. data/vendor/faiss/faiss/IndexIVFEDEN.h +70 -0
  31. data/vendor/faiss/faiss/IndexIVFFastScan.cpp +5 -6
  32. data/vendor/faiss/faiss/IndexIVFFlat.cpp +3 -4
  33. data/vendor/faiss/faiss/IndexIVFIndependentQuantizer.cpp +1 -1
  34. data/vendor/faiss/faiss/IndexIVFPQ.cpp +49 -23
  35. data/vendor/faiss/faiss/IndexIVFPQ.h +11 -0
  36. data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +0 -1
  37. data/vendor/faiss/faiss/IndexIVFRaBitQ.cpp +19 -49
  38. data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.cpp +180 -76
  39. data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.h +5 -4
  40. data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +8 -6
  41. data/vendor/faiss/faiss/IndexLSH.cpp +2 -3
  42. data/vendor/faiss/faiss/IndexLattice.cpp +5 -0
  43. data/vendor/faiss/faiss/IndexNNDescent.cpp +9 -2
  44. data/vendor/faiss/faiss/IndexNSG.cpp +7 -2
  45. data/vendor/faiss/faiss/IndexPQ.cpp +6 -8
  46. data/vendor/faiss/faiss/IndexPreTransform.cpp +15 -0
  47. data/vendor/faiss/faiss/IndexRaBitQ.cpp +2 -2
  48. data/vendor/faiss/faiss/IndexRaBitQFastScan.cpp +1 -2
  49. data/vendor/faiss/faiss/IndexRaBitQFastScan.h +5 -1
  50. data/vendor/faiss/faiss/IndexRefine.cpp +30 -1
  51. data/vendor/faiss/faiss/IndexReplicas.cpp +1 -2
  52. data/vendor/faiss/faiss/IndexShards.cpp +5 -5
  53. data/vendor/faiss/faiss/IndexShardsIVF.cpp +6 -5
  54. data/vendor/faiss/faiss/MetaIndexes.cpp +2 -4
  55. data/vendor/faiss/faiss/SuperKMeans.cpp +286 -247
  56. data/vendor/faiss/faiss/SuperKMeans.h +33 -2
  57. data/vendor/faiss/faiss/VectorTransform.cpp +71 -2
  58. data/vendor/faiss/faiss/VectorTransform.h +3 -0
  59. data/vendor/faiss/faiss/clone_index.cpp +8 -0
  60. data/vendor/faiss/faiss/factory_tools.cpp +47 -4
  61. data/vendor/faiss/faiss/gpu/GpuCloner.cpp +11 -11
  62. data/vendor/faiss/faiss/gpu/GpuClonerOptions.h +1 -5
  63. data/vendor/faiss/faiss/gpu/GpuDistance.h +2 -5
  64. data/vendor/faiss/faiss/gpu/GpuIndex.h +38 -16
  65. data/vendor/faiss/faiss/gpu/GpuIndexCagra.h +71 -1
  66. data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +17 -0
  67. data/vendor/faiss/faiss/gpu/GpuIndexIVFScalarQuantizer.h +16 -0
  68. data/vendor/faiss/faiss/gpu/perf/PerfClustering.cpp +1 -1
  69. data/vendor/faiss/faiss/gpu/perf/PerfIVFPQAdd.cpp +2 -2
  70. data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFScalarQuantizer.cpp +180 -0
  71. data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFFlat.h +1 -5
  72. data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFPQ.h +88 -0
  73. data/vendor/faiss/faiss/gpu_metal/impl/MetalIVFPQ.h +134 -0
  74. data/vendor/faiss/faiss/impl/AdditiveQuantizer.cpp +1 -1
  75. data/vendor/faiss/faiss/impl/ClusteringInitialization.cpp +7 -4
  76. data/vendor/faiss/faiss/impl/DistanceComputer.h +34 -0
  77. data/vendor/faiss/faiss/impl/EDENQuantizer.h +119 -0
  78. data/vendor/faiss/faiss/impl/HNSW.cpp +528 -267
  79. data/vendor/faiss/faiss/impl/HNSW.h +46 -7
  80. data/vendor/faiss/faiss/impl/IDSelector.h +44 -0
  81. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +2 -2
  82. data/vendor/faiss/faiss/impl/NNDescent.cpp +10 -3
  83. data/vendor/faiss/faiss/impl/NSG.cpp +3 -1
  84. data/vendor/faiss/faiss/impl/Panorama.h +20 -9
  85. data/vendor/faiss/faiss/impl/PolysemousTraining.cpp +152 -84
  86. data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +38 -26
  87. data/vendor/faiss/faiss/impl/RaBitQUtils.cpp +45 -37
  88. data/vendor/faiss/faiss/impl/RaBitQUtils.h +35 -0
  89. data/vendor/faiss/faiss/impl/RaBitQuantizer.cpp +239 -72
  90. data/vendor/faiss/faiss/impl/RaBitQuantizer.h +66 -4
  91. data/vendor/faiss/faiss/impl/RaBitQuantizerMultiBit.cpp +4 -13
  92. data/vendor/faiss/faiss/impl/ResultHandler.h +34 -34
  93. data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +287 -84
  94. data/vendor/faiss/faiss/impl/ScalarQuantizer.h +26 -10
  95. data/vendor/faiss/faiss/impl/ThreadedIndex-inl.h +2 -2
  96. data/vendor/faiss/faiss/impl/VisitedTable.cpp +22 -2
  97. data/vendor/faiss/faiss/impl/VisitedTable.h +20 -0
  98. data/vendor/faiss/faiss/impl/binary_hamming/IndexBinaryIVF_impl.h +90 -14
  99. data/vendor/faiss/faiss/impl/binary_hamming/avx2.cpp +4 -4
  100. data/vendor/faiss/faiss/impl/expanded_scanners.h +5 -1
  101. data/vendor/faiss/faiss/impl/fast_scan/decompose_qbs.h +1 -0
  102. data/vendor/faiss/faiss/impl/fast_scan/dispatching.h +35 -2
  103. data/vendor/faiss/faiss/impl/hnsw/LockVector.cpp +1 -1
  104. data/vendor/faiss/faiss/impl/index_read.cpp +491 -50
  105. data/vendor/faiss/faiss/impl/index_write.cpp +86 -30
  106. data/vendor/faiss/faiss/impl/lattice_Zn.cpp +8 -9
  107. data/vendor/faiss/faiss/impl/platform_macros.h +3 -1
  108. data/vendor/faiss/faiss/impl/polysemous_training/avx512.cpp +284 -0
  109. data/vendor/faiss/faiss/impl/polysemous_training/dispatch.h +115 -0
  110. data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQScanner_impl.h +73 -39
  111. data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQ_QueryTables.cpp +0 -1
  112. data/vendor/faiss/faiss/impl/pq_code_distance/PQDistanceComputer_impl.h +26 -15
  113. data/vendor/faiss/faiss/impl/pq_code_distance/avx2.cpp +4 -4
  114. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-generic.cpp +4 -4
  115. data/vendor/faiss/faiss/impl/result_handler/ResultHandler.cpp +195 -0
  116. data/vendor/faiss/faiss/impl/result_handler/avx2.cpp +133 -0
  117. data/vendor/faiss/faiss/impl/result_handler/avx512.cpp +281 -0
  118. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx2.cpp +72 -0
  119. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx512.cpp +228 -0
  120. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer.cpp +887 -0
  121. data/vendor/faiss/faiss/impl/scalar_quantizer/distance_computers.h +2 -2
  122. data/vendor/faiss/faiss/impl/scalar_quantizer/quantizers.h +9 -8
  123. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx2.cpp +90 -24
  124. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-impl.h +30 -30
  125. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-spr.cpp +4 -5
  126. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512.cpp +101 -34
  127. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-dispatch.h +169 -13
  128. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-neon.cpp +125 -26
  129. data/vendor/faiss/faiss/impl/simd_dispatch.h +70 -31
  130. data/vendor/faiss/faiss/index_factory.cpp +40 -7
  131. data/vendor/faiss/faiss/invlists/DirectMap.cpp +1 -1
  132. data/vendor/faiss/faiss/invlists/InvertedLists.cpp +9 -6
  133. data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +29 -8
  134. data/vendor/faiss/faiss/python/python_callbacks.cpp +3 -1
  135. data/vendor/faiss/faiss/svs/IndexSVSFaissUtils.h +60 -0
  136. data/vendor/faiss/faiss/svs/IndexSVSFlat.cpp +26 -1
  137. data/vendor/faiss/faiss/svs/IndexSVSFlat.h +13 -0
  138. data/vendor/faiss/faiss/svs/IndexSVSIVF.cpp +1 -1
  139. data/vendor/faiss/faiss/svs/IndexSVSIVFLeanVec.cpp +1 -1
  140. data/vendor/faiss/faiss/svs/IndexSVSVamana.cpp +47 -5
  141. data/vendor/faiss/faiss/svs/IndexSVSVamana.h +23 -3
  142. data/vendor/faiss/faiss/svs/IndexSVSVamanaLVQ.cpp +4 -2
  143. data/vendor/faiss/faiss/svs/IndexSVSVamanaLVQ.h +2 -1
  144. data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.cpp +10 -4
  145. data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.h +2 -1
  146. data/vendor/faiss/faiss/utils/approx_topk_hamming/approx_topk_hamming.h +1 -1
  147. data/vendor/faiss/faiss/utils/distances.cpp +30 -11
  148. data/vendor/faiss/faiss/utils/distances_dispatch.h +30 -24
  149. data/vendor/faiss/faiss/utils/distances_fused/distances_fused.cpp +1 -1
  150. data/vendor/faiss/faiss/utils/distances_simd.cpp +4 -3
  151. data/vendor/faiss/faiss/utils/extra_distances.cpp +4 -14
  152. data/vendor/faiss/faiss/utils/extra_distances.h +1 -2
  153. data/vendor/faiss/faiss/utils/hamming.cpp +16 -10
  154. data/vendor/faiss/faiss/utils/hamming.h +10 -1
  155. data/vendor/faiss/faiss/utils/hamming_distance/common.h +14 -3
  156. data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512_vpopcnt.cpp +24 -0
  157. data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-avx512.h +1 -1
  158. data/vendor/faiss/faiss/utils/hamming_distance/{hamming_computer-avx512_spr.h → hamming_computer-avx512_vpopcnt.h} +85 -24
  159. data/vendor/faiss/faiss/utils/hamming_distance/hamming_impl.h +141 -0
  160. data/vendor/faiss/faiss/utils/quantize_lut.cpp +29 -8
  161. data/vendor/faiss/faiss/utils/rabitq_simd.h +202 -0
  162. data/vendor/faiss/faiss/utils/simd_impl/distances_arm_sve.cpp +194 -30
  163. data/vendor/faiss/faiss/utils/simd_impl/distances_avx2.cpp +0 -1
  164. data/vendor/faiss/faiss/utils/simd_impl/distances_avx512.cpp +263 -15
  165. data/vendor/faiss/faiss/utils/simd_impl/distances_rvv.cpp +198 -18
  166. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx2.cpp +245 -0
  167. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512.cpp +330 -40
  168. data/vendor/faiss/faiss/utils/simd_impl/{rabitq_avx512_spr.cpp → rabitq_avx512_vpopcnt.cpp} +112 -23
  169. data/vendor/faiss/faiss/utils/simd_impl/rabitq_neon.cpp +11 -0
  170. data/vendor/faiss/faiss/utils/simd_impl/rabitq_rvv.cpp +143 -6
  171. data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_dispatch.h +2 -7
  172. data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels.h +6 -1
  173. data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels_sve.cpp +34 -0
  174. data/vendor/faiss/faiss/utils/simd_levels.cpp +196 -47
  175. data/vendor/faiss/faiss/utils/simd_levels.h +33 -8
  176. data/vendor/faiss/faiss/utils/utils.cpp +9 -27
  177. metadata +21 -5
  178. data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512_spr.cpp +0 -15
@@ -21,11 +21,13 @@
21
21
  #include <faiss/Index2Layer.h>
22
22
  #include <faiss/IndexAdditiveQuantizer.h>
23
23
  #include <faiss/IndexAdditiveQuantizerFastScan.h>
24
+ #include <faiss/IndexEDEN.h>
24
25
  #include <faiss/IndexFlat.h>
25
26
  #include <faiss/IndexHNSW.h>
26
27
  #include <faiss/IndexIVF.h>
27
28
  #include <faiss/IndexIVFAdditiveQuantizer.h>
28
29
  #include <faiss/IndexIVFAdditiveQuantizerFastScan.h>
30
+ #include <faiss/IndexIVFEDEN.h>
29
31
  #include <faiss/IndexIVFFlat.h>
30
32
  #include <faiss/IndexIVFFlatPanorama.h>
31
33
  #include <faiss/IndexIVFPQ.h>
@@ -315,8 +317,8 @@ Index* parse_coarse_quantizer(
315
317
  SVSStorageKind storage = SVSStorageKind::SVS_FP32;
316
318
  if (sm[3].matched) {
317
319
  std::string s = sm[3].str().substr(1);
318
- if (s == "SQI8") {
319
- storage = SVSStorageKind::SVS_SQI8;
320
+ if (s == "SQ8") {
321
+ storage = SVSStorageKind::SVS_SQ8;
320
322
  } else if (s == "FP16") {
321
323
  storage = SVSStorageKind::SVS_FP16;
322
324
  } else if (s == "FP32") {
@@ -383,7 +385,7 @@ IndexIVF* parse_IndexIVF(
383
385
  }
384
386
  if (match("FlatPanorama([0-9]+)?(_([0-9]+))?")) {
385
387
  int nlevels = mres_to_int(sm[1], 8); // default to 8 levels
386
- int bs = mres_to_int(sm[3], 128);
388
+ int bs = mres_to_int(sm[3], Panorama::kDefaultBatchSize);
387
389
  return new IndexIVFFlatPanorama(
388
390
  get_q(), d, nlist, nlevels, mt, own_il, bs);
389
391
  }
@@ -514,6 +516,18 @@ IndexIVF* parse_IndexIVF(
514
516
  uint8_t nb_bits = sm[1].length() > 0 ? std::stoi(sm[1].str()) : 1;
515
517
  return new IndexIVFRaBitQ(get_q(), d, nlist, mt, own_il, nb_bits);
516
518
  }
519
+ // IndexIVFEDEN with optional nb_bits (1-8) and scale type.
520
+ // Accepts: "EDEN" (default 1-bit), "EDEN{nb_bits}" (e.g., "EDEN4"),
521
+ // or "EDEN{nb_bits}BIASED" for the MSE-minimizing scale.
522
+ if (match("EDEN([1-8])?(BIASED|BIAS)?")) {
523
+ uint8_t nb_bits = sm[1].length() > 0 ? std::stoi(sm[1].str()) : 1;
524
+ EDENScaleType scale_type =
525
+ sm[2].str() == "BIASED" || sm[2].str() == "BIAS"
526
+ ? EDENScaleType_BIASED
527
+ : EDENScaleType_UNBIASED;
528
+ return new IndexIVFEDEN(
529
+ get_q(), d, nlist, mt, own_il, nb_bits, scale_type);
530
+ }
517
531
  // Accepts: "RaBitQfs" (default 1-bit, batch size 32)
518
532
  // "RaBitQfs{nb_bits}" (e.g., "RaBitQfs4")
519
533
  // "RaBitQfs_64" (1-bit, batch size 64)
@@ -561,6 +575,13 @@ IndexHNSW* parse_IndexHNSW(
561
575
  if (match(sq_pattern)) {
562
576
  return new IndexHNSWSQ(d, sq_types[sm[1].str()], hnsw_M, mt);
563
577
  }
578
+ // Keep the bare RaBitQ token consistent with Flat and IVF: it means 1 bit.
579
+ // Use an explicit width such as RaBitQ4 to enable staged refinement.
580
+ if (match("RaBitQ([1-9])?")) {
581
+ // the capture is the bare digit, so no substr offset here
582
+ int nb_bits = mres_to_int(sm[1], 1);
583
+ return new IndexHNSWRaBitQ(d, hnsw_M, nb_bits, mt);
584
+ }
564
585
  if (match("([0-9]+)\\+PQ([0-9]+)?")) {
565
586
  int ncent = mres_to_int(sm[1]);
566
587
  int pq_m = mres_to_int(sm[2]);
@@ -681,16 +702,16 @@ Index* parse_svs_datatype(
681
702
  }
682
703
  FAISS_ASSERT(false && "Unsupported SVS index type for Float16");
683
704
  }
684
- if (re_match(datatype_string, "SQI8", sm)) {
705
+ if (re_match(datatype_string, "SQ8", sm)) {
685
706
  if (index_type == "Vamana") {
686
707
  return new IndexSVSVamana(
687
- d, std::stoul(arg_string), mt, SVSStorageKind::SVS_SQI8);
708
+ d, std::stoul(arg_string), mt, SVSStorageKind::SVS_SQ8);
688
709
  }
689
710
  if (index_type == "IVF") {
690
711
  return new IndexSVSIVF(
691
- d, std::stoul(arg_string), mt, SVSStorageKind::SVS_SQI8);
712
+ d, std::stoul(arg_string), mt, SVSStorageKind::SVS_SQ8);
692
713
  }
693
- FAISS_ASSERT(false && "Unsupported SVS index type for SQI8");
714
+ FAISS_ASSERT(false && "Unsupported SVS index type for SQ8");
694
715
  }
695
716
  if (re_match(datatype_string, "(LVQ[0-9]+x[0-9]+)", sm)) {
696
717
  if (index_type == "Vamana") {
@@ -917,6 +938,18 @@ Index* parse_other_indexes(
917
938
  return new IndexRaBitQ(d, metric, nb_bits);
918
939
  }
919
940
 
941
+ // IndexEDEN with optional nb_bits (1-8) and scale type.
942
+ // Accepts: "EDEN" (default 1-bit), "EDEN{nb_bits}" (e.g., "EDEN4"),
943
+ // or "EDEN{nb_bits}BIASED" for the MSE-minimizing scale.
944
+ if (match("EDEN([1-8])?(BIASED|BIAS)?")) {
945
+ uint8_t nb_bits = sm[1].length() > 0 ? std::stoi(sm[1].str()) : 1;
946
+ EDENScaleType scale_type =
947
+ sm[2].str() == "BIASED" || sm[2].str() == "BIAS"
948
+ ? EDENScaleType_BIASED
949
+ : EDENScaleType_UNBIASED;
950
+ return new IndexEDEN(d, metric, nb_bits, scale_type);
951
+ }
952
+
920
953
  if (match("RaBitQfs([1-9])?(_[0-9]+)?")) {
921
954
  uint8_t nb_bits = sm[1].length() > 0 ? std::stoi(sm[1].str()) : 1;
922
955
  int bbs = mres_to_int(sm[2], 32, 1);
@@ -80,7 +80,7 @@ idx_t DirectMap::get(idx_t key) const {
80
80
  return lo;
81
81
  } else if (type == Hashtable) {
82
82
  auto res = hashtable.find(key);
83
- FAISS_THROW_IF_NOT_MSG(res != hashtable.end(), "key not found");
83
+ FAISS_THROW_IF_MSG(res == hashtable.end(), "key not found");
84
84
  return res->second;
85
85
  } else {
86
86
  FAISS_THROW_MSG("direct map not initialized");
@@ -371,8 +371,8 @@ ArrayInvertedListsPanorama::ArrayInvertedListsPanorama(
371
371
  pano(code_size_in, n_levels_in, batch_size) {
372
372
  FAISS_THROW_IF_NOT(n_levels_in > 0);
373
373
  FAISS_THROW_IF_NOT(code_size_in % sizeof(float) == 0);
374
- FAISS_THROW_IF_NOT_MSG(
375
- !use_iterator,
374
+ FAISS_THROW_IF_MSG(
375
+ use_iterator,
376
376
  "IndexIVFFlatPanorama does not support iterators, use vanilla IndexIVFFlat instead");
377
377
  FAISS_ASSERT(level_width % sizeof(float) == 0);
378
378
 
@@ -440,8 +440,11 @@ void ArrayInvertedListsPanorama::resize(size_t list_no, size_t new_size) {
440
440
  const uint8_t* ArrayInvertedListsPanorama::get_single_code(
441
441
  size_t list_no,
442
442
  size_t offset) const {
443
- assert(list_no < nlist);
444
- assert(offset < ids[list_no].size());
443
+ // Throw rather than assert: Panorama::reconstruct takes an unsized
444
+ // pointer, so these are the only bounds available and they must hold
445
+ // in opt builds too.
446
+ FAISS_THROW_IF_NOT(list_no < nlist);
447
+ FAISS_THROW_IF_NOT(offset < ids[list_no].size());
445
448
 
446
449
  uint8_t* recons_buffer = new uint8_t[code_size];
447
450
 
@@ -669,10 +672,10 @@ namespace {
669
672
  int translate_list_no(const VStackInvertedLists* vil, idx_t list_no) {
670
673
  FAISS_THROW_IF_NOT(
671
674
  list_no >= 0 && static_cast<size_t>(list_no) < vil->nlist);
672
- int i0 = 0, i1 = vil->ils.size();
675
+ size_t i0 = 0, i1 = vil->ils.size();
673
676
  const idx_t* cumsz = vil->cumsz.data();
674
677
  while (i0 + 1 < i1) {
675
- int imed = (i0 + i1) / 2;
678
+ size_t imed = i0 + (i1 - i0) / 2;
676
679
  if (list_no >= cumsz[imed]) {
677
680
  i0 = imed;
678
681
  } else {
@@ -11,6 +11,7 @@
11
11
 
12
12
  #include <pthread.h>
13
13
 
14
+ #include <memory>
14
15
  #include <unordered_set>
15
16
 
16
17
  #include <sys/mman.h>
@@ -405,7 +406,8 @@ void OnDiskInvertedLists::update_entries(
405
406
  size_t n_entry,
406
407
  const idx_t* ids_in,
407
408
  const uint8_t* codes_in) {
408
- FAISS_THROW_IF_NOT(!read_only);
409
+ FAISS_THROW_IF_MSG(
410
+ read_only, "cannot modify a read-only OnDiskInvertedLists");
409
411
  if (n_entry == 0) {
410
412
  return;
411
413
  }
@@ -422,7 +424,8 @@ size_t OnDiskInvertedLists::add_entries(
422
424
  size_t n_entry,
423
425
  const idx_t* ids,
424
426
  const uint8_t* code) {
425
- FAISS_THROW_IF_NOT(!read_only);
427
+ FAISS_THROW_IF_MSG(
428
+ read_only, "cannot modify a read-only OnDiskInvertedLists");
426
429
  locks->lock_1(list_no);
427
430
  size_t o = list_size(list_no);
428
431
  resize_locked(list_no, n_entry + o);
@@ -432,7 +435,8 @@ size_t OnDiskInvertedLists::add_entries(
432
435
  }
433
436
 
434
437
  void OnDiskInvertedLists::resize(size_t list_no, size_t new_size) {
435
- FAISS_THROW_IF_NOT(!read_only);
438
+ FAISS_THROW_IF_MSG(
439
+ read_only, "cannot modify a read-only OnDiskInvertedLists");
436
440
  locks->lock_1(list_no);
437
441
  resize_locked(list_no, new_size);
438
442
  locks->unlock_1(list_no);
@@ -711,12 +715,17 @@ void OnDiskInvertedListsIOHook::write(const InvertedLists* ils, IOWriter* f)
711
715
 
712
716
  InvertedLists* OnDiskInvertedListsIOHook::read(IOReader* f, int io_flags)
713
717
  const {
714
- OnDiskInvertedLists* od = new OnDiskInvertedLists();
718
+ auto od = std::make_unique<OnDiskInvertedLists>();
715
719
  od->read_only = io_flags & IO_FLAG_READ_ONLY;
716
720
  READ1(od->nlist);
717
721
  READ1(od->code_size);
718
722
  // this is a POD object
719
723
  READVECTOR(od->lists);
724
+ FAISS_THROW_IF_NOT_FMT(
725
+ od->lists.size() == od->nlist,
726
+ "OnDisk inverted lists: read %zu lists for nlist %zu",
727
+ od->lists.size(),
728
+ od->nlist);
720
729
  {
721
730
  std::vector<OnDiskInvertedLists::Slot> v;
722
731
  READVECTOR(v);
@@ -756,7 +765,7 @@ InvertedLists* OnDiskInvertedListsIOHook::read(IOReader* f, int io_flags)
756
765
  if (!(io_flags & IO_FLAG_SKIP_IVF_DATA)) {
757
766
  od->do_mmap();
758
767
  }
759
- return od;
768
+ return od.release();
760
769
  }
761
770
 
762
771
  /** read from a ArrayInvertedLists into this invertedlist type */
@@ -766,7 +775,7 @@ InvertedLists* OnDiskInvertedListsIOHook::read_ArrayInvertedLists(
766
775
  size_t nlist,
767
776
  size_t code_size,
768
777
  const std::vector<size_t>& sizes) const {
769
- auto ails = new OnDiskInvertedLists();
778
+ auto ails = std::make_unique<OnDiskInvertedLists>();
770
779
  ails->nlist = nlist;
771
780
  ails->code_size = code_size;
772
781
  ails->read_only = true;
@@ -799,12 +808,24 @@ InvertedLists* OnDiskInvertedListsIOHook::read_ArrayInvertedLists(
799
808
  OnDiskInvertedLists::List& l = ails->lists[i];
800
809
  l.size = l.capacity = sizes[i];
801
810
  l.offset = o;
802
- o += l.size * (sizeof(idx_t) + ails->code_size);
811
+ size_t elem_size = add_no_overflow(
812
+ sizeof(idx_t), ails->code_size, "OnDisk inverted list element");
813
+ size_t list_bytes =
814
+ mul_no_overflow(l.size, elem_size, "OnDisk inverted list");
815
+ o = add_no_overflow(o, list_bytes, "OnDisk inverted list offset");
816
+ FAISS_THROW_IF_NOT_FMT(
817
+ o <= ails->totsize,
818
+ "inverted list %zu at offset %zu with %zu bytes exceeds "
819
+ "mapped file size %zu",
820
+ i,
821
+ l.offset,
822
+ list_bytes,
823
+ ails->totsize);
803
824
  }
804
825
  // resume normal reading of file
805
826
  fseek(fdesc, o, SEEK_SET);
806
827
 
807
- return ails;
828
+ return ails.release();
808
829
  }
809
830
 
810
831
  } // namespace faiss
@@ -151,7 +151,9 @@ int64_t PyCallbackShardingFunction::operator()(int64_t i, int64_t shard_count) {
151
151
  if (shard_id == nullptr) {
152
152
  FAISS_THROW_MSG("propagate py error");
153
153
  }
154
- return PyLong_AsLongLong(shard_id);
154
+ int64_t rv = PyLong_AsLongLong(shard_id);
155
+ Py_DECREF(shard_id);
156
+ return rv;
155
157
  }
156
158
 
157
159
  PyCallbackShardingFunction::~PyCallbackShardingFunction() {
@@ -30,6 +30,7 @@
30
30
  #include <faiss/impl/AuxIndexStructures.h>
31
31
  #include <faiss/impl/FaissAssert.h>
32
32
  #include <faiss/impl/IDSelector.h>
33
+ #include <faiss/impl/mapped_io.h>
33
34
 
34
35
  #include <algorithm>
35
36
  #include <concepts>
@@ -248,4 +249,63 @@ struct FaissResultsAllocator : public svs_runtime::ResultsAllocator {
248
249
  using LabelsConverter = OutputBufferConverter<size_t, faiss::idx_t>;
249
250
  mutable LabelsConverter labels_converter;
250
251
  };
252
+
253
+ // Helper for memory-mapped SVS index loading.
254
+ // Acquires a pointer to the remaining mapped region and returns the data
255
+ // pointer, size in bytes, and starting position. Validates that mmap returns
256
+ // expected byte count. MappedFileIOReader::mmap returns number of items (not
257
+ // bytes); we always request size=1 so items == bytes, but we name variables
258
+ // explicitly to avoid confusion.
259
+ struct MmapSpan {
260
+ void* data = nullptr;
261
+ size_t size_bytes = 0;
262
+ size_t start_pos = 0;
263
+ };
264
+
265
+ inline MmapSpan acquire_mmap_span(MappedFileIOReader* mf) {
266
+ FAISS_THROW_IF_NOT(mf);
267
+ FAISS_THROW_IF_NOT(mf->mmap_owner);
268
+ size_t pos = mf->pos;
269
+ size_t size_to_end = mf->mmap_owner->size() - pos;
270
+ // Reject an empty span: MappedFileIOReader::mmap() returns 0 without
271
+ // writing *ptr when no bytes remain, which would otherwise pass the
272
+ // size check below and hand a nullptr / zero size to the SVS runtime
273
+ // (e.g. for a truncated or corrupt file).
274
+ FAISS_THROW_IF_NOT_FMT(
275
+ size_to_end > 0,
276
+ "acquire_mmap_span: no mapped bytes remain at reader position %zu",
277
+ pos);
278
+ void* data = nullptr;
279
+ // mmap returns actual_nitems; with size=1 this equals bytes
280
+ size_t actual_nitems = mf->mmap(&data, 1, size_to_end);
281
+ FAISS_THROW_IF_NOT_FMT(
282
+ actual_nitems == size_to_end,
283
+ "mmap() returned unexpected size: %zu items (expected %zu bytes)",
284
+ actual_nitems,
285
+ size_to_end);
286
+ return {data, size_to_end, pos};
287
+ }
288
+
289
+ // Adjusts MappedFileIOReader position after SVS consumes read_bytes,
290
+ // storing mmap_owner reference to keep mapping alive.
291
+ inline void finalize_mmap_span(
292
+ MappedFileIOReader* mf,
293
+ const MmapSpan& span,
294
+ size_t read_bytes,
295
+ std::shared_ptr<MmappedFileMappingOwner>& mmap_owner_out) {
296
+ // Take ownership of the mapping BEFORE validating read_bytes. By this point
297
+ // the caller's impl already holds pointers into the mapped region, so the
298
+ // index must keep the mapping alive even on the throw path. Otherwise the
299
+ // index would be left with a live impl but no mmap_owner, and once the
300
+ // reader's mapping reference is released the index destructor (which calls
301
+ // destroy(impl)) would touch unmapped memory.
302
+ mmap_owner_out = mf->mmap_owner;
303
+ FAISS_THROW_IF_NOT_FMT(
304
+ read_bytes > 0 && read_bytes <= span.size_bytes,
305
+ "map_to_memory returned invalid read_bytes: %zu (span size %zu)",
306
+ read_bytes,
307
+ span.size_bytes);
308
+ mf->pos = span.start_pos + read_bytes;
309
+ }
310
+
251
311
  } // namespace faiss
@@ -22,6 +22,7 @@
22
22
  */
23
23
 
24
24
  #include <faiss/Index.h>
25
+ #include <faiss/impl/mapped_io.h>
25
26
  #include <faiss/svs/IndexSVSFaissUtils.h>
26
27
  #include <faiss/svs/IndexSVSFlat.h>
27
28
 
@@ -55,11 +56,16 @@ void IndexSVSFlat::add(idx_t n, const float* x) {
55
56
 
56
57
  void IndexSVSFlat::reset() {
57
58
  if (impl) {
58
- auto status = impl->reset();
59
+ // Destroy impl to ensure no dangling pointers to mmap region remain.
60
+ // FlatIndex::reset may retain views; destroy guarantees clean state
61
+ // matching Vamana static behavior.
62
+ auto status = svs_runtime::FlatIndex::destroy(impl);
59
63
  if (!status.ok()) {
60
64
  FAISS_THROW_MSG(status.message());
61
65
  }
66
+ impl = nullptr;
62
67
  }
68
+ mmap_owner.reset(); // Release the memory mapping
63
69
  ntotal = 0;
64
70
  }
65
71
 
@@ -114,4 +120,23 @@ void IndexSVSFlat::deserialize_impl(std::istream& in) {
114
120
  FAISS_THROW_IF_NOT_MSG(impl, "Failed to load SVS Flat index.");
115
121
  }
116
122
 
123
+ void IndexSVSFlat::map_to(MappedFileIOReader* mf) {
124
+ FAISS_THROW_IF_MSG(impl, "Cannot map_to: SVS index already loaded.");
125
+ FAISS_THROW_IF_NOT(mf);
126
+
127
+ MmapSpan span = acquire_mmap_span(mf);
128
+
129
+ auto svs_metric = to_svs_metric(metric_type);
130
+
131
+ size_t read_bytes = 0;
132
+ auto status = svs_runtime::FlatIndex::map_to_memory(
133
+ &impl, span.data, span.size_bytes, svs_metric, &read_bytes);
134
+
135
+ if (!status.ok()) {
136
+ FAISS_THROW_MSG(status.message());
137
+ }
138
+
139
+ finalize_mmap_span(mf, span, read_bytes, mmap_owner);
140
+ }
141
+
117
142
  } // namespace faiss
@@ -29,9 +29,14 @@
29
29
  #include <svs/runtime/flat_index.h>
30
30
 
31
31
  #include <iostream>
32
+ #include <memory>
32
33
 
33
34
  namespace faiss {
34
35
 
36
+ // Forward declarations
37
+ struct MappedFileIOReader;
38
+ struct MmappedFileMappingOwner;
39
+
35
40
  struct IndexSVSFlat : Index {
36
41
  // sequential labels
37
42
  size_t nlabels{0};
@@ -56,10 +61,18 @@ struct IndexSVSFlat : Index {
56
61
  /* The actual SVS implementation */
57
62
  svs_runtime::FlatIndex* impl{nullptr};
58
63
 
64
+ // Holds a reference to the memory-mapped file owner to keep the memory
65
+ // mapping alive for the lifetime of this index. Only used when index is
66
+ // loaded via map_to() with memory-mapped I/O.
67
+ std::shared_ptr<MmappedFileMappingOwner> mmap_owner{nullptr};
68
+
59
69
  /* Serialization */
60
70
  void serialize_impl(std::ostream& out) const;
61
71
  void deserialize_impl(std::istream& in);
62
72
 
73
+ /* Memory-mapped deserialization */
74
+ void map_to(MappedFileIOReader* mf);
75
+
63
76
  protected:
64
77
  /* Initializes the implementation*/
65
78
  virtual void create_impl();
@@ -222,7 +222,7 @@ size_t IndexSVSIVF::remove_ids(const IDSelector& sel) {
222
222
  }
223
223
 
224
224
  void IndexSVSIVF::create_impl(idx_t n, const float* x) {
225
- FAISS_THROW_IF_NOT(!impl);
225
+ FAISS_THROW_IF_MSG(impl, "impl already created");
226
226
  ntotal = 0;
227
227
  auto svs_metric = to_svs_metric(metric_type);
228
228
  auto svs_storage_kind = to_svs_storage_kind(storage_kind);
@@ -119,7 +119,7 @@ void IndexSVSIVFLeanVec::deserialize_training_data(std::istream& in) {
119
119
  }
120
120
 
121
121
  void IndexSVSIVFLeanVec::create_impl(idx_t n, const float* x) {
122
- FAISS_THROW_IF_NOT(!impl);
122
+ FAISS_THROW_IF_MSG(impl, "impl already created");
123
123
  ntotal = 0;
124
124
  auto svs_metric = to_svs_metric(metric_type);
125
125
  auto svs_storage_kind = to_svs_storage_kind(storage_kind);
@@ -25,6 +25,7 @@
25
25
  #include <faiss/svs/IndexSVSVamana.h>
26
26
 
27
27
  #include <faiss/Index.h>
28
+ #include <faiss/impl/mapped_io.h>
28
29
 
29
30
  #include <svs/runtime/api_defs.h>
30
31
  #include <svs/runtime/dynamic_vamana_index.h>
@@ -66,11 +67,13 @@ IndexSVSVamana::IndexSVSVamana(
66
67
  size_t degree,
67
68
  MetricType metric,
68
69
  SVSStorageKind storage,
69
- bool is_static)
70
+ bool is_static,
71
+ bool store_vectors)
70
72
  : Index(d, metric),
71
73
  graph_max_degree{degree},
72
74
  is_static{is_static},
73
- storage_kind{storage} {
75
+ storage_kind{storage},
76
+ store_vectors{store_vectors} {
74
77
  prune_to = graph_max_degree < 4 ? graph_max_degree : graph_max_degree - 4;
75
78
  alpha = metric == METRIC_L2 ? 1.2f : 0.95f;
76
79
 
@@ -123,6 +126,14 @@ IndexSVSVamana::~IndexSVSVamana() {
123
126
  }
124
127
 
125
128
  void IndexSVSVamana::add(idx_t n, const float* x) {
129
+ // Opting out after data has been added would leave stored_vectors
130
+ // misaligned with the ids in the index, so release it instead of growing.
131
+ if (!store_vectors && stored_vectors_valid) {
132
+ stored_vectors.clear();
133
+ stored_vectors.shrink_to_fit();
134
+ stored_vectors_valid = false;
135
+ }
136
+
126
137
  if (is_static) {
127
138
  FAISS_THROW_IF_MSG(
128
139
  impl,
@@ -166,7 +177,8 @@ void IndexSVSVamana::reconstruct(idx_t key, float* recons) const {
166
177
  FAISS_THROW_IF_NOT_MSG(
167
178
  stored_vectors_valid && !stored_vectors.empty(),
168
179
  "IndexSVSVamana::reconstruct: stored_vectors unavailable "
169
- "(invalidated by remove_ids or not restored after deserialization)");
180
+ "(store_vectors disabled, invalidated by remove_ids, or not "
181
+ "restored after deserialization)");
170
182
  std::memcpy(recons, stored_vectors.data() + key * d, sizeof(float) * d);
171
183
  }
172
184
 
@@ -186,7 +198,9 @@ void IndexSVSVamana::reset() {
186
198
  }
187
199
  }
188
200
  stored_vectors.clear();
189
- stored_vectors_valid = true;
201
+ stored_vectors.shrink_to_fit();
202
+ stored_vectors_valid = store_vectors;
203
+ mmap_owner.reset(); // Release the memory mapping
190
204
  is_trained = false;
191
205
  ntotal = 0;
192
206
  }
@@ -266,7 +280,7 @@ size_t IndexSVSVamana::remove_ids(const IDSelector& sel) {
266
280
  }
267
281
 
268
282
  void IndexSVSVamana::create_impl(idx_t n, const float* x) {
269
- FAISS_THROW_IF_NOT(!impl);
283
+ FAISS_THROW_IF_MSG(impl, "impl already created");
270
284
  ntotal = 0;
271
285
  auto svs_metric = to_svs_metric(metric_type);
272
286
  auto svs_storage_kind = to_svs_storage_kind(storage_kind);
@@ -363,4 +377,32 @@ svs_runtime::DynamicVamanaIndex* IndexSVSVamana::dynamic_impl() const {
363
377
  return static_cast<svs_runtime::DynamicVamanaIndex*>(impl);
364
378
  }
365
379
 
380
+ void IndexSVSVamana::map_to(MappedFileIOReader* mf) {
381
+ FAISS_THROW_IF_MSG(
382
+ !is_static,
383
+ "map_to() is only supported for static Vamana indices.");
384
+ FAISS_THROW_IF_MSG(impl, "Cannot map_to: SVS index already loaded.");
385
+ FAISS_THROW_IF_NOT(mf);
386
+
387
+ MmapSpan span = acquire_mmap_span(mf);
388
+
389
+ auto svs_metric = to_svs_metric(metric_type);
390
+ auto svs_storage_kind = to_svs_storage_kind(storage_kind);
391
+
392
+ size_t read_bytes = 0;
393
+ auto status = svs_runtime::VamanaIndex::map_to_memory(
394
+ &impl,
395
+ span.data,
396
+ span.size_bytes,
397
+ svs_metric,
398
+ svs_storage_kind,
399
+ &read_bytes);
400
+
401
+ if (!status.ok()) {
402
+ FAISS_THROW_MSG(status.message());
403
+ }
404
+
405
+ finalize_mmap_span(mf, span, read_bytes, mmap_owner);
406
+ }
407
+
366
408
  } // namespace faiss
@@ -30,11 +30,16 @@
30
30
  #include <svs/runtime/dynamic_vamana_index.h>
31
31
 
32
32
  #include <iostream>
33
+ #include <memory>
33
34
  #include <type_traits>
34
35
  #include <vector>
35
36
 
36
37
  namespace faiss {
37
38
 
39
+ // Forward declarations
40
+ struct MappedFileIOReader;
41
+ struct MmappedFileMappingOwner;
42
+
38
43
  struct SearchParametersSVSVamana : public SearchParameters {
39
44
  size_t search_window_size = 0;
40
45
  size_t search_buffer_capacity = 0;
@@ -44,7 +49,7 @@ struct SearchParametersSVSVamana : public SearchParameters {
44
49
  enum SVSStorageKind {
45
50
  SVS_FP32,
46
51
  SVS_FP16,
47
- SVS_SQI8,
52
+ SVS_SQ8,
48
53
  SVS_LVQ4x0,
49
54
  SVS_LVQ4x4,
50
55
  SVS_LVQ4x8,
@@ -61,7 +66,7 @@ inline svs_runtime::StorageKind to_svs_storage_kind(SVSStorageKind kind) {
61
66
  return svs_runtime::StorageKind::FP32;
62
67
  case SVS_FP16:
63
68
  return svs_runtime::StorageKind::FP16;
64
- case SVS_SQI8:
69
+ case SVS_SQ8:
65
70
  return svs_runtime::StorageKind::SQI8;
66
71
  case SVS_LVQ4x0:
67
72
  return svs_runtime::StorageKind::LVQ4x0;
@@ -106,7 +111,8 @@ struct IndexSVSVamana : Index {
106
111
  size_t degree,
107
112
  MetricType metric = METRIC_L2,
108
113
  SVSStorageKind storage = SVSStorageKind::SVS_FP32,
109
- bool is_static = false);
114
+ bool is_static = false,
115
+ bool store_vectors = true);
110
116
 
111
117
  ~IndexSVSVamana() override;
112
118
 
@@ -141,16 +147,30 @@ struct IndexSVSVamana : Index {
141
147
  void serialize_impl(std::ostream& out) const;
142
148
  virtual void deserialize_impl(std::istream& in);
143
149
 
150
+ /* Memory-mapped deserialization for static indices */
151
+ virtual void map_to(MappedFileIOReader* mf);
152
+
144
153
  /* The actual SVS implementation (VamanaIndex is the base for both
145
154
  static and dynamic variants) */
146
155
  svs_runtime::VamanaIndex* impl{nullptr};
147
156
 
157
+ // Holds a reference to the memory-mapped file owner to keep the memory
158
+ // mapping alive for the lifetime of this index. Only used when index is
159
+ // loaded via map_to() with memory-mapped I/O.
160
+ std::shared_ptr<MmappedFileMappingOwner> mmap_owner{nullptr};
161
+
148
162
  // The SVS runtime API does not expose vector retrieval, so we keep a copy
149
163
  // of added vectors to support reconstruct(). When used as a coarse
150
164
  // quantizer this holds only nlist centroids.
151
165
  std::vector<float> stored_vectors;
152
166
  bool stored_vectors_valid{true};
153
167
 
168
+ // Set to false before the first add() to skip the stored_vectors copy,
169
+ // saving ntotal * d * 4 bytes at the cost of reconstruct() support and
170
+ // hence of use as an IVF coarse quantizer. Clearing it after vectors have
171
+ // been added drops the copy, which can no longer be aligned with the ids.
172
+ bool store_vectors{true};
173
+
154
174
  protected:
155
175
  /* Initializes the implementation. For static indexes the data is consumed
156
176
  at build time; for dynamic indexes n/x are ignored and add() populates
@@ -34,7 +34,9 @@ IndexSVSVamanaLVQ::IndexSVSVamanaLVQ(
34
34
  size_t degree,
35
35
  MetricType metric,
36
36
  SVSStorageKind storage,
37
- bool is_static)
38
- : IndexSVSVamana(d, degree, metric, storage, is_static) {}
37
+ bool is_static,
38
+ bool store_vectors)
39
+ : IndexSVSVamana(d, degree, metric, storage, is_static, store_vectors) {
40
+ }
39
41
 
40
42
  } // namespace faiss
@@ -35,7 +35,8 @@ struct IndexSVSVamanaLVQ : IndexSVSVamana {
35
35
  size_t degree,
36
36
  MetricType metric = METRIC_L2,
37
37
  SVSStorageKind storage = SVSStorageKind::SVS_LVQ4x0,
38
- bool is_static = false);
38
+ bool is_static = false,
39
+ bool store_vectors = true);
39
40
 
40
41
  ~IndexSVSVamanaLVQ() override = default;
41
42
  };
@@ -29,7 +29,6 @@
29
29
  #include <svs/runtime/vamana_index.h>
30
30
 
31
31
  #include <memory>
32
- #include <span>
33
32
  #include "faiss/svs/IndexSVSVamana.h"
34
33
 
35
34
  namespace faiss {
@@ -45,8 +44,15 @@ IndexSVSVamanaLeanVec::IndexSVSVamanaLeanVec(
45
44
  MetricType metric,
46
45
  size_t leanvec_dims,
47
46
  SVSStorageKind storage_kind,
48
- bool is_static)
49
- : IndexSVSVamana(d, degree, metric, storage_kind, is_static) {
47
+ bool is_static,
48
+ bool store_vectors)
49
+ : IndexSVSVamana(
50
+ d,
51
+ degree,
52
+ metric,
53
+ storage_kind,
54
+ is_static,
55
+ store_vectors) {
50
56
  is_trained = false;
51
57
  leanvec_d = leanvec_dims == 0 ? d / 2 : leanvec_dims;
52
58
  }
@@ -122,7 +128,7 @@ void IndexSVSVamanaLeanVec::deserialize_training_data(std::istream& in) {
122
128
  }
123
129
 
124
130
  void IndexSVSVamanaLeanVec::create_impl(idx_t n, const float* x) {
125
- FAISS_THROW_IF_NOT(!impl);
131
+ FAISS_THROW_IF_MSG(impl, "impl already created");
126
132
  ntotal = 0;
127
133
  auto svs_metric = to_svs_metric(metric_type);
128
134
  auto svs_storage_kind = to_svs_storage_kind(storage_kind);