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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/lib/faiss/version.rb +1 -1
- data/vendor/faiss/faiss/AutoTune.cpp +3 -1
- data/vendor/faiss/faiss/Clustering.cpp +9 -1
- data/vendor/faiss/faiss/Clustering.h +8 -0
- data/vendor/faiss/faiss/IVFlib.cpp +14 -3
- data/vendor/faiss/faiss/Index.h +2 -2
- data/vendor/faiss/faiss/IndexAdditiveQuantizer.cpp +9 -10
- data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.cpp +2 -3
- data/vendor/faiss/faiss/IndexBinaryFromFloat.cpp +24 -4
- data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +16 -145
- data/vendor/faiss/faiss/IndexBinaryHNSW.h +0 -6
- data/vendor/faiss/faiss/IndexBinaryHash.cpp +5 -9
- data/vendor/faiss/faiss/IndexBinaryIVF.cpp +8 -18
- data/vendor/faiss/faiss/IndexBinaryIVF.h +8 -1
- data/vendor/faiss/faiss/IndexEDEN.cpp +273 -0
- data/vendor/faiss/faiss/IndexEDEN.h +57 -0
- data/vendor/faiss/faiss/IndexFastScan.cpp +15 -4
- data/vendor/faiss/faiss/IndexFlat.cpp +21 -54
- data/vendor/faiss/faiss/IndexFlat.h +2 -2
- data/vendor/faiss/faiss/IndexHNSW.cpp +311 -102
- data/vendor/faiss/faiss/IndexHNSW.h +31 -7
- data/vendor/faiss/faiss/IndexIDMap.cpp +26 -8
- data/vendor/faiss/faiss/IndexIDMap.h +2 -0
- data/vendor/faiss/faiss/IndexIVF.cpp +36 -10
- data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +1 -1
- data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.cpp +3 -4
- data/vendor/faiss/faiss/IndexIVFEDEN.cpp +302 -0
- data/vendor/faiss/faiss/IndexIVFEDEN.h +70 -0
- data/vendor/faiss/faiss/IndexIVFFastScan.cpp +5 -6
- data/vendor/faiss/faiss/IndexIVFFlat.cpp +3 -4
- data/vendor/faiss/faiss/IndexIVFIndependentQuantizer.cpp +1 -1
- data/vendor/faiss/faiss/IndexIVFPQ.cpp +49 -23
- data/vendor/faiss/faiss/IndexIVFPQ.h +11 -0
- data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +0 -1
- data/vendor/faiss/faiss/IndexIVFRaBitQ.cpp +19 -49
- data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.cpp +180 -76
- data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.h +5 -4
- data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +8 -6
- data/vendor/faiss/faiss/IndexLSH.cpp +2 -3
- data/vendor/faiss/faiss/IndexLattice.cpp +5 -0
- data/vendor/faiss/faiss/IndexNNDescent.cpp +9 -2
- data/vendor/faiss/faiss/IndexNSG.cpp +7 -2
- data/vendor/faiss/faiss/IndexPQ.cpp +6 -8
- data/vendor/faiss/faiss/IndexPreTransform.cpp +15 -0
- data/vendor/faiss/faiss/IndexRaBitQ.cpp +2 -2
- data/vendor/faiss/faiss/IndexRaBitQFastScan.cpp +1 -2
- data/vendor/faiss/faiss/IndexRaBitQFastScan.h +5 -1
- data/vendor/faiss/faiss/IndexRefine.cpp +30 -1
- data/vendor/faiss/faiss/IndexReplicas.cpp +1 -2
- data/vendor/faiss/faiss/IndexShards.cpp +5 -5
- data/vendor/faiss/faiss/IndexShardsIVF.cpp +6 -5
- data/vendor/faiss/faiss/MetaIndexes.cpp +2 -4
- data/vendor/faiss/faiss/SuperKMeans.cpp +286 -247
- data/vendor/faiss/faiss/SuperKMeans.h +33 -2
- data/vendor/faiss/faiss/VectorTransform.cpp +71 -2
- data/vendor/faiss/faiss/VectorTransform.h +3 -0
- data/vendor/faiss/faiss/clone_index.cpp +8 -0
- data/vendor/faiss/faiss/factory_tools.cpp +47 -4
- data/vendor/faiss/faiss/gpu/GpuCloner.cpp +11 -11
- data/vendor/faiss/faiss/gpu/GpuClonerOptions.h +1 -5
- data/vendor/faiss/faiss/gpu/GpuDistance.h +2 -5
- data/vendor/faiss/faiss/gpu/GpuIndex.h +38 -16
- data/vendor/faiss/faiss/gpu/GpuIndexCagra.h +71 -1
- data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +17 -0
- data/vendor/faiss/faiss/gpu/GpuIndexIVFScalarQuantizer.h +16 -0
- data/vendor/faiss/faiss/gpu/perf/PerfClustering.cpp +1 -1
- data/vendor/faiss/faiss/gpu/perf/PerfIVFPQAdd.cpp +2 -2
- data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFScalarQuantizer.cpp +180 -0
- data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFFlat.h +1 -5
- data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFPQ.h +88 -0
- data/vendor/faiss/faiss/gpu_metal/impl/MetalIVFPQ.h +134 -0
- data/vendor/faiss/faiss/impl/AdditiveQuantizer.cpp +1 -1
- data/vendor/faiss/faiss/impl/ClusteringInitialization.cpp +7 -4
- data/vendor/faiss/faiss/impl/DistanceComputer.h +34 -0
- data/vendor/faiss/faiss/impl/EDENQuantizer.h +119 -0
- data/vendor/faiss/faiss/impl/HNSW.cpp +528 -267
- data/vendor/faiss/faiss/impl/HNSW.h +46 -7
- data/vendor/faiss/faiss/impl/IDSelector.h +44 -0
- data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +2 -2
- data/vendor/faiss/faiss/impl/NNDescent.cpp +10 -3
- data/vendor/faiss/faiss/impl/NSG.cpp +3 -1
- data/vendor/faiss/faiss/impl/Panorama.h +20 -9
- data/vendor/faiss/faiss/impl/PolysemousTraining.cpp +152 -84
- data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +38 -26
- data/vendor/faiss/faiss/impl/RaBitQUtils.cpp +45 -37
- data/vendor/faiss/faiss/impl/RaBitQUtils.h +35 -0
- data/vendor/faiss/faiss/impl/RaBitQuantizer.cpp +239 -72
- data/vendor/faiss/faiss/impl/RaBitQuantizer.h +66 -4
- data/vendor/faiss/faiss/impl/RaBitQuantizerMultiBit.cpp +4 -13
- data/vendor/faiss/faiss/impl/ResultHandler.h +34 -34
- data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +287 -84
- data/vendor/faiss/faiss/impl/ScalarQuantizer.h +26 -10
- data/vendor/faiss/faiss/impl/ThreadedIndex-inl.h +2 -2
- data/vendor/faiss/faiss/impl/VisitedTable.cpp +22 -2
- data/vendor/faiss/faiss/impl/VisitedTable.h +20 -0
- data/vendor/faiss/faiss/impl/binary_hamming/IndexBinaryIVF_impl.h +90 -14
- data/vendor/faiss/faiss/impl/binary_hamming/avx2.cpp +4 -4
- data/vendor/faiss/faiss/impl/expanded_scanners.h +5 -1
- data/vendor/faiss/faiss/impl/fast_scan/decompose_qbs.h +1 -0
- data/vendor/faiss/faiss/impl/fast_scan/dispatching.h +35 -2
- data/vendor/faiss/faiss/impl/hnsw/LockVector.cpp +1 -1
- data/vendor/faiss/faiss/impl/index_read.cpp +491 -50
- data/vendor/faiss/faiss/impl/index_write.cpp +86 -30
- data/vendor/faiss/faiss/impl/lattice_Zn.cpp +8 -9
- data/vendor/faiss/faiss/impl/platform_macros.h +3 -1
- data/vendor/faiss/faiss/impl/polysemous_training/avx512.cpp +284 -0
- data/vendor/faiss/faiss/impl/polysemous_training/dispatch.h +115 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQScanner_impl.h +73 -39
- data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQ_QueryTables.cpp +0 -1
- data/vendor/faiss/faiss/impl/pq_code_distance/PQDistanceComputer_impl.h +26 -15
- data/vendor/faiss/faiss/impl/pq_code_distance/avx2.cpp +4 -4
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-generic.cpp +4 -4
- data/vendor/faiss/faiss/impl/result_handler/ResultHandler.cpp +195 -0
- data/vendor/faiss/faiss/impl/result_handler/avx2.cpp +133 -0
- data/vendor/faiss/faiss/impl/result_handler/avx512.cpp +281 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx2.cpp +72 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx512.cpp +228 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer.cpp +887 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/distance_computers.h +2 -2
- data/vendor/faiss/faiss/impl/scalar_quantizer/quantizers.h +9 -8
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx2.cpp +90 -24
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-impl.h +30 -30
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-spr.cpp +4 -5
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512.cpp +101 -34
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-dispatch.h +169 -13
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-neon.cpp +125 -26
- data/vendor/faiss/faiss/impl/simd_dispatch.h +70 -31
- data/vendor/faiss/faiss/index_factory.cpp +40 -7
- data/vendor/faiss/faiss/invlists/DirectMap.cpp +1 -1
- data/vendor/faiss/faiss/invlists/InvertedLists.cpp +9 -6
- data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +29 -8
- data/vendor/faiss/faiss/python/python_callbacks.cpp +3 -1
- data/vendor/faiss/faiss/svs/IndexSVSFaissUtils.h +60 -0
- data/vendor/faiss/faiss/svs/IndexSVSFlat.cpp +26 -1
- data/vendor/faiss/faiss/svs/IndexSVSFlat.h +13 -0
- data/vendor/faiss/faiss/svs/IndexSVSIVF.cpp +1 -1
- data/vendor/faiss/faiss/svs/IndexSVSIVFLeanVec.cpp +1 -1
- data/vendor/faiss/faiss/svs/IndexSVSVamana.cpp +47 -5
- data/vendor/faiss/faiss/svs/IndexSVSVamana.h +23 -3
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLVQ.cpp +4 -2
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLVQ.h +2 -1
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.cpp +10 -4
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.h +2 -1
- data/vendor/faiss/faiss/utils/approx_topk_hamming/approx_topk_hamming.h +1 -1
- data/vendor/faiss/faiss/utils/distances.cpp +30 -11
- data/vendor/faiss/faiss/utils/distances_dispatch.h +30 -24
- data/vendor/faiss/faiss/utils/distances_fused/distances_fused.cpp +1 -1
- data/vendor/faiss/faiss/utils/distances_simd.cpp +4 -3
- data/vendor/faiss/faiss/utils/extra_distances.cpp +4 -14
- data/vendor/faiss/faiss/utils/extra_distances.h +1 -2
- data/vendor/faiss/faiss/utils/hamming.cpp +16 -10
- data/vendor/faiss/faiss/utils/hamming.h +10 -1
- data/vendor/faiss/faiss/utils/hamming_distance/common.h +14 -3
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512_vpopcnt.cpp +24 -0
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-avx512.h +1 -1
- data/vendor/faiss/faiss/utils/hamming_distance/{hamming_computer-avx512_spr.h → hamming_computer-avx512_vpopcnt.h} +85 -24
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_impl.h +141 -0
- data/vendor/faiss/faiss/utils/quantize_lut.cpp +29 -8
- data/vendor/faiss/faiss/utils/rabitq_simd.h +202 -0
- data/vendor/faiss/faiss/utils/simd_impl/distances_arm_sve.cpp +194 -30
- data/vendor/faiss/faiss/utils/simd_impl/distances_avx2.cpp +0 -1
- data/vendor/faiss/faiss/utils/simd_impl/distances_avx512.cpp +263 -15
- data/vendor/faiss/faiss/utils/simd_impl/distances_rvv.cpp +198 -18
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx2.cpp +245 -0
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512.cpp +330 -40
- data/vendor/faiss/faiss/utils/simd_impl/{rabitq_avx512_spr.cpp → rabitq_avx512_vpopcnt.cpp} +112 -23
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_neon.cpp +11 -0
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_rvv.cpp +143 -6
- data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_dispatch.h +2 -7
- data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels.h +6 -1
- data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels_sve.cpp +34 -0
- data/vendor/faiss/faiss/utils/simd_levels.cpp +196 -47
- data/vendor/faiss/faiss/utils/simd_levels.h +33 -8
- data/vendor/faiss/faiss/utils/utils.cpp +9 -27
- metadata +21 -5
- 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 == "
|
|
319
|
-
storage = SVSStorageKind::
|
|
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],
|
|
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, "
|
|
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::
|
|
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::
|
|
712
|
+
d, std::stoul(arg_string), mt, SVSStorageKind::SVS_SQ8);
|
|
692
713
|
}
|
|
693
|
-
FAISS_ASSERT(false && "Unsupported SVS index type for
|
|
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
|
-
|
|
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
|
-
|
|
375
|
-
|
|
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
|
|
444
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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);
|