faiss 0.6.0 → 0.6.2
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/ext/faiss/extconf.rb +2 -1
- data/ext/faiss/{index_rb.cpp → index.cpp} +1 -1
- data/ext/faiss/index_binary.cpp +1 -1
- data/ext/faiss/kmeans.cpp +1 -1
- data/ext/faiss/pca_matrix.cpp +1 -1
- data/ext/faiss/product_quantizer.cpp +1 -1
- data/ext/faiss/{utils_rb.cpp → utils.cpp} +1 -1
- data/lib/faiss/version.rb +1 -1
- data/vendor/faiss/faiss/AutoTune.cpp +93 -80
- data/vendor/faiss/faiss/Clustering.cpp +39 -240
- data/vendor/faiss/faiss/Clustering.h +6 -0
- data/vendor/faiss/faiss/IVFlib.cpp +41 -21
- data/vendor/faiss/faiss/Index.cpp +6 -5
- data/vendor/faiss/faiss/Index.h +5 -5
- data/vendor/faiss/faiss/Index2Layer.cpp +37 -53
- data/vendor/faiss/faiss/IndexAdditiveQuantizer.cpp +49 -37
- data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.cpp +36 -34
- data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.h +4 -1
- data/vendor/faiss/faiss/IndexBinary.cpp +5 -3
- data/vendor/faiss/faiss/IndexBinary.h +4 -4
- data/vendor/faiss/faiss/IndexBinaryFlat.cpp +1 -1
- data/vendor/faiss/faiss/IndexBinaryFlat.h +1 -1
- data/vendor/faiss/faiss/IndexBinaryFromFloat.cpp +4 -4
- data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +88 -97
- data/vendor/faiss/faiss/IndexBinaryHNSW.h +9 -3
- data/vendor/faiss/faiss/IndexBinaryHash.cpp +45 -236
- data/vendor/faiss/faiss/IndexBinaryHash.h +6 -6
- data/vendor/faiss/faiss/IndexBinaryIVF.cpp +89 -417
- data/vendor/faiss/faiss/IndexFastScan.cpp +72 -109
- data/vendor/faiss/faiss/IndexFastScan.h +25 -23
- data/vendor/faiss/faiss/IndexFlat.cpp +27 -20
- data/vendor/faiss/faiss/IndexFlat.h +21 -18
- data/vendor/faiss/faiss/IndexFlatCodes.cpp +42 -19
- data/vendor/faiss/faiss/IndexHNSW.cpp +374 -206
- data/vendor/faiss/faiss/IndexHNSW.h +16 -2
- data/vendor/faiss/faiss/IndexIDMap.cpp +25 -21
- data/vendor/faiss/faiss/IndexIDMap.h +9 -7
- data/vendor/faiss/faiss/IndexIVF.cpp +467 -364
- data/vendor/faiss/faiss/IndexIVF.h +33 -12
- data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +79 -76
- data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.cpp +96 -93
- data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.h +4 -1
- data/vendor/faiss/faiss/IndexIVFFastScan.cpp +357 -238
- data/vendor/faiss/faiss/IndexIVFFastScan.h +42 -41
- data/vendor/faiss/faiss/IndexIVFFlat.cpp +39 -69
- data/vendor/faiss/faiss/IndexIVFFlat.h +32 -0
- data/vendor/faiss/faiss/IndexIVFFlatPanorama.cpp +56 -33
- data/vendor/faiss/faiss/IndexIVFFlatPanorama.h +3 -1
- data/vendor/faiss/faiss/IndexIVFIndependentQuantizer.cpp +18 -15
- data/vendor/faiss/faiss/IndexIVFPQ.cpp +73 -846
- data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +151 -121
- data/vendor/faiss/faiss/IndexIVFPQFastScan.h +3 -0
- data/vendor/faiss/faiss/IndexIVFPQR.cpp +23 -20
- data/vendor/faiss/faiss/IndexIVFRaBitQ.cpp +30 -52
- data/vendor/faiss/faiss/IndexIVFRaBitQ.h +2 -1
- data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.cpp +475 -476
- data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.h +248 -93
- data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +41 -127
- data/vendor/faiss/faiss/IndexIVFSpectralHash.h +1 -1
- data/vendor/faiss/faiss/IndexLSH.cpp +36 -19
- data/vendor/faiss/faiss/IndexLattice.cpp +13 -13
- data/vendor/faiss/faiss/IndexNNDescent.cpp +36 -21
- data/vendor/faiss/faiss/IndexNNDescent.h +2 -2
- data/vendor/faiss/faiss/IndexNSG.cpp +38 -23
- data/vendor/faiss/faiss/IndexNeuralNetCodec.cpp +31 -11
- data/vendor/faiss/faiss/IndexPQ.cpp +128 -221
- data/vendor/faiss/faiss/IndexPQ.h +3 -2
- data/vendor/faiss/faiss/IndexPQFastScan.cpp +20 -14
- data/vendor/faiss/faiss/IndexPQFastScan.h +3 -0
- data/vendor/faiss/faiss/IndexPreTransform.cpp +25 -18
- data/vendor/faiss/faiss/IndexPreTransform.h +1 -1
- data/vendor/faiss/faiss/IndexRaBitQ.cpp +11 -36
- data/vendor/faiss/faiss/IndexRaBitQ.h +2 -1
- data/vendor/faiss/faiss/IndexRaBitQFastScan.cpp +41 -277
- data/vendor/faiss/faiss/IndexRaBitQFastScan.h +183 -27
- data/vendor/faiss/faiss/IndexRefine.cpp +30 -25
- data/vendor/faiss/faiss/IndexRefine.h +4 -4
- data/vendor/faiss/faiss/IndexReplicas.cpp +6 -6
- data/vendor/faiss/faiss/IndexRowwiseMinMax.cpp +15 -14
- data/vendor/faiss/faiss/IndexRowwiseMinMax.h +1 -1
- data/vendor/faiss/faiss/IndexScalarQuantizer.cpp +150 -20
- data/vendor/faiss/faiss/IndexScalarQuantizer.h +10 -0
- data/vendor/faiss/faiss/IndexShards.cpp +10 -9
- data/vendor/faiss/faiss/IndexShardsIVF.cpp +21 -15
- data/vendor/faiss/faiss/MatrixStats.cpp +5 -4
- data/vendor/faiss/faiss/MetaIndexes.cpp +19 -17
- data/vendor/faiss/faiss/MetaIndexes.h +1 -1
- data/vendor/faiss/faiss/MetricType.h +14 -7
- data/vendor/faiss/faiss/SuperKMeans.cpp +656 -0
- data/vendor/faiss/faiss/SuperKMeans.h +97 -0
- data/vendor/faiss/faiss/VectorTransform.cpp +237 -149
- data/vendor/faiss/faiss/VectorTransform.h +16 -16
- data/vendor/faiss/faiss/build.cpp +23 -0
- data/vendor/faiss/faiss/build.h +15 -0
- data/vendor/faiss/faiss/clone_index.cpp +48 -47
- data/vendor/faiss/faiss/cppcontrib/SaDecodeKernels.h +1 -1
- data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-avx2-inl.h +47 -47
- data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-inl.h +11 -0
- data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-neon-inl.h +902 -12
- data/vendor/faiss/faiss/cppcontrib/sa_decode/PQ-avx2-inl.h +38 -38
- data/vendor/faiss/faiss/cppcontrib/sa_decode/PQ-inl.h +11 -0
- data/vendor/faiss/faiss/cppcontrib/sa_decode/PQ-neon-inl.h +702 -10
- data/vendor/faiss/faiss/factory_tools.cpp +9 -0
- data/vendor/faiss/faiss/gpu/GpuIndexCagra.h +6 -5
- data/vendor/faiss/faiss/gpu/GpuResources.h +3 -2
- data/vendor/faiss/faiss/gpu/StandardGpuResources.cpp +15 -16
- data/vendor/faiss/faiss/gpu/StandardGpuResources.h +5 -4
- data/vendor/faiss/faiss/gpu/test/TestGpuIndexFlat.cpp +46 -0
- data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFFlat.cpp +56 -0
- data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFPQ.cpp +78 -1
- data/vendor/faiss/faiss/gpu/test/TestUtils.cpp +72 -0
- data/vendor/faiss/faiss/gpu/test/TestUtils.h +23 -0
- data/vendor/faiss/faiss/gpu/utils/CuvsFilterConvert.h +1 -1
- data/vendor/faiss/faiss/gpu/utils/CuvsUtils.h +21 -10
- data/vendor/faiss/faiss/gpu_metal/GpuIndexFlat.h +22 -0
- data/vendor/faiss/faiss/gpu_metal/MetalCloner.h +35 -0
- data/vendor/faiss/faiss/gpu_metal/MetalDistance.h +87 -0
- data/vendor/faiss/faiss/gpu_metal/MetalFlatKernels.h +40 -0
- data/vendor/faiss/faiss/gpu_metal/MetalIndex.h +58 -0
- data/vendor/faiss/faiss/gpu_metal/MetalIndexFlat.h +65 -0
- data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFFlat.h +181 -0
- data/vendor/faiss/faiss/gpu_metal/MetalKernels.h +111 -0
- data/vendor/faiss/faiss/gpu_metal/MetalPythonBridge.h +45 -0
- data/vendor/faiss/faiss/gpu_metal/MetalResources.h +79 -0
- data/vendor/faiss/faiss/gpu_metal/StandardMetalResources.h +35 -0
- data/vendor/faiss/faiss/gpu_metal/impl/MetalIVFFlat.h +193 -0
- data/vendor/faiss/faiss/impl/AdSampling.cpp +103 -0
- data/vendor/faiss/faiss/impl/AdSampling.h +35 -0
- data/vendor/faiss/faiss/impl/AdditiveQuantizer.cpp +29 -25
- data/vendor/faiss/faiss/impl/AdditiveQuantizer.h +1 -0
- data/vendor/faiss/faiss/impl/AuxIndexStructures.cpp +10 -9
- data/vendor/faiss/faiss/impl/AuxIndexStructures.h +3 -0
- data/vendor/faiss/faiss/impl/ClusteringHelpers.cpp +244 -0
- data/vendor/faiss/faiss/impl/ClusteringHelpers.h +94 -0
- data/vendor/faiss/faiss/impl/ClusteringInitialization.cpp +16 -16
- data/vendor/faiss/faiss/impl/CodePacker.cpp +3 -3
- data/vendor/faiss/faiss/impl/CodePackerRaBitQ.cpp +1 -1
- data/vendor/faiss/faiss/impl/DistanceComputer.h +8 -8
- data/vendor/faiss/faiss/impl/FaissAssert.h +6 -3
- data/vendor/faiss/faiss/impl/FaissException.h +50 -3
- data/vendor/faiss/faiss/impl/HNSW.cpp +639 -507
- data/vendor/faiss/faiss/impl/HNSW.h +61 -44
- data/vendor/faiss/faiss/impl/IDSelector.cpp +15 -11
- data/vendor/faiss/faiss/impl/IDSelector.h +8 -8
- data/vendor/faiss/faiss/impl/InvertedListScannerStats.h +26 -0
- data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +82 -77
- data/vendor/faiss/faiss/impl/NNDescent.cpp +62 -25
- data/vendor/faiss/faiss/impl/NNDescent.h +6 -2
- data/vendor/faiss/faiss/impl/NSG.cpp +53 -32
- data/vendor/faiss/faiss/impl/NSG.h +4 -4
- data/vendor/faiss/faiss/impl/Panorama.cpp +23 -6
- data/vendor/faiss/faiss/impl/Panorama.h +269 -87
- data/vendor/faiss/faiss/impl/PdxLayout.cpp +93 -0
- data/vendor/faiss/faiss/impl/PdxLayout.h +41 -0
- data/vendor/faiss/faiss/impl/PolysemousTraining.cpp +46 -32
- data/vendor/faiss/faiss/impl/PolysemousTraining.h +3 -3
- data/vendor/faiss/faiss/impl/ProductAdditiveQuantizer.cpp +35 -35
- data/vendor/faiss/faiss/impl/ProductQuantizer-inl.h +21 -16
- data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +55 -25
- data/vendor/faiss/faiss/impl/Quantizer.h +2 -2
- data/vendor/faiss/faiss/impl/RaBitQUtils.cpp +55 -49
- data/vendor/faiss/faiss/impl/RaBitQUtils.h +65 -0
- data/vendor/faiss/faiss/impl/RaBitQuantizer.cpp +302 -283
- data/vendor/faiss/faiss/impl/ResidualQuantizer.cpp +26 -23
- data/vendor/faiss/faiss/impl/ResidualQuantizer.h +1 -1
- data/vendor/faiss/faiss/impl/ResultHandler.h +100 -75
- data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +318 -7
- data/vendor/faiss/faiss/impl/ScalarQuantizer.h +77 -1
- data/vendor/faiss/faiss/impl/ThreadedIndex-inl.h +14 -11
- data/vendor/faiss/faiss/impl/VisitedTable.cpp +10 -10
- data/vendor/faiss/faiss/impl/VisitedTable.h +70 -28
- data/vendor/faiss/faiss/impl/approx_topk/approx_topk.h +276 -0
- data/vendor/faiss/faiss/impl/approx_topk/avx2.cpp +68 -0
- data/vendor/faiss/faiss/{utils → impl}/approx_topk/generic.h +15 -8
- data/vendor/faiss/faiss/impl/approx_topk/neon.cpp +68 -0
- data/vendor/faiss/faiss/impl/approx_topk/rq_beam_search_tab-inl.h +169 -0
- data/vendor/faiss/faiss/impl/approx_topk/rq_beam_search_tab.h +117 -0
- data/vendor/faiss/faiss/impl/approx_topk/simdlib256-inl.h +146 -0
- data/vendor/faiss/faiss/impl/binary_hamming/IndexBinaryHNSW_impl.h +73 -0
- data/vendor/faiss/faiss/impl/binary_hamming/IndexBinaryHash_impl.h +270 -0
- data/vendor/faiss/faiss/impl/binary_hamming/IndexBinaryIVF_impl.h +460 -0
- data/vendor/faiss/faiss/impl/binary_hamming/IndexIVFSpectralHash_impl.h +159 -0
- data/vendor/faiss/faiss/impl/binary_hamming/IndexPQ_impl.h +92 -0
- data/vendor/faiss/faiss/impl/binary_hamming/avx2.cpp +26 -0
- data/vendor/faiss/faiss/impl/binary_hamming/avx512.cpp +26 -0
- data/vendor/faiss/faiss/impl/binary_hamming/dispatch.h +143 -0
- data/vendor/faiss/faiss/impl/binary_hamming/neon.cpp +26 -0
- data/vendor/faiss/faiss/impl/binary_hamming/rvv.cpp +26 -0
- data/vendor/faiss/faiss/impl/expanded_scanners.h +8 -3
- data/vendor/faiss/faiss/impl/{FastScanDistancePostProcessing.h → fast_scan/FastScanDistancePostProcessing.h} +13 -6
- data/vendor/faiss/faiss/impl/{LookupTableScaler.h → fast_scan/LookupTableScaler.h} +16 -5
- data/vendor/faiss/faiss/impl/fast_scan/accumulate_loops.h +237 -0
- data/vendor/faiss/faiss/impl/fast_scan/accumulate_loops_512.h +185 -0
- data/vendor/faiss/faiss/impl/fast_scan/decompose_qbs.h +229 -0
- data/vendor/faiss/faiss/impl/fast_scan/dispatching.h +270 -0
- data/vendor/faiss/faiss/impl/{pq4_fast_scan.cpp → fast_scan/fast_scan.cpp} +169 -2
- data/vendor/faiss/faiss/impl/fast_scan/fast_scan.h +341 -0
- data/vendor/faiss/faiss/impl/fast_scan/impl-avx2.cpp +36 -0
- data/vendor/faiss/faiss/impl/fast_scan/impl-avx512.cpp +40 -0
- data/vendor/faiss/faiss/impl/fast_scan/impl-neon.cpp +120 -0
- data/vendor/faiss/faiss/impl/fast_scan/impl-riscv.cpp +104 -0
- data/vendor/faiss/faiss/impl/fast_scan/kernels_simd256.h +213 -0
- data/vendor/faiss/faiss/impl/{pq4_fast_scan_search_qbs.cpp → fast_scan/kernels_simd512.h} +26 -356
- data/vendor/faiss/faiss/impl/fast_scan/rabitq_dispatching.h +90 -0
- data/vendor/faiss/faiss/impl/fast_scan/rabitq_result_handler.h +108 -0
- data/vendor/faiss/faiss/impl/{simd_result_handlers.h → fast_scan/simd_result_handlers.h} +282 -134
- data/vendor/faiss/faiss/impl/hnsw/LockVector.cpp +54 -0
- data/vendor/faiss/faiss/impl/hnsw/LockVector.h +64 -0
- data/vendor/faiss/faiss/impl/hnsw/MinimaxHeap.cpp +83 -0
- data/vendor/faiss/faiss/impl/hnsw/MinimaxHeap.h +113 -0
- data/vendor/faiss/faiss/impl/hnsw/avx2.cpp +150 -0
- data/vendor/faiss/faiss/impl/hnsw/avx512.cpp +142 -0
- data/vendor/faiss/faiss/impl/index_read.cpp +1227 -79
- data/vendor/faiss/faiss/impl/index_read_utils.h +1 -1
- data/vendor/faiss/faiss/impl/index_write.cpp +96 -13
- data/vendor/faiss/faiss/impl/io.cpp +6 -6
- data/vendor/faiss/faiss/impl/io_macros.h +58 -16
- data/vendor/faiss/faiss/impl/kmeans1d.cpp +10 -10
- data/vendor/faiss/faiss/impl/lattice_Zn.cpp +37 -23
- data/vendor/faiss/faiss/impl/lattice_Zn.h +6 -6
- data/vendor/faiss/faiss/impl/mapped_io.cpp +6 -6
- data/vendor/faiss/faiss/impl/platform_macros.h +15 -4
- data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQScanner_impl.h +549 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQ_QueryTables.cpp +245 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQ_QueryTables.h +105 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/PQDistanceComputer_impl.h +106 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/avx2.cpp +23 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/avx512.cpp +23 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/neon.cpp +23 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/{pq_code_distance-avx2.cpp → pq_code_distance-avx2.h} +9 -13
- data/vendor/faiss/faiss/impl/pq_code_distance/{pq_code_distance-avx512.cpp → pq_code_distance-avx512.h} +9 -57
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-generic.cpp +45 -107
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-generic.h +96 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-inl.h +274 -5
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-sve.cpp +10 -7
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_scan_impl.h +105 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/rvv.cpp +70 -0
- data/vendor/faiss/faiss/impl/residual_quantizer_encode_steps.cpp +311 -477
- data/vendor/faiss/faiss/impl/residual_quantizer_encode_steps.h +1 -1
- data/vendor/faiss/faiss/impl/scalar_quantizer/codecs.h +1 -1
- data/vendor/faiss/faiss/impl/scalar_quantizer/distance_computers.h +9 -2
- data/vendor/faiss/faiss/impl/scalar_quantizer/quantizers.h +419 -19
- data/vendor/faiss/faiss/impl/scalar_quantizer/scanners.h +27 -1
- data/vendor/faiss/faiss/impl/scalar_quantizer/similarities.h +3 -3
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx2.cpp +387 -2
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-impl.h +553 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-spr.cpp +559 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512.cpp +341 -2
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-dispatch.h +425 -3
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-neon.cpp +290 -2
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-rvv.cpp +337 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/training.cpp +192 -8
- data/vendor/faiss/faiss/impl/scalar_quantizer/training.h +12 -0
- data/vendor/faiss/faiss/impl/simd_dispatch.h +157 -66
- data/vendor/faiss/faiss/impl/simdlib/simdlib.h +57 -0
- data/vendor/faiss/faiss/{utils → impl/simdlib}/simdlib_avx2.h +264 -172
- data/vendor/faiss/faiss/impl/simdlib/simdlib_avx512.h +414 -0
- data/vendor/faiss/faiss/impl/simdlib/simdlib_dispatch.h +44 -0
- data/vendor/faiss/faiss/{utils → impl/simdlib}/simdlib_emulated.h +231 -166
- data/vendor/faiss/faiss/{utils → impl/simdlib}/simdlib_neon.h +270 -218
- data/vendor/faiss/faiss/{utils → impl/simdlib}/simdlib_ppc64.h +201 -160
- data/vendor/faiss/faiss/impl/svs_io.cpp +12 -3
- data/vendor/faiss/faiss/impl/svs_io.h +8 -2
- data/vendor/faiss/faiss/index_factory.cpp +90 -18
- data/vendor/faiss/faiss/index_io.h +40 -0
- data/vendor/faiss/faiss/invlists/BlockInvertedLists.cpp +66 -16
- data/vendor/faiss/faiss/invlists/DirectMap.cpp +28 -15
- data/vendor/faiss/faiss/invlists/DirectMap.h +4 -3
- data/vendor/faiss/faiss/invlists/InvertedLists.cpp +170 -86
- data/vendor/faiss/faiss/invlists/InvertedLists.h +88 -25
- data/vendor/faiss/faiss/invlists/InvertedListsIOHook.cpp +4 -4
- data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +13 -13
- data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.h +1 -1
- data/vendor/faiss/faiss/svs/IndexSVSFaissUtils.h +1 -1
- data/vendor/faiss/faiss/svs/IndexSVSFlat.cpp +2 -2
- data/vendor/faiss/faiss/svs/IndexSVSIVF.cpp +350 -0
- data/vendor/faiss/faiss/svs/IndexSVSIVF.h +128 -0
- data/vendor/faiss/faiss/svs/IndexSVSIVFLVQ.cpp +40 -0
- data/vendor/faiss/faiss/svs/IndexSVSIVFLVQ.h +43 -0
- data/vendor/faiss/faiss/svs/IndexSVSIVFLeanVec.cpp +225 -0
- data/vendor/faiss/faiss/svs/IndexSVSIVFLeanVec.h +71 -0
- data/vendor/faiss/faiss/svs/IndexSVSVamana.cpp +142 -21
- data/vendor/faiss/faiss/svs/IndexSVSVamana.h +33 -7
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLVQ.cpp +3 -2
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLVQ.h +2 -1
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.cpp +77 -27
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.h +10 -4
- data/vendor/faiss/faiss/utils/Heap.cpp +10 -10
- data/vendor/faiss/faiss/utils/NeuralNet.cpp +47 -36
- data/vendor/faiss/faiss/utils/NeuralNet.h +1 -1
- data/vendor/faiss/faiss/utils/approx_topk_hamming/approx_topk_hamming.h +10 -4
- data/vendor/faiss/faiss/utils/bf16.h +34 -0
- data/vendor/faiss/faiss/utils/distances.cpp +390 -560
- data/vendor/faiss/faiss/utils/distances.h +20 -1
- data/vendor/faiss/faiss/utils/distances_dispatch.h +117 -37
- data/vendor/faiss/faiss/utils/distances_fused/avx512.cpp +8 -7
- data/vendor/faiss/faiss/utils/distances_fused/distances_fused.cpp +33 -14
- data/vendor/faiss/faiss/utils/distances_fused/distances_fused.h +12 -1
- data/vendor/faiss/faiss/utils/distances_fused/simdlib_based.cpp +16 -293
- data/vendor/faiss/faiss/utils/distances_fused/simdlib_based_neon.cpp +57 -0
- data/vendor/faiss/faiss/utils/distances_fused/simdlib_kernel-inl.h +290 -0
- data/vendor/faiss/faiss/utils/distances_simd.cpp +5 -178
- data/vendor/faiss/faiss/utils/extra_distances.cpp +9 -8
- data/vendor/faiss/faiss/utils/extra_distances.h +32 -6
- data/vendor/faiss/faiss/utils/hamming-inl.h +13 -11
- data/vendor/faiss/faiss/utils/hamming.cpp +66 -517
- data/vendor/faiss/faiss/utils/hamming.h +92 -2
- data/vendor/faiss/faiss/utils/hamming_distance/common.h +287 -10
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx2.cpp +16 -0
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512.cpp +15 -0
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512_spr.cpp +15 -0
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-avx2.h +142 -0
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-avx512.h +210 -0
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-avx512_spr.h +171 -0
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-generic.h +368 -0
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-neon.h +322 -0
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-rvv.h +39 -0
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer.h +146 -0
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_impl.h +481 -0
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_neon.cpp +15 -0
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_rvv.cpp +15 -0
- data/vendor/faiss/faiss/utils/partitioning.cpp +66 -989
- data/vendor/faiss/faiss/utils/partitioning.h +31 -0
- data/vendor/faiss/faiss/utils/popcount.h +29 -0
- data/vendor/faiss/faiss/utils/pq_code_distance.h +2 -2
- data/vendor/faiss/faiss/utils/prefetch.h +2 -2
- data/vendor/faiss/faiss/utils/quantize_lut.cpp +30 -30
- data/vendor/faiss/faiss/utils/quantize_lut.h +1 -1
- data/vendor/faiss/faiss/utils/rabitq_simd.h +57 -536
- data/vendor/faiss/faiss/utils/random.cpp +6 -6
- data/vendor/faiss/faiss/utils/simd_impl/IVFFlatScanner-inl.h +51 -0
- data/vendor/faiss/faiss/utils/simd_impl/distances_aarch64.cpp +5 -1
- data/vendor/faiss/faiss/utils/simd_impl/distances_arm_sve.cpp +213 -4
- data/vendor/faiss/faiss/utils/simd_impl/distances_autovec-inl.h +163 -10
- data/vendor/faiss/faiss/utils/simd_impl/distances_avx2.cpp +250 -4
- data/vendor/faiss/faiss/utils/simd_impl/distances_avx512.cpp +7 -4
- data/vendor/faiss/faiss/utils/simd_impl/distances_rvv.cpp +189 -0
- data/vendor/faiss/faiss/utils/simd_impl/distances_simdlib256.h +195 -0
- data/vendor/faiss/faiss/utils/simd_impl/distances_sse-inl.h +2 -1
- data/vendor/faiss/faiss/utils/{distances_fused/simdlib_based.h → simd_impl/exhaustive_L2sqr_blas_cmax.h} +5 -10
- data/vendor/faiss/faiss/utils/simd_impl/hamming_impl.h +481 -0
- data/vendor/faiss/faiss/utils/simd_impl/partitioning_avx2.cpp +14 -0
- data/vendor/faiss/faiss/utils/simd_impl/partitioning_neon.cpp +14 -0
- data/vendor/faiss/faiss/utils/simd_impl/partitioning_simdlib256.h +1031 -0
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx2.cpp +355 -0
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512.cpp +477 -0
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512_spr.cpp +343 -0
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_neon.cpp +55 -0
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_rvv.cpp +55 -0
- data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_dispatch.h +32 -0
- data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels.h +43 -0
- data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels_avx2.cpp +57 -0
- data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels_avx512.cpp +45 -0
- data/vendor/faiss/faiss/utils/simd_levels.cpp +29 -7
- data/vendor/faiss/faiss/utils/simd_levels.h +93 -1
- data/vendor/faiss/faiss/utils/sorting.cpp +48 -36
- data/vendor/faiss/faiss/utils/utils.cpp +5 -5
- data/vendor/faiss/faiss/utils/utils.h +3 -3
- metadata +129 -34
- data/vendor/faiss/faiss/impl/RaBitQStats.cpp +0 -29
- data/vendor/faiss/faiss/impl/RaBitQStats.h +0 -56
- data/vendor/faiss/faiss/impl/pq4_fast_scan.h +0 -224
- data/vendor/faiss/faiss/impl/pq4_fast_scan_search_1.cpp +0 -230
- data/vendor/faiss/faiss/utils/approx_topk/approx_topk.h +0 -84
- data/vendor/faiss/faiss/utils/approx_topk/avx2-inl.h +0 -196
- data/vendor/faiss/faiss/utils/approx_topk/mode.h +0 -34
- data/vendor/faiss/faiss/utils/distances_fused/avx512.h +0 -36
- data/vendor/faiss/faiss/utils/extra_distances-inl.h +0 -235
- data/vendor/faiss/faiss/utils/hamming_distance/avx2-inl.h +0 -462
- data/vendor/faiss/faiss/utils/hamming_distance/avx512-inl.h +0 -490
- data/vendor/faiss/faiss/utils/hamming_distance/generic-inl.h +0 -449
- data/vendor/faiss/faiss/utils/hamming_distance/hamdis-inl.h +0 -87
- data/vendor/faiss/faiss/utils/hamming_distance/neon-inl.h +0 -524
- data/vendor/faiss/faiss/utils/simdlib.h +0 -42
- data/vendor/faiss/faiss/utils/simdlib_avx512.h +0 -365
- /data/ext/faiss/{utils_rb.h → utils.h} +0 -0
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
#include <faiss/IndexHNSW.h>
|
|
9
9
|
|
|
10
10
|
#include <omp.h>
|
|
11
|
+
#include <atomic>
|
|
11
12
|
#include <cinttypes>
|
|
12
13
|
#include <cstdio>
|
|
13
14
|
#include <cstdlib>
|
|
@@ -26,14 +27,15 @@
|
|
|
26
27
|
#include <faiss/IndexIVFPQ.h>
|
|
27
28
|
#include <faiss/impl/AuxIndexStructures.h>
|
|
28
29
|
#include <faiss/impl/FaissAssert.h>
|
|
30
|
+
#include <faiss/impl/FaissException.h>
|
|
29
31
|
#include <faiss/impl/ResultHandler.h>
|
|
30
32
|
#include <faiss/impl/VisitedTable.h>
|
|
33
|
+
#include <faiss/impl/hnsw/MinimaxHeap.h>
|
|
31
34
|
#include <faiss/utils/random.h>
|
|
32
35
|
#include <faiss/utils/sorting.h>
|
|
33
36
|
|
|
34
37
|
namespace faiss {
|
|
35
38
|
|
|
36
|
-
using MinimaxHeap = HNSW::MinimaxHeap;
|
|
37
39
|
using storage_idx_t = HNSW::storage_idx_t;
|
|
38
40
|
using NodeDistFarther = HNSW::NodeDistFarther;
|
|
39
41
|
|
|
@@ -45,12 +47,17 @@ HNSWStats hnsw_stats;
|
|
|
45
47
|
|
|
46
48
|
namespace {
|
|
47
49
|
|
|
50
|
+
// Returns the storage's native distance computer. For similarity metrics
|
|
51
|
+
// (e.g. METRIC_INNER_PRODUCT), distance values are real similarity scores
|
|
52
|
+
// (larger = better); HNSW handles the ordering via `hnsw.is_similarity`.
|
|
53
|
+
//
|
|
54
|
+
// NOTE: callers that drive the legacy max-heap-only code paths (notably
|
|
55
|
+
// `search_from_candidates_2` in the IndexHNSW2Level mixed search) cannot
|
|
56
|
+
// consume similarity scores directly; they assume smaller-is-better.
|
|
57
|
+
// Those paths only fire for the (default) L2 IndexHNSW2Level + Index2Layer
|
|
58
|
+
// configuration today, so passing the native DC is safe in practice.
|
|
48
59
|
DistanceComputer* storage_distance_computer(const Index* storage) {
|
|
49
|
-
|
|
50
|
-
return new NegativeDistanceComputer(storage->get_distance_computer());
|
|
51
|
-
} else {
|
|
52
|
-
return storage->get_distance_computer();
|
|
53
|
-
}
|
|
60
|
+
return storage->get_distance_computer();
|
|
54
61
|
}
|
|
55
62
|
|
|
56
63
|
void hnsw_add_vertices(
|
|
@@ -82,10 +89,8 @@ void hnsw_add_vertices(
|
|
|
82
89
|
printf(" max_level = %d\n", max_level);
|
|
83
90
|
}
|
|
84
91
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
omp_init_lock(&locks[i]);
|
|
88
|
-
}
|
|
92
|
+
auto& locks = index_hnsw.locks;
|
|
93
|
+
locks.prepare(ntotal);
|
|
89
94
|
|
|
90
95
|
// add vectors from highest to lowest level
|
|
91
96
|
std::vector<int> hist;
|
|
@@ -94,10 +99,10 @@ void hnsw_add_vertices(
|
|
|
94
99
|
{ // make buckets with vectors of the same level
|
|
95
100
|
|
|
96
101
|
// build histogram
|
|
97
|
-
for (
|
|
98
|
-
storage_idx_t pt_id = i + n0;
|
|
102
|
+
for (size_t i = 0; i < n; i++) {
|
|
103
|
+
storage_idx_t pt_id = static_cast<storage_idx_t>(i + n0);
|
|
99
104
|
int pt_level = hnsw.levels[pt_id] - 1;
|
|
100
|
-
while (pt_level >= hist.size()) {
|
|
105
|
+
while (pt_level >= static_cast<int>(hist.size())) {
|
|
101
106
|
hist.push_back(0);
|
|
102
107
|
}
|
|
103
108
|
hist[pt_level]++;
|
|
@@ -105,13 +110,13 @@ void hnsw_add_vertices(
|
|
|
105
110
|
|
|
106
111
|
// accumulate
|
|
107
112
|
std::vector<int> offsets(hist.size() + 1, 0);
|
|
108
|
-
for (
|
|
113
|
+
for (size_t i = 0; i < hist.size() - 1; i++) {
|
|
109
114
|
offsets[i + 1] = offsets[i] + hist[i];
|
|
110
115
|
}
|
|
111
116
|
|
|
112
117
|
// bucket sort
|
|
113
|
-
for (
|
|
114
|
-
storage_idx_t pt_id = i + n0;
|
|
118
|
+
for (size_t i = 0; i < n; i++) {
|
|
119
|
+
storage_idx_t pt_id = static_cast<storage_idx_t>(i + n0);
|
|
115
120
|
int pt_level = hnsw.levels[pt_id] - 1;
|
|
116
121
|
order[offsets[pt_level]++] = pt_id;
|
|
117
122
|
}
|
|
@@ -123,39 +128,42 @@ void hnsw_add_vertices(
|
|
|
123
128
|
{ // perform add
|
|
124
129
|
RandomGenerator rng2(789);
|
|
125
130
|
|
|
126
|
-
|
|
131
|
+
size_t i1 = static_cast<int>(n);
|
|
127
132
|
|
|
128
|
-
for (int pt_level = hist.size() - 1;
|
|
133
|
+
for (int pt_level = static_cast<int>(hist.size()) - 1;
|
|
129
134
|
pt_level >= int(!index_hnsw.init_level0);
|
|
130
135
|
pt_level--) {
|
|
131
|
-
|
|
136
|
+
size_t i0 = i1 - hist[pt_level];
|
|
132
137
|
|
|
133
138
|
if (verbose) {
|
|
134
|
-
printf("Adding %
|
|
139
|
+
printf("Adding %zu elements at level %d\n", i1 - i0, pt_level);
|
|
135
140
|
}
|
|
136
141
|
|
|
137
142
|
// random permutation to get rid of dataset order bias
|
|
138
|
-
for (
|
|
139
|
-
std::swap(
|
|
143
|
+
for (size_t j = i0; j < i1; j++) {
|
|
144
|
+
std::swap(
|
|
145
|
+
order[j],
|
|
146
|
+
order[j + rng2.rand_int(static_cast<int>(i1 - j))]);
|
|
140
147
|
}
|
|
141
148
|
|
|
142
149
|
bool interrupt = false;
|
|
143
150
|
|
|
144
151
|
#pragma omp parallel if (i1 > i0 + 100)
|
|
145
152
|
{
|
|
146
|
-
VisitedTable vt
|
|
153
|
+
std::unique_ptr<VisitedTable> vt =
|
|
154
|
+
VisitedTable::create(ntotal, hnsw.use_visited_hashset);
|
|
147
155
|
|
|
148
156
|
std::unique_ptr<DistanceComputer> dis(
|
|
149
157
|
storage_distance_computer(index_hnsw.storage));
|
|
150
|
-
|
|
151
|
-
|
|
158
|
+
bool do_display = verbose && omp_get_thread_num() == 0;
|
|
159
|
+
size_t prev_display = 0;
|
|
152
160
|
size_t counter = 0;
|
|
153
161
|
|
|
154
162
|
// here we should do schedule(dynamic) but this segfaults for
|
|
155
163
|
// some versions of LLVM. The performance impact should not be
|
|
156
164
|
// too large when (i1 - i0) / num_threads >> 1
|
|
157
165
|
#pragma omp for schedule(static)
|
|
158
|
-
for (
|
|
166
|
+
for (int64_t i = i0; i < i1; i++) {
|
|
159
167
|
storage_idx_t pt_id = order[i];
|
|
160
168
|
dis->set_query(x + (pt_id - n0) * d);
|
|
161
169
|
|
|
@@ -169,12 +177,12 @@ void hnsw_add_vertices(
|
|
|
169
177
|
pt_level,
|
|
170
178
|
pt_id,
|
|
171
179
|
locks,
|
|
172
|
-
vt,
|
|
180
|
+
*vt,
|
|
173
181
|
index_hnsw.keep_max_size_level0 && (pt_level == 0));
|
|
174
182
|
|
|
175
|
-
if (
|
|
183
|
+
if (do_display && i - i0 > prev_display + 10000) {
|
|
176
184
|
prev_display = i - i0;
|
|
177
|
-
printf(" %
|
|
185
|
+
printf(" %zu / %zu\r", i - i0, i1 - i0);
|
|
178
186
|
fflush(stdout);
|
|
179
187
|
}
|
|
180
188
|
if (counter % check_period == 0) {
|
|
@@ -199,9 +207,8 @@ void hnsw_add_vertices(
|
|
|
199
207
|
if (verbose) {
|
|
200
208
|
printf("Done in %.3f ms\n", getmillisecs() - t0);
|
|
201
209
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
omp_destroy_lock(&locks[i]);
|
|
210
|
+
if (!index_hnsw.retain_locks) {
|
|
211
|
+
locks.clear();
|
|
205
212
|
}
|
|
206
213
|
}
|
|
207
214
|
|
|
@@ -211,12 +218,17 @@ void hnsw_add_vertices(
|
|
|
211
218
|
* IndexHNSW implementation
|
|
212
219
|
**************************************************************/
|
|
213
220
|
|
|
214
|
-
IndexHNSW::IndexHNSW(int
|
|
215
|
-
: Index(
|
|
221
|
+
IndexHNSW::IndexHNSW(int d_in, int M, MetricType metric)
|
|
222
|
+
: Index(d_in, metric), hnsw(M) {
|
|
223
|
+
hnsw.is_similarity = is_similarity_metric(metric);
|
|
224
|
+
}
|
|
216
225
|
|
|
217
|
-
IndexHNSW::IndexHNSW(Index*
|
|
218
|
-
: Index(
|
|
226
|
+
IndexHNSW::IndexHNSW(Index* storage_in, int M)
|
|
227
|
+
: Index(storage_in->d, storage_in->metric_type),
|
|
228
|
+
hnsw(M),
|
|
229
|
+
storage(storage_in) {
|
|
219
230
|
metric_arg = storage->metric_arg;
|
|
231
|
+
hnsw.is_similarity = is_similarity_metric(metric_type);
|
|
220
232
|
}
|
|
221
233
|
|
|
222
234
|
IndexHNSW::~IndexHNSW() {
|
|
@@ -263,28 +275,48 @@ void hnsw_search(
|
|
|
263
275
|
|
|
264
276
|
for (idx_t i0 = 0; i0 < n; i0 += check_period) {
|
|
265
277
|
idx_t i1 = std::min(i0 + check_period, n);
|
|
278
|
+
std::exception_ptr ex;
|
|
279
|
+
std::atomic<bool> interrupt{false};
|
|
266
280
|
|
|
267
281
|
#pragma omp parallel if (i1 - i0 > 1)
|
|
268
282
|
{
|
|
269
|
-
VisitedTable vt
|
|
270
|
-
typename BlockResultHandler::SingleResultHandler
|
|
271
|
-
|
|
272
|
-
std::unique_ptr<DistanceComputer> dis
|
|
273
|
-
|
|
283
|
+
std::unique_ptr<VisitedTable> vt;
|
|
284
|
+
std::unique_ptr<typename BlockResultHandler::SingleResultHandler>
|
|
285
|
+
res;
|
|
286
|
+
std::unique_ptr<DistanceComputer> dis;
|
|
287
|
+
try {
|
|
288
|
+
vt = VisitedTable::create(
|
|
289
|
+
index->ntotal, hnsw.use_visited_hashset);
|
|
290
|
+
res = std::make_unique<
|
|
291
|
+
typename BlockResultHandler::SingleResultHandler>(bres);
|
|
292
|
+
dis.reset(storage_distance_computer(index->storage));
|
|
293
|
+
} catch (...) {
|
|
294
|
+
omp_capture_exception(ex, [&] { interrupt = true; });
|
|
295
|
+
}
|
|
274
296
|
|
|
275
297
|
#pragma omp for reduction(+ : n1, n2, ndis, nhops) schedule(guided)
|
|
276
298
|
for (idx_t i = i0; i < i1; i++) {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
299
|
+
if (interrupt.load(std::memory_order_relaxed)) {
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
try {
|
|
303
|
+
res->begin(i);
|
|
304
|
+
dis->set_query(x + i * index->d);
|
|
305
|
+
|
|
306
|
+
HNSWStats stats =
|
|
307
|
+
hnsw.search(*dis, index, *res, *vt, params);
|
|
308
|
+
n1 += stats.n1;
|
|
309
|
+
n2 += stats.n2;
|
|
310
|
+
ndis += stats.ndis;
|
|
311
|
+
nhops += stats.nhops;
|
|
312
|
+
res->end();
|
|
313
|
+
vt->advance();
|
|
314
|
+
} catch (...) {
|
|
315
|
+
omp_capture_exception(ex, [&] { interrupt = true; });
|
|
316
|
+
}
|
|
286
317
|
}
|
|
287
318
|
}
|
|
319
|
+
omp_rethrow_if_exception(ex);
|
|
288
320
|
InterruptCallback::check();
|
|
289
321
|
}
|
|
290
322
|
|
|
@@ -302,16 +334,14 @@ void IndexHNSW::search(
|
|
|
302
334
|
const SearchParameters* params) const {
|
|
303
335
|
FAISS_THROW_IF_NOT(k > 0);
|
|
304
336
|
|
|
305
|
-
using RH = HeapBlockResultHandler<HNSW::C>;
|
|
306
|
-
RH bres(n, distances, labels, k);
|
|
307
|
-
|
|
308
|
-
hnsw_search(this, n, x, bres, params);
|
|
309
|
-
|
|
310
337
|
if (is_similarity_metric(this->metric_type)) {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
338
|
+
using RH = HeapBlockResultHandler<HNSW::C_similarity>;
|
|
339
|
+
RH bres(n, distances, labels, k);
|
|
340
|
+
hnsw_search(this, n, x, bres, params);
|
|
341
|
+
} else {
|
|
342
|
+
using RH = HeapBlockResultHandler<HNSW::C_distance>;
|
|
343
|
+
RH bres(n, distances, labels, k);
|
|
344
|
+
hnsw_search(this, n, x, bres, params);
|
|
315
345
|
}
|
|
316
346
|
}
|
|
317
347
|
|
|
@@ -321,16 +351,14 @@ void IndexHNSW::range_search(
|
|
|
321
351
|
float radius,
|
|
322
352
|
RangeSearchResult* result,
|
|
323
353
|
const SearchParameters* params) const {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
result->distances[i] = -result->distances[i];
|
|
333
|
-
}
|
|
354
|
+
if (is_similarity_metric(metric_type)) {
|
|
355
|
+
using RH = RangeSearchBlockResultHandler<HNSW::C_similarity>;
|
|
356
|
+
RH bres(result, radius);
|
|
357
|
+
hnsw_search(this, n, x, bres, params);
|
|
358
|
+
} else {
|
|
359
|
+
using RH = RangeSearchBlockResultHandler<HNSW::C_distance>;
|
|
360
|
+
RH bres(result, radius);
|
|
361
|
+
hnsw_search(this, n, x, bres, params);
|
|
334
362
|
}
|
|
335
363
|
}
|
|
336
364
|
|
|
@@ -338,8 +366,13 @@ void IndexHNSW::search1(
|
|
|
338
366
|
const float* x,
|
|
339
367
|
ResultHandler& handler,
|
|
340
368
|
SearchParameters* params) const {
|
|
341
|
-
|
|
342
|
-
|
|
369
|
+
if (is_similarity_metric(metric_type)) {
|
|
370
|
+
SingleQueryBlockResultHandler<HNSW::C_similarity, false> bres(handler);
|
|
371
|
+
hnsw_search(this, 1, x, bres, params);
|
|
372
|
+
} else {
|
|
373
|
+
SingleQueryBlockResultHandler<HNSW::C_distance, false> bres(handler);
|
|
374
|
+
hnsw_search(this, 1, x, bres, params);
|
|
375
|
+
}
|
|
343
376
|
}
|
|
344
377
|
|
|
345
378
|
void IndexHNSW::add(idx_t n, const float* x) {
|
|
@@ -347,15 +380,22 @@ void IndexHNSW::add(idx_t n, const float* x) {
|
|
|
347
380
|
storage,
|
|
348
381
|
"Please use IndexHNSWFlat (or variants) instead of IndexHNSW directly");
|
|
349
382
|
FAISS_THROW_IF_NOT(is_trained);
|
|
350
|
-
|
|
383
|
+
size_t n0 = ntotal;
|
|
351
384
|
storage->add(n, x);
|
|
352
385
|
ntotal = storage->ntotal;
|
|
353
386
|
|
|
354
|
-
hnsw_add_vertices(
|
|
387
|
+
hnsw_add_vertices(
|
|
388
|
+
*this,
|
|
389
|
+
n0,
|
|
390
|
+
n,
|
|
391
|
+
x,
|
|
392
|
+
verbose,
|
|
393
|
+
hnsw.levels.size() == static_cast<size_t>(ntotal));
|
|
355
394
|
}
|
|
356
395
|
|
|
357
396
|
void IndexHNSW::reset() {
|
|
358
397
|
hnsw.reset();
|
|
398
|
+
locks.clear();
|
|
359
399
|
storage->reset();
|
|
360
400
|
ntotal = 0;
|
|
361
401
|
}
|
|
@@ -427,48 +467,66 @@ void IndexHNSW::search_level_0(
|
|
|
427
467
|
FAISS_THROW_IF_NOT(k > 0);
|
|
428
468
|
FAISS_THROW_IF_NOT(nprobe > 0);
|
|
429
469
|
|
|
430
|
-
|
|
470
|
+
size_t hnsw_ntotal = hnsw.levels.size();
|
|
431
471
|
|
|
432
|
-
|
|
433
|
-
|
|
472
|
+
auto run = [&]<class C>() {
|
|
473
|
+
using RH = HeapBlockResultHandler<C>;
|
|
474
|
+
RH bres(n, distances, labels, k);
|
|
434
475
|
|
|
476
|
+
std::exception_ptr ex;
|
|
477
|
+
std::atomic<bool> interrupt{false};
|
|
435
478
|
#pragma omp parallel
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
479
|
+
{
|
|
480
|
+
std::unique_ptr<DistanceComputer> qdis;
|
|
481
|
+
HNSWStats search_stats;
|
|
482
|
+
std::unique_ptr<VisitedTable> vt;
|
|
483
|
+
std::unique_ptr<typename RH::SingleResultHandler> res;
|
|
484
|
+
try {
|
|
485
|
+
qdis.reset(storage_distance_computer(storage));
|
|
486
|
+
vt = VisitedTable::create(
|
|
487
|
+
hnsw_ntotal, hnsw.use_visited_hashset);
|
|
488
|
+
res = std::make_unique<typename RH::SingleResultHandler>(bres);
|
|
489
|
+
} catch (...) {
|
|
490
|
+
omp_capture_exception(ex, [&] { interrupt = true; });
|
|
491
|
+
}
|
|
442
492
|
|
|
443
493
|
#pragma omp for
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
494
|
+
for (idx_t i = 0; i < n; i++) {
|
|
495
|
+
if (interrupt.load(std::memory_order_relaxed)) {
|
|
496
|
+
continue;
|
|
497
|
+
}
|
|
498
|
+
try {
|
|
499
|
+
res->begin(i);
|
|
500
|
+
qdis->set_query(x + i * d);
|
|
501
|
+
|
|
502
|
+
hnsw.search_level_0(
|
|
503
|
+
*qdis.get(),
|
|
504
|
+
*res,
|
|
505
|
+
nprobe,
|
|
506
|
+
nearest + i * nprobe,
|
|
507
|
+
nearest_d + i * nprobe,
|
|
508
|
+
search_type,
|
|
509
|
+
search_stats,
|
|
510
|
+
*vt,
|
|
511
|
+
params);
|
|
512
|
+
res->end();
|
|
513
|
+
vt->advance();
|
|
514
|
+
} catch (...) {
|
|
515
|
+
omp_capture_exception(ex, [&] { interrupt = true; });
|
|
516
|
+
}
|
|
517
|
+
}
|
|
461
518
|
#pragma omp critical
|
|
462
|
-
|
|
463
|
-
|
|
519
|
+
{
|
|
520
|
+
hnsw_stats.combine(search_stats);
|
|
521
|
+
}
|
|
464
522
|
}
|
|
465
|
-
|
|
523
|
+
omp_rethrow_if_exception(ex);
|
|
524
|
+
};
|
|
525
|
+
|
|
466
526
|
if (is_similarity_metric(this->metric_type)) {
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
distances[i] = -distances[i];
|
|
471
|
-
}
|
|
527
|
+
run.template operator()<HNSW::C_similarity>();
|
|
528
|
+
} else {
|
|
529
|
+
run.template operator()<HNSW::C_distance>();
|
|
472
530
|
}
|
|
473
531
|
}
|
|
474
532
|
|
|
@@ -487,8 +545,8 @@ void IndexHNSW::init_level_0_from_knngraph(
|
|
|
487
545
|
|
|
488
546
|
std::priority_queue<NodeDistFarther> initial_list;
|
|
489
547
|
|
|
490
|
-
for (
|
|
491
|
-
int v1 = I[i * k + j];
|
|
548
|
+
for (int j = 0; j < k; j++) {
|
|
549
|
+
int v1 = static_cast<int>(I[i * k + j]);
|
|
492
550
|
if (v1 == i) {
|
|
493
551
|
continue;
|
|
494
552
|
}
|
|
@@ -518,14 +576,12 @@ void IndexHNSW::init_level_0_from_entry_points(
|
|
|
518
576
|
int n,
|
|
519
577
|
const storage_idx_t* points,
|
|
520
578
|
const storage_idx_t* nearests) {
|
|
521
|
-
|
|
522
|
-
for (int i = 0; i < ntotal; i++) {
|
|
523
|
-
omp_init_lock(&locks[i]);
|
|
524
|
-
}
|
|
579
|
+
locks.prepare(ntotal);
|
|
525
580
|
|
|
526
581
|
#pragma omp parallel
|
|
527
582
|
{
|
|
528
|
-
VisitedTable vt
|
|
583
|
+
std::unique_ptr<VisitedTable> vt =
|
|
584
|
+
VisitedTable::create(ntotal, hnsw.use_visited_hashset);
|
|
529
585
|
|
|
530
586
|
std::unique_ptr<DistanceComputer> dis(
|
|
531
587
|
storage_distance_computer(storage));
|
|
@@ -539,7 +595,7 @@ void IndexHNSW::init_level_0_from_entry_points(
|
|
|
539
595
|
dis->set_query(vec.data());
|
|
540
596
|
|
|
541
597
|
hnsw.add_links_starting_from(
|
|
542
|
-
*dis, pt_id, nearest, (*dis)(nearest), 0, locks
|
|
598
|
+
*dis, pt_id, nearest, (*dis)(nearest), 0, locks, *vt);
|
|
543
599
|
|
|
544
600
|
if (verbose && i % 10000 == 0) {
|
|
545
601
|
printf(" %d / %d\r", i, n);
|
|
@@ -551,8 +607,8 @@ void IndexHNSW::init_level_0_from_entry_points(
|
|
|
551
607
|
printf("\n");
|
|
552
608
|
}
|
|
553
609
|
|
|
554
|
-
|
|
555
|
-
|
|
610
|
+
if (!retain_locks) {
|
|
611
|
+
locks.clear();
|
|
556
612
|
}
|
|
557
613
|
}
|
|
558
614
|
|
|
@@ -595,7 +651,7 @@ void IndexHNSW::link_singletons() {
|
|
|
595
651
|
|
|
596
652
|
std::vector<bool> seen(ntotal);
|
|
597
653
|
|
|
598
|
-
for (
|
|
654
|
+
for (idx_t i = 0; i < ntotal; i++) {
|
|
599
655
|
size_t begin, end;
|
|
600
656
|
hnsw.neighbor_range(i, 0, &begin, &end);
|
|
601
657
|
for (size_t j = begin; j < end; j++) {
|
|
@@ -624,7 +680,7 @@ void IndexHNSW::link_singletons() {
|
|
|
624
680
|
n_sing_l1);
|
|
625
681
|
|
|
626
682
|
std::vector<float> recons(singletons.size() * d);
|
|
627
|
-
for (
|
|
683
|
+
for (size_t i = 0; i < singletons.size(); i++) {
|
|
628
684
|
FAISS_ASSERT(false); // not implemented
|
|
629
685
|
}
|
|
630
686
|
}
|
|
@@ -649,10 +705,10 @@ IndexHNSWFlat::IndexHNSWFlat() {
|
|
|
649
705
|
is_trained = true;
|
|
650
706
|
}
|
|
651
707
|
|
|
652
|
-
IndexHNSWFlat::IndexHNSWFlat(int
|
|
708
|
+
IndexHNSWFlat::IndexHNSWFlat(int d_in, int M, MetricType metric)
|
|
653
709
|
: IndexHNSW(
|
|
654
|
-
(metric == METRIC_L2) ? new IndexFlatL2(
|
|
655
|
-
: new IndexFlat(
|
|
710
|
+
(metric == METRIC_L2) ? new IndexFlatL2(d_in)
|
|
711
|
+
: new IndexFlat(d_in, metric),
|
|
656
712
|
M) {
|
|
657
713
|
own_fields = true;
|
|
658
714
|
is_trained = true;
|
|
@@ -663,17 +719,20 @@ IndexHNSWFlat::IndexHNSWFlat(int d, int M, MetricType metric)
|
|
|
663
719
|
**************************************************************/
|
|
664
720
|
|
|
665
721
|
IndexHNSWFlatPanorama::IndexHNSWFlatPanorama()
|
|
666
|
-
: IndexHNSWFlat(),
|
|
722
|
+
: IndexHNSWFlat(),
|
|
723
|
+
cum_sums(),
|
|
724
|
+
pano(sizeof(float), 1, 1),
|
|
725
|
+
num_panorama_levels(0) {}
|
|
667
726
|
|
|
668
727
|
IndexHNSWFlatPanorama::IndexHNSWFlatPanorama(
|
|
669
|
-
int
|
|
728
|
+
int d_in,
|
|
670
729
|
int M,
|
|
671
|
-
int
|
|
730
|
+
int num_panorama_levels_in,
|
|
672
731
|
MetricType metric)
|
|
673
|
-
: IndexHNSWFlat(
|
|
732
|
+
: IndexHNSWFlat(d_in, M, metric),
|
|
674
733
|
cum_sums(),
|
|
675
|
-
pano(
|
|
676
|
-
num_panorama_levels(
|
|
734
|
+
pano(d_in * sizeof(float), num_panorama_levels_in, 1),
|
|
735
|
+
num_panorama_levels(num_panorama_levels_in) {
|
|
677
736
|
// For now, we only support L2 distance.
|
|
678
737
|
// Supporting dot product and cosine distance is a trivial addition
|
|
679
738
|
// left for future work.
|
|
@@ -718,12 +777,12 @@ void IndexHNSWFlatPanorama::permute_entries(const idx_t* perm) {
|
|
|
718
777
|
IndexHNSWPQ::IndexHNSWPQ() = default;
|
|
719
778
|
|
|
720
779
|
IndexHNSWPQ::IndexHNSWPQ(
|
|
721
|
-
int
|
|
780
|
+
int d_in,
|
|
722
781
|
int pq_m,
|
|
723
782
|
int M,
|
|
724
783
|
int pq_nbits,
|
|
725
784
|
MetricType metric)
|
|
726
|
-
: IndexHNSW(new IndexPQ(
|
|
785
|
+
: IndexHNSW(new IndexPQ(d_in, pq_m, pq_nbits, metric), M) {
|
|
727
786
|
own_fields = true;
|
|
728
787
|
is_trained = false;
|
|
729
788
|
}
|
|
@@ -738,11 +797,11 @@ void IndexHNSWPQ::train(idx_t n, const float* x) {
|
|
|
738
797
|
**************************************************************/
|
|
739
798
|
|
|
740
799
|
IndexHNSWSQ::IndexHNSWSQ(
|
|
741
|
-
int
|
|
800
|
+
int d_in,
|
|
742
801
|
ScalarQuantizer::QuantizerType qtype,
|
|
743
802
|
int M,
|
|
744
803
|
MetricType metric)
|
|
745
|
-
: IndexHNSW(new IndexScalarQuantizer(
|
|
804
|
+
: IndexHNSW(new IndexScalarQuantizer(d_in, qtype, metric), M) {
|
|
746
805
|
is_trained = this->storage->is_trained;
|
|
747
806
|
own_fields = true;
|
|
748
807
|
}
|
|
@@ -777,7 +836,7 @@ int search_from_candidates_2(
|
|
|
777
836
|
idx_t* I,
|
|
778
837
|
float* D,
|
|
779
838
|
MinimaxHeap& candidates,
|
|
780
|
-
|
|
839
|
+
VisitedTableVector& vt,
|
|
781
840
|
HNSWStats& stats,
|
|
782
841
|
int level,
|
|
783
842
|
int nres_in = 0) {
|
|
@@ -855,8 +914,11 @@ void IndexHNSW2Level::search(
|
|
|
855
914
|
|
|
856
915
|
const IndexIVFPQ* index_ivfpq =
|
|
857
916
|
dynamic_cast<const IndexIVFPQ*>(storage);
|
|
917
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
918
|
+
index_ivfpq,
|
|
919
|
+
"IndexHNSW2Level mixed search requires IndexIVFPQ storage");
|
|
858
920
|
|
|
859
|
-
|
|
921
|
+
size_t nprobe = index_ivfpq->nprobe;
|
|
860
922
|
|
|
861
923
|
std::unique_ptr<idx_t[]> coarse_assign(new idx_t[n * nprobe]);
|
|
862
924
|
std::unique_ptr<float[]> coarse_dis(new float[n * nprobe]);
|
|
@@ -874,72 +936,87 @@ void IndexHNSW2Level::search(
|
|
|
874
936
|
labels,
|
|
875
937
|
false);
|
|
876
938
|
|
|
939
|
+
std::exception_ptr ex;
|
|
940
|
+
std::atomic<bool> interrupt{false};
|
|
877
941
|
#pragma omp parallel
|
|
878
942
|
{
|
|
879
943
|
// visited table (not hash set) for tri-state flags.
|
|
880
|
-
VisitedTable vt
|
|
881
|
-
std::unique_ptr<DistanceComputer> dis
|
|
882
|
-
storage_distance_computer(storage));
|
|
883
|
-
|
|
944
|
+
std::unique_ptr<VisitedTable> vt;
|
|
945
|
+
std::unique_ptr<DistanceComputer> dis;
|
|
884
946
|
constexpr int candidates_size = 1;
|
|
885
|
-
MinimaxHeap candidates
|
|
947
|
+
std::unique_ptr<MinimaxHeap> candidates;
|
|
948
|
+
try {
|
|
949
|
+
vt = VisitedTable::create(ntotal, /*use_hashset=*/false);
|
|
950
|
+
dis.reset(storage_distance_computer(storage));
|
|
951
|
+
candidates = std::make_unique<MinimaxHeap>(candidates_size);
|
|
952
|
+
} catch (...) {
|
|
953
|
+
omp_capture_exception(ex, [&] { interrupt = true; });
|
|
954
|
+
}
|
|
886
955
|
|
|
887
956
|
#pragma omp for reduction(+ : n1, n2, ndis, nhops)
|
|
888
957
|
for (idx_t i = 0; i < n; i++) {
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
958
|
+
if (interrupt.load(std::memory_order_relaxed)) {
|
|
959
|
+
continue;
|
|
960
|
+
}
|
|
961
|
+
try {
|
|
962
|
+
idx_t* idxi = labels + i * k;
|
|
963
|
+
float* simi = distances + i * k;
|
|
964
|
+
dis->set_query(x + i * d);
|
|
965
|
+
|
|
966
|
+
// mark all inverted list elements as visited
|
|
967
|
+
for (size_t j = 0; j < nprobe; j++) {
|
|
968
|
+
idx_t key = coarse_assign[j + i * nprobe];
|
|
969
|
+
if (key < 0) {
|
|
970
|
+
break;
|
|
971
|
+
}
|
|
972
|
+
size_t list_length = index_ivfpq->get_list_size(key);
|
|
973
|
+
const idx_t* ids = index_ivfpq->invlists->get_ids(key);
|
|
894
974
|
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
break;
|
|
975
|
+
for (size_t jj = 0; jj < list_length; jj++) {
|
|
976
|
+
vt->set(ids[jj]);
|
|
977
|
+
}
|
|
899
978
|
}
|
|
900
|
-
size_t list_length = index_ivfpq->get_list_size(key);
|
|
901
|
-
const idx_t* ids = index_ivfpq->invlists->get_ids(key);
|
|
902
979
|
|
|
903
|
-
|
|
904
|
-
|
|
980
|
+
candidates->clear();
|
|
981
|
+
|
|
982
|
+
for (int j = 0; j < k; j++) {
|
|
983
|
+
if (idxi[j] < 0) {
|
|
984
|
+
break;
|
|
985
|
+
}
|
|
986
|
+
candidates->push(
|
|
987
|
+
static_cast<storage_idx_t>(idxi[j]), simi[j]);
|
|
905
988
|
}
|
|
906
|
-
}
|
|
907
989
|
|
|
908
|
-
|
|
990
|
+
// reorder from sorted to heap
|
|
991
|
+
maxheap_heapify(k, simi, idxi, simi, idxi, k);
|
|
909
992
|
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
993
|
+
HNSWStats search_stats;
|
|
994
|
+
search_from_candidates_2(
|
|
995
|
+
hnsw,
|
|
996
|
+
*dis,
|
|
997
|
+
k,
|
|
998
|
+
idxi,
|
|
999
|
+
simi,
|
|
1000
|
+
*candidates,
|
|
1001
|
+
static_cast<VisitedTableVector&>(*vt),
|
|
1002
|
+
search_stats,
|
|
1003
|
+
0,
|
|
1004
|
+
k);
|
|
1005
|
+
n1 += search_stats.n1;
|
|
1006
|
+
n2 += search_stats.n2;
|
|
1007
|
+
ndis += search_stats.ndis;
|
|
1008
|
+
nhops += search_stats.nhops;
|
|
1009
|
+
|
|
1010
|
+
vt->advance();
|
|
1011
|
+
vt->advance();
|
|
1012
|
+
|
|
1013
|
+
maxheap_reorder(k, simi, idxi);
|
|
1014
|
+
} catch (...) {
|
|
1015
|
+
omp_capture_exception(ex, [&] { interrupt = true; });
|
|
915
1016
|
}
|
|
916
|
-
|
|
917
|
-
// reorder from sorted to heap
|
|
918
|
-
maxheap_heapify(k, simi, idxi, simi, idxi, k);
|
|
919
|
-
|
|
920
|
-
HNSWStats search_stats;
|
|
921
|
-
search_from_candidates_2(
|
|
922
|
-
hnsw,
|
|
923
|
-
*dis,
|
|
924
|
-
k,
|
|
925
|
-
idxi,
|
|
926
|
-
simi,
|
|
927
|
-
candidates,
|
|
928
|
-
vt,
|
|
929
|
-
search_stats,
|
|
930
|
-
0,
|
|
931
|
-
k);
|
|
932
|
-
n1 += search_stats.n1;
|
|
933
|
-
n2 += search_stats.n2;
|
|
934
|
-
ndis += search_stats.ndis;
|
|
935
|
-
nhops += search_stats.nhops;
|
|
936
|
-
|
|
937
|
-
vt.advance();
|
|
938
|
-
vt.advance();
|
|
939
|
-
|
|
940
|
-
maxheap_reorder(k, simi, idxi);
|
|
941
1017
|
}
|
|
942
1018
|
}
|
|
1019
|
+
omp_rethrow_if_exception(ex);
|
|
943
1020
|
|
|
944
1021
|
hnsw_stats.combine({n1, n2, ndis, nhops});
|
|
945
1022
|
}
|
|
@@ -976,11 +1053,11 @@ IndexHNSWCagra::IndexHNSWCagra() {
|
|
|
976
1053
|
}
|
|
977
1054
|
|
|
978
1055
|
IndexHNSWCagra::IndexHNSWCagra(
|
|
979
|
-
int
|
|
1056
|
+
int d_in,
|
|
980
1057
|
int M,
|
|
981
1058
|
MetricType metric,
|
|
982
1059
|
NumericType numeric_type)
|
|
983
|
-
: IndexHNSW(
|
|
1060
|
+
: IndexHNSW(d_in, M, metric) {
|
|
984
1061
|
FAISS_THROW_IF_NOT_MSG(
|
|
985
1062
|
((metric == METRIC_L2) || (metric == METRIC_INNER_PRODUCT)),
|
|
986
1063
|
"unsupported metric type for IndexHNSWCagra");
|
|
@@ -1024,31 +1101,51 @@ void IndexHNSWCagra::search(
|
|
|
1024
1101
|
if (!base_level_only) {
|
|
1025
1102
|
IndexHNSW::search(n, x, k, distances, labels, params);
|
|
1026
1103
|
} else {
|
|
1104
|
+
if (ntotal == 0) {
|
|
1105
|
+
std::fill(
|
|
1106
|
+
distances,
|
|
1107
|
+
distances + n * k,
|
|
1108
|
+
std::numeric_limits<float>::max());
|
|
1109
|
+
std::fill(labels, labels + n * k, -1);
|
|
1110
|
+
return;
|
|
1111
|
+
}
|
|
1027
1112
|
std::vector<storage_idx_t> nearest(n);
|
|
1028
1113
|
std::vector<float> nearest_d(n);
|
|
1029
1114
|
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1115
|
+
auto pick_entrypoints = [&]<class C>() {
|
|
1116
|
+
#pragma omp parallel for
|
|
1117
|
+
for (idx_t i = 0; i < n; i++) {
|
|
1118
|
+
std::unique_ptr<DistanceComputer> dis(
|
|
1119
|
+
storage_distance_computer(this->storage));
|
|
1120
|
+
dis->set_query(x + i * d);
|
|
1121
|
+
nearest[i] = -1;
|
|
1122
|
+
// C::neutral() is the "worst possible" value: +inf for
|
|
1123
|
+
// CMax (distance) and -inf for CMin (similarity). The
|
|
1124
|
+
// first real candidate will always be strictly better.
|
|
1125
|
+
nearest_d[i] = C::neutral();
|
|
1126
|
+
|
|
1127
|
+
std::random_device rd;
|
|
1128
|
+
std::mt19937 gen(rd());
|
|
1129
|
+
std::uniform_int_distribution<idx_t> distrib(
|
|
1130
|
+
0, this->ntotal - 1);
|
|
1131
|
+
|
|
1132
|
+
for (idx_t j = 0; j < num_base_level_search_entrypoints; j++) {
|
|
1133
|
+
auto idx = distrib(gen);
|
|
1134
|
+
auto distance = (*dis)(idx);
|
|
1135
|
+
if (C::cmp(nearest_d[i], distance)) {
|
|
1136
|
+
nearest[i] = static_cast<storage_idx_t>(idx);
|
|
1137
|
+
nearest_d[i] = distance;
|
|
1138
|
+
}
|
|
1048
1139
|
}
|
|
1140
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
1141
|
+
nearest[i] >= 0, "Could not find a valid entrypoint.");
|
|
1049
1142
|
}
|
|
1050
|
-
|
|
1051
|
-
|
|
1143
|
+
};
|
|
1144
|
+
|
|
1145
|
+
if (is_similarity_metric(metric_type)) {
|
|
1146
|
+
pick_entrypoints.template operator()<HNSW::C_similarity>();
|
|
1147
|
+
} else {
|
|
1148
|
+
pick_entrypoints.template operator()<HNSW::C_distance>();
|
|
1052
1149
|
}
|
|
1053
1150
|
|
|
1054
1151
|
search_level_0(
|
|
@@ -1065,6 +1162,77 @@ void IndexHNSWCagra::search(
|
|
|
1065
1162
|
}
|
|
1066
1163
|
}
|
|
1067
1164
|
|
|
1165
|
+
void IndexHNSWCagra::range_search(
|
|
1166
|
+
idx_t n,
|
|
1167
|
+
const float* x,
|
|
1168
|
+
float radius,
|
|
1169
|
+
RangeSearchResult* result,
|
|
1170
|
+
const SearchParameters* params) const {
|
|
1171
|
+
if (!base_level_only) {
|
|
1172
|
+
IndexHNSW::range_search(n, x, radius, result, params);
|
|
1173
|
+
return;
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
auto run = [&]<class C>() {
|
|
1177
|
+
const HNSW& hnsw = this->hnsw;
|
|
1178
|
+
size_t n1 = 0, n2 = 0, ndis = 0, nhops = 0;
|
|
1179
|
+
RangeSearchPartialResult pres(result);
|
|
1180
|
+
|
|
1181
|
+
for (idx_t i = 0; i < n; i++) {
|
|
1182
|
+
std::unique_ptr<DistanceComputer> dis(
|
|
1183
|
+
storage_distance_computer(storage));
|
|
1184
|
+
dis->set_query(x + i * d);
|
|
1185
|
+
|
|
1186
|
+
storage_idx_t nearest = -1;
|
|
1187
|
+
// C::neutral() is the "worst possible" value under C: +inf for
|
|
1188
|
+
// CMax (distance) and -inf for CMin (similarity). The first
|
|
1189
|
+
// real candidate will always be strictly better.
|
|
1190
|
+
float nearest_d = C::neutral();
|
|
1191
|
+
|
|
1192
|
+
std::random_device rd;
|
|
1193
|
+
std::mt19937 gen(rd());
|
|
1194
|
+
std::uniform_int_distribution<idx_t> distrib(0, ntotal - 1);
|
|
1195
|
+
|
|
1196
|
+
for (idx_t j = 0; j < num_base_level_search_entrypoints; j++) {
|
|
1197
|
+
auto idx = distrib(gen);
|
|
1198
|
+
auto distance = (*dis)(idx);
|
|
1199
|
+
// C::cmp(nearest_d, distance) is true iff distance is
|
|
1200
|
+
// strictly better than the current nearest_d.
|
|
1201
|
+
if (C::cmp(nearest_d, distance)) {
|
|
1202
|
+
nearest = idx;
|
|
1203
|
+
nearest_d = distance;
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
1207
|
+
nearest >= 0, "Could not find a valid entrypoint.");
|
|
1208
|
+
|
|
1209
|
+
RangeQueryResult& qres = pres.new_result(i);
|
|
1210
|
+
RangeResultHandler<C> res(&qres, radius);
|
|
1211
|
+
std::unique_ptr<VisitedTable> vt =
|
|
1212
|
+
VisitedTable::create(ntotal, hnsw.use_visited_hashset);
|
|
1213
|
+
HNSWStats stats;
|
|
1214
|
+
hnsw.search_level_0(
|
|
1215
|
+
*dis, res, 1, &nearest, &nearest_d, 1, stats, *vt, params);
|
|
1216
|
+
n1 += stats.n1;
|
|
1217
|
+
n2 += stats.n2;
|
|
1218
|
+
ndis += stats.ndis;
|
|
1219
|
+
nhops += stats.nhops;
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
pres.set_lims();
|
|
1223
|
+
result->do_allocation();
|
|
1224
|
+
pres.copy_result();
|
|
1225
|
+
|
|
1226
|
+
hnsw_stats.combine({n1, n2, ndis, nhops});
|
|
1227
|
+
};
|
|
1228
|
+
|
|
1229
|
+
if (is_similarity_metric(metric_type)) {
|
|
1230
|
+
run.template operator()<HNSW::C_similarity>();
|
|
1231
|
+
} else {
|
|
1232
|
+
run.template operator()<HNSW::C_distance>();
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1068
1236
|
faiss::NumericType IndexHNSWCagra::get_numeric_type() const {
|
|
1069
1237
|
return numeric_type_;
|
|
1070
1238
|
}
|