faiss 0.6.4 → 0.6.5
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/ext/faiss/extconf.rb +1 -1
- data/lib/faiss/version.rb +1 -1
- data/vendor/faiss/faiss/AutoTune.cpp +175 -0
- data/vendor/faiss/faiss/Clustering.cpp +150 -60
- data/vendor/faiss/faiss/Clustering.h +29 -0
- data/vendor/faiss/faiss/IVFlib.cpp +99 -0
- data/vendor/faiss/faiss/IVFlib.h +15 -0
- data/vendor/faiss/faiss/Index.cpp +44 -0
- data/vendor/faiss/faiss/Index.h +19 -14
- data/vendor/faiss/faiss/IndexBinary.cpp +8 -0
- data/vendor/faiss/faiss/IndexBinary.h +8 -0
- data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +82 -4
- data/vendor/faiss/faiss/IndexBinaryHNSW.h +19 -0
- data/vendor/faiss/faiss/IndexBinaryIVF.cpp +34 -0
- data/vendor/faiss/faiss/IndexFastScan.cpp +33 -17
- data/vendor/faiss/faiss/IndexFastScan.h +6 -3
- data/vendor/faiss/faiss/IndexFlat.cpp +56 -0
- data/vendor/faiss/faiss/IndexFlat.h +31 -0
- data/vendor/faiss/faiss/IndexFlatCodes.cpp +6 -1
- data/vendor/faiss/faiss/IndexHNSW.cpp +456 -10
- data/vendor/faiss/faiss/IndexHNSW.h +38 -0
- data/vendor/faiss/faiss/IndexIDMap.cpp +32 -0
- data/vendor/faiss/faiss/IndexIDMap.h +7 -0
- data/vendor/faiss/faiss/IndexIVF.cpp +281 -31
- data/vendor/faiss/faiss/IndexIVF.h +53 -1
- data/vendor/faiss/faiss/IndexIVFFastScan.cpp +46 -14
- data/vendor/faiss/faiss/IndexIVFFastScan.h +4 -2
- data/vendor/faiss/faiss/IndexIVFFlat.cpp +33 -0
- data/vendor/faiss/faiss/IndexIVFFlat.h +16 -0
- data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +1 -0
- data/vendor/faiss/faiss/IndexIVFRaBitQ.cpp +3 -20
- data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.cpp +50 -14
- data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.h +5 -2
- data/vendor/faiss/faiss/IndexIVFSQFastScan.cpp +855 -0
- data/vendor/faiss/faiss/IndexIVFSQFastScan.h +145 -0
- data/vendor/faiss/faiss/IndexNNDescent.cpp +0 -3
- data/vendor/faiss/faiss/IndexPiPNN.cpp +201 -0
- data/vendor/faiss/faiss/IndexPiPNN.h +83 -0
- data/vendor/faiss/faiss/IndexRaBitQFastScan.cpp +6 -3
- data/vendor/faiss/faiss/IndexRaBitQFastScan.h +10 -4
- data/vendor/faiss/faiss/IndexReplicas.cpp +20 -0
- data/vendor/faiss/faiss/IndexReplicas.h +9 -0
- data/vendor/faiss/faiss/IndexSQFastScan.cpp +648 -0
- data/vendor/faiss/faiss/IndexSQFastScan.h +129 -0
- data/vendor/faiss/faiss/IndexShards.cpp +10 -0
- data/vendor/faiss/faiss/IndexShards.h +5 -0
- data/vendor/faiss/faiss/SuperKMeans.cpp +57 -15
- data/vendor/faiss/faiss/SuperKMeans.h +9 -4
- data/vendor/faiss/faiss/VectorTransform.cpp +3 -2
- data/vendor/faiss/faiss/clone_index.cpp +24 -0
- data/vendor/faiss/faiss/gpu/Dataset.h +112 -0
- data/vendor/faiss/faiss/gpu/GpuCloner.cpp +16 -13
- data/vendor/faiss/faiss/gpu/GpuCloner.h +4 -0
- data/vendor/faiss/faiss/gpu/GpuClonerOptions.h +3 -0
- data/vendor/faiss/faiss/gpu/GpuIndex.h +4 -13
- data/vendor/faiss/faiss/gpu/GpuIndexBinaryCagra.h +26 -13
- data/vendor/faiss/faiss/gpu/GpuIndexCagra.h +45 -22
- data/vendor/faiss/faiss/gpu/GpuIndexFlat.h +11 -0
- data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +6 -0
- data/vendor/faiss/faiss/gpu/test/TestGpuDatasetHeader.cpp +18 -0
- data/vendor/faiss/faiss/gpu/test/TestGpuIndexFlat.cpp +215 -0
- data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFFlat.cpp +98 -0
- data/vendor/faiss/faiss/gpu/utils/DeviceUtils.h +11 -0
- data/vendor/faiss/faiss/gpu/utils/StackDeviceMemory.cpp +1 -1
- data/vendor/faiss/faiss/gpu_metal/MetalCloner.h +11 -0
- data/vendor/faiss/faiss/gpu_metal/MetalDistance.h +92 -0
- data/vendor/faiss/faiss/gpu_metal/MetalIndex.h +4 -0
- data/vendor/faiss/faiss/gpu_metal/MetalIndexBinaryFlat.h +69 -0
- data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFPQ.h +38 -0
- data/vendor/faiss/faiss/gpu_metal/MetalKernels.h +106 -0
- data/vendor/faiss/faiss/gpu_metal/MetalPythonBridge.h +10 -0
- data/vendor/faiss/faiss/impl/AuxIndexStructures.cpp +2 -0
- data/vendor/faiss/faiss/impl/AuxIndexStructures.h +1 -6
- data/vendor/faiss/faiss/impl/ClusteringHelpers.cpp +134 -45
- data/vendor/faiss/faiss/impl/ClusteringHelpers.h +36 -0
- data/vendor/faiss/faiss/impl/ClusteringInitialization.cpp +286 -136
- data/vendor/faiss/faiss/impl/DistanceComputer.cpp +63 -0
- data/vendor/faiss/faiss/impl/DistanceComputer.h +3 -29
- data/vendor/faiss/faiss/impl/HNSW.cpp +46 -10
- data/vendor/faiss/faiss/impl/HNSW.h +72 -0
- data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +6 -19
- data/vendor/faiss/faiss/impl/NNDescent.cpp +2 -1
- data/vendor/faiss/faiss/impl/NSG.cpp +3 -2
- data/vendor/faiss/faiss/impl/Panorama.h +3 -2
- data/vendor/faiss/faiss/impl/PiPNN.cpp +822 -0
- data/vendor/faiss/faiss/impl/PiPNN.h +122 -0
- data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +54 -11
- data/vendor/faiss/faiss/impl/RaBitQUtils.h +1 -1
- data/vendor/faiss/faiss/impl/RaBitQuantizer.cpp +81 -57
- data/vendor/faiss/faiss/impl/RaBitQuantizer.h +15 -0
- data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +29 -0
- data/vendor/faiss/faiss/impl/ScalarQuantizer.h +1 -6
- data/vendor/faiss/faiss/impl/approx_topk/avx2.cpp +0 -4
- data/vendor/faiss/faiss/impl/approx_topk/neon.cpp +0 -4
- data/vendor/faiss/faiss/impl/binary_hamming/IndexBinaryHash_impl.h +5 -2
- data/vendor/faiss/faiss/impl/binary_hamming/avx2.cpp +0 -4
- data/vendor/faiss/faiss/impl/binary_hamming/avx512.cpp +0 -4
- data/vendor/faiss/faiss/impl/binary_hamming/neon.cpp +0 -4
- data/vendor/faiss/faiss/impl/binary_hamming/rvv.cpp +0 -4
- data/vendor/faiss/faiss/impl/expanded_scanners.h +88 -0
- data/vendor/faiss/faiss/impl/fast_scan/FastScanDistancePostProcessing.h +4 -0
- data/vendor/faiss/faiss/impl/fast_scan/accumulate_loops.h +61 -64
- data/vendor/faiss/faiss/impl/fast_scan/accumulate_loops_512.h +13 -14
- data/vendor/faiss/faiss/impl/fast_scan/decompose_qbs.h +17 -129
- data/vendor/faiss/faiss/impl/fast_scan/dispatching.h +25 -19
- data/vendor/faiss/faiss/impl/fast_scan/fast_scan.cpp +5 -0
- data/vendor/faiss/faiss/impl/fast_scan/impl-avx2.cpp +0 -4
- data/vendor/faiss/faiss/impl/fast_scan/impl-avx512.cpp +0 -4
- data/vendor/faiss/faiss/impl/fast_scan/impl-neon.cpp +0 -88
- data/vendor/faiss/faiss/impl/fast_scan/impl-riscv.cpp +0 -4
- data/vendor/faiss/faiss/impl/fast_scan/kernels_neon.h +155 -0
- data/vendor/faiss/faiss/impl/fast_scan/kernels_simd256.h +22 -1
- data/vendor/faiss/faiss/impl/fast_scan/kernels_simd512.h +3 -2
- data/vendor/faiss/faiss/impl/fast_scan/simd_result_handlers.h +41 -23
- data/vendor/faiss/faiss/impl/hnsw/avx2.cpp +0 -4
- data/vendor/faiss/faiss/impl/hnsw/avx512.cpp +0 -4
- data/vendor/faiss/faiss/impl/index_read.cpp +172 -0
- data/vendor/faiss/faiss/impl/index_write.cpp +95 -0
- data/vendor/faiss/faiss/impl/pipnn/HashPrune.cpp +159 -0
- data/vendor/faiss/faiss/impl/pipnn/HashPrune.h +69 -0
- data/vendor/faiss/faiss/impl/pipnn/Partition.cpp +587 -0
- data/vendor/faiss/faiss/impl/pipnn/Partition.h +93 -0
- data/vendor/faiss/faiss/impl/pipnn/kernels.cpp +326 -0
- data/vendor/faiss/faiss/impl/pipnn/kernels.h +92 -0
- data/vendor/faiss/faiss/impl/platform_macros.h +45 -0
- data/vendor/faiss/faiss/impl/polysemous_training/avx512.cpp +0 -4
- data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQScanner_impl.h +79 -4
- data/vendor/faiss/faiss/impl/pq_code_distance/PQDistanceComputer_impl.h +6 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/avx2.cpp +0 -4
- data/vendor/faiss/faiss/impl/pq_code_distance/avx512.cpp +0 -4
- data/vendor/faiss/faiss/impl/pq_code_distance/neon.cpp +0 -4
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-avx2.h +4 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-avx512.h +4 -1
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-generic.cpp +19 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-generic.h +6 -6
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-inl.h +131 -6
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-sve.cpp +0 -4
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_rvv_kernel.h +89 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_scan_impl.h +21 -10
- data/vendor/faiss/faiss/impl/pq_code_distance/rvv.cpp +45 -18
- data/vendor/faiss/faiss/impl/residual_quantizer_encode_steps.cpp +2 -1
- data/vendor/faiss/faiss/impl/result_handler/avx2.cpp +0 -4
- data/vendor/faiss/faiss/impl/result_handler/avx512.cpp +0 -4
- data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx2.cpp +0 -4
- data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx512.cpp +0 -4
- data/vendor/faiss/faiss/impl/scalar_quantizer/distance_computers.h +5 -1
- data/vendor/faiss/faiss/impl/scalar_quantizer/quantizers.h +28 -52
- data/vendor/faiss/faiss/impl/scalar_quantizer/scanners.h +59 -11
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx2.cpp +226 -77
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-impl.h +482 -103
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-spr.cpp +2 -149
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512.cpp +3 -698
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-dispatch.h +66 -57
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-neon.cpp +101 -96
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-rvv.cpp +3185 -144
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq8_coefficients.h +48 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq8_rvv_kernel.h +546 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/training.cpp +2 -2
- data/vendor/faiss/faiss/impl/simd_dispatch.h +7 -0
- data/vendor/faiss/faiss/impl/simdlib/simdlib_avx2.h +14 -0
- data/vendor/faiss/faiss/impl/simdlib/simdlib_dispatch.h +7 -8
- data/vendor/faiss/faiss/impl/sq_fastscan_utils.h +232 -0
- data/vendor/faiss/faiss/index_factory.cpp +76 -0
- data/vendor/faiss/faiss/invlists/InvertedLists.cpp +3 -1
- data/vendor/faiss/faiss/svs/IndexSVSVamana.h +3 -2
- data/vendor/faiss/faiss/utils/AlignedTable.h +6 -1
- data/vendor/faiss/faiss/utils/Heap.cpp +4 -3
- data/vendor/faiss/faiss/utils/approx_topk_hamming/approx_topk_hamming.h +16 -5
- data/vendor/faiss/faiss/utils/bf16.h +36 -0
- data/vendor/faiss/faiss/utils/distances.cpp +226 -15
- data/vendor/faiss/faiss/utils/distances.h +34 -0
- data/vendor/faiss/faiss/utils/distances_dispatch.h +6 -4
- data/vendor/faiss/faiss/utils/distances_fused/avx512.cpp +2 -5
- data/vendor/faiss/faiss/utils/distances_fused/distances_fused.cpp +0 -14
- data/vendor/faiss/faiss/utils/distances_fused/rvv.cpp +25 -0
- data/vendor/faiss/faiss/utils/distances_fused/simdlib_based.cpp +0 -4
- data/vendor/faiss/faiss/utils/distances_fused/simdlib_based_neon.cpp +0 -4
- data/vendor/faiss/faiss/utils/distances_fused/simdlib_kernel-inl.h +2 -1
- data/vendor/faiss/faiss/utils/distances_simd.cpp +9 -0
- data/vendor/faiss/faiss/utils/fp16-fp16c.h +4 -0
- data/vendor/faiss/faiss/utils/fp16-inl.h +26 -52
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx2.cpp +0 -4
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512.cpp +0 -4
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512_vpopcnt.cpp +0 -4
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-avx512.h +33 -5
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-avx512_vpopcnt.h +15 -30
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-neon.h +0 -4
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_impl.h +2 -1
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_neon.cpp +0 -4
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_rvv.cpp +0 -4
- data/vendor/faiss/faiss/utils/pq_code_distance.h +8 -4
- data/vendor/faiss/faiss/utils/prefetch.h +1 -26
- data/vendor/faiss/faiss/utils/quantize_lut.cpp +26 -27
- data/vendor/faiss/faiss/utils/quantize_lut.h +11 -0
- data/vendor/faiss/faiss/utils/rabitq_simd.h +51 -16
- data/vendor/faiss/faiss/utils/simd_impl/distances_aarch64.cpp +9 -4
- data/vendor/faiss/faiss/utils/simd_impl/distances_arm_sve.cpp +37 -5
- data/vendor/faiss/faiss/utils/simd_impl/distances_avx2.cpp +64 -5
- data/vendor/faiss/faiss/utils/simd_impl/distances_avx512.cpp +64 -5
- data/vendor/faiss/faiss/utils/simd_impl/distances_rvv.cpp +353 -71
- data/vendor/faiss/faiss/utils/simd_impl/distances_rvv_kernel.h +68 -0
- data/vendor/faiss/faiss/utils/simd_impl/exhaustive_L2sqr_blas_cmax.h +93 -0
- data/vendor/faiss/faiss/utils/simd_impl/fp16_kernels.h +76 -0
- data/vendor/faiss/faiss/utils/simd_impl/fp16_kernels_avx2.cpp +52 -0
- data/vendor/faiss/faiss/utils/simd_impl/fp16_kernels_avx512.cpp +52 -0
- data/vendor/faiss/faiss/utils/simd_impl/fp16_kernels_neon.cpp +48 -0
- data/vendor/faiss/faiss/utils/simd_impl/masked_sum-avx2.h +44 -0
- data/vendor/faiss/faiss/utils/simd_impl/masked_sum-avx512.h +43 -0
- data/vendor/faiss/faiss/utils/simd_impl/masked_sum.h +38 -0
- data/vendor/faiss/faiss/utils/simd_impl/partitioning_avx2.cpp +0 -4
- data/vendor/faiss/faiss/utils/simd_impl/partitioning_neon.cpp +0 -4
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx2.cpp +54 -15
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512.cpp +38 -21
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512_vpopcnt.cpp +51 -14
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_neon.cpp +297 -10
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_rvv.cpp +0 -4
- data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels_avx2.cpp +0 -4
- data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels_avx512.cpp +0 -4
- data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels_sve.cpp +0 -4
- data/vendor/faiss/faiss/utils/simd_levels.cpp +19 -3
- data/vendor/faiss/faiss/utils/simd_levels.h +74 -1
- data/vendor/faiss/faiss/utils/transpose/transpose-avx2-inl.h +0 -4
- data/vendor/faiss/faiss/utils/transpose/transpose-avx512-inl.h +0 -4
- data/vendor/faiss/faiss/utils/utils.cpp +80 -0
- data/vendor/faiss/faiss/utils/utils.h +24 -0
- metadata +33 -1
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
#include <faiss/IndexIVFPQR.h>
|
|
46
46
|
#include <faiss/IndexIVFRaBitQ.h>
|
|
47
47
|
#include <faiss/IndexIVFRaBitQFastScan.h>
|
|
48
|
+
#include <faiss/IndexIVFSQFastScan.h>
|
|
48
49
|
#include <faiss/IndexIVFSpectralHash.h>
|
|
49
50
|
#include <faiss/IndexLSH.h>
|
|
50
51
|
#include <faiss/IndexLattice.h>
|
|
@@ -52,11 +53,13 @@
|
|
|
52
53
|
#include <faiss/IndexNSG.h>
|
|
53
54
|
#include <faiss/IndexPQ.h>
|
|
54
55
|
#include <faiss/IndexPQFastScan.h>
|
|
56
|
+
#include <faiss/IndexPiPNN.h>
|
|
55
57
|
#include <faiss/IndexPreTransform.h>
|
|
56
58
|
#include <faiss/IndexRaBitQ.h>
|
|
57
59
|
#include <faiss/IndexRaBitQFastScan.h>
|
|
58
60
|
#include <faiss/IndexRefine.h>
|
|
59
61
|
#include <faiss/IndexRowwiseMinMax.h>
|
|
62
|
+
#include <faiss/IndexSQFastScan.h>
|
|
60
63
|
#ifdef FAISS_ENABLE_SVS
|
|
61
64
|
#include <faiss/impl/svs_io.h>
|
|
62
65
|
#include <faiss/svs/IndexSVSFlat.h>
|
|
@@ -765,6 +768,10 @@ void read_ProductQuantizer(ProductQuantizer* pq, IOReader* f) {
|
|
|
765
768
|
pq->d * pq->ksub);
|
|
766
769
|
}
|
|
767
770
|
|
|
771
|
+
static void validate_codebooks_size(
|
|
772
|
+
const AdditiveQuantizer& aq,
|
|
773
|
+
size_t effective_d);
|
|
774
|
+
|
|
768
775
|
static void read_ResidualQuantizer_old(ResidualQuantizer& rq, IOReader* f) {
|
|
769
776
|
READ1(rq.d);
|
|
770
777
|
FAISS_THROW_IF_NOT_FMT(
|
|
@@ -786,6 +793,7 @@ static void read_ResidualQuantizer_old(ResidualQuantizer& rq, IOReader* f) {
|
|
|
786
793
|
READ1(rq.norm_min);
|
|
787
794
|
READ1(rq.norm_max);
|
|
788
795
|
rq.set_derived_values();
|
|
796
|
+
validate_codebooks_size(rq, rq.d);
|
|
789
797
|
}
|
|
790
798
|
|
|
791
799
|
static void read_AdditiveQuantizer(AdditiveQuantizer& aq, IOReader* f) {
|
|
@@ -847,6 +855,9 @@ static void read_AdditiveQuantizer(AdditiveQuantizer& aq, IOReader* f) {
|
|
|
847
855
|
static void validate_codebooks_size(
|
|
848
856
|
const AdditiveQuantizer& aq,
|
|
849
857
|
size_t effective_d) {
|
|
858
|
+
if (!aq.is_trained && aq.codebooks.empty()) {
|
|
859
|
+
return;
|
|
860
|
+
}
|
|
850
861
|
size_t required = mul_no_overflow(
|
|
851
862
|
effective_d, aq.total_codebook_size, "codebooks validation");
|
|
852
863
|
FAISS_THROW_IF_NOT_FMT(
|
|
@@ -1359,6 +1370,59 @@ static void read_NSG(NSG& nsg, IOReader* f) {
|
|
|
1359
1370
|
FAISS_CHECK_RANGE(nsg.enterpoint, 0, N);
|
|
1360
1371
|
}
|
|
1361
1372
|
|
|
1373
|
+
static void read_PiPNN(PiPNN& pipnn, idx_t index_ntotal, IOReader* f) {
|
|
1374
|
+
READ1(pipnn.R);
|
|
1375
|
+
READ1(pipnn.leaf_k);
|
|
1376
|
+
READ1(pipnn.hash_bits);
|
|
1377
|
+
READ1(pipnn.reservoir_size);
|
|
1378
|
+
READ1(pipnn.c_max);
|
|
1379
|
+
READ1(pipnn.c_min);
|
|
1380
|
+
READ1(pipnn.leader_cap);
|
|
1381
|
+
// Former replicas field: build metadata that search does not need.
|
|
1382
|
+
int replicas;
|
|
1383
|
+
READ1(replicas);
|
|
1384
|
+
READ1(pipnn.leader_fraction);
|
|
1385
|
+
READ1(pipnn.alpha);
|
|
1386
|
+
READVECTOR(pipnn.fanout);
|
|
1387
|
+
READ1(pipnn.seed);
|
|
1388
|
+
READ1_BOOL(pipnn.ip_partition_by_angle);
|
|
1389
|
+
READ1(pipnn.search_L);
|
|
1390
|
+
pipnn.check_params();
|
|
1391
|
+
READ1(pipnn.ntotal);
|
|
1392
|
+
READ1(pipnn.entry_point);
|
|
1393
|
+
// Checked before the graph is allocated; ntotal == 0 means unbuilt.
|
|
1394
|
+
if (pipnn.ntotal != 0) {
|
|
1395
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
1396
|
+
pipnn.ntotal == index_ntotal,
|
|
1397
|
+
"PiPNN ntotal %" PRId64 " != index ntotal %" PRId64,
|
|
1398
|
+
pipnn.ntotal,
|
|
1399
|
+
index_ntotal);
|
|
1400
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
1401
|
+
pipnn.ntotal <= INT32_MAX,
|
|
1402
|
+
"built PiPNN ntotal %" PRId64 " exceeds INT32_MAX",
|
|
1403
|
+
pipnn.ntotal);
|
|
1404
|
+
FAISS_CHECK_RANGE(pipnn.entry_point, 0, pipnn.ntotal);
|
|
1405
|
+
}
|
|
1406
|
+
const size_t graph_size = mul_no_overflow(
|
|
1407
|
+
(size_t)pipnn.ntotal, (size_t)pipnn.R, "PiPNN graph");
|
|
1408
|
+
// Views (IO_FLAG_MMAP_IFC, zero-copy) skip the scan: it would fault in
|
|
1409
|
+
// the whole graph. Search bounds-checks every neighbour id instead.
|
|
1410
|
+
if (!read_vector_base(pipnn.graph, f, graph_size, std::nullopt)) {
|
|
1411
|
+
FAISS_THROW_IF_NOT(
|
|
1412
|
+
graph_size <
|
|
1413
|
+
get_deserialization_vector_byte_limit() / sizeof(int32_t));
|
|
1414
|
+
pipnn.graph.resize(graph_size);
|
|
1415
|
+
READANDCHECK(pipnn.graph.data(), graph_size);
|
|
1416
|
+
for (int32_t id : pipnn.graph) {
|
|
1417
|
+
FAISS_CHECK_RANGE(id, -1, pipnn.ntotal);
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
read_vector(pipnn.next_copy, f);
|
|
1421
|
+
FAISS_THROW_IF_NOT(
|
|
1422
|
+
pipnn.next_copy.size() == 0 ||
|
|
1423
|
+
pipnn.next_copy.size() == size_t(pipnn.ntotal));
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1362
1426
|
static void read_NNDescent(NNDescent& nnd, IOReader* f) {
|
|
1363
1427
|
READ1(nnd.ntotal);
|
|
1364
1428
|
READ1(nnd.d);
|
|
@@ -1841,6 +1905,14 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
1841
1905
|
} else {
|
|
1842
1906
|
read_ResidualQuantizer(idxr->rq, f, io_flags);
|
|
1843
1907
|
}
|
|
1908
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
1909
|
+
idxr->rq.is_trained == idxr->is_trained,
|
|
1910
|
+
"IndexResidualQuantizer is_trained does not match "
|
|
1911
|
+
"ResidualQuantizer is_trained");
|
|
1912
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
1913
|
+
idxr->ntotal == 0 || idxr->rq.is_trained,
|
|
1914
|
+
"IndexResidualQuantizer with ntotal > 0 must have trained "
|
|
1915
|
+
"ResidualQuantizer");
|
|
1844
1916
|
validate_aq_dimension_match(
|
|
1845
1917
|
idxr->rq, idxr->d, "IndexResidualQuantizer");
|
|
1846
1918
|
READ1(idxr->code_size);
|
|
@@ -2760,6 +2832,66 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
2760
2832
|
idxnnd->d);
|
|
2761
2833
|
}
|
|
2762
2834
|
idx = std::move(idxnnd);
|
|
2835
|
+
} else if (h == fourcc("IPNf") || h == fourcc("IPNs")) {
|
|
2836
|
+
std::unique_ptr<IndexPiPNN> idxpipnn;
|
|
2837
|
+
if (h == fourcc("IPNf")) {
|
|
2838
|
+
idxpipnn = std::make_unique<IndexPiPNNFlat>();
|
|
2839
|
+
} else {
|
|
2840
|
+
idxpipnn = std::make_unique<IndexPiPNNSQ>();
|
|
2841
|
+
}
|
|
2842
|
+
read_index_header(*idxpipnn, f);
|
|
2843
|
+
READ1_BOOL(idxpipnn->defer_build);
|
|
2844
|
+
read_PiPNN(idxpipnn->pipnn, idxpipnn->ntotal, f);
|
|
2845
|
+
idxpipnn->storage = read_index(f, io_flags);
|
|
2846
|
+
idxpipnn->own_fields = true;
|
|
2847
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
2848
|
+
idxpipnn->storage, "IndexPiPNN requires non-null storage");
|
|
2849
|
+
IndexPiPNN::check_storage_supported(*idxpipnn->storage);
|
|
2850
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
2851
|
+
idxpipnn->storage->ntotal == idxpipnn->ntotal,
|
|
2852
|
+
"PiPNN storage ntotal %" PRId64 " != index ntotal %" PRId64,
|
|
2853
|
+
idxpipnn->storage->ntotal,
|
|
2854
|
+
idxpipnn->ntotal);
|
|
2855
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
2856
|
+
idxpipnn->storage->d == idxpipnn->d,
|
|
2857
|
+
"PiPNN storage d %d != index d %d",
|
|
2858
|
+
idxpipnn->storage->d,
|
|
2859
|
+
idxpipnn->d);
|
|
2860
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
2861
|
+
idxpipnn->storage->metric_type == idxpipnn->metric_type,
|
|
2862
|
+
"PiPNN storage metric %d != index metric %d",
|
|
2863
|
+
(int)idxpipnn->storage->metric_type,
|
|
2864
|
+
(int)idxpipnn->metric_type);
|
|
2865
|
+
idx = std::move(idxpipnn);
|
|
2866
|
+
} else if (h == fourcc("ISfs")) {
|
|
2867
|
+
auto idxsqfs = std::make_unique<IndexSQFastScan>();
|
|
2868
|
+
read_index_header(*idxsqfs, f);
|
|
2869
|
+
read_ScalarQuantizer(&idxsqfs->sq, f, *idxsqfs);
|
|
2870
|
+
READ1(idxsqfs->implem);
|
|
2871
|
+
READ1(idxsqfs->bbs);
|
|
2872
|
+
READ1(idxsqfs->qbs);
|
|
2873
|
+
FAISS_THROW_IF_NOT_MSG(idxsqfs->qbs >= 0, "qbs must be non-negative");
|
|
2874
|
+
READ1(idxsqfs->ntotal2);
|
|
2875
|
+
READ1(idxsqfs->M2);
|
|
2876
|
+
READVECTOR(idxsqfs->codes);
|
|
2877
|
+
READ1(idxsqfs->rerank_factor);
|
|
2878
|
+
READVECTOR(idxsqfs->lo_codes);
|
|
2879
|
+
|
|
2880
|
+
// Restore FastScan base-class fields from the SQ
|
|
2881
|
+
idxsqfs->M = idxsqfs->sq.d;
|
|
2882
|
+
idxsqfs->nbits = 4;
|
|
2883
|
+
idxsqfs->ksub = 16;
|
|
2884
|
+
idxsqfs->code_size = idxsqfs->M2 / 2;
|
|
2885
|
+
|
|
2886
|
+
validate_fastscan_fields(
|
|
2887
|
+
idxsqfs->M,
|
|
2888
|
+
idxsqfs->M2,
|
|
2889
|
+
idxsqfs->ksub,
|
|
2890
|
+
idxsqfs->bbs,
|
|
2891
|
+
"IndexSQFastScan");
|
|
2892
|
+
|
|
2893
|
+
idx = std::move(idxsqfs);
|
|
2894
|
+
|
|
2763
2895
|
} else if (h == fourcc("IPfs")) {
|
|
2764
2896
|
auto idxpqfs = std::make_unique<IndexPQFastScan>();
|
|
2765
2897
|
read_index_header(*idxpqfs, f);
|
|
@@ -2787,6 +2919,46 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
|
|
|
2787
2919
|
|
|
2788
2920
|
idx = std::move(idxpqfs);
|
|
2789
2921
|
|
|
2922
|
+
} else if (h == fourcc("IwSf")) {
|
|
2923
|
+
auto ivfsqfs = std::make_unique<IndexIVFSQFastScan>();
|
|
2924
|
+
read_ivf_header(ivfsqfs.get(), f);
|
|
2925
|
+
READ1_BOOL(ivfsqfs->by_residual);
|
|
2926
|
+
READ1(ivfsqfs->code_size);
|
|
2927
|
+
READ1(ivfsqfs->bbs);
|
|
2928
|
+
READ1(ivfsqfs->M2);
|
|
2929
|
+
READ1(ivfsqfs->implem);
|
|
2930
|
+
READ1(ivfsqfs->rerank_factor);
|
|
2931
|
+
read_ScalarQuantizer(&ivfsqfs->sq, f, *ivfsqfs);
|
|
2932
|
+
read_InvertedLists(*ivfsqfs, f, io_flags);
|
|
2933
|
+
|
|
2934
|
+
ivfsqfs->M = ivfsqfs->d;
|
|
2935
|
+
ivfsqfs->nbits = 4;
|
|
2936
|
+
ivfsqfs->ksub = 16;
|
|
2937
|
+
ivfsqfs->init_code_packer();
|
|
2938
|
+
|
|
2939
|
+
bool has_orig;
|
|
2940
|
+
READ1(has_orig);
|
|
2941
|
+
if (has_orig) {
|
|
2942
|
+
ivfsqfs->lo_codes_invlists = read_InvertedLists(f, io_flags);
|
|
2943
|
+
// Rebuild direct_map from lo_codes_invlists for reranking
|
|
2944
|
+
ivfsqfs->direct_map.set_type(
|
|
2945
|
+
DirectMap::Hashtable, ivfsqfs->invlists, 0);
|
|
2946
|
+
for (size_t list_no = 0; list_no < ivfsqfs->nlist; list_no++) {
|
|
2947
|
+
size_t list_size =
|
|
2948
|
+
ivfsqfs->lo_codes_invlists->list_size(list_no);
|
|
2949
|
+
if (list_size == 0) {
|
|
2950
|
+
continue;
|
|
2951
|
+
}
|
|
2952
|
+
InvertedLists::ScopedIds ids(
|
|
2953
|
+
ivfsqfs->lo_codes_invlists, list_no);
|
|
2954
|
+
for (size_t j = 0; j < list_size; j++) {
|
|
2955
|
+
ivfsqfs->direct_map.add_single_id(ids[j], list_no, j);
|
|
2956
|
+
}
|
|
2957
|
+
}
|
|
2958
|
+
}
|
|
2959
|
+
|
|
2960
|
+
idx = std::move(ivfsqfs);
|
|
2961
|
+
|
|
2790
2962
|
} else if (h == fourcc("IwPf")) {
|
|
2791
2963
|
auto ivpq = std::make_unique<IndexIVFPQFastScan>();
|
|
2792
2964
|
read_ivf_header(ivpq.get(), f);
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
#include <faiss/IndexIVFPQR.h>
|
|
41
41
|
#include <faiss/IndexIVFRaBitQ.h>
|
|
42
42
|
#include <faiss/IndexIVFRaBitQFastScan.h>
|
|
43
|
+
#include <faiss/IndexIVFSQFastScan.h>
|
|
43
44
|
#include <faiss/IndexIVFSpectralHash.h>
|
|
44
45
|
#include <faiss/IndexLSH.h>
|
|
45
46
|
#include <faiss/IndexLattice.h>
|
|
@@ -47,11 +48,13 @@
|
|
|
47
48
|
#include <faiss/IndexNSG.h>
|
|
48
49
|
#include <faiss/IndexPQ.h>
|
|
49
50
|
#include <faiss/IndexPQFastScan.h>
|
|
51
|
+
#include <faiss/IndexPiPNN.h>
|
|
50
52
|
#include <faiss/IndexPreTransform.h>
|
|
51
53
|
#include <faiss/IndexRaBitQ.h>
|
|
52
54
|
#include <faiss/IndexRaBitQFastScan.h>
|
|
53
55
|
#include <faiss/IndexRefine.h>
|
|
54
56
|
#include <faiss/IndexRowwiseMinMax.h>
|
|
57
|
+
#include <faiss/IndexSQFastScan.h>
|
|
55
58
|
#ifdef FAISS_ENABLE_SVS
|
|
56
59
|
#include <faiss/impl/svs_io.h>
|
|
57
60
|
#include <faiss/svs/IndexSVSFlat.h>
|
|
@@ -421,6 +424,29 @@ static void write_NNDescent(const NNDescent* nnd, IOWriter* f) {
|
|
|
421
424
|
WRITEVECTOR(nnd->final_graph);
|
|
422
425
|
}
|
|
423
426
|
|
|
427
|
+
static void write_PiPNN(const PiPNN& pipnn, IOWriter* f) {
|
|
428
|
+
WRITE1(pipnn.R);
|
|
429
|
+
WRITE1(pipnn.leaf_k);
|
|
430
|
+
WRITE1(pipnn.hash_bits);
|
|
431
|
+
WRITE1(pipnn.reservoir_size);
|
|
432
|
+
WRITE1(pipnn.c_max);
|
|
433
|
+
WRITE1(pipnn.c_min);
|
|
434
|
+
WRITE1(pipnn.leader_cap);
|
|
435
|
+
// Former replicas field, kept so that the format does not change.
|
|
436
|
+
const int replicas = 1;
|
|
437
|
+
WRITE1(replicas);
|
|
438
|
+
WRITE1(pipnn.leader_fraction);
|
|
439
|
+
WRITE1(pipnn.alpha);
|
|
440
|
+
WRITEVECTOR(pipnn.fanout);
|
|
441
|
+
WRITE1(pipnn.seed);
|
|
442
|
+
WRITE1(pipnn.ip_partition_by_angle);
|
|
443
|
+
WRITE1(pipnn.search_L);
|
|
444
|
+
WRITE1(pipnn.ntotal);
|
|
445
|
+
WRITE1(pipnn.entry_point);
|
|
446
|
+
WRITEANDCHECK(pipnn.graph.data(), pipnn.graph.size());
|
|
447
|
+
WRITEVECTOR(pipnn.next_copy);
|
|
448
|
+
}
|
|
449
|
+
|
|
424
450
|
// Write RaBitQuantizer for 1-bit format (backward compatible)
|
|
425
451
|
static void write_RaBitQuantizer(
|
|
426
452
|
const RaBitQuantizer* rabitq,
|
|
@@ -938,6 +964,40 @@ void write_index(const Index* idx, IOWriter* f, int io_flags) {
|
|
|
938
964
|
WRITE1(idxnsg->nndescent_iter);
|
|
939
965
|
write_NSG(&idxnsg->nsg, f);
|
|
940
966
|
write_index(idxnsg->storage, f);
|
|
967
|
+
} else if (
|
|
968
|
+
const IndexPiPNN* idxpipnn = dynamic_cast<const IndexPiPNN*>(idx)) {
|
|
969
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
970
|
+
typeid(*idx) == typeid(IndexPiPNN) ||
|
|
971
|
+
typeid(*idx) == typeid(IndexPiPNNFlat) ||
|
|
972
|
+
typeid(*idx) == typeid(IndexPiPNNSQ),
|
|
973
|
+
"don't know how to serialize this IndexPiPNN subtype: %s",
|
|
974
|
+
typeid(*idx).name());
|
|
975
|
+
const Index* storage = idxpipnn->storage;
|
|
976
|
+
const PiPNN& state = idxpipnn->pipnn;
|
|
977
|
+
// The reader rejects these states, so they are not written either.
|
|
978
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
979
|
+
storage, "cannot serialize an IndexPiPNN without storage");
|
|
980
|
+
IndexPiPNN::check_storage_supported(*storage);
|
|
981
|
+
state.check_params();
|
|
982
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
983
|
+
storage->ntotal == idxpipnn->ntotal &&
|
|
984
|
+
storage->d == idxpipnn->d &&
|
|
985
|
+
storage->metric_type == idxpipnn->metric_type,
|
|
986
|
+
"cannot serialize IndexPiPNN: the storage is inconsistent "
|
|
987
|
+
"with the index (was the storage modified directly?)");
|
|
988
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
989
|
+
state.graph.size() == size_t(state.ntotal) * size_t(state.R),
|
|
990
|
+
"cannot serialize IndexPiPNN: graph size != ntotal * R");
|
|
991
|
+
// The subclasses differ only by their constructors: the fourcc names
|
|
992
|
+
// the storage.
|
|
993
|
+
const uint32_t h = dynamic_cast<const IndexScalarQuantizer*>(storage)
|
|
994
|
+
? fourcc("IPNs")
|
|
995
|
+
: fourcc("IPNf");
|
|
996
|
+
WRITE1(h);
|
|
997
|
+
write_index_header(idxpipnn, f);
|
|
998
|
+
WRITE1(idxpipnn->defer_build);
|
|
999
|
+
write_PiPNN(state, f);
|
|
1000
|
+
write_index(storage, f);
|
|
941
1001
|
} else if (
|
|
942
1002
|
const IndexNNDescent* idxnnd =
|
|
943
1003
|
dynamic_cast<const IndexNNDescent*>(idx)) {
|
|
@@ -951,6 +1011,21 @@ void write_index(const Index* idx, IOWriter* f, int io_flags) {
|
|
|
951
1011
|
write_index_header(idxnnd, f);
|
|
952
1012
|
write_NNDescent(&idxnnd->nndescent, f);
|
|
953
1013
|
write_index(idxnnd->storage, f);
|
|
1014
|
+
} else if (
|
|
1015
|
+
const IndexSQFastScan* idxsqfs =
|
|
1016
|
+
dynamic_cast<const IndexSQFastScan*>(idx)) {
|
|
1017
|
+
uint32_t h = fourcc("ISfs");
|
|
1018
|
+
WRITE1(h);
|
|
1019
|
+
write_index_header(idxsqfs, f);
|
|
1020
|
+
write_ScalarQuantizer(&idxsqfs->sq, f);
|
|
1021
|
+
WRITE1(idxsqfs->implem);
|
|
1022
|
+
WRITE1(idxsqfs->bbs);
|
|
1023
|
+
WRITE1(idxsqfs->qbs);
|
|
1024
|
+
WRITE1(idxsqfs->ntotal2);
|
|
1025
|
+
WRITE1(idxsqfs->M2);
|
|
1026
|
+
WRITEVECTOR(idxsqfs->codes);
|
|
1027
|
+
WRITE1(idxsqfs->rerank_factor);
|
|
1028
|
+
WRITEVECTOR(idxsqfs->lo_codes);
|
|
954
1029
|
} else if (
|
|
955
1030
|
const IndexPQFastScan* idxpqfs =
|
|
956
1031
|
dynamic_cast<const IndexPQFastScan*>(idx)) {
|
|
@@ -964,6 +1039,26 @@ void write_index(const Index* idx, IOWriter* f, int io_flags) {
|
|
|
964
1039
|
WRITE1(idxpqfs->ntotal2);
|
|
965
1040
|
WRITE1(idxpqfs->M2);
|
|
966
1041
|
WRITEVECTOR(idxpqfs->codes);
|
|
1042
|
+
} else if (
|
|
1043
|
+
const IndexIVFSQFastScan* ivfsqfs =
|
|
1044
|
+
dynamic_cast<const IndexIVFSQFastScan*>(idx)) {
|
|
1045
|
+
uint32_t h = fourcc("IwSf");
|
|
1046
|
+
WRITE1(h);
|
|
1047
|
+
write_ivf_header(ivfsqfs, f);
|
|
1048
|
+
WRITE1(ivfsqfs->by_residual);
|
|
1049
|
+
WRITE1(ivfsqfs->code_size);
|
|
1050
|
+
WRITE1(ivfsqfs->bbs);
|
|
1051
|
+
WRITE1(ivfsqfs->M2);
|
|
1052
|
+
WRITE1(ivfsqfs->implem);
|
|
1053
|
+
WRITE1(ivfsqfs->rerank_factor);
|
|
1054
|
+
write_ScalarQuantizer(&ivfsqfs->sq, f);
|
|
1055
|
+
write_InvertedLists(ivfsqfs->invlists, f);
|
|
1056
|
+
// Write lo_codes_invlists if present
|
|
1057
|
+
bool has_orig = (ivfsqfs->lo_codes_invlists != nullptr);
|
|
1058
|
+
WRITE1(has_orig);
|
|
1059
|
+
if (has_orig) {
|
|
1060
|
+
write_InvertedLists(ivfsqfs->lo_codes_invlists, f);
|
|
1061
|
+
}
|
|
967
1062
|
} else if (
|
|
968
1063
|
const IndexIVFPQFastScan* ivpq_2 =
|
|
969
1064
|
dynamic_cast<const IndexIVFPQFastScan*>(idx)) {
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#include <faiss/impl/pipnn/HashPrune.h>
|
|
9
|
+
|
|
10
|
+
#include <cstring>
|
|
11
|
+
|
|
12
|
+
#include <faiss/impl/FaissAssert.h>
|
|
13
|
+
#include <faiss/impl/platform_macros.h>
|
|
14
|
+
#include <faiss/utils/bf16.h>
|
|
15
|
+
#include <faiss/utils/random.h>
|
|
16
|
+
|
|
17
|
+
namespace faiss {
|
|
18
|
+
namespace pipnn {
|
|
19
|
+
|
|
20
|
+
uint16_t distance_key(float v) {
|
|
21
|
+
// Normalized on the bit pattern, so -ffast-math cannot remove the checks.
|
|
22
|
+
uint32_t u;
|
|
23
|
+
std::memcpy(&u, &v, sizeof(u));
|
|
24
|
+
if ((u & 0x7fffffffu) == 0) {
|
|
25
|
+
u = 0; // -0 -> +0
|
|
26
|
+
} else if ((u & 0x7f800000u) == 0x7f800000u && (u & 0x007fffffu) != 0) {
|
|
27
|
+
u = 0x7f800000u; // NaN -> +inf
|
|
28
|
+
}
|
|
29
|
+
std::memcpy(&v, &u, sizeof(v));
|
|
30
|
+
// Scalar `encode_bf16` only: the SIMD path rounds differently, so keys
|
|
31
|
+
// would depend on the CPU.
|
|
32
|
+
const uint16_t b = encode_bf16(v);
|
|
33
|
+
return (b & 0x8000) ? static_cast<uint16_t>(~b)
|
|
34
|
+
: static_cast<uint16_t>(b | 0x8000);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
bool ReservoirRef::offer(int32_t id, uint16_t hash, uint16_t key) {
|
|
38
|
+
const int n = *count;
|
|
39
|
+
// A full reservoir rejects anything not below its maximum (rules 1 and 3).
|
|
40
|
+
if (n == capacity && *farthest != kNoFarthest) {
|
|
41
|
+
const Slot& f = slots[*farthest];
|
|
42
|
+
if (!slot_less(key, id, f.key, f.id)) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
int lo = 0;
|
|
48
|
+
int hi = n;
|
|
49
|
+
while (lo < hi) {
|
|
50
|
+
const int mid = (lo + hi) / 2;
|
|
51
|
+
if (slots[mid].hash < hash) {
|
|
52
|
+
lo = mid + 1;
|
|
53
|
+
} else {
|
|
54
|
+
hi = mid;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Rule 1: bucket hit. The cached farthest stays valid only when a
|
|
59
|
+
// non-farthest slot is lowered.
|
|
60
|
+
if (lo < n && slots[lo].hash == hash) {
|
|
61
|
+
Slot& s = slots[lo];
|
|
62
|
+
if (!slot_less(key, id, s.key, s.id)) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
s.id = id;
|
|
66
|
+
s.key = key;
|
|
67
|
+
if (*farthest == lo) {
|
|
68
|
+
*farthest = kNoFarthest;
|
|
69
|
+
}
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Rule 2: miss with room.
|
|
74
|
+
if (n < capacity) {
|
|
75
|
+
std::memmove(
|
|
76
|
+
slots + lo + 1,
|
|
77
|
+
slots + lo,
|
|
78
|
+
sizeof(Slot) * static_cast<size_t>(n - lo));
|
|
79
|
+
slots[lo] = Slot{id, hash, key};
|
|
80
|
+
*count = static_cast<uint8_t>(n + 1);
|
|
81
|
+
*farthest = kNoFarthest;
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Rule 3: miss, full. Compare against the slot_less-maximum.
|
|
86
|
+
int z = *farthest;
|
|
87
|
+
if (z == kNoFarthest) {
|
|
88
|
+
z = 0;
|
|
89
|
+
for (int i = 1; i < n; i++) {
|
|
90
|
+
if (slot_less(
|
|
91
|
+
slots[z].key, slots[z].id, slots[i].key, slots[i].id)) {
|
|
92
|
+
z = i;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
*farthest = static_cast<uint8_t>(z);
|
|
96
|
+
}
|
|
97
|
+
const Slot& zs = slots[z];
|
|
98
|
+
if (!slot_less(key, id, zs.key, zs.id)) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
if (z < lo) {
|
|
102
|
+
std::memmove(
|
|
103
|
+
slots + z,
|
|
104
|
+
slots + z + 1,
|
|
105
|
+
sizeof(Slot) * static_cast<size_t>(lo - 1 - z));
|
|
106
|
+
slots[lo - 1] = Slot{id, hash, key};
|
|
107
|
+
} else {
|
|
108
|
+
std::memmove(
|
|
109
|
+
slots + lo + 1,
|
|
110
|
+
slots + lo,
|
|
111
|
+
sizeof(Slot) * static_cast<size_t>(z - lo));
|
|
112
|
+
slots[lo] = Slot{id, hash, key};
|
|
113
|
+
}
|
|
114
|
+
*farthest = kNoFarthest;
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
Hyperplanes::Hyperplanes(int d, int m, int64_t seed) : d(d), m(m) {
|
|
119
|
+
FAISS_THROW_IF_NOT_FMT(d >= 1, "Hyperplanes: d must be >= 1, got %d", d);
|
|
120
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
121
|
+
m >= 1 && m <= 16, "Hyperplanes: m must be in [1, 16], got %d", m);
|
|
122
|
+
std::vector<float> h(static_cast<size_t>(m) * d);
|
|
123
|
+
float_randn(h.data(), h.size(), seed);
|
|
124
|
+
ht.assign(static_cast<size_t>(d) * 16, 0.0f);
|
|
125
|
+
for (int i = 0; i < m; i++) {
|
|
126
|
+
for (int j = 0; j < d; j++) {
|
|
127
|
+
ht[static_cast<size_t>(j) * 16 + i] =
|
|
128
|
+
h[static_cast<size_t>(i) * d + j];
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
FAISS_NOINLINE void Hyperplanes::sketch(const float* x, float* out16) const {
|
|
134
|
+
// Local accumulators, j ascending: the result depends only on the values
|
|
135
|
+
// of x, never on its buffer, alignment or caller.
|
|
136
|
+
float acc[16] = {};
|
|
137
|
+
const float* h = ht.data();
|
|
138
|
+
for (int j = 0; j < d; j++) {
|
|
139
|
+
const float xj = x[j];
|
|
140
|
+
const float* hj = h + static_cast<size_t>(j) * 16;
|
|
141
|
+
for (int i = 0; i < 16; i++) {
|
|
142
|
+
acc[i] += xj * hj[i];
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
std::memcpy(out16, acc, sizeof(acc));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
uint16_t residual_hash(const float* sketch_p, const float* sketch_c, int m) {
|
|
149
|
+
uint16_t h = 0;
|
|
150
|
+
for (int i = 0; i < m; i++) {
|
|
151
|
+
if (sketch_c[i] - sketch_p[i] >= 0) {
|
|
152
|
+
h = static_cast<uint16_t>(h | (1u << i));
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return h;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
} // namespace pipnn
|
|
159
|
+
} // namespace faiss
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#include <cstdint>
|
|
11
|
+
#include <vector>
|
|
12
|
+
|
|
13
|
+
namespace faiss {
|
|
14
|
+
namespace pipnn {
|
|
15
|
+
|
|
16
|
+
/// One reservoir slot: candidate id, residual-LSH bucket, order-preserving key.
|
|
17
|
+
struct Slot {
|
|
18
|
+
int32_t id;
|
|
19
|
+
uint16_t hash;
|
|
20
|
+
uint16_t key;
|
|
21
|
+
};
|
|
22
|
+
static_assert(sizeof(Slot) == 8, "PiPNN reservoir slots must be 8 bytes");
|
|
23
|
+
|
|
24
|
+
/// "No cached farthest slot"; never a slot index since capacity <= 255.
|
|
25
|
+
constexpr uint8_t kNoFarthest = 0xFF;
|
|
26
|
+
|
|
27
|
+
/// Monotone 16-bit key of a distance, which may be negative, from its scalar
|
|
28
|
+
/// bf16 encoding. NaN maps to +inf and -0 to +0.
|
|
29
|
+
uint16_t distance_key(float v);
|
|
30
|
+
|
|
31
|
+
/// Strict (key, id) order. Deciding key ties by id makes the reservoir
|
|
32
|
+
/// independent of the offer order.
|
|
33
|
+
inline bool slot_less(uint16_t ka, int32_t ia, uint16_t kb, int32_t ib) {
|
|
34
|
+
return ka < kb || (ka == kb && ia < ib);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/// One point's reservoir in caller-owned storage; not thread-safe. Slots are
|
|
38
|
+
/// sorted by distinct hash, and *farthest caches the slot_less-maximum.
|
|
39
|
+
struct ReservoirRef {
|
|
40
|
+
Slot* slots;
|
|
41
|
+
uint8_t* count; // 0 when fresh
|
|
42
|
+
uint8_t* farthest; // kNoFarthest when fresh or unknown
|
|
43
|
+
int capacity; // 1..255
|
|
44
|
+
|
|
45
|
+
/// Keeps the smaller offer on a bucket hit, else inserts or evicts the
|
|
46
|
+
/// maximum. An id must always come with the same hash. True iff changed.
|
|
47
|
+
bool offer(int32_t id, uint16_t hash, uint16_t key);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/// m <= 16 Gaussian hyperplanes from float_randn(seed), stored transposed
|
|
51
|
+
/// and zero-padded: ht[j * 16 + i].
|
|
52
|
+
struct Hyperplanes {
|
|
53
|
+
int d = 0;
|
|
54
|
+
int m = 0;
|
|
55
|
+
std::vector<float> ht; // d * 16
|
|
56
|
+
|
|
57
|
+
Hyperplanes() = default;
|
|
58
|
+
Hyperplanes(int d, int m, int64_t seed);
|
|
59
|
+
|
|
60
|
+
/// out16[i] = sum over ascending j of x[j] * ht[j * 16 + i]. Not inlined,
|
|
61
|
+
/// so all call sites produce bitwise-identical sketches.
|
|
62
|
+
void sketch(const float* x, float* out16) const;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/// Bit i (i < m <= 16) is set iff sketch_c[i] - sketch_p[i] >= 0.
|
|
66
|
+
uint16_t residual_hash(const float* sketch_p, const float* sketch_c, int m);
|
|
67
|
+
|
|
68
|
+
} // namespace pipnn
|
|
69
|
+
} // namespace faiss
|