faiss 0.6.2 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -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/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 +1 -2
- data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +4 -5
- data/vendor/faiss/faiss/IndexBinaryHash.cpp +5 -9
- data/vendor/faiss/faiss/IndexBinaryIVF.cpp +2 -4
- 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 +13 -50
- data/vendor/faiss/faiss/IndexHNSW.cpp +10 -11
- data/vendor/faiss/faiss/IndexIDMap.cpp +16 -3
- data/vendor/faiss/faiss/IndexIDMap.h +2 -0
- data/vendor/faiss/faiss/IndexIVF.cpp +17 -6
- 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 +40 -22
- 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 +2 -2
- data/vendor/faiss/faiss/IndexShardsIVF.cpp +2 -2
- data/vendor/faiss/faiss/MetaIndexes.cpp +2 -4
- data/vendor/faiss/faiss/SuperKMeans.cpp +256 -240
- data/vendor/faiss/faiss/SuperKMeans.h +30 -0
- data/vendor/faiss/faiss/VectorTransform.cpp +33 -2
- data/vendor/faiss/faiss/clone_index.cpp +5 -0
- data/vendor/faiss/faiss/factory_tools.cpp +47 -4
- data/vendor/faiss/faiss/gpu/GpuCloner.cpp +11 -11
- data/vendor/faiss/faiss/gpu/GpuIndex.h +34 -11
- data/vendor/faiss/faiss/gpu/GpuIndexCagra.h +47 -0
- 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/ClusteringInitialization.cpp +2 -2
- 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 +109 -152
- data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +2 -2
- data/vendor/faiss/faiss/impl/NSG.cpp +3 -1
- data/vendor/faiss/faiss/impl/Panorama.h +9 -7
- data/vendor/faiss/faiss/impl/PolysemousTraining.cpp +152 -84
- data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +34 -22
- data/vendor/faiss/faiss/impl/RaBitQUtils.cpp +44 -36
- data/vendor/faiss/faiss/impl/RaBitQUtils.h +35 -0
- data/vendor/faiss/faiss/impl/RaBitQuantizer.cpp +168 -67
- data/vendor/faiss/faiss/impl/RaBitQuantizer.h +19 -0
- data/vendor/faiss/faiss/impl/RaBitQuantizerMultiBit.cpp +2 -11
- data/vendor/faiss/faiss/impl/ResultHandler.h +25 -31
- data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +258 -57
- data/vendor/faiss/faiss/impl/ScalarQuantizer.h +20 -0
- 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 +1 -1
- data/vendor/faiss/faiss/impl/binary_hamming/avx2.cpp +4 -4
- 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 +376 -36
- data/vendor/faiss/faiss/impl/index_write.cpp +55 -4
- 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/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/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 +882 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/quantizers.h +9 -8
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx2.cpp +85 -23
- 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 +136 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-neon.cpp +16 -16
- data/vendor/faiss/faiss/impl/simd_dispatch.h +30 -9
- data/vendor/faiss/faiss/index_factory.cpp +32 -6
- data/vendor/faiss/faiss/invlists/DirectMap.cpp +1 -1
- data/vendor/faiss/faiss/invlists/InvertedLists.cpp +2 -2
- data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +19 -4
- 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 +31 -1
- data/vendor/faiss/faiss/svs/IndexSVSVamana.h +15 -2
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.cpp +1 -2
- data/vendor/faiss/faiss/utils/approx_topk_hamming/approx_topk_hamming.h +1 -1
- data/vendor/faiss/faiss/utils/distances.cpp +14 -2
- 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 +1 -1
- 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_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 +160 -18
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx2.cpp +245 -0
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512.cpp +273 -0
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512_spr.cpp +92 -0
- 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_levels.cpp +44 -0
- data/vendor/faiss/faiss/utils/simd_levels.h +14 -0
- data/vendor/faiss/faiss/utils/utils.cpp +9 -27
- metadata +16 -1
|
@@ -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")) {
|
|
@@ -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");
|
|
@@ -862,6 +869,11 @@ static void validate_fastscan_fields(
|
|
|
862
869
|
index_type,
|
|
863
870
|
M,
|
|
864
871
|
ksub);
|
|
872
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
873
|
+
ksub == 16,
|
|
874
|
+
"%s: invalid ksub=%zd (fast-scan requires nbits=4 / ksub=16)",
|
|
875
|
+
index_type,
|
|
876
|
+
ksub);
|
|
865
877
|
FAISS_THROW_IF_NOT_FMT(
|
|
866
878
|
bbs > 0 && bbs % 32 == 0,
|
|
867
879
|
"%s: invalid bbs=%d (must be > 0 and a multiple of 32)",
|
|
@@ -1086,6 +1098,30 @@ void read_ScalarQuantizer(
|
|
|
1086
1098
|
case ScalarQuantizer::QT_8bit_tqmse:
|
|
1087
1099
|
expected = 256 + 255;
|
|
1088
1100
|
break;
|
|
1101
|
+
case ScalarQuantizer::QT_1bit_eden:
|
|
1102
|
+
expected = 2 + 1; // 2^bits centroids + (2^bits - 1) boundaries
|
|
1103
|
+
break;
|
|
1104
|
+
case ScalarQuantizer::QT_2bit_eden:
|
|
1105
|
+
expected = 4 + 3;
|
|
1106
|
+
break;
|
|
1107
|
+
case ScalarQuantizer::QT_3bit_eden:
|
|
1108
|
+
expected = 8 + 7;
|
|
1109
|
+
break;
|
|
1110
|
+
case ScalarQuantizer::QT_4bit_eden:
|
|
1111
|
+
expected = 16 + 15;
|
|
1112
|
+
break;
|
|
1113
|
+
case ScalarQuantizer::QT_5bit_eden:
|
|
1114
|
+
expected = 32 + 31;
|
|
1115
|
+
break;
|
|
1116
|
+
case ScalarQuantizer::QT_6bit_eden:
|
|
1117
|
+
expected = 64 + 63;
|
|
1118
|
+
break;
|
|
1119
|
+
case ScalarQuantizer::QT_7bit_eden:
|
|
1120
|
+
expected = 128 + 127;
|
|
1121
|
+
break;
|
|
1122
|
+
case ScalarQuantizer::QT_8bit_eden:
|
|
1123
|
+
expected = 256 + 255;
|
|
1124
|
+
break;
|
|
1089
1125
|
case ScalarQuantizer::QT_2bit_tq:
|
|
1090
1126
|
case ScalarQuantizer::QT_3bit_tq:
|
|
1091
1127
|
case ScalarQuantizer::QT_4bit_tq:
|
|
@@ -1339,13 +1375,15 @@ static void read_NNDescent(NNDescent& nnd, IOReader* f) {
|
|
|
1339
1375
|
READVECTOR(nnd.final_graph);
|
|
1340
1376
|
// Validate neighbor IDs in the graph
|
|
1341
1377
|
if (nnd.has_built && nnd.K > 0 && nnd.ntotal > 0) {
|
|
1378
|
+
const size_t expected_final_graph_size = mul_no_overflow(
|
|
1379
|
+
(size_t)nnd.ntotal, (size_t)nnd.K, "NNDescent final_graph");
|
|
1342
1380
|
FAISS_THROW_IF_NOT_FMT(
|
|
1343
|
-
nnd.final_graph.size() ==
|
|
1381
|
+
nnd.final_graph.size() == expected_final_graph_size,
|
|
1344
1382
|
"NNDescent final_graph size %zu != ntotal * K (%d * %d = %zu)",
|
|
1345
1383
|
nnd.final_graph.size(),
|
|
1346
1384
|
nnd.ntotal,
|
|
1347
1385
|
nnd.K,
|
|
1348
|
-
|
|
1386
|
+
expected_final_graph_size);
|
|
1349
1387
|
for (size_t i = 0; i < nnd.final_graph.size(); i++) {
|
|
1350
1388
|
int id = nnd.final_graph[i];
|
|
1351
1389
|
FAISS_THROW_IF_NOT_FMT(
|
|
@@ -1402,6 +1440,64 @@ static void read_RaBitQuantizer(
|
|
|
1402
1440
|
expected_d);
|
|
1403
1441
|
}
|
|
1404
1442
|
|
|
1443
|
+
static void read_EDENScalarQuantizer(
|
|
1444
|
+
ScalarQuantizer& sq,
|
|
1445
|
+
EDENScaleType& scale_type,
|
|
1446
|
+
IOReader* f,
|
|
1447
|
+
int expected_d,
|
|
1448
|
+
MetricType expected_metric_type,
|
|
1449
|
+
bool read_scale_type) {
|
|
1450
|
+
size_t d;
|
|
1451
|
+
size_t stored_code_size;
|
|
1452
|
+
size_t nb_bits;
|
|
1453
|
+
|
|
1454
|
+
READ1(d);
|
|
1455
|
+
READ1(stored_code_size);
|
|
1456
|
+
int metric_type_int;
|
|
1457
|
+
READ1(metric_type_int);
|
|
1458
|
+
const MetricType metric_type = metric_type_from_int(metric_type_int);
|
|
1459
|
+
READ1(nb_bits);
|
|
1460
|
+
if (read_scale_type) {
|
|
1461
|
+
int scale_type_int;
|
|
1462
|
+
READ1(scale_type_int);
|
|
1463
|
+
if (scale_type_int == 0) {
|
|
1464
|
+
scale_type = EDENScaleType_UNBIASED;
|
|
1465
|
+
} else {
|
|
1466
|
+
scale_type = static_cast<EDENScaleType>(scale_type_int);
|
|
1467
|
+
}
|
|
1468
|
+
} else {
|
|
1469
|
+
scale_type = EDENScaleType_UNBIASED;
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
1473
|
+
d == static_cast<size_t>(expected_d),
|
|
1474
|
+
"EDEN ScalarQuantizer dimension mismatch: sq.d=%zu vs index d=%d",
|
|
1475
|
+
d,
|
|
1476
|
+
expected_d);
|
|
1477
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
1478
|
+
metric_type == expected_metric_type,
|
|
1479
|
+
"EDEN ScalarQuantizer metric mismatch: stored=%d vs index=%d",
|
|
1480
|
+
metric_type_int,
|
|
1481
|
+
static_cast<int>(expected_metric_type));
|
|
1482
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
1483
|
+
nb_bits >= 1 && nb_bits <= 8,
|
|
1484
|
+
"invalid EDEN nb_bits=%zu (must be in [1, 8])",
|
|
1485
|
+
nb_bits);
|
|
1486
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
1487
|
+
scale_type == EDENScaleType_UNBIASED ||
|
|
1488
|
+
scale_type == EDENScaleType_BIASED,
|
|
1489
|
+
"invalid EDEN scale_type=%d",
|
|
1490
|
+
static_cast<int>(scale_type));
|
|
1491
|
+
sq = ScalarQuantizer(d, eden_utils::quantizer_type_for_bits(nb_bits));
|
|
1492
|
+
sq.train(0, nullptr);
|
|
1493
|
+
const size_t expected_code_size = eden_utils::code_size(d, nb_bits);
|
|
1494
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
1495
|
+
stored_code_size == expected_code_size,
|
|
1496
|
+
"EDEN ScalarQuantizer code_size mismatch: stored=%zu vs expected=%zu",
|
|
1497
|
+
stored_code_size,
|
|
1498
|
+
expected_code_size);
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1405
1501
|
void read_direct_map(DirectMap* dm, IOReader* f) {
|
|
1406
1502
|
char maintain_direct_map;
|
|
1407
1503
|
READ1(maintain_direct_map);
|
|
@@ -1453,6 +1549,45 @@ ArrayInvertedLists* set_array_invlist(
|
|
|
1453
1549
|
return result;
|
|
1454
1550
|
}
|
|
1455
1551
|
|
|
1552
|
+
static void validate_ivfpq_precomputed_table_size(
|
|
1553
|
+
const Index* quantizer,
|
|
1554
|
+
const ProductQuantizer& pq) {
|
|
1555
|
+
// The precomputed table is not stored; precompute_table() rebuilds it on
|
|
1556
|
+
// load at a size derived from attacker-controlled header fields. Bound
|
|
1557
|
+
// every table initialize_IVFPQ_precomputed_table() may allocate.
|
|
1558
|
+
const size_t m_ksub =
|
|
1559
|
+
mul_no_overflow(pq.M, pq.ksub, "IVFPQ precomputed_table");
|
|
1560
|
+
// type 1: nlist (== quantizer->ntotal) * pq.M * pq.ksub.
|
|
1561
|
+
size_t precompute_elems = mul_no_overflow(
|
|
1562
|
+
static_cast<size_t>(quantizer->ntotal),
|
|
1563
|
+
m_ksub,
|
|
1564
|
+
"IVFPQ precomputed_table");
|
|
1565
|
+
// type 2 (MultiIndexQuantizer coarse quantizer): cpq.ksub * pq.M * pq.ksub,
|
|
1566
|
+
// plus a temporary quantizer->d * cpq.ksub centroid table. Both derive from
|
|
1567
|
+
// the coarse PQ's ksub, which is independent of quantizer->ntotal, so the
|
|
1568
|
+
// type-1 bound above does not cover them.
|
|
1569
|
+
if (const auto* miq = dynamic_cast<const MultiIndexQuantizer*>(quantizer)) {
|
|
1570
|
+
const size_t cpq_ksub = miq->pq.ksub;
|
|
1571
|
+
const size_t type2_table =
|
|
1572
|
+
mul_no_overflow(cpq_ksub, m_ksub, "IVFPQ precomputed_table");
|
|
1573
|
+
const size_t type2_centroids = mul_no_overflow(
|
|
1574
|
+
static_cast<size_t>(quantizer->d),
|
|
1575
|
+
cpq_ksub,
|
|
1576
|
+
"IVFPQ precomputed_table");
|
|
1577
|
+
if (type2_table > precompute_elems) {
|
|
1578
|
+
precompute_elems = type2_table;
|
|
1579
|
+
}
|
|
1580
|
+
if (type2_centroids > precompute_elems) {
|
|
1581
|
+
precompute_elems = type2_centroids;
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1584
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
1585
|
+
precompute_elems <
|
|
1586
|
+
get_deserialization_vector_byte_limit() / sizeof(float),
|
|
1587
|
+
"IVFPQ precomputed_table allocation would exceed deserialization "
|
|
1588
|
+
"byte limit");
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1456
1591
|
static std::unique_ptr<IndexIVFPQ> read_ivfpq(
|
|
1457
1592
|
IOReader* f,
|
|
1458
1593
|
uint32_t h,
|
|
@@ -1470,6 +1605,8 @@ static std::unique_ptr<IndexIVFPQ> read_ivfpq(
|
|
|
1470
1605
|
|
|
1471
1606
|
std::vector<std::vector<idx_t>> ids;
|
|
1472
1607
|
read_ivf_header(ivpq.get(), f, legacy ? &ids : nullptr);
|
|
1608
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
1609
|
+
ivpq->quantizer != nullptr, "IVFPQ coarse quantizer is null");
|
|
1473
1610
|
READ1_BOOL(ivpq->by_residual);
|
|
1474
1611
|
READ1(ivpq->code_size);
|
|
1475
1612
|
read_ProductQuantizer(&ivpq->pq, f);
|
|
@@ -1488,6 +1625,8 @@ static std::unique_ptr<IndexIVFPQ> read_ivfpq(
|
|
|
1488
1625
|
ivpq->use_precomputed_table = 0;
|
|
1489
1626
|
if (ivpq->by_residual) {
|
|
1490
1627
|
if ((io_flags & IO_FLAG_SKIP_PRECOMPUTE_TABLE) == 0) {
|
|
1628
|
+
validate_ivfpq_precomputed_table_size(
|
|
1629
|
+
ivpq->quantizer, ivpq->pq);
|
|
1491
1630
|
ivpq->precompute_table();
|
|
1492
1631
|
}
|
|
1493
1632
|
}
|
|
@@ -1516,7 +1655,29 @@ static std::unique_ptr<IndexIVFPQ> read_ivfpq(
|
|
|
1516
1655
|
|
|
1517
1656
|
int read_old_fmt_hack = 0;
|
|
1518
1657
|
|
|
1658
|
+
namespace {
|
|
1659
|
+
|
|
1660
|
+
constexpr int kMaxIndexNestingDepth = 50;
|
|
1661
|
+
thread_local int index_read_nesting_depth = 0;
|
|
1662
|
+
|
|
1663
|
+
struct IndexNestingGuard {
|
|
1664
|
+
IndexNestingGuard() {
|
|
1665
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
1666
|
+
index_read_nesting_depth < kMaxIndexNestingDepth,
|
|
1667
|
+
"faiss index nesting depth exceeds limit of %d; "
|
|
1668
|
+
"input may be corrupt or malicious",
|
|
1669
|
+
kMaxIndexNestingDepth);
|
|
1670
|
+
++index_read_nesting_depth;
|
|
1671
|
+
}
|
|
1672
|
+
~IndexNestingGuard() {
|
|
1673
|
+
--index_read_nesting_depth;
|
|
1674
|
+
}
|
|
1675
|
+
};
|
|
1676
|
+
|
|
1677
|
+
} // namespace
|
|
1678
|
+
|
|
1519
1679
|
std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
1680
|
+
IndexNestingGuard nesting_guard;
|
|
1520
1681
|
std::unique_ptr<Index> idx;
|
|
1521
1682
|
uint32_t h;
|
|
1522
1683
|
READ1(h);
|
|
@@ -1530,6 +1691,8 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
1530
1691
|
READ1(n_levels);
|
|
1531
1692
|
FAISS_THROW_IF_NOT_FMT(n_levels > 0, "invalid n_levels %zd", n_levels);
|
|
1532
1693
|
READ1(batch_size);
|
|
1694
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
1695
|
+
batch_size > 0, "invalid IxFP batch_size %zd", batch_size);
|
|
1533
1696
|
std::unique_ptr<IndexFlatPanorama> idxp;
|
|
1534
1697
|
if (h == fourcc("IxFP")) {
|
|
1535
1698
|
idxp = std::make_unique<IndexFlatL2Panorama>(
|
|
@@ -1542,6 +1705,21 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
1542
1705
|
READ1_BOOL(idxp->is_trained);
|
|
1543
1706
|
READVECTOR(idxp->codes);
|
|
1544
1707
|
READVECTOR(idxp->cum_sums);
|
|
1708
|
+
size_t num_slots = mul_no_overflow(
|
|
1709
|
+
((size_t)idxp->ntotal + idxp->batch_size - 1) /
|
|
1710
|
+
idxp->batch_size,
|
|
1711
|
+
idxp->batch_size,
|
|
1712
|
+
"IndexFlatPanorama num_batches*batch_size");
|
|
1713
|
+
FAISS_THROW_IF_NOT(
|
|
1714
|
+
idxp->codes.size() ==
|
|
1715
|
+
mul_no_overflow(
|
|
1716
|
+
num_slots, idxp->code_size, "IndexFlatPanorama codes"));
|
|
1717
|
+
FAISS_THROW_IF_NOT(
|
|
1718
|
+
idxp->cum_sums.size() ==
|
|
1719
|
+
mul_no_overflow(
|
|
1720
|
+
num_slots,
|
|
1721
|
+
idxp->pano.n_levels + 1,
|
|
1722
|
+
"IndexFlatPanorama cum_sums"));
|
|
1545
1723
|
idxp->verbose = false;
|
|
1546
1724
|
idx = std::move(idxp);
|
|
1547
1725
|
} else if (
|
|
@@ -1558,7 +1736,11 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
1558
1736
|
idxf->code_size = idxf->d * sizeof(float);
|
|
1559
1737
|
read_xb_vector(idxf->codes, f);
|
|
1560
1738
|
FAISS_THROW_IF_NOT(
|
|
1561
|
-
idxf->codes.size() ==
|
|
1739
|
+
idxf->codes.size() ==
|
|
1740
|
+
mul_no_overflow(
|
|
1741
|
+
(size_t)idxf->ntotal,
|
|
1742
|
+
idxf->code_size,
|
|
1743
|
+
"IndexFlat codes"));
|
|
1562
1744
|
idx = std::move(idxf);
|
|
1563
1745
|
} else if (h == fourcc("IxHE") || h == fourcc("IxHe")) {
|
|
1564
1746
|
auto idxl = std::make_unique<IndexLSH>();
|
|
@@ -1597,7 +1779,11 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
1597
1779
|
FAISS_THROW_IF_NOT(
|
|
1598
1780
|
idxl->rrot.d_in == idxl->d && idxl->rrot.d_out == idxl->nbits);
|
|
1599
1781
|
FAISS_THROW_IF_NOT(
|
|
1600
|
-
idxl->codes.size() ==
|
|
1782
|
+
idxl->codes.size() ==
|
|
1783
|
+
mul_no_overflow(
|
|
1784
|
+
(size_t)idxl->ntotal,
|
|
1785
|
+
idxl->code_size,
|
|
1786
|
+
"IndexLSH codes"));
|
|
1601
1787
|
idx = std::move(idxl);
|
|
1602
1788
|
} else if (
|
|
1603
1789
|
h == fourcc("IxPQ") || h == fourcc("IxPo") || h == fourcc("IxPq")) {
|
|
@@ -1607,8 +1793,16 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
1607
1793
|
read_ProductQuantizer(&idxp->pq, f);
|
|
1608
1794
|
idxp->code_size = idxp->pq.code_size;
|
|
1609
1795
|
read_vector(idxp->codes, f);
|
|
1796
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
1797
|
+
idxp->code_size > 0 || idxp->ntotal == 0,
|
|
1798
|
+
"IndexPQ with ntotal > 0 must have code_size > 0 "
|
|
1799
|
+
"(corrupt ProductQuantizer nbits?)");
|
|
1610
1800
|
FAISS_THROW_IF_NOT(
|
|
1611
|
-
idxp->codes.size() ==
|
|
1801
|
+
idxp->codes.size() ==
|
|
1802
|
+
mul_no_overflow(
|
|
1803
|
+
(size_t)idxp->ntotal,
|
|
1804
|
+
idxp->code_size,
|
|
1805
|
+
"IndexPQ codes"));
|
|
1612
1806
|
if (h == fourcc("IxPo") || h == fourcc("IxPq")) {
|
|
1613
1807
|
READ1(idxp->search_type);
|
|
1614
1808
|
READ1_BOOL(idxp->encode_signs);
|
|
@@ -1636,7 +1830,11 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
1636
1830
|
idxr->code_size, idxr->rq.code_size, "IndexResidualQuantizer");
|
|
1637
1831
|
read_vector(idxr->codes, f);
|
|
1638
1832
|
FAISS_THROW_IF_NOT(
|
|
1639
|
-
idxr->codes.size() ==
|
|
1833
|
+
idxr->codes.size() ==
|
|
1834
|
+
mul_no_overflow(
|
|
1835
|
+
(size_t)idxr->ntotal,
|
|
1836
|
+
idxr->code_size,
|
|
1837
|
+
"IndexResidualQuantizer codes"));
|
|
1640
1838
|
idx = std::move(idxr);
|
|
1641
1839
|
} else if (h == fourcc("IxLS")) {
|
|
1642
1840
|
auto idxr = std::make_unique<IndexLocalSearchQuantizer>();
|
|
@@ -1651,7 +1849,11 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
1651
1849
|
"IndexLocalSearchQuantizer");
|
|
1652
1850
|
read_vector(idxr->codes, f);
|
|
1653
1851
|
FAISS_THROW_IF_NOT(
|
|
1654
|
-
idxr->codes.size() ==
|
|
1852
|
+
idxr->codes.size() ==
|
|
1853
|
+
mul_no_overflow(
|
|
1854
|
+
(size_t)idxr->ntotal,
|
|
1855
|
+
idxr->code_size,
|
|
1856
|
+
"IndexLocalSearchQuantizer codes"));
|
|
1655
1857
|
idx = std::move(idxr);
|
|
1656
1858
|
} else if (h == fourcc("IxPR")) {
|
|
1657
1859
|
auto idxpr = std::make_unique<IndexProductResidualQuantizer>();
|
|
@@ -1666,7 +1868,11 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
1666
1868
|
"IndexProductResidualQuantizer");
|
|
1667
1869
|
read_vector(idxpr->codes, f);
|
|
1668
1870
|
FAISS_THROW_IF_NOT(
|
|
1669
|
-
idxpr->codes.size() ==
|
|
1871
|
+
idxpr->codes.size() ==
|
|
1872
|
+
mul_no_overflow(
|
|
1873
|
+
(size_t)idxpr->ntotal,
|
|
1874
|
+
idxpr->code_size,
|
|
1875
|
+
"IndexProductResidualQuantizer codes"));
|
|
1670
1876
|
idx = std::move(idxpr);
|
|
1671
1877
|
} else if (h == fourcc("IxPL")) {
|
|
1672
1878
|
auto idxpl = std::make_unique<IndexProductLocalSearchQuantizer>();
|
|
@@ -1681,7 +1887,11 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
1681
1887
|
"IndexProductLocalSearchQuantizer");
|
|
1682
1888
|
read_vector(idxpl->codes, f);
|
|
1683
1889
|
FAISS_THROW_IF_NOT(
|
|
1684
|
-
idxpl->codes.size() ==
|
|
1890
|
+
idxpl->codes.size() ==
|
|
1891
|
+
mul_no_overflow(
|
|
1892
|
+
(size_t)idxpl->ntotal,
|
|
1893
|
+
idxpl->code_size,
|
|
1894
|
+
"IndexProductLocalSearchQuantizer codes"));
|
|
1685
1895
|
idx = std::move(idxpl);
|
|
1686
1896
|
} else if (h == fourcc("ImRQ")) {
|
|
1687
1897
|
auto idxr = std::make_unique<ResidualCoarseQuantizer>();
|
|
@@ -1725,6 +1935,16 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
1725
1935
|
idxr->ntotal,
|
|
1726
1936
|
idxr->rq.M);
|
|
1727
1937
|
}
|
|
1938
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
1939
|
+
idxr->rq.tot_bits <= 63,
|
|
1940
|
+
"ResidualCoarseQuantizer tot_bits too large (max 63)");
|
|
1941
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
1942
|
+
static_cast<size_t>(idxr->ntotal) ==
|
|
1943
|
+
(((size_t)1) << idxr->rq.tot_bits),
|
|
1944
|
+
"ResidualCoarseQuantizer ntotal %" PRId64
|
|
1945
|
+
" inconsistent with 2^tot_bits (tot_bits=%zu)",
|
|
1946
|
+
idxr->ntotal,
|
|
1947
|
+
idxr->rq.tot_bits);
|
|
1728
1948
|
idxr->set_beam_factor(idxr->beam_factor);
|
|
1729
1949
|
idx = std::move(idxr);
|
|
1730
1950
|
} else if (
|
|
@@ -1859,9 +2079,28 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
1859
2079
|
ivfl->code_size = ivfl->d * sizeof(float);
|
|
1860
2080
|
ArrayInvertedLists* ail = set_array_invlist(ivfl.get(), ids);
|
|
1861
2081
|
|
|
2082
|
+
// Legacy IVF serialized ids and codes as separate vectors.
|
|
2083
|
+
// Check not required in default IVF, due to single sizes vector.
|
|
2084
|
+
auto validate_legacy_codes_size = [&](size_t i) {
|
|
2085
|
+
const size_t expected_codes_bytes = mul_no_overflow(
|
|
2086
|
+
ail->ids[i].size(),
|
|
2087
|
+
ivfl->code_size,
|
|
2088
|
+
"legacy IVFFlat inverted list codes");
|
|
2089
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
2090
|
+
ail->codes[i].size() == expected_codes_bytes,
|
|
2091
|
+
"Legacy IVFFlat inverted list %zu: codes size %zu bytes "
|
|
2092
|
+
"does not match ids size %zu * code_size %zu = %zu bytes",
|
|
2093
|
+
i,
|
|
2094
|
+
ail->codes[i].size(),
|
|
2095
|
+
ail->ids[i].size(),
|
|
2096
|
+
(size_t)ivfl->code_size,
|
|
2097
|
+
expected_codes_bytes);
|
|
2098
|
+
};
|
|
2099
|
+
|
|
1862
2100
|
if (h == fourcc("IvFL")) {
|
|
1863
2101
|
for (size_t i = 0; i < ivfl->nlist; i++) {
|
|
1864
2102
|
READVECTOR(ail->codes[i]);
|
|
2103
|
+
validate_legacy_codes_size(i);
|
|
1865
2104
|
}
|
|
1866
2105
|
} else { // old format
|
|
1867
2106
|
for (size_t i = 0; i < ivfl->nlist; i++) {
|
|
@@ -1869,6 +2108,7 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
1869
2108
|
READVECTOR(vec);
|
|
1870
2109
|
ail->codes[i].resize(vec.size() * sizeof(float));
|
|
1871
2110
|
memcpy(ail->codes[i].data(), vec.data(), ail->codes[i].size());
|
|
2111
|
+
validate_legacy_codes_size(i);
|
|
1872
2112
|
}
|
|
1873
2113
|
}
|
|
1874
2114
|
idx = std::move(ivfl);
|
|
@@ -1905,6 +2145,10 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
1905
2145
|
ivfp->code_size = ivfp->d * sizeof(float);
|
|
1906
2146
|
READ1(ivfp->n_levels);
|
|
1907
2147
|
READ1(ivfp->batch_size);
|
|
2148
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
2149
|
+
ivfp->batch_size > 0,
|
|
2150
|
+
"invalid IwP2 batch_size %zd",
|
|
2151
|
+
ivfp->batch_size);
|
|
1908
2152
|
read_InvertedLists(*ivfp, f, io_flags);
|
|
1909
2153
|
idx = std::move(ivfp);
|
|
1910
2154
|
} else if (h == fourcc("IwFl")) {
|
|
@@ -1983,6 +2227,16 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
1983
2227
|
r2);
|
|
1984
2228
|
}
|
|
1985
2229
|
read_index_header(*idxl, f);
|
|
2230
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
2231
|
+
idxl->ntotal == 0,
|
|
2232
|
+
"IndexLattice deserialization carries no code storage; "
|
|
2233
|
+
"ntotal=%zd != 0 is corrupt",
|
|
2234
|
+
(size_t)idxl->ntotal);
|
|
2235
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
2236
|
+
idxl->d == d,
|
|
2237
|
+
"IndexLattice header d=%d inconsistent with encoded d=%d",
|
|
2238
|
+
idxl->d,
|
|
2239
|
+
d);
|
|
1986
2240
|
READVECTOR(idxl->trained);
|
|
1987
2241
|
idx = std::move(idxl);
|
|
1988
2242
|
} else if (h == fourcc("IvSQ")) { // legacy
|
|
@@ -2158,6 +2412,8 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
2158
2412
|
read_index_header(*idxrf, f);
|
|
2159
2413
|
auto base = read_index_up(f, io_flags);
|
|
2160
2414
|
auto refine = read_index_up(f, io_flags);
|
|
2415
|
+
FAISS_THROW_IF_NOT_MSG(base, "IndexRefine base index is null");
|
|
2416
|
+
FAISS_THROW_IF_NOT_MSG(refine, "IndexRefine refine index is null");
|
|
2161
2417
|
READ1(idxrf->k_factor);
|
|
2162
2418
|
// Same rationale as IndexIVFPQR k_factor above.
|
|
2163
2419
|
FAISS_THROW_IF_NOT_FMT(
|
|
@@ -2218,6 +2474,10 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
2218
2474
|
READ1(idxp->code_size_1);
|
|
2219
2475
|
READ1(idxp->code_size_2);
|
|
2220
2476
|
READ1(idxp->code_size);
|
|
2477
|
+
validate_code_size_match(
|
|
2478
|
+
idxp->code_size_1,
|
|
2479
|
+
idxp->q1.coarse_code_size(),
|
|
2480
|
+
"Index2Layer code_size_1");
|
|
2221
2481
|
validate_code_size_match(
|
|
2222
2482
|
idxp->code_size_2,
|
|
2223
2483
|
idxp->pq.code_size,
|
|
@@ -2227,31 +2487,33 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
2227
2487
|
idxp->code_size_1 + idxp->code_size_2,
|
|
2228
2488
|
"Index2Layer");
|
|
2229
2489
|
read_vector(idxp->codes, f);
|
|
2490
|
+
FAISS_THROW_IF_NOT(
|
|
2491
|
+
idxp->codes.size() ==
|
|
2492
|
+
mul_no_overflow(
|
|
2493
|
+
(size_t)idxp->ntotal,
|
|
2494
|
+
idxp->code_size,
|
|
2495
|
+
"Index2Layer codes"));
|
|
2230
2496
|
idx = std::move(idxp);
|
|
2231
2497
|
} else if (
|
|
2232
2498
|
h == fourcc("IHNf") || h == fourcc("IHNp") || h == fourcc("IHNs") ||
|
|
2233
2499
|
h == fourcc("IHN2") || h == fourcc("IHNc") || h == fourcc("IHc2") ||
|
|
2234
|
-
h == fourcc("IHfP")) {
|
|
2500
|
+
h == fourcc("IHfP") || h == fourcc("IH00")) {
|
|
2235
2501
|
std::unique_ptr<IndexHNSW> idxhnsw;
|
|
2236
|
-
if (h == fourcc("
|
|
2502
|
+
if (h == fourcc("IH00")) {
|
|
2503
|
+
idxhnsw = std::make_unique<IndexHNSW>();
|
|
2504
|
+
} else if (h == fourcc("IHNf")) {
|
|
2237
2505
|
idxhnsw = std::make_unique<IndexHNSWFlat>();
|
|
2238
|
-
}
|
|
2239
|
-
if (h == fourcc("IHfP")) {
|
|
2506
|
+
} else if (h == fourcc("IHfP")) {
|
|
2240
2507
|
idxhnsw = std::make_unique<IndexHNSWFlatPanorama>();
|
|
2241
|
-
}
|
|
2242
|
-
if (h == fourcc("IHNp")) {
|
|
2508
|
+
} else if (h == fourcc("IHNp")) {
|
|
2243
2509
|
idxhnsw = std::make_unique<IndexHNSWPQ>();
|
|
2244
|
-
}
|
|
2245
|
-
if (h == fourcc("IHNs")) {
|
|
2510
|
+
} else if (h == fourcc("IHNs")) {
|
|
2246
2511
|
idxhnsw = std::make_unique<IndexHNSWSQ>();
|
|
2247
|
-
}
|
|
2248
|
-
if (h == fourcc("IHN2")) {
|
|
2512
|
+
} else if (h == fourcc("IHN2")) {
|
|
2249
2513
|
idxhnsw = std::make_unique<IndexHNSW2Level>();
|
|
2250
|
-
}
|
|
2251
|
-
if (h == fourcc("IHNc")) {
|
|
2514
|
+
} else if (h == fourcc("IHNc")) {
|
|
2252
2515
|
idxhnsw = std::make_unique<IndexHNSWCagra>();
|
|
2253
|
-
}
|
|
2254
|
-
if (h == fourcc("IHc2")) {
|
|
2516
|
+
} else if (h == fourcc("IHc2")) {
|
|
2255
2517
|
idxhnsw = std::make_unique<IndexHNSWCagra>();
|
|
2256
2518
|
}
|
|
2257
2519
|
read_index_header(*idxhnsw, f);
|
|
@@ -2267,8 +2529,7 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
2267
2529
|
const_cast<Panorama&>(idx_panorama->pano) =
|
|
2268
2530
|
Panorama(idx_panorama->d * sizeof(float), nlevels, 1);
|
|
2269
2531
|
READVECTOR(idx_panorama->cum_sums);
|
|
2270
|
-
}
|
|
2271
|
-
if (h == fourcc("IHNc") || h == fourcc("IHc2")) {
|
|
2532
|
+
} else if (h == fourcc("IHNc") || h == fourcc("IHc2")) {
|
|
2272
2533
|
READ1_BOOL(idxhnsw->keep_max_size_level0);
|
|
2273
2534
|
auto idx_hnsw_cagra = dynamic_cast<IndexHNSWCagra*>(idxhnsw.get());
|
|
2274
2535
|
FAISS_THROW_IF_NOT_MSG(
|
|
@@ -2430,6 +2691,9 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
2430
2691
|
} else if (h == fourcc("IwPf")) {
|
|
2431
2692
|
auto ivpq = std::make_unique<IndexIVFPQFastScan>();
|
|
2432
2693
|
read_ivf_header(ivpq.get(), f);
|
|
2694
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
2695
|
+
ivpq->quantizer != nullptr,
|
|
2696
|
+
"IVFPQFastScan coarse quantizer is null");
|
|
2433
2697
|
READ1_BOOL(ivpq->by_residual);
|
|
2434
2698
|
READ1(ivpq->code_size);
|
|
2435
2699
|
READ1(ivpq->bbs);
|
|
@@ -2438,6 +2702,7 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
2438
2702
|
READ1(ivpq->qbs2);
|
|
2439
2703
|
read_ProductQuantizer(&ivpq->pq, f);
|
|
2440
2704
|
read_InvertedLists(*ivpq, f, io_flags);
|
|
2705
|
+
validate_ivfpq_precomputed_table_size(ivpq->quantizer, ivpq->pq);
|
|
2441
2706
|
ivpq->precompute_table();
|
|
2442
2707
|
|
|
2443
2708
|
const auto& pq = ivpq->pq;
|
|
@@ -2467,6 +2732,45 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
2467
2732
|
imm->own_fields = true;
|
|
2468
2733
|
|
|
2469
2734
|
idx = std::move(imm);
|
|
2735
|
+
} else if (h == fourcc("IxEd") || h == fourcc("IxEe")) {
|
|
2736
|
+
auto idxe = std::make_unique<IndexEDEN>();
|
|
2737
|
+
read_index_header(*idxe, f);
|
|
2738
|
+
read_EDENScalarQuantizer(
|
|
2739
|
+
idxe->sq,
|
|
2740
|
+
idxe->scale_type,
|
|
2741
|
+
f,
|
|
2742
|
+
idxe->d,
|
|
2743
|
+
idxe->metric_type,
|
|
2744
|
+
h == fourcc("IxEe"));
|
|
2745
|
+
READVECTOR(idxe->codes);
|
|
2746
|
+
READVECTOR(idxe->center);
|
|
2747
|
+
|
|
2748
|
+
idxe->code_size = eden_utils::code_size(idxe->d, idxe->sq.bits);
|
|
2749
|
+
FAISS_THROW_IF_NOT(
|
|
2750
|
+
idxe->codes.size() == idxe->ntotal * idxe->code_size);
|
|
2751
|
+
idx = std::move(idxe);
|
|
2752
|
+
} else if (h == fourcc("IwEd") || h == fourcc("IwEe")) {
|
|
2753
|
+
auto iveden = std::make_unique<IndexIVFEDEN>();
|
|
2754
|
+
read_ivf_header(iveden.get(), f);
|
|
2755
|
+
read_EDENScalarQuantizer(
|
|
2756
|
+
iveden->sq,
|
|
2757
|
+
iveden->scale_type,
|
|
2758
|
+
f,
|
|
2759
|
+
iveden->d,
|
|
2760
|
+
iveden->metric_type,
|
|
2761
|
+
h == fourcc("IwEe"));
|
|
2762
|
+
size_t stored_ivf_code_size;
|
|
2763
|
+
READ1(stored_ivf_code_size);
|
|
2764
|
+
READ1(iveden->by_residual);
|
|
2765
|
+
|
|
2766
|
+
iveden->code_size = eden_utils::code_size(iveden->d, iveden->sq.bits);
|
|
2767
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
2768
|
+
stored_ivf_code_size == iveden->code_size,
|
|
2769
|
+
"IndexIVFEDEN code_size mismatch: stored=%zu vs expected=%zu",
|
|
2770
|
+
stored_ivf_code_size,
|
|
2771
|
+
iveden->code_size);
|
|
2772
|
+
read_InvertedLists(*iveden, f, io_flags);
|
|
2773
|
+
idx = std::move(iveden);
|
|
2470
2774
|
} else if (h == fourcc("Irfn") || h == fourcc("Irfs")) {
|
|
2471
2775
|
// Irfn = new format (aux data embedded in SIMD blocks)
|
|
2472
2776
|
// Irfs = legacy format (flat_storage separate, needs migration)
|
|
@@ -2645,10 +2949,22 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
2645
2949
|
bool initialized;
|
|
2646
2950
|
READ1_BOOL(initialized);
|
|
2647
2951
|
if (initialized) {
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2952
|
+
if ((io_flags & IO_FLAG_MMAP_IFC) == IO_FLAG_MMAP_IFC &&
|
|
2953
|
+
svs->is_static) {
|
|
2954
|
+
// Use memory-mapped I/O for static indices
|
|
2955
|
+
auto* mf = dynamic_cast<MappedFileIOReader*>(f);
|
|
2956
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
2957
|
+
mf,
|
|
2958
|
+
"IO_FLAG_MMAP_IFC flag set but IOReader is not "
|
|
2959
|
+
"MappedFileIOReader");
|
|
2960
|
+
svs->map_to(mf);
|
|
2961
|
+
} else {
|
|
2962
|
+
// Use standard deserialization
|
|
2963
|
+
faiss::svs_io::ReaderStreambuf rbuf(
|
|
2964
|
+
f, get_deserialization_vector_byte_limit());
|
|
2965
|
+
std::istream is(&rbuf);
|
|
2966
|
+
svs->deserialize_impl(is);
|
|
2967
|
+
}
|
|
2652
2968
|
}
|
|
2653
2969
|
if (h == fourcc("ISVL")) {
|
|
2654
2970
|
bool trained;
|
|
@@ -2666,6 +2982,13 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
2666
2982
|
}
|
|
2667
2983
|
if (h == fourcc("ISV2")) {
|
|
2668
2984
|
READVECTOR(svs->stored_vectors);
|
|
2985
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
2986
|
+
svs->stored_vectors.size() ==
|
|
2987
|
+
mul_no_overflow(
|
|
2988
|
+
(size_t)svs->ntotal,
|
|
2989
|
+
(size_t)svs->d,
|
|
2990
|
+
"IndexSVSVamana stored_vectors"),
|
|
2991
|
+
"ISV2: stored_vectors size inconsistent with ntotal * d");
|
|
2669
2992
|
} else {
|
|
2670
2993
|
svs->stored_vectors_valid = false;
|
|
2671
2994
|
}
|
|
@@ -2677,10 +3000,21 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
2677
3000
|
bool initialized;
|
|
2678
3001
|
READ1_BOOL(initialized);
|
|
2679
3002
|
if (initialized) {
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
3003
|
+
if ((io_flags & IO_FLAG_MMAP_IFC) == IO_FLAG_MMAP_IFC) {
|
|
3004
|
+
// Use memory-mapped I/O
|
|
3005
|
+
auto* mf = dynamic_cast<MappedFileIOReader*>(f);
|
|
3006
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
3007
|
+
mf,
|
|
3008
|
+
"IO_FLAG_MMAP_IFC flag set but IOReader is not "
|
|
3009
|
+
"MappedFileIOReader");
|
|
3010
|
+
svs->map_to(mf);
|
|
3011
|
+
} else {
|
|
3012
|
+
// Use standard deserialization
|
|
3013
|
+
faiss::svs_io::ReaderStreambuf rbuf(
|
|
3014
|
+
f, get_deserialization_vector_byte_limit());
|
|
3015
|
+
std::istream is(&rbuf);
|
|
3016
|
+
svs->deserialize_impl(is);
|
|
3017
|
+
}
|
|
2684
3018
|
}
|
|
2685
3019
|
idx = std::move(svs);
|
|
2686
3020
|
} else if (
|
|
@@ -3024,6 +3358,7 @@ static void read_binary_multi_hash_map(
|
|
|
3024
3358
|
}
|
|
3025
3359
|
|
|
3026
3360
|
std::unique_ptr<IndexBinary> read_index_binary_up(IOReader* f, int io_flags) {
|
|
3361
|
+
IndexNestingGuard nesting_guard;
|
|
3027
3362
|
std::unique_ptr<IndexBinary> idx;
|
|
3028
3363
|
uint32_t h;
|
|
3029
3364
|
READ1(h);
|
|
@@ -3031,7 +3366,12 @@ std::unique_ptr<IndexBinary> read_index_binary_up(IOReader* f, int io_flags) {
|
|
|
3031
3366
|
auto idxf = std::make_unique<IndexBinaryFlat>();
|
|
3032
3367
|
read_index_binary_header(*idxf, f);
|
|
3033
3368
|
read_vector(idxf->xb, f);
|
|
3034
|
-
FAISS_THROW_IF_NOT(
|
|
3369
|
+
FAISS_THROW_IF_NOT(
|
|
3370
|
+
idxf->xb.size() ==
|
|
3371
|
+
mul_no_overflow(
|
|
3372
|
+
(size_t)idxf->ntotal,
|
|
3373
|
+
idxf->code_size,
|
|
3374
|
+
"IndexBinaryFlat xb"));
|
|
3035
3375
|
idx = std::move(idxf);
|
|
3036
3376
|
} else if (h == fourcc("IBwF")) {
|
|
3037
3377
|
auto ivf = std::make_unique<IndexBinaryIVF>();
|