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
|
@@ -30,11 +30,13 @@
|
|
|
30
30
|
#include <faiss/Index2Layer.h>
|
|
31
31
|
#include <faiss/IndexAdditiveQuantizer.h>
|
|
32
32
|
#include <faiss/IndexAdditiveQuantizerFastScan.h>
|
|
33
|
+
#include <faiss/IndexEDEN.h>
|
|
33
34
|
#include <faiss/IndexFlat.h>
|
|
34
35
|
#include <faiss/IndexHNSW.h>
|
|
35
36
|
#include <faiss/IndexIVF.h>
|
|
36
37
|
#include <faiss/IndexIVFAdditiveQuantizer.h>
|
|
37
38
|
#include <faiss/IndexIVFAdditiveQuantizerFastScan.h>
|
|
39
|
+
#include <faiss/IndexIVFEDEN.h>
|
|
38
40
|
#include <faiss/IndexIVFFlat.h>
|
|
39
41
|
#include <faiss/IndexIVFFlatPanorama.h>
|
|
40
42
|
#include <faiss/IndexIVFIndependentQuantizer.h>
|
|
@@ -68,6 +70,7 @@
|
|
|
68
70
|
#include <faiss/IndexScalarQuantizer.h>
|
|
69
71
|
#include <faiss/MetaIndexes.h>
|
|
70
72
|
#include <faiss/VectorTransform.h>
|
|
73
|
+
#include <faiss/impl/EDENQuantizer.h>
|
|
71
74
|
|
|
72
75
|
#include <faiss/IndexBinaryFlat.h>
|
|
73
76
|
#include <faiss/IndexBinaryFromFloat.h>
|
|
@@ -337,7 +340,9 @@ std::unique_ptr<VectorTransform> read_VectorTransform_up(IOReader* f) {
|
|
|
337
340
|
READVECTOR(lt->b);
|
|
338
341
|
FAISS_THROW_IF_NOT(
|
|
339
342
|
lt->A.size() >= size_t(lt->d_in) * size_t(lt->d_out));
|
|
340
|
-
|
|
343
|
+
FAISS_THROW_IF_MSG(
|
|
344
|
+
lt->have_bias && lt->b.size() < size_t(lt->d_out),
|
|
345
|
+
"bias vector smaller than d_out");
|
|
341
346
|
lt->set_is_orthonormal();
|
|
342
347
|
vt = std::move(lt);
|
|
343
348
|
} else if (h == fourcc("RmDT")) {
|
|
@@ -540,7 +545,7 @@ std::unique_ptr<InvertedLists> read_InvertedLists_up(
|
|
|
540
545
|
READ1(n_levels);
|
|
541
546
|
FAISS_THROW_IF_NOT_FMT(
|
|
542
547
|
n_levels > 0, "invalid ilpn n_levels %zd", n_levels);
|
|
543
|
-
constexpr size_t bs = Panorama::
|
|
548
|
+
constexpr size_t bs = Panorama::kLegacyBatchSize;
|
|
544
549
|
auto ailp = std::make_unique<ArrayInvertedListsPanorama>(
|
|
545
550
|
nlist, code_size, n_levels, bs);
|
|
546
551
|
std::vector<size_t> sizes(nlist);
|
|
@@ -732,7 +737,9 @@ void read_ProductQuantizer(ProductQuantizer* pq, IOReader* f) {
|
|
|
732
737
|
FAISS_THROW_IF_NOT_FMT(
|
|
733
738
|
pq->M > 0, "invalid ProductQuantizer M=%zd (must be > 0)", pq->M);
|
|
734
739
|
FAISS_THROW_IF_NOT_FMT(
|
|
735
|
-
pq->nbits
|
|
740
|
+
pq->nbits >= 1 && pq->nbits <= 24,
|
|
741
|
+
"invalid ProductQuantizer nbits=%zd (must be in [1, 24])",
|
|
742
|
+
pq->nbits);
|
|
736
743
|
{
|
|
737
744
|
size_t ksub = size_t{1} << pq->nbits;
|
|
738
745
|
size_t n = mul_no_overflow(pq->d, ksub, "PQ centroids");
|
|
@@ -814,6 +821,10 @@ static void read_AdditiveQuantizer(AdditiveQuantizer& aq, IOReader* f) {
|
|
|
814
821
|
}
|
|
815
822
|
|
|
816
823
|
aq.set_derived_values();
|
|
824
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
825
|
+
aq.code_size > 0,
|
|
826
|
+
"invalid AdditiveQuantizer: nbits sum to 0 bits, code_size %zd",
|
|
827
|
+
aq.code_size);
|
|
817
828
|
|
|
818
829
|
// Sanity-check codebooks size without knowing the effective dimension.
|
|
819
830
|
// codebooks stores effective_d * total_codebook_size floats, so its
|
|
@@ -862,6 +873,11 @@ static void validate_fastscan_fields(
|
|
|
862
873
|
index_type,
|
|
863
874
|
M,
|
|
864
875
|
ksub);
|
|
876
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
877
|
+
ksub == 16,
|
|
878
|
+
"%s: invalid ksub=%zd (fast-scan requires nbits=4 / ksub=16)",
|
|
879
|
+
index_type,
|
|
880
|
+
ksub);
|
|
865
881
|
FAISS_THROW_IF_NOT_FMT(
|
|
866
882
|
bbs > 0 && bbs % 32 == 0,
|
|
867
883
|
"%s: invalid bbs=%d (must be > 0 and a multiple of 32)",
|
|
@@ -1086,6 +1102,30 @@ void read_ScalarQuantizer(
|
|
|
1086
1102
|
case ScalarQuantizer::QT_8bit_tqmse:
|
|
1087
1103
|
expected = 256 + 255;
|
|
1088
1104
|
break;
|
|
1105
|
+
case ScalarQuantizer::QT_1bit_eden:
|
|
1106
|
+
expected = 2 + 1; // 2^bits centroids + (2^bits - 1) boundaries
|
|
1107
|
+
break;
|
|
1108
|
+
case ScalarQuantizer::QT_2bit_eden:
|
|
1109
|
+
expected = 4 + 3;
|
|
1110
|
+
break;
|
|
1111
|
+
case ScalarQuantizer::QT_3bit_eden:
|
|
1112
|
+
expected = 8 + 7;
|
|
1113
|
+
break;
|
|
1114
|
+
case ScalarQuantizer::QT_4bit_eden:
|
|
1115
|
+
expected = 16 + 15;
|
|
1116
|
+
break;
|
|
1117
|
+
case ScalarQuantizer::QT_5bit_eden:
|
|
1118
|
+
expected = 32 + 31;
|
|
1119
|
+
break;
|
|
1120
|
+
case ScalarQuantizer::QT_6bit_eden:
|
|
1121
|
+
expected = 64 + 63;
|
|
1122
|
+
break;
|
|
1123
|
+
case ScalarQuantizer::QT_7bit_eden:
|
|
1124
|
+
expected = 128 + 127;
|
|
1125
|
+
break;
|
|
1126
|
+
case ScalarQuantizer::QT_8bit_eden:
|
|
1127
|
+
expected = 256 + 255;
|
|
1128
|
+
break;
|
|
1089
1129
|
case ScalarQuantizer::QT_2bit_tq:
|
|
1090
1130
|
case ScalarQuantizer::QT_3bit_tq:
|
|
1091
1131
|
case ScalarQuantizer::QT_4bit_tq:
|
|
@@ -1124,8 +1164,7 @@ void read_ScalarQuantizer(
|
|
|
1124
1164
|
}
|
|
1125
1165
|
}
|
|
1126
1166
|
|
|
1127
|
-
// TurboQ full types: extract seed and qjl_type from trained
|
|
1128
|
-
// regenerate projection matrix.
|
|
1167
|
+
// TurboQ full types: extract seed and qjl_type from trained.
|
|
1129
1168
|
if (ScalarQuantizer::TurboQuantRefine::is_turboq_full(ivsc->qtype) &&
|
|
1130
1169
|
ivsc->trained.size() >= 3) {
|
|
1131
1170
|
size_t n = ivsc->trained.size();
|
|
@@ -1134,7 +1173,6 @@ void read_ScalarQuantizer(
|
|
|
1134
1173
|
ivsc->turboq_refine.seed =
|
|
1135
1174
|
ScalarQuantizer::TurboQuantRefine::unpack_seed(
|
|
1136
1175
|
ivsc->trained[n - 3], ivsc->trained[n - 2]);
|
|
1137
|
-
ivsc->turboq_refine.init_projection(ivsc->d);
|
|
1138
1176
|
}
|
|
1139
1177
|
}
|
|
1140
1178
|
|
|
@@ -1339,13 +1377,15 @@ static void read_NNDescent(NNDescent& nnd, IOReader* f) {
|
|
|
1339
1377
|
READVECTOR(nnd.final_graph);
|
|
1340
1378
|
// Validate neighbor IDs in the graph
|
|
1341
1379
|
if (nnd.has_built && nnd.K > 0 && nnd.ntotal > 0) {
|
|
1380
|
+
const size_t expected_final_graph_size = mul_no_overflow(
|
|
1381
|
+
(size_t)nnd.ntotal, (size_t)nnd.K, "NNDescent final_graph");
|
|
1342
1382
|
FAISS_THROW_IF_NOT_FMT(
|
|
1343
|
-
nnd.final_graph.size() ==
|
|
1383
|
+
nnd.final_graph.size() == expected_final_graph_size,
|
|
1344
1384
|
"NNDescent final_graph size %zu != ntotal * K (%d * %d = %zu)",
|
|
1345
1385
|
nnd.final_graph.size(),
|
|
1346
1386
|
nnd.ntotal,
|
|
1347
1387
|
nnd.K,
|
|
1348
|
-
|
|
1388
|
+
expected_final_graph_size);
|
|
1349
1389
|
for (size_t i = 0; i < nnd.final_graph.size(); i++) {
|
|
1350
1390
|
int id = nnd.final_graph[i];
|
|
1351
1391
|
FAISS_THROW_IF_NOT_FMT(
|
|
@@ -1402,6 +1442,64 @@ static void read_RaBitQuantizer(
|
|
|
1402
1442
|
expected_d);
|
|
1403
1443
|
}
|
|
1404
1444
|
|
|
1445
|
+
static void read_EDENScalarQuantizer(
|
|
1446
|
+
ScalarQuantizer& sq,
|
|
1447
|
+
EDENScaleType& scale_type,
|
|
1448
|
+
IOReader* f,
|
|
1449
|
+
int expected_d,
|
|
1450
|
+
MetricType expected_metric_type,
|
|
1451
|
+
bool read_scale_type) {
|
|
1452
|
+
size_t d;
|
|
1453
|
+
size_t stored_code_size;
|
|
1454
|
+
size_t nb_bits;
|
|
1455
|
+
|
|
1456
|
+
READ1(d);
|
|
1457
|
+
READ1(stored_code_size);
|
|
1458
|
+
int metric_type_int;
|
|
1459
|
+
READ1(metric_type_int);
|
|
1460
|
+
const MetricType metric_type = metric_type_from_int(metric_type_int);
|
|
1461
|
+
READ1(nb_bits);
|
|
1462
|
+
if (read_scale_type) {
|
|
1463
|
+
int scale_type_int;
|
|
1464
|
+
READ1(scale_type_int);
|
|
1465
|
+
if (scale_type_int == 0) {
|
|
1466
|
+
scale_type = EDENScaleType_UNBIASED;
|
|
1467
|
+
} else {
|
|
1468
|
+
scale_type = static_cast<EDENScaleType>(scale_type_int);
|
|
1469
|
+
}
|
|
1470
|
+
} else {
|
|
1471
|
+
scale_type = EDENScaleType_UNBIASED;
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
1475
|
+
d == static_cast<size_t>(expected_d),
|
|
1476
|
+
"EDEN ScalarQuantizer dimension mismatch: sq.d=%zu vs index d=%d",
|
|
1477
|
+
d,
|
|
1478
|
+
expected_d);
|
|
1479
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
1480
|
+
metric_type == expected_metric_type,
|
|
1481
|
+
"EDEN ScalarQuantizer metric mismatch: stored=%d vs index=%d",
|
|
1482
|
+
metric_type_int,
|
|
1483
|
+
static_cast<int>(expected_metric_type));
|
|
1484
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
1485
|
+
nb_bits >= 1 && nb_bits <= 8,
|
|
1486
|
+
"invalid EDEN nb_bits=%zu (must be in [1, 8])",
|
|
1487
|
+
nb_bits);
|
|
1488
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
1489
|
+
scale_type == EDENScaleType_UNBIASED ||
|
|
1490
|
+
scale_type == EDENScaleType_BIASED,
|
|
1491
|
+
"invalid EDEN scale_type=%d",
|
|
1492
|
+
static_cast<int>(scale_type));
|
|
1493
|
+
sq = ScalarQuantizer(d, eden_utils::quantizer_type_for_bits(nb_bits));
|
|
1494
|
+
sq.train(0, nullptr);
|
|
1495
|
+
const size_t expected_code_size = eden_utils::code_size(d, nb_bits);
|
|
1496
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
1497
|
+
stored_code_size == expected_code_size,
|
|
1498
|
+
"EDEN ScalarQuantizer code_size mismatch: stored=%zu vs expected=%zu",
|
|
1499
|
+
stored_code_size,
|
|
1500
|
+
expected_code_size);
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1405
1503
|
void read_direct_map(DirectMap* dm, IOReader* f) {
|
|
1406
1504
|
char maintain_direct_map;
|
|
1407
1505
|
READ1(maintain_direct_map);
|
|
@@ -1453,6 +1551,45 @@ ArrayInvertedLists* set_array_invlist(
|
|
|
1453
1551
|
return result;
|
|
1454
1552
|
}
|
|
1455
1553
|
|
|
1554
|
+
static void validate_ivfpq_precomputed_table_size(
|
|
1555
|
+
const Index* quantizer,
|
|
1556
|
+
const ProductQuantizer& pq) {
|
|
1557
|
+
// The precomputed table is not stored; precompute_table() rebuilds it on
|
|
1558
|
+
// load at a size derived from attacker-controlled header fields. Bound
|
|
1559
|
+
// every table initialize_IVFPQ_precomputed_table() may allocate.
|
|
1560
|
+
const size_t m_ksub =
|
|
1561
|
+
mul_no_overflow(pq.M, pq.ksub, "IVFPQ precomputed_table");
|
|
1562
|
+
// type 1: nlist (== quantizer->ntotal) * pq.M * pq.ksub.
|
|
1563
|
+
size_t precompute_elems = mul_no_overflow(
|
|
1564
|
+
static_cast<size_t>(quantizer->ntotal),
|
|
1565
|
+
m_ksub,
|
|
1566
|
+
"IVFPQ precomputed_table");
|
|
1567
|
+
// type 2 (MultiIndexQuantizer coarse quantizer): cpq.ksub * pq.M * pq.ksub,
|
|
1568
|
+
// plus a temporary quantizer->d * cpq.ksub centroid table. Both derive from
|
|
1569
|
+
// the coarse PQ's ksub, which is independent of quantizer->ntotal, so the
|
|
1570
|
+
// type-1 bound above does not cover them.
|
|
1571
|
+
if (const auto* miq = dynamic_cast<const MultiIndexQuantizer*>(quantizer)) {
|
|
1572
|
+
const size_t cpq_ksub = miq->pq.ksub;
|
|
1573
|
+
const size_t type2_table =
|
|
1574
|
+
mul_no_overflow(cpq_ksub, m_ksub, "IVFPQ precomputed_table");
|
|
1575
|
+
const size_t type2_centroids = mul_no_overflow(
|
|
1576
|
+
static_cast<size_t>(quantizer->d),
|
|
1577
|
+
cpq_ksub,
|
|
1578
|
+
"IVFPQ precomputed_table");
|
|
1579
|
+
if (type2_table > precompute_elems) {
|
|
1580
|
+
precompute_elems = type2_table;
|
|
1581
|
+
}
|
|
1582
|
+
if (type2_centroids > precompute_elems) {
|
|
1583
|
+
precompute_elems = type2_centroids;
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
1587
|
+
precompute_elems <
|
|
1588
|
+
get_deserialization_vector_byte_limit() / sizeof(float),
|
|
1589
|
+
"IVFPQ precomputed_table allocation would exceed deserialization "
|
|
1590
|
+
"byte limit");
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1456
1593
|
static std::unique_ptr<IndexIVFPQ> read_ivfpq(
|
|
1457
1594
|
IOReader* f,
|
|
1458
1595
|
uint32_t h,
|
|
@@ -1470,6 +1607,8 @@ static std::unique_ptr<IndexIVFPQ> read_ivfpq(
|
|
|
1470
1607
|
|
|
1471
1608
|
std::vector<std::vector<idx_t>> ids;
|
|
1472
1609
|
read_ivf_header(ivpq.get(), f, legacy ? &ids : nullptr);
|
|
1610
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
1611
|
+
ivpq->quantizer != nullptr, "IVFPQ coarse quantizer is null");
|
|
1473
1612
|
READ1_BOOL(ivpq->by_residual);
|
|
1474
1613
|
READ1(ivpq->code_size);
|
|
1475
1614
|
read_ProductQuantizer(&ivpq->pq, f);
|
|
@@ -1488,6 +1627,8 @@ static std::unique_ptr<IndexIVFPQ> read_ivfpq(
|
|
|
1488
1627
|
ivpq->use_precomputed_table = 0;
|
|
1489
1628
|
if (ivpq->by_residual) {
|
|
1490
1629
|
if ((io_flags & IO_FLAG_SKIP_PRECOMPUTE_TABLE) == 0) {
|
|
1630
|
+
validate_ivfpq_precomputed_table_size(
|
|
1631
|
+
ivpq->quantizer, ivpq->pq);
|
|
1491
1632
|
ivpq->precompute_table();
|
|
1492
1633
|
}
|
|
1493
1634
|
}
|
|
@@ -1516,7 +1657,29 @@ static std::unique_ptr<IndexIVFPQ> read_ivfpq(
|
|
|
1516
1657
|
|
|
1517
1658
|
int read_old_fmt_hack = 0;
|
|
1518
1659
|
|
|
1660
|
+
namespace {
|
|
1661
|
+
|
|
1662
|
+
constexpr int kMaxIndexNestingDepth = 50;
|
|
1663
|
+
thread_local int index_read_nesting_depth = 0;
|
|
1664
|
+
|
|
1665
|
+
struct IndexNestingGuard {
|
|
1666
|
+
IndexNestingGuard() {
|
|
1667
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
1668
|
+
index_read_nesting_depth < kMaxIndexNestingDepth,
|
|
1669
|
+
"faiss index nesting depth exceeds limit of %d; "
|
|
1670
|
+
"input may be corrupt or malicious",
|
|
1671
|
+
kMaxIndexNestingDepth);
|
|
1672
|
+
++index_read_nesting_depth;
|
|
1673
|
+
}
|
|
1674
|
+
~IndexNestingGuard() {
|
|
1675
|
+
--index_read_nesting_depth;
|
|
1676
|
+
}
|
|
1677
|
+
};
|
|
1678
|
+
|
|
1679
|
+
} // namespace
|
|
1680
|
+
|
|
1519
1681
|
std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
1682
|
+
IndexNestingGuard nesting_guard;
|
|
1520
1683
|
std::unique_ptr<Index> idx;
|
|
1521
1684
|
uint32_t h;
|
|
1522
1685
|
READ1(h);
|
|
@@ -1527,9 +1690,15 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
1527
1690
|
int d;
|
|
1528
1691
|
size_t n_levels, batch_size;
|
|
1529
1692
|
READ1(d);
|
|
1693
|
+
// This branch does not go through read_index_header, so the range
|
|
1694
|
+
// check that guards `d` for every other index type has to be
|
|
1695
|
+
// repeated here.
|
|
1696
|
+
FAISS_CHECK_RANGE(d, 0, (1 << 20) + 1);
|
|
1530
1697
|
READ1(n_levels);
|
|
1531
1698
|
FAISS_THROW_IF_NOT_FMT(n_levels > 0, "invalid n_levels %zd", n_levels);
|
|
1532
1699
|
READ1(batch_size);
|
|
1700
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
1701
|
+
batch_size > 0, "invalid IxFP batch_size %zd", batch_size);
|
|
1533
1702
|
std::unique_ptr<IndexFlatPanorama> idxp;
|
|
1534
1703
|
if (h == fourcc("IxFP")) {
|
|
1535
1704
|
idxp = std::make_unique<IndexFlatL2Panorama>(
|
|
@@ -1539,9 +1708,36 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
1539
1708
|
d, n_levels, batch_size);
|
|
1540
1709
|
}
|
|
1541
1710
|
READ1(idxp->ntotal);
|
|
1711
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
1712
|
+
idxp->ntotal >= 0,
|
|
1713
|
+
"invalid ntotal %" PRId64 " read from IxFP index",
|
|
1714
|
+
(int64_t)idxp->ntotal);
|
|
1542
1715
|
READ1_BOOL(idxp->is_trained);
|
|
1543
1716
|
READVECTOR(idxp->codes);
|
|
1544
1717
|
READVECTOR(idxp->cum_sums);
|
|
1718
|
+
const size_t ntotal = (size_t)idxp->ntotal;
|
|
1719
|
+
const size_t num_batches =
|
|
1720
|
+
ntotal / batch_size + (ntotal % batch_size != 0);
|
|
1721
|
+
const size_t num_slots = mul_no_overflow(
|
|
1722
|
+
num_batches,
|
|
1723
|
+
batch_size,
|
|
1724
|
+
"IndexFlatPanorama num_batches*batch_size");
|
|
1725
|
+
const size_t expected_codes_size = mul_no_overflow(
|
|
1726
|
+
num_slots, idxp->code_size, "IndexFlatPanorama codes");
|
|
1727
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
1728
|
+
idxp->codes.size() == expected_codes_size,
|
|
1729
|
+
"IndexFlatPanorama codes size mismatch: got %zu, expected %zu",
|
|
1730
|
+
idxp->codes.size(),
|
|
1731
|
+
expected_codes_size);
|
|
1732
|
+
const size_t expected_cum_sums_size = mul_no_overflow(
|
|
1733
|
+
num_slots,
|
|
1734
|
+
idxp->pano.n_levels + 1,
|
|
1735
|
+
"IndexFlatPanorama cum_sums");
|
|
1736
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
1737
|
+
idxp->cum_sums.size() == expected_cum_sums_size,
|
|
1738
|
+
"IndexFlatPanorama cum_sums size mismatch: got %zu, expected %zu",
|
|
1739
|
+
idxp->cum_sums.size(),
|
|
1740
|
+
expected_cum_sums_size);
|
|
1545
1741
|
idxp->verbose = false;
|
|
1546
1742
|
idx = std::move(idxp);
|
|
1547
1743
|
} else if (
|
|
@@ -1558,7 +1754,11 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
1558
1754
|
idxf->code_size = idxf->d * sizeof(float);
|
|
1559
1755
|
read_xb_vector(idxf->codes, f);
|
|
1560
1756
|
FAISS_THROW_IF_NOT(
|
|
1561
|
-
idxf->codes.size() ==
|
|
1757
|
+
idxf->codes.size() ==
|
|
1758
|
+
mul_no_overflow(
|
|
1759
|
+
(size_t)idxf->ntotal,
|
|
1760
|
+
idxf->code_size,
|
|
1761
|
+
"IndexFlat codes"));
|
|
1562
1762
|
idx = std::move(idxf);
|
|
1563
1763
|
} else if (h == fourcc("IxHE") || h == fourcc("IxHe")) {
|
|
1564
1764
|
auto idxl = std::make_unique<IndexLSH>();
|
|
@@ -1597,7 +1797,11 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
1597
1797
|
FAISS_THROW_IF_NOT(
|
|
1598
1798
|
idxl->rrot.d_in == idxl->d && idxl->rrot.d_out == idxl->nbits);
|
|
1599
1799
|
FAISS_THROW_IF_NOT(
|
|
1600
|
-
idxl->codes.size() ==
|
|
1800
|
+
idxl->codes.size() ==
|
|
1801
|
+
mul_no_overflow(
|
|
1802
|
+
(size_t)idxl->ntotal,
|
|
1803
|
+
idxl->code_size,
|
|
1804
|
+
"IndexLSH codes"));
|
|
1601
1805
|
idx = std::move(idxl);
|
|
1602
1806
|
} else if (
|
|
1603
1807
|
h == fourcc("IxPQ") || h == fourcc("IxPo") || h == fourcc("IxPq")) {
|
|
@@ -1607,8 +1811,16 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
1607
1811
|
read_ProductQuantizer(&idxp->pq, f);
|
|
1608
1812
|
idxp->code_size = idxp->pq.code_size;
|
|
1609
1813
|
read_vector(idxp->codes, f);
|
|
1814
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
1815
|
+
idxp->code_size > 0 || idxp->ntotal == 0,
|
|
1816
|
+
"IndexPQ with ntotal > 0 must have code_size > 0 "
|
|
1817
|
+
"(corrupt ProductQuantizer nbits?)");
|
|
1610
1818
|
FAISS_THROW_IF_NOT(
|
|
1611
|
-
idxp->codes.size() ==
|
|
1819
|
+
idxp->codes.size() ==
|
|
1820
|
+
mul_no_overflow(
|
|
1821
|
+
(size_t)idxp->ntotal,
|
|
1822
|
+
idxp->code_size,
|
|
1823
|
+
"IndexPQ codes"));
|
|
1612
1824
|
if (h == fourcc("IxPo") || h == fourcc("IxPq")) {
|
|
1613
1825
|
READ1(idxp->search_type);
|
|
1614
1826
|
READ1_BOOL(idxp->encode_signs);
|
|
@@ -1636,7 +1848,11 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
1636
1848
|
idxr->code_size, idxr->rq.code_size, "IndexResidualQuantizer");
|
|
1637
1849
|
read_vector(idxr->codes, f);
|
|
1638
1850
|
FAISS_THROW_IF_NOT(
|
|
1639
|
-
idxr->codes.size() ==
|
|
1851
|
+
idxr->codes.size() ==
|
|
1852
|
+
mul_no_overflow(
|
|
1853
|
+
(size_t)idxr->ntotal,
|
|
1854
|
+
idxr->code_size,
|
|
1855
|
+
"IndexResidualQuantizer codes"));
|
|
1640
1856
|
idx = std::move(idxr);
|
|
1641
1857
|
} else if (h == fourcc("IxLS")) {
|
|
1642
1858
|
auto idxr = std::make_unique<IndexLocalSearchQuantizer>();
|
|
@@ -1651,7 +1867,11 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
1651
1867
|
"IndexLocalSearchQuantizer");
|
|
1652
1868
|
read_vector(idxr->codes, f);
|
|
1653
1869
|
FAISS_THROW_IF_NOT(
|
|
1654
|
-
idxr->codes.size() ==
|
|
1870
|
+
idxr->codes.size() ==
|
|
1871
|
+
mul_no_overflow(
|
|
1872
|
+
(size_t)idxr->ntotal,
|
|
1873
|
+
idxr->code_size,
|
|
1874
|
+
"IndexLocalSearchQuantizer codes"));
|
|
1655
1875
|
idx = std::move(idxr);
|
|
1656
1876
|
} else if (h == fourcc("IxPR")) {
|
|
1657
1877
|
auto idxpr = std::make_unique<IndexProductResidualQuantizer>();
|
|
@@ -1666,7 +1886,11 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
1666
1886
|
"IndexProductResidualQuantizer");
|
|
1667
1887
|
read_vector(idxpr->codes, f);
|
|
1668
1888
|
FAISS_THROW_IF_NOT(
|
|
1669
|
-
idxpr->codes.size() ==
|
|
1889
|
+
idxpr->codes.size() ==
|
|
1890
|
+
mul_no_overflow(
|
|
1891
|
+
(size_t)idxpr->ntotal,
|
|
1892
|
+
idxpr->code_size,
|
|
1893
|
+
"IndexProductResidualQuantizer codes"));
|
|
1670
1894
|
idx = std::move(idxpr);
|
|
1671
1895
|
} else if (h == fourcc("IxPL")) {
|
|
1672
1896
|
auto idxpl = std::make_unique<IndexProductLocalSearchQuantizer>();
|
|
@@ -1681,7 +1905,11 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
1681
1905
|
"IndexProductLocalSearchQuantizer");
|
|
1682
1906
|
read_vector(idxpl->codes, f);
|
|
1683
1907
|
FAISS_THROW_IF_NOT(
|
|
1684
|
-
idxpl->codes.size() ==
|
|
1908
|
+
idxpl->codes.size() ==
|
|
1909
|
+
mul_no_overflow(
|
|
1910
|
+
(size_t)idxpl->ntotal,
|
|
1911
|
+
idxpl->code_size,
|
|
1912
|
+
"IndexProductLocalSearchQuantizer codes"));
|
|
1685
1913
|
idx = std::move(idxpl);
|
|
1686
1914
|
} else if (h == fourcc("ImRQ")) {
|
|
1687
1915
|
auto idxr = std::make_unique<ResidualCoarseQuantizer>();
|
|
@@ -1725,6 +1953,16 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
1725
1953
|
idxr->ntotal,
|
|
1726
1954
|
idxr->rq.M);
|
|
1727
1955
|
}
|
|
1956
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
1957
|
+
idxr->rq.tot_bits <= 63,
|
|
1958
|
+
"ResidualCoarseQuantizer tot_bits too large (max 63)");
|
|
1959
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
1960
|
+
static_cast<size_t>(idxr->ntotal) ==
|
|
1961
|
+
(((size_t)1) << idxr->rq.tot_bits),
|
|
1962
|
+
"ResidualCoarseQuantizer ntotal %" PRId64
|
|
1963
|
+
" inconsistent with 2^tot_bits (tot_bits=%zu)",
|
|
1964
|
+
idxr->ntotal,
|
|
1965
|
+
idxr->rq.tot_bits);
|
|
1728
1966
|
idxr->set_beam_factor(idxr->beam_factor);
|
|
1729
1967
|
idx = std::move(idxr);
|
|
1730
1968
|
} else if (
|
|
@@ -1859,9 +2097,28 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
1859
2097
|
ivfl->code_size = ivfl->d * sizeof(float);
|
|
1860
2098
|
ArrayInvertedLists* ail = set_array_invlist(ivfl.get(), ids);
|
|
1861
2099
|
|
|
2100
|
+
// Legacy IVF serialized ids and codes as separate vectors.
|
|
2101
|
+
// Check not required in default IVF, due to single sizes vector.
|
|
2102
|
+
auto validate_legacy_codes_size = [&](size_t i) {
|
|
2103
|
+
const size_t expected_codes_bytes = mul_no_overflow(
|
|
2104
|
+
ail->ids[i].size(),
|
|
2105
|
+
ivfl->code_size,
|
|
2106
|
+
"legacy IVFFlat inverted list codes");
|
|
2107
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
2108
|
+
ail->codes[i].size() == expected_codes_bytes,
|
|
2109
|
+
"Legacy IVFFlat inverted list %zu: codes size %zu bytes "
|
|
2110
|
+
"does not match ids size %zu * code_size %zu = %zu bytes",
|
|
2111
|
+
i,
|
|
2112
|
+
ail->codes[i].size(),
|
|
2113
|
+
ail->ids[i].size(),
|
|
2114
|
+
(size_t)ivfl->code_size,
|
|
2115
|
+
expected_codes_bytes);
|
|
2116
|
+
};
|
|
2117
|
+
|
|
1862
2118
|
if (h == fourcc("IvFL")) {
|
|
1863
2119
|
for (size_t i = 0; i < ivfl->nlist; i++) {
|
|
1864
2120
|
READVECTOR(ail->codes[i]);
|
|
2121
|
+
validate_legacy_codes_size(i);
|
|
1865
2122
|
}
|
|
1866
2123
|
} else { // old format
|
|
1867
2124
|
for (size_t i = 0; i < ivfl->nlist; i++) {
|
|
@@ -1869,6 +2126,7 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
1869
2126
|
READVECTOR(vec);
|
|
1870
2127
|
ail->codes[i].resize(vec.size() * sizeof(float));
|
|
1871
2128
|
memcpy(ail->codes[i].data(), vec.data(), ail->codes[i].size());
|
|
2129
|
+
validate_legacy_codes_size(i);
|
|
1872
2130
|
}
|
|
1873
2131
|
}
|
|
1874
2132
|
idx = std::move(ivfl);
|
|
@@ -1896,7 +2154,7 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
1896
2154
|
read_ivf_header(ivfp.get(), f);
|
|
1897
2155
|
ivfp->code_size = ivfp->d * sizeof(float);
|
|
1898
2156
|
READ1(ivfp->n_levels);
|
|
1899
|
-
ivfp->batch_size = Panorama::
|
|
2157
|
+
ivfp->batch_size = Panorama::kLegacyBatchSize;
|
|
1900
2158
|
read_InvertedLists(*ivfp, f, io_flags);
|
|
1901
2159
|
idx = std::move(ivfp);
|
|
1902
2160
|
} else if (h == fourcc("IwP2")) {
|
|
@@ -1905,6 +2163,10 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
1905
2163
|
ivfp->code_size = ivfp->d * sizeof(float);
|
|
1906
2164
|
READ1(ivfp->n_levels);
|
|
1907
2165
|
READ1(ivfp->batch_size);
|
|
2166
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
2167
|
+
ivfp->batch_size > 0,
|
|
2168
|
+
"invalid IwP2 batch_size %zd",
|
|
2169
|
+
ivfp->batch_size);
|
|
1908
2170
|
read_InvertedLists(*ivfp, f, io_flags);
|
|
1909
2171
|
idx = std::move(ivfp);
|
|
1910
2172
|
} else if (h == fourcc("IwFl")) {
|
|
@@ -1919,6 +2181,12 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
1919
2181
|
read_ScalarQuantizer(&idxs->sq, f, *idxs);
|
|
1920
2182
|
read_vector(idxs->codes, f);
|
|
1921
2183
|
idxs->code_size = idxs->sq.code_size;
|
|
2184
|
+
FAISS_THROW_IF_NOT(
|
|
2185
|
+
idxs->codes.size() ==
|
|
2186
|
+
mul_no_overflow(
|
|
2187
|
+
(size_t)idxs->ntotal,
|
|
2188
|
+
idxs->code_size,
|
|
2189
|
+
"IndexScalarQuantizer codes"));
|
|
1922
2190
|
idx = std::move(idxs);
|
|
1923
2191
|
} else if (h == fourcc("IxLa")) {
|
|
1924
2192
|
int d, nsq, scale_nbit, r2;
|
|
@@ -1983,6 +2251,16 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
1983
2251
|
r2);
|
|
1984
2252
|
}
|
|
1985
2253
|
read_index_header(*idxl, f);
|
|
2254
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
2255
|
+
idxl->ntotal == 0,
|
|
2256
|
+
"IndexLattice deserialization carries no code storage; "
|
|
2257
|
+
"ntotal=%zd != 0 is corrupt",
|
|
2258
|
+
(size_t)idxl->ntotal);
|
|
2259
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
2260
|
+
idxl->d == d,
|
|
2261
|
+
"IndexLattice header d=%d inconsistent with encoded d=%d",
|
|
2262
|
+
idxl->d,
|
|
2263
|
+
d);
|
|
1986
2264
|
READVECTOR(idxl->trained);
|
|
1987
2265
|
idx = std::move(idxl);
|
|
1988
2266
|
} else if (h == fourcc("IvSQ")) { // legacy
|
|
@@ -2120,8 +2398,18 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
2120
2398
|
// Validate transform chain dimension consistency:
|
|
2121
2399
|
// chain[0].d_in must equal the outer index d, consecutive
|
|
2122
2400
|
// transforms must have matching d_out/d_in, and the last
|
|
2123
|
-
// transform's d_out must equal the sub-index d.
|
|
2124
|
-
|
|
2401
|
+
// transform's d_out must equal the sub-index d. With an empty
|
|
2402
|
+
// chain the sub-index d must equal the outer d directly, because
|
|
2403
|
+
// reconstruct() then hands the caller's buffer -- sized from the
|
|
2404
|
+
// outer d -- straight to the sub-index.
|
|
2405
|
+
if (nt == 0 && ixpt->index) {
|
|
2406
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
2407
|
+
ixpt->index->d == ixpt->d,
|
|
2408
|
+
"IndexPreTransform empty chain: sub-index d=%d "
|
|
2409
|
+
"!= index d=%d",
|
|
2410
|
+
ixpt->index->d,
|
|
2411
|
+
ixpt->d);
|
|
2412
|
+
} else if (nt > 0) {
|
|
2125
2413
|
FAISS_THROW_IF_NOT_FMT(
|
|
2126
2414
|
ixpt->chain[0]->d_in == ixpt->d,
|
|
2127
2415
|
"IndexPreTransform chain[0] d_in=%d != index d=%d",
|
|
@@ -2158,6 +2446,8 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
2158
2446
|
read_index_header(*idxrf, f);
|
|
2159
2447
|
auto base = read_index_up(f, io_flags);
|
|
2160
2448
|
auto refine = read_index_up(f, io_flags);
|
|
2449
|
+
FAISS_THROW_IF_NOT_MSG(base, "IndexRefine base index is null");
|
|
2450
|
+
FAISS_THROW_IF_NOT_MSG(refine, "IndexRefine refine index is null");
|
|
2161
2451
|
READ1(idxrf->k_factor);
|
|
2162
2452
|
// Same rationale as IndexIVFPQR k_factor above.
|
|
2163
2453
|
FAISS_THROW_IF_NOT_FMT(
|
|
@@ -2218,6 +2508,10 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
2218
2508
|
READ1(idxp->code_size_1);
|
|
2219
2509
|
READ1(idxp->code_size_2);
|
|
2220
2510
|
READ1(idxp->code_size);
|
|
2511
|
+
validate_code_size_match(
|
|
2512
|
+
idxp->code_size_1,
|
|
2513
|
+
idxp->q1.coarse_code_size(),
|
|
2514
|
+
"Index2Layer code_size_1");
|
|
2221
2515
|
validate_code_size_match(
|
|
2222
2516
|
idxp->code_size_2,
|
|
2223
2517
|
idxp->pq.code_size,
|
|
@@ -2227,32 +2521,36 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
2227
2521
|
idxp->code_size_1 + idxp->code_size_2,
|
|
2228
2522
|
"Index2Layer");
|
|
2229
2523
|
read_vector(idxp->codes, f);
|
|
2524
|
+
FAISS_THROW_IF_NOT(
|
|
2525
|
+
idxp->codes.size() ==
|
|
2526
|
+
mul_no_overflow(
|
|
2527
|
+
(size_t)idxp->ntotal,
|
|
2528
|
+
idxp->code_size,
|
|
2529
|
+
"Index2Layer codes"));
|
|
2230
2530
|
idx = std::move(idxp);
|
|
2231
2531
|
} else if (
|
|
2232
2532
|
h == fourcc("IHNf") || h == fourcc("IHNp") || h == fourcc("IHNs") ||
|
|
2233
2533
|
h == fourcc("IHN2") || h == fourcc("IHNc") || h == fourcc("IHc2") ||
|
|
2234
|
-
h == fourcc("IHfP")) {
|
|
2534
|
+
h == fourcc("IHfP") || h == fourcc("IHNr") || h == fourcc("IH00")) {
|
|
2235
2535
|
std::unique_ptr<IndexHNSW> idxhnsw;
|
|
2236
|
-
if (h == fourcc("
|
|
2536
|
+
if (h == fourcc("IH00")) {
|
|
2537
|
+
idxhnsw = std::make_unique<IndexHNSW>();
|
|
2538
|
+
} else if (h == fourcc("IHNf")) {
|
|
2237
2539
|
idxhnsw = std::make_unique<IndexHNSWFlat>();
|
|
2238
|
-
}
|
|
2239
|
-
if (h == fourcc("IHfP")) {
|
|
2540
|
+
} else if (h == fourcc("IHfP")) {
|
|
2240
2541
|
idxhnsw = std::make_unique<IndexHNSWFlatPanorama>();
|
|
2241
|
-
}
|
|
2242
|
-
if (h == fourcc("IHNp")) {
|
|
2542
|
+
} else if (h == fourcc("IHNp")) {
|
|
2243
2543
|
idxhnsw = std::make_unique<IndexHNSWPQ>();
|
|
2244
|
-
}
|
|
2245
|
-
if (h == fourcc("IHNs")) {
|
|
2544
|
+
} else if (h == fourcc("IHNs")) {
|
|
2246
2545
|
idxhnsw = std::make_unique<IndexHNSWSQ>();
|
|
2247
|
-
}
|
|
2248
|
-
if (h == fourcc("IHN2")) {
|
|
2546
|
+
} else if (h == fourcc("IHN2")) {
|
|
2249
2547
|
idxhnsw = std::make_unique<IndexHNSW2Level>();
|
|
2250
|
-
}
|
|
2251
|
-
if (h == fourcc("IHNc")) {
|
|
2548
|
+
} else if (h == fourcc("IHNc")) {
|
|
2252
2549
|
idxhnsw = std::make_unique<IndexHNSWCagra>();
|
|
2253
|
-
}
|
|
2254
|
-
if (h == fourcc("IHc2")) {
|
|
2550
|
+
} else if (h == fourcc("IHc2")) {
|
|
2255
2551
|
idxhnsw = std::make_unique<IndexHNSWCagra>();
|
|
2552
|
+
} else if (h == fourcc("IHNr")) {
|
|
2553
|
+
idxhnsw = std::make_unique<IndexHNSWRaBitQ>();
|
|
2256
2554
|
}
|
|
2257
2555
|
read_index_header(*idxhnsw, f);
|
|
2258
2556
|
if (h == fourcc("IHfP")) {
|
|
@@ -2263,12 +2561,22 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
2263
2561
|
"dynamic_cast to IndexHNSWFlatPanorama failed");
|
|
2264
2562
|
size_t nlevels;
|
|
2265
2563
|
READ1(nlevels);
|
|
2564
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
2565
|
+
nlevels > 0, "invalid IHfP n_levels %zd", nlevels);
|
|
2266
2566
|
const_cast<size_t&>(idx_panorama->num_panorama_levels) = nlevels;
|
|
2267
2567
|
const_cast<Panorama&>(idx_panorama->pano) =
|
|
2268
2568
|
Panorama(idx_panorama->d * sizeof(float), nlevels, 1);
|
|
2269
2569
|
READVECTOR(idx_panorama->cum_sums);
|
|
2270
|
-
|
|
2271
|
-
|
|
2570
|
+
// Both the search path and get_cum_sum() index cum_sums at
|
|
2571
|
+
// stride pano.n_levels + 1, which may be lower than the
|
|
2572
|
+
// serialized nlevels if set_derived_values() truncated it.
|
|
2573
|
+
FAISS_THROW_IF_NOT(
|
|
2574
|
+
idx_panorama->cum_sums.size() ==
|
|
2575
|
+
mul_no_overflow(
|
|
2576
|
+
(size_t)idx_panorama->ntotal,
|
|
2577
|
+
idx_panorama->pano.n_levels + 1,
|
|
2578
|
+
"IndexHNSWFlatPanorama cum_sums"));
|
|
2579
|
+
} else if (h == fourcc("IHNc") || h == fourcc("IHc2")) {
|
|
2272
2580
|
READ1_BOOL(idxhnsw->keep_max_size_level0);
|
|
2273
2581
|
auto idx_hnsw_cagra = dynamic_cast<IndexHNSWCagra*>(idxhnsw.get());
|
|
2274
2582
|
FAISS_THROW_IF_NOT_MSG(
|
|
@@ -2288,7 +2596,8 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
2288
2596
|
"HNSW levels size %zu != index ntotal %" PRId64,
|
|
2289
2597
|
idxhnsw->hnsw.levels.size(),
|
|
2290
2598
|
idxhnsw->ntotal);
|
|
2291
|
-
idxhnsw->hnsw.
|
|
2599
|
+
idxhnsw->hnsw.search_method =
|
|
2600
|
+
h == fourcc("IHfP") ? HNSW::SM_PANORAMA : HNSW::SM_DEFAULT;
|
|
2292
2601
|
// `HNSW::is_similarity` is intentionally not serialized, so we
|
|
2293
2602
|
// re-derive it here from the persisted metric type. Without this,
|
|
2294
2603
|
// a saved IP/similarity index would come back configured as a
|
|
@@ -2310,6 +2619,57 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
2310
2619
|
idxhnsw->storage->d,
|
|
2311
2620
|
idxhnsw->d);
|
|
2312
2621
|
}
|
|
2622
|
+
if (h == fourcc("IHNr")) {
|
|
2623
|
+
auto* idx_rabitq = dynamic_cast<IndexHNSWRaBitQ*>(idxhnsw.get());
|
|
2624
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
2625
|
+
idx_rabitq, "IHNr must deserialize to an IndexHNSWRaBitQ");
|
|
2626
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
2627
|
+
idxhnsw->metric_type == METRIC_L2,
|
|
2628
|
+
"IndexHNSWRaBitQ supports only the L2 metric");
|
|
2629
|
+
bool staged;
|
|
2630
|
+
READ1_BOOL(staged);
|
|
2631
|
+
idxhnsw->hnsw.search_method =
|
|
2632
|
+
staged ? HNSW::SM_RABITQ : HNSW::SM_DEFAULT;
|
|
2633
|
+
if (idxhnsw->storage) {
|
|
2634
|
+
auto* rq = dynamic_cast<IndexRaBitQ*>(idxhnsw->storage);
|
|
2635
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
2636
|
+
rq, "IndexHNSWRaBitQ storage must be an IndexRaBitQ");
|
|
2637
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
2638
|
+
rq->metric_type == idxhnsw->metric_type &&
|
|
2639
|
+
rq->rabitq.metric_type == idxhnsw->metric_type,
|
|
2640
|
+
"IndexHNSWRaBitQ storage metric mismatch");
|
|
2641
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
2642
|
+
rq->is_trained == idxhnsw->is_trained,
|
|
2643
|
+
"IndexHNSWRaBitQ storage training state mismatch");
|
|
2644
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
2645
|
+
rq->rabitq.nb_bits >= 1 && rq->rabitq.nb_bits <= 9,
|
|
2646
|
+
"invalid RaBitQ nb_bits=%zu",
|
|
2647
|
+
rq->rabitq.nb_bits);
|
|
2648
|
+
const size_t expected_code_size =
|
|
2649
|
+
rq->rabitq.compute_code_size(rq->d, rq->rabitq.nb_bits);
|
|
2650
|
+
validate_code_size_match(
|
|
2651
|
+
rq->rabitq.code_size,
|
|
2652
|
+
expected_code_size,
|
|
2653
|
+
"IndexHNSWRaBitQ quantizer");
|
|
2654
|
+
validate_code_size_match(
|
|
2655
|
+
rq->code_size,
|
|
2656
|
+
expected_code_size,
|
|
2657
|
+
"IndexHNSWRaBitQ storage");
|
|
2658
|
+
FAISS_THROW_IF_NOT(
|
|
2659
|
+
rq->codes.size() ==
|
|
2660
|
+
mul_no_overflow(
|
|
2661
|
+
static_cast<size_t>(rq->ntotal),
|
|
2662
|
+
rq->code_size,
|
|
2663
|
+
"IndexHNSWRaBitQ codes"));
|
|
2664
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
2665
|
+
!rq->is_trained ||
|
|
2666
|
+
rq->center.size() == static_cast<size_t>(rq->d),
|
|
2667
|
+
"IndexHNSWRaBitQ center size mismatch");
|
|
2668
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
2669
|
+
staged == (rq->rabitq.nb_bits >= 2),
|
|
2670
|
+
"IndexHNSWRaBitQ staged-search metadata mismatch");
|
|
2671
|
+
}
|
|
2672
|
+
}
|
|
2313
2673
|
if (h == fourcc("IHN2")) {
|
|
2314
2674
|
FAISS_THROW_IF_NOT_MSG(
|
|
2315
2675
|
idxhnsw->storage,
|
|
@@ -2430,6 +2790,9 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
2430
2790
|
} else if (h == fourcc("IwPf")) {
|
|
2431
2791
|
auto ivpq = std::make_unique<IndexIVFPQFastScan>();
|
|
2432
2792
|
read_ivf_header(ivpq.get(), f);
|
|
2793
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
2794
|
+
ivpq->quantizer != nullptr,
|
|
2795
|
+
"IVFPQFastScan coarse quantizer is null");
|
|
2433
2796
|
READ1_BOOL(ivpq->by_residual);
|
|
2434
2797
|
READ1(ivpq->code_size);
|
|
2435
2798
|
READ1(ivpq->bbs);
|
|
@@ -2438,6 +2801,7 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
2438
2801
|
READ1(ivpq->qbs2);
|
|
2439
2802
|
read_ProductQuantizer(&ivpq->pq, f);
|
|
2440
2803
|
read_InvertedLists(*ivpq, f, io_flags);
|
|
2804
|
+
validate_ivfpq_precomputed_table_size(ivpq->quantizer, ivpq->pq);
|
|
2441
2805
|
ivpq->precompute_table();
|
|
2442
2806
|
|
|
2443
2807
|
const auto& pq = ivpq->pq;
|
|
@@ -2467,6 +2831,45 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
2467
2831
|
imm->own_fields = true;
|
|
2468
2832
|
|
|
2469
2833
|
idx = std::move(imm);
|
|
2834
|
+
} else if (h == fourcc("IxEd") || h == fourcc("IxEe")) {
|
|
2835
|
+
auto idxe = std::make_unique<IndexEDEN>();
|
|
2836
|
+
read_index_header(*idxe, f);
|
|
2837
|
+
read_EDENScalarQuantizer(
|
|
2838
|
+
idxe->sq,
|
|
2839
|
+
idxe->scale_type,
|
|
2840
|
+
f,
|
|
2841
|
+
idxe->d,
|
|
2842
|
+
idxe->metric_type,
|
|
2843
|
+
h == fourcc("IxEe"));
|
|
2844
|
+
READVECTOR(idxe->codes);
|
|
2845
|
+
READVECTOR(idxe->center);
|
|
2846
|
+
|
|
2847
|
+
idxe->code_size = eden_utils::code_size(idxe->d, idxe->sq.bits);
|
|
2848
|
+
FAISS_THROW_IF_NOT(
|
|
2849
|
+
idxe->codes.size() == idxe->ntotal * idxe->code_size);
|
|
2850
|
+
idx = std::move(idxe);
|
|
2851
|
+
} else if (h == fourcc("IwEd") || h == fourcc("IwEe")) {
|
|
2852
|
+
auto iveden = std::make_unique<IndexIVFEDEN>();
|
|
2853
|
+
read_ivf_header(iveden.get(), f);
|
|
2854
|
+
read_EDENScalarQuantizer(
|
|
2855
|
+
iveden->sq,
|
|
2856
|
+
iveden->scale_type,
|
|
2857
|
+
f,
|
|
2858
|
+
iveden->d,
|
|
2859
|
+
iveden->metric_type,
|
|
2860
|
+
h == fourcc("IwEe"));
|
|
2861
|
+
size_t stored_ivf_code_size;
|
|
2862
|
+
READ1(stored_ivf_code_size);
|
|
2863
|
+
READ1(iveden->by_residual);
|
|
2864
|
+
|
|
2865
|
+
iveden->code_size = eden_utils::code_size(iveden->d, iveden->sq.bits);
|
|
2866
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
2867
|
+
stored_ivf_code_size == iveden->code_size,
|
|
2868
|
+
"IndexIVFEDEN code_size mismatch: stored=%zu vs expected=%zu",
|
|
2869
|
+
stored_ivf_code_size,
|
|
2870
|
+
iveden->code_size);
|
|
2871
|
+
read_InvertedLists(*iveden, f, io_flags);
|
|
2872
|
+
idx = std::move(iveden);
|
|
2470
2873
|
} else if (h == fourcc("Irfn") || h == fourcc("Irfs")) {
|
|
2471
2874
|
// Irfn = new format (aux data embedded in SIMD blocks)
|
|
2472
2875
|
// Irfs = legacy format (flat_storage separate, needs migration)
|
|
@@ -2534,7 +2937,7 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
2534
2937
|
auto idxq = std::make_unique<IndexRaBitQ>();
|
|
2535
2938
|
read_index_header(*idxq, f);
|
|
2536
2939
|
read_RaBitQuantizer(idxq->rabitq, f, idxq->d, false);
|
|
2537
|
-
|
|
2940
|
+
read_vector(idxq->codes, f);
|
|
2538
2941
|
READVECTOR(idxq->center);
|
|
2539
2942
|
READ1(idxq->qb);
|
|
2540
2943
|
// qb=0: Not quantized - direct distance computation on given float32s.
|
|
@@ -2553,7 +2956,7 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
2553
2956
|
read_index_header(*idxq, f);
|
|
2554
2957
|
read_RaBitQuantizer(
|
|
2555
2958
|
idxq->rabitq, f, idxq->d, true); // Reads nb_bits from file
|
|
2556
|
-
|
|
2959
|
+
read_vector(idxq->codes, f);
|
|
2557
2960
|
READVECTOR(idxq->center);
|
|
2558
2961
|
READ1(idxq->qb);
|
|
2559
2962
|
// qb=0: Not quantized - direct distance computation on given float32s.
|
|
@@ -2645,10 +3048,22 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
2645
3048
|
bool initialized;
|
|
2646
3049
|
READ1_BOOL(initialized);
|
|
2647
3050
|
if (initialized) {
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
3051
|
+
if ((io_flags & IO_FLAG_MMAP_IFC) == IO_FLAG_MMAP_IFC &&
|
|
3052
|
+
svs->is_static) {
|
|
3053
|
+
// Use memory-mapped I/O for static indices
|
|
3054
|
+
auto* mf = dynamic_cast<MappedFileIOReader*>(f);
|
|
3055
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
3056
|
+
mf,
|
|
3057
|
+
"IO_FLAG_MMAP_IFC flag set but IOReader is not "
|
|
3058
|
+
"MappedFileIOReader");
|
|
3059
|
+
svs->map_to(mf);
|
|
3060
|
+
} else {
|
|
3061
|
+
// Use standard deserialization
|
|
3062
|
+
faiss::svs_io::ReaderStreambuf rbuf(
|
|
3063
|
+
f, get_deserialization_vector_byte_limit());
|
|
3064
|
+
std::istream is(&rbuf);
|
|
3065
|
+
svs->deserialize_impl(is);
|
|
3066
|
+
}
|
|
2652
3067
|
}
|
|
2653
3068
|
if (h == fourcc("ISVL")) {
|
|
2654
3069
|
bool trained;
|
|
@@ -2666,6 +3081,13 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
2666
3081
|
}
|
|
2667
3082
|
if (h == fourcc("ISV2")) {
|
|
2668
3083
|
READVECTOR(svs->stored_vectors);
|
|
3084
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
3085
|
+
svs->stored_vectors.size() ==
|
|
3086
|
+
mul_no_overflow(
|
|
3087
|
+
(size_t)svs->ntotal,
|
|
3088
|
+
(size_t)svs->d,
|
|
3089
|
+
"IndexSVSVamana stored_vectors"),
|
|
3090
|
+
"ISV2: stored_vectors size inconsistent with ntotal * d");
|
|
2669
3091
|
} else {
|
|
2670
3092
|
svs->stored_vectors_valid = false;
|
|
2671
3093
|
}
|
|
@@ -2677,10 +3099,21 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
2677
3099
|
bool initialized;
|
|
2678
3100
|
READ1_BOOL(initialized);
|
|
2679
3101
|
if (initialized) {
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
3102
|
+
if ((io_flags & IO_FLAG_MMAP_IFC) == IO_FLAG_MMAP_IFC) {
|
|
3103
|
+
// Use memory-mapped I/O
|
|
3104
|
+
auto* mf = dynamic_cast<MappedFileIOReader*>(f);
|
|
3105
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
3106
|
+
mf,
|
|
3107
|
+
"IO_FLAG_MMAP_IFC flag set but IOReader is not "
|
|
3108
|
+
"MappedFileIOReader");
|
|
3109
|
+
svs->map_to(mf);
|
|
3110
|
+
} else {
|
|
3111
|
+
// Use standard deserialization
|
|
3112
|
+
faiss::svs_io::ReaderStreambuf rbuf(
|
|
3113
|
+
f, get_deserialization_vector_byte_limit());
|
|
3114
|
+
std::istream is(&rbuf);
|
|
3115
|
+
svs->deserialize_impl(is);
|
|
3116
|
+
}
|
|
2684
3117
|
}
|
|
2685
3118
|
idx = std::move(svs);
|
|
2686
3119
|
} else if (
|
|
@@ -2718,7 +3151,8 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
2718
3151
|
bool initialized;
|
|
2719
3152
|
READ1_BOOL(initialized);
|
|
2720
3153
|
if (initialized) {
|
|
2721
|
-
faiss::svs_io::ReaderStreambuf rbuf(
|
|
3154
|
+
faiss::svs_io::ReaderStreambuf rbuf(
|
|
3155
|
+
f, get_deserialization_vector_byte_limit());
|
|
2722
3156
|
std::istream is(&rbuf);
|
|
2723
3157
|
svs_ivf->deserialize_impl(is);
|
|
2724
3158
|
}
|
|
@@ -2726,7 +3160,8 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
2726
3160
|
bool trained;
|
|
2727
3161
|
READ1_BOOL(trained);
|
|
2728
3162
|
if (trained) {
|
|
2729
|
-
faiss::svs_io::ReaderStreambuf rbuf(
|
|
3163
|
+
faiss::svs_io::ReaderStreambuf rbuf(
|
|
3164
|
+
f, get_deserialization_vector_byte_limit());
|
|
2730
3165
|
std::istream is(&rbuf);
|
|
2731
3166
|
auto* leanvec =
|
|
2732
3167
|
dynamic_cast<IndexSVSIVFLeanVec*>(svs_ivf.get());
|
|
@@ -3024,6 +3459,7 @@ static void read_binary_multi_hash_map(
|
|
|
3024
3459
|
}
|
|
3025
3460
|
|
|
3026
3461
|
std::unique_ptr<IndexBinary> read_index_binary_up(IOReader* f, int io_flags) {
|
|
3462
|
+
IndexNestingGuard nesting_guard;
|
|
3027
3463
|
std::unique_ptr<IndexBinary> idx;
|
|
3028
3464
|
uint32_t h;
|
|
3029
3465
|
READ1(h);
|
|
@@ -3031,7 +3467,12 @@ std::unique_ptr<IndexBinary> read_index_binary_up(IOReader* f, int io_flags) {
|
|
|
3031
3467
|
auto idxf = std::make_unique<IndexBinaryFlat>();
|
|
3032
3468
|
read_index_binary_header(*idxf, f);
|
|
3033
3469
|
read_vector(idxf->xb, f);
|
|
3034
|
-
FAISS_THROW_IF_NOT(
|
|
3470
|
+
FAISS_THROW_IF_NOT(
|
|
3471
|
+
idxf->xb.size() ==
|
|
3472
|
+
mul_no_overflow(
|
|
3473
|
+
(size_t)idxf->ntotal,
|
|
3474
|
+
idxf->code_size,
|
|
3475
|
+
"IndexBinaryFlat xb"));
|
|
3035
3476
|
idx = std::move(idxf);
|
|
3036
3477
|
} else if (h == fourcc("IBwF")) {
|
|
3037
3478
|
auto ivf = std::make_unique<IndexBinaryIVF>();
|
|
@@ -3050,7 +3491,7 @@ std::unique_ptr<IndexBinary> read_index_binary_up(IOReader* f, int io_flags) {
|
|
|
3050
3491
|
auto idxhnsw = std::make_unique<IndexBinaryHNSW>();
|
|
3051
3492
|
read_index_binary_header(*idxhnsw, f);
|
|
3052
3493
|
read_HNSW(idxhnsw->hnsw, f);
|
|
3053
|
-
idxhnsw->hnsw.
|
|
3494
|
+
idxhnsw->hnsw.search_method = HNSW::SM_DEFAULT;
|
|
3054
3495
|
FAISS_THROW_IF_NOT_FMT(
|
|
3055
3496
|
idxhnsw->hnsw.levels.size() == (size_t)idxhnsw->ntotal,
|
|
3056
3497
|
"IndexBinaryHNSW HNSW levels size %zu != ntotal %" PRId64,
|
|
@@ -3074,7 +3515,7 @@ std::unique_ptr<IndexBinary> read_index_binary_up(IOReader* f, int io_flags) {
|
|
|
3074
3515
|
READ1_BOOL(idxhnsw->base_level_only);
|
|
3075
3516
|
READ1(idxhnsw->num_base_level_search_entrypoints);
|
|
3076
3517
|
read_HNSW(idxhnsw->hnsw, f);
|
|
3077
|
-
idxhnsw->hnsw.
|
|
3518
|
+
idxhnsw->hnsw.search_method = HNSW::SM_DEFAULT;
|
|
3078
3519
|
FAISS_THROW_IF_NOT_FMT(
|
|
3079
3520
|
idxhnsw->hnsw.levels.size() == (size_t)idxhnsw->ntotal,
|
|
3080
3521
|
"IndexBinaryHNSWCagra HNSW levels size %zu != ntotal %" PRId64,
|