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
|
@@ -0,0 +1,326 @@
|
|
|
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/kernels.h>
|
|
9
|
+
|
|
10
|
+
#include <algorithm>
|
|
11
|
+
#include <cmath>
|
|
12
|
+
#include <limits>
|
|
13
|
+
#include <memory>
|
|
14
|
+
#include <typeinfo>
|
|
15
|
+
#include <vector>
|
|
16
|
+
|
|
17
|
+
#include <faiss/IndexScalarQuantizer.h>
|
|
18
|
+
#include <faiss/impl/FaissAssert.h>
|
|
19
|
+
#include <faiss/utils/Heap.h>
|
|
20
|
+
|
|
21
|
+
extern "C" {
|
|
22
|
+
|
|
23
|
+
// this is to keep the clang syntax checker happy
|
|
24
|
+
#ifndef FINTEGER
|
|
25
|
+
#define FINTEGER int
|
|
26
|
+
#endif
|
|
27
|
+
|
|
28
|
+
/* declare BLAS functions, see http://www.netlib.org/clapack/cblas/ */
|
|
29
|
+
|
|
30
|
+
int sgemm_(
|
|
31
|
+
const char* transa,
|
|
32
|
+
const char* transb,
|
|
33
|
+
FINTEGER* m,
|
|
34
|
+
FINTEGER* n,
|
|
35
|
+
FINTEGER* k,
|
|
36
|
+
const float* alpha,
|
|
37
|
+
const float* a,
|
|
38
|
+
FINTEGER* lda,
|
|
39
|
+
const float* b,
|
|
40
|
+
FINTEGER* ldb,
|
|
41
|
+
float* beta,
|
|
42
|
+
float* c,
|
|
43
|
+
FINTEGER* ldc);
|
|
44
|
+
|
|
45
|
+
int ssyrk_(
|
|
46
|
+
const char* uplo,
|
|
47
|
+
const char* trans,
|
|
48
|
+
FINTEGER* n,
|
|
49
|
+
FINTEGER* k,
|
|
50
|
+
float* alpha,
|
|
51
|
+
float* a,
|
|
52
|
+
FINTEGER* lda,
|
|
53
|
+
float* beta,
|
|
54
|
+
float* c,
|
|
55
|
+
FINTEGER* ldc);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
namespace faiss {
|
|
59
|
+
namespace pipnn {
|
|
60
|
+
|
|
61
|
+
namespace {
|
|
62
|
+
|
|
63
|
+
FINTEGER to_finteger(size_t v, const char* what) {
|
|
64
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
65
|
+
v <= size_t(std::numeric_limits<FINTEGER>::max()),
|
|
66
|
+
"PiPNN kernel: %s=%zu exceeds the BLAS integer range",
|
|
67
|
+
what,
|
|
68
|
+
v);
|
|
69
|
+
return static_cast<FINTEGER>(v);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
float nan_to_inf(float v) {
|
|
73
|
+
return std::isnan(v) ? std::numeric_limits<float>::infinity() : v;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/// Top-k in (dist, index) order on a Faiss max-heap. Empty slots are
|
|
77
|
+
/// (+inf, INT32_MAX), so +inf offers still fill them, in index order.
|
|
78
|
+
using TopK = CMax<float, int32_t>;
|
|
79
|
+
constexpr int32_t kEmpty = std::numeric_limits<int32_t>::max();
|
|
80
|
+
|
|
81
|
+
void topk_init(float* D, int32_t* I, size_t k) {
|
|
82
|
+
std::fill(D, D + k, std::numeric_limits<float>::infinity());
|
|
83
|
+
std::fill(I, I + k, kEmpty);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
void topk_offer(float* D, int32_t* I, size_t k, float v, int32_t id) {
|
|
87
|
+
if (TopK::cmp2(D[0], v, I[0], id)) {
|
|
88
|
+
heap_replace_top<TopK>(k, D, I, v, id);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/// Sorts the slots by (dist, index); slots never filled become (+inf, -1).
|
|
93
|
+
void topk_finish(float* D, int32_t* I, size_t k) {
|
|
94
|
+
heap_reorder<TopK>(k, D, I);
|
|
95
|
+
std::replace(I, I + k, kEmpty, int32_t(-1));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
} // namespace
|
|
99
|
+
|
|
100
|
+
void stripe_assign(
|
|
101
|
+
const float* points,
|
|
102
|
+
size_t S,
|
|
103
|
+
const float* leaders,
|
|
104
|
+
const float* leader_norms,
|
|
105
|
+
size_t L,
|
|
106
|
+
size_t d,
|
|
107
|
+
Ranking ranking,
|
|
108
|
+
int fanout,
|
|
109
|
+
float* scratch,
|
|
110
|
+
uint16_t* out) {
|
|
111
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
112
|
+
L >= 1 && L <= 65535,
|
|
113
|
+
"stripe_assign: L=%zu must be in [1, 65535]",
|
|
114
|
+
L);
|
|
115
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
116
|
+
fanout >= 1 && size_t(fanout) <= L,
|
|
117
|
+
"stripe_assign: fanout=%d must be in [1, L=%zu]",
|
|
118
|
+
fanout,
|
|
119
|
+
L);
|
|
120
|
+
FAISS_THROW_IF_NOT_MSG(d >= 1, "stripe_assign: d must be >= 1");
|
|
121
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
122
|
+
ranking == Ranking::IP || leader_norms,
|
|
123
|
+
"stripe_assign: leader_norms is required for the L2 and Angle rankings");
|
|
124
|
+
if (S == 0) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
FINTEGER li = to_finteger(L, "L");
|
|
128
|
+
FINTEGER si = to_finteger(S, "S");
|
|
129
|
+
FINTEGER di = to_finteger(d, "d");
|
|
130
|
+
|
|
131
|
+
// Column-major BLAS sees row-major scratch (S x L) as L x S, so "T", "N"
|
|
132
|
+
// gives scratch[i * L + j] = alpha * p_i.l_j + beta * scratch[i * L + j].
|
|
133
|
+
float alpha = -1;
|
|
134
|
+
float beta = 0; // BLAS does not read C when beta == 0
|
|
135
|
+
if (ranking == Ranking::L2) {
|
|
136
|
+
for (size_t i = 0; i < S; i++) {
|
|
137
|
+
std::copy(leader_norms, leader_norms + L, scratch + i * L);
|
|
138
|
+
}
|
|
139
|
+
alpha = -2;
|
|
140
|
+
beta = 1;
|
|
141
|
+
}
|
|
142
|
+
sgemm_("T",
|
|
143
|
+
"N",
|
|
144
|
+
&li,
|
|
145
|
+
&si,
|
|
146
|
+
&di,
|
|
147
|
+
&alpha,
|
|
148
|
+
leaders,
|
|
149
|
+
&di,
|
|
150
|
+
points,
|
|
151
|
+
&di,
|
|
152
|
+
&beta,
|
|
153
|
+
scratch,
|
|
154
|
+
&li);
|
|
155
|
+
|
|
156
|
+
if (ranking == Ranking::Angle) {
|
|
157
|
+
// A zero-norm leader has no direction: rank it +inf, not the -inf of
|
|
158
|
+
// a positive dot product divided by 0.
|
|
159
|
+
for (size_t i = 0; i < S; i++) {
|
|
160
|
+
float* row = scratch + i * L;
|
|
161
|
+
for (size_t j = 0; j < L; j++) {
|
|
162
|
+
const float len = std::sqrt(leader_norms[j]);
|
|
163
|
+
row[j] = len > 0 ? row[j] / len
|
|
164
|
+
: std::numeric_limits<float>::infinity();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const size_t f = size_t(fanout);
|
|
170
|
+
std::vector<float> D(f);
|
|
171
|
+
std::vector<int32_t> I(f);
|
|
172
|
+
for (size_t i = 0; i < S; i++) {
|
|
173
|
+
topk_init(D.data(), I.data(), f);
|
|
174
|
+
const float* row = scratch + i * L;
|
|
175
|
+
for (size_t j = 0; j < L; j++) {
|
|
176
|
+
topk_offer(D.data(), I.data(), f, nan_to_inf(row[j]), int32_t(j));
|
|
177
|
+
}
|
|
178
|
+
topk_finish(D.data(), I.data(), f);
|
|
179
|
+
// L >= fanout and every offer precedes an empty slot, so all fanout
|
|
180
|
+
// slots are filled, even when the whole row is +inf.
|
|
181
|
+
for (size_t r = 0; r < f; r++) {
|
|
182
|
+
out[i * f + r] = uint16_t(I[r]);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
namespace {
|
|
188
|
+
|
|
189
|
+
/// Distance from a Gram entry: L2 max(0, ni + nj - 2g), IP -g. NaN is mapped
|
|
190
|
+
/// to +inf before the L2 clamp, which would otherwise turn it into 0.
|
|
191
|
+
float gram_to_distance(bool is_l2, float ni, float nj, float g) {
|
|
192
|
+
if (is_l2) {
|
|
193
|
+
const float v = ni + nj - 2 * g;
|
|
194
|
+
if (std::isnan(v)) {
|
|
195
|
+
return std::numeric_limits<float>::infinity();
|
|
196
|
+
}
|
|
197
|
+
return v < 0 ? 0 : v;
|
|
198
|
+
}
|
|
199
|
+
return nan_to_inf(-g);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/// Lower triangle of X X^T, diagonal included, into row-major gram (s x s);
|
|
203
|
+
/// the strict upper triangle is not written.
|
|
204
|
+
void gram_lower(const float* X, size_t s, size_t d, float* gram) {
|
|
205
|
+
// Column-major BLAS reads X as A = X^T (d x s); the upper triangle of
|
|
206
|
+
// C = A^T A ("U", "T") is the row-major lower triangle of gram.
|
|
207
|
+
FINTEGER si = to_finteger(s, "s");
|
|
208
|
+
FINTEGER di = to_finteger(d, "d");
|
|
209
|
+
float one = 1;
|
|
210
|
+
float zero = 0; // BLAS does not read C when beta == 0
|
|
211
|
+
ssyrk_("U",
|
|
212
|
+
"T",
|
|
213
|
+
&si,
|
|
214
|
+
&di,
|
|
215
|
+
&one,
|
|
216
|
+
const_cast<float*>(X),
|
|
217
|
+
&di,
|
|
218
|
+
&zero,
|
|
219
|
+
gram,
|
|
220
|
+
&si);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
} // namespace
|
|
224
|
+
|
|
225
|
+
void leaf_knn(
|
|
226
|
+
const float* X,
|
|
227
|
+
const float* norms,
|
|
228
|
+
size_t s,
|
|
229
|
+
size_t d,
|
|
230
|
+
MetricType metric,
|
|
231
|
+
int k,
|
|
232
|
+
float* gram,
|
|
233
|
+
int32_t* nn_idx,
|
|
234
|
+
float* nn_dist) {
|
|
235
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
236
|
+
metric == METRIC_L2 || metric == METRIC_INNER_PRODUCT,
|
|
237
|
+
"leaf_knn: metric must be METRIC_L2 or METRIC_INNER_PRODUCT");
|
|
238
|
+
FAISS_THROW_IF_NOT_MSG(k >= 1, "leaf_knn: k must be >= 1");
|
|
239
|
+
FAISS_THROW_IF_NOT_MSG(d >= 1, "leaf_knn: d must be >= 1");
|
|
240
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
241
|
+
metric == METRIC_INNER_PRODUCT || norms,
|
|
242
|
+
"leaf_knn: norms is required for METRIC_L2");
|
|
243
|
+
const size_t kk = size_t(k);
|
|
244
|
+
for (size_t i = 0; i < s; i++) {
|
|
245
|
+
topk_init(nn_dist + i * kk, nn_idx + i * kk, kk);
|
|
246
|
+
}
|
|
247
|
+
if (s >= 2) {
|
|
248
|
+
gram_lower(X, s, d, gram);
|
|
249
|
+
}
|
|
250
|
+
const bool is_l2 = metric == METRIC_L2;
|
|
251
|
+
for (size_t i = 1; i < s; i++) {
|
|
252
|
+
const float* gi = gram + i * s;
|
|
253
|
+
const float ni = is_l2 ? norms[i] : 0;
|
|
254
|
+
for (size_t j = 0; j < i; j++) {
|
|
255
|
+
const float nj = is_l2 ? norms[j] : 0;
|
|
256
|
+
const float v = gram_to_distance(is_l2, ni, nj, gi[j]);
|
|
257
|
+
topk_offer(nn_dist + i * kk, nn_idx + i * kk, kk, v, int32_t(j));
|
|
258
|
+
topk_offer(nn_dist + j * kk, nn_idx + j * kk, kk, v, int32_t(i));
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
for (size_t i = 0; i < s; i++) {
|
|
262
|
+
topk_finish(nn_dist + i * kk, nn_idx + i * kk, kk);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
void pairwise_distances(
|
|
267
|
+
const float* X,
|
|
268
|
+
const float* norms,
|
|
269
|
+
size_t n,
|
|
270
|
+
size_t d,
|
|
271
|
+
MetricType metric,
|
|
272
|
+
float* out) {
|
|
273
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
274
|
+
metric == METRIC_L2 || metric == METRIC_INNER_PRODUCT,
|
|
275
|
+
"pairwise_distances: metric must be METRIC_L2 or METRIC_INNER_PRODUCT");
|
|
276
|
+
FAISS_THROW_IF_NOT_MSG(d >= 1, "pairwise_distances: d must be >= 1");
|
|
277
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
278
|
+
metric == METRIC_INNER_PRODUCT || norms,
|
|
279
|
+
"pairwise_distances: norms is required for METRIC_L2");
|
|
280
|
+
if (n == 0) {
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
// Row i reads only its lower part of the Gram scratch; mirrored writes of
|
|
284
|
+
// earlier rows go to their strict upper triangle.
|
|
285
|
+
gram_lower(X, n, d, out);
|
|
286
|
+
const bool is_l2 = metric == METRIC_L2;
|
|
287
|
+
for (size_t i = 0; i < n; i++) {
|
|
288
|
+
float* oi = out + i * n;
|
|
289
|
+
const float ni = is_l2 ? norms[i] : 0;
|
|
290
|
+
for (size_t j = 0; j < i; j++) {
|
|
291
|
+
const float nj = is_l2 ? norms[j] : 0;
|
|
292
|
+
const float v = gram_to_distance(is_l2, ni, nj, oi[j]);
|
|
293
|
+
oi[j] = v;
|
|
294
|
+
out[j * n + i] = v;
|
|
295
|
+
}
|
|
296
|
+
oi[i] = gram_to_distance(is_l2, ni, ni, oi[i]);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
void gather_rows(
|
|
301
|
+
const Index& storage,
|
|
302
|
+
const int32_t* ids,
|
|
303
|
+
size_t k,
|
|
304
|
+
float* out) {
|
|
305
|
+
const size_t d = static_cast<size_t>(storage.d);
|
|
306
|
+
if (typeid(storage) == typeid(IndexScalarQuantizer)) {
|
|
307
|
+
// Not reconstruct: ScalarQuantizer::decode opens an OpenMP region, and
|
|
308
|
+
// a nested region inside the build's dynamic loops crashes libomp.
|
|
309
|
+
const auto& sq = static_cast<const IndexScalarQuantizer&>(storage);
|
|
310
|
+
std::unique_ptr<ScalarQuantizer::SQuantizer> quant(
|
|
311
|
+
sq.sq.select_quantizer());
|
|
312
|
+
for (size_t i = 0; i < k; i++) {
|
|
313
|
+
quant->decode_vector(
|
|
314
|
+
sq.codes.data() +
|
|
315
|
+
static_cast<size_t>(ids[i]) * sq.code_size,
|
|
316
|
+
out + i * d);
|
|
317
|
+
}
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
for (size_t i = 0; i < k; i++) {
|
|
321
|
+
storage.reconstruct(ids[i], out + i * d);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
} // namespace pipnn
|
|
326
|
+
} // namespace faiss
|
|
@@ -0,0 +1,92 @@
|
|
|
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 <faiss/MetricType.h>
|
|
11
|
+
#include <faiss/utils/AlignedTable.h>
|
|
12
|
+
#include <cstddef>
|
|
13
|
+
#include <cstdint>
|
|
14
|
+
|
|
15
|
+
/*
|
|
16
|
+
* Each kernel makes one BLAS call (sgemm_ or ssyrk_), and results are bitwise
|
|
17
|
+
* reproducible across thread counts only if that call runs single-threaded.
|
|
18
|
+
* So call the kernels inside an OpenMP parallel region, or from serial code
|
|
19
|
+
* only when omp_get_max_threads() == 1, and keep BLAS from threading on its
|
|
20
|
+
* own: MKL_NUM_THREADS unset or 1, OPENBLAS_NUM_THREADS=1 for pthreads
|
|
21
|
+
* OpenBLAS, VECLIB_MAXIMUM_THREADS=1 on macOS, OMP_NUM_THREADS=1 for an
|
|
22
|
+
* OpenMP BLAS in a Faiss build without OpenMP. Inputs should be 64-byte
|
|
23
|
+
* aligned: some BLAS round differently on differently aligned buffers.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
namespace faiss {
|
|
27
|
+
|
|
28
|
+
struct Index;
|
|
29
|
+
|
|
30
|
+
namespace pipnn {
|
|
31
|
+
|
|
32
|
+
/// Points per stripe item of the partition kernel. Changing it changes graphs.
|
|
33
|
+
constexpr size_t kStripe = 1024;
|
|
34
|
+
|
|
35
|
+
enum class Ranking : uint8_t { L2 = 0, IP = 1, Angle = 2 };
|
|
36
|
+
|
|
37
|
+
/// out (S x fanout): each point's nearest leaders in (rank, index) order, with
|
|
38
|
+
/// rank L2 ||l||^2 - 2 p.l, IP -p.l, Angle -p.l / ||l|| (+inf if ||l|| = 0).
|
|
39
|
+
/// NaN ranks +inf. scratch: S * L floats; leader_norms may be null for IP.
|
|
40
|
+
void stripe_assign(
|
|
41
|
+
const float* points,
|
|
42
|
+
size_t S,
|
|
43
|
+
const float* leaders,
|
|
44
|
+
const float* leader_norms,
|
|
45
|
+
size_t L,
|
|
46
|
+
size_t d,
|
|
47
|
+
Ranking ranking,
|
|
48
|
+
int fanout,
|
|
49
|
+
float* scratch,
|
|
50
|
+
uint16_t* out);
|
|
51
|
+
|
|
52
|
+
/// k nearest neighbours (s x k) of each leaf point in (dist, index) order;
|
|
53
|
+
/// unfilled slots are -1 / +inf. gram: s * s floats; norms null for IP only.
|
|
54
|
+
void leaf_knn(
|
|
55
|
+
const float* X,
|
|
56
|
+
const float* norms,
|
|
57
|
+
size_t s,
|
|
58
|
+
size_t d,
|
|
59
|
+
MetricType metric,
|
|
60
|
+
int k,
|
|
61
|
+
float* gram,
|
|
62
|
+
int32_t* nn_idx,
|
|
63
|
+
float* nn_dist);
|
|
64
|
+
|
|
65
|
+
/// n x n distances (L2 clamped at 0, IP -dot); out is also the Gram scratch.
|
|
66
|
+
/// The L2 diagonal is small and non-negative, but not necessarily 0.
|
|
67
|
+
void pairwise_distances(
|
|
68
|
+
const float* X,
|
|
69
|
+
const float* norms,
|
|
70
|
+
size_t n,
|
|
71
|
+
size_t d,
|
|
72
|
+
MetricType metric,
|
|
73
|
+
float* out);
|
|
74
|
+
|
|
75
|
+
/// Rows ids[0..k) of `storage` as floats into out (k x d). SQ rows are decoded
|
|
76
|
+
/// directly; other types use reconstruct(), which must not open OpenMP regions.
|
|
77
|
+
void gather_rows(
|
|
78
|
+
const Index& storage,
|
|
79
|
+
const int32_t* ids,
|
|
80
|
+
size_t k,
|
|
81
|
+
float* out);
|
|
82
|
+
|
|
83
|
+
/// Grows a per-thread scratch table and never shrinks it: AlignedTable::resize
|
|
84
|
+
/// reallocates whenever the rounded capacity changes, shrinking included.
|
|
85
|
+
inline void ensure_size(AlignedTable<float, 64>& table, size_t n) {
|
|
86
|
+
if (table.size() < n) {
|
|
87
|
+
table.resize(n);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
} // namespace pipnn
|
|
92
|
+
} // namespace faiss
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
#pragma once
|
|
9
9
|
|
|
10
10
|
// basic int types and size_t
|
|
11
|
+
#include <atomic>
|
|
11
12
|
#include <cstdint>
|
|
12
13
|
#include <cstdio>
|
|
13
14
|
|
|
@@ -146,6 +147,33 @@ inline int __builtin_clzll(uint64_t x) {
|
|
|
146
147
|
#define FAISS_DEPRECATED(msg)
|
|
147
148
|
#endif // GCC or Clang
|
|
148
149
|
|
|
150
|
+
// Never inlined, so floating-point results do not depend on the compile
|
|
151
|
+
// flags of the call site (e.g. under LTO).
|
|
152
|
+
#if defined(_MSC_VER)
|
|
153
|
+
#define FAISS_NOINLINE __declspec(noinline)
|
|
154
|
+
#elif defined(__clang__)
|
|
155
|
+
#define FAISS_NOINLINE __attribute__((noinline))
|
|
156
|
+
#elif defined(__GNUC__)
|
|
157
|
+
#define FAISS_NOINLINE __attribute__((noinline, noclone))
|
|
158
|
+
#else
|
|
159
|
+
#define FAISS_NOINLINE
|
|
160
|
+
#endif
|
|
161
|
+
|
|
162
|
+
namespace faiss {
|
|
163
|
+
namespace detail {
|
|
164
|
+
|
|
165
|
+
template <typename T>
|
|
166
|
+
inline void atomic_fetch_add_relaxed(T& target, T value) {
|
|
167
|
+
#if defined(__cpp_lib_atomic_ref) && __cpp_lib_atomic_ref >= 201806L
|
|
168
|
+
std::atomic_ref<T>(target).fetch_add(value, std::memory_order_relaxed);
|
|
169
|
+
#else
|
|
170
|
+
__atomic_fetch_add(&target, value, __ATOMIC_RELAXED);
|
|
171
|
+
#endif
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
} // namespace detail
|
|
175
|
+
} // namespace faiss
|
|
176
|
+
|
|
149
177
|
// Localized enablement of imprecise floating point operations
|
|
150
178
|
// You need to use all 3 macros to cover all compilers.
|
|
151
179
|
#if defined(_MSC_VER)
|
|
@@ -226,3 +254,20 @@ inline int __builtin_clzll(uint64_t x) {
|
|
|
226
254
|
#define FAISS_MAYBE_UNUSED [[maybe_unused]]
|
|
227
255
|
#define FAISS_FINAL final
|
|
228
256
|
#endif
|
|
257
|
+
|
|
258
|
+
/*******************************************************
|
|
259
|
+
* OpenMP dynamic scheduling
|
|
260
|
+
*******************************************************/
|
|
261
|
+
|
|
262
|
+
// Use as schedule(FAISS_OMP_DYNAMIC) or schedule(FAISS_OMP_DYNAMIC, chunk).
|
|
263
|
+
// OpenMP 5.0 makes schedule(dynamic) nonmonotonic, and libomp 12 runs
|
|
264
|
+
// nonmonotonic dynamic loops with its static-steal scheduler, which crashes
|
|
265
|
+
// intermittently under load (libomp itself keeps it off by default). MSVC's
|
|
266
|
+
// OpenMP 2.0 has no schedule modifiers.
|
|
267
|
+
// clang-format off
|
|
268
|
+
#ifdef _MSC_VER
|
|
269
|
+
#define FAISS_OMP_DYNAMIC dynamic
|
|
270
|
+
#else
|
|
271
|
+
#define FAISS_OMP_DYNAMIC monotonic : dynamic
|
|
272
|
+
#endif
|
|
273
|
+
// clang-format on
|
|
@@ -7,8 +7,6 @@
|
|
|
7
7
|
|
|
8
8
|
// -*- c++ -*-
|
|
9
9
|
|
|
10
|
-
#ifdef COMPILE_SIMD_AVX512
|
|
11
|
-
|
|
12
10
|
#include <faiss/impl/PolysemousTraining.h>
|
|
13
11
|
#include <faiss/impl/polysemous_training/dispatch.h>
|
|
14
12
|
#include <faiss/utils/popcount.h>
|
|
@@ -280,5 +278,3 @@ double distances_cost_update<SIMDLevel::AVX512>(
|
|
|
280
278
|
|
|
281
279
|
} // namespace polysemous_training
|
|
282
280
|
} // namespace faiss
|
|
283
|
-
|
|
284
|
-
#endif // COMPILE_SIMD_AVX512
|
|
@@ -11,9 +11,14 @@
|
|
|
11
11
|
#error "THE_SIMD_LEVEL must be defined before including IVFPQScanner_impl.h"
|
|
12
12
|
#endif
|
|
13
13
|
|
|
14
|
+
#include <algorithm>
|
|
15
|
+
#include <cstring>
|
|
16
|
+
#include <type_traits>
|
|
17
|
+
|
|
14
18
|
#include <faiss/IndexIVFPQ.h>
|
|
15
19
|
#include <faiss/impl/IDSelector.h>
|
|
16
20
|
#include <faiss/impl/ResultHandler.h>
|
|
21
|
+
#include <faiss/impl/platform_macros.h>
|
|
17
22
|
#include <faiss/impl/pq_code_distance/IVFPQ_QueryTables.h>
|
|
18
23
|
#include <faiss/impl/pq_code_distance/pq_code_distance-inl.h>
|
|
19
24
|
#include <faiss/impl/simd_dispatch.h>
|
|
@@ -70,6 +75,48 @@ struct WrappedSearchResult {
|
|
|
70
75
|
}
|
|
71
76
|
};
|
|
72
77
|
|
|
78
|
+
/** For each sub-quantizer, a block of codes reads one 1 KB table slice, which
|
|
79
|
+
* stays in L1; code by code, a table larger than L1 makes every lookup an L1
|
|
80
|
+
* miss. SL as in PQCodeDistanceScalar. */
|
|
81
|
+
template <SIMDLevel SL>
|
|
82
|
+
void pq_distances_8bit_by_block(
|
|
83
|
+
size_t M,
|
|
84
|
+
const float* sim_table,
|
|
85
|
+
float dis0,
|
|
86
|
+
size_t n,
|
|
87
|
+
const uint8_t* codes,
|
|
88
|
+
float* distances) {
|
|
89
|
+
constexpr size_t kBlock = 64;
|
|
90
|
+
constexpr size_t ksub = PQCodeDistanceScalar8<SL>::ksub;
|
|
91
|
+
for (size_t j0 = 0; j0 < n; j0 += kBlock) {
|
|
92
|
+
const size_t nb = std::min(kBlock, n - j0);
|
|
93
|
+
const uint8_t* block = codes + j0 * M;
|
|
94
|
+
float* acc = distances + j0;
|
|
95
|
+
std::fill(acc, acc + nb, 0.0f);
|
|
96
|
+
const float* tab = sim_table;
|
|
97
|
+
size_t m = 0;
|
|
98
|
+
for (; m + 4 <= M; m += 4, tab += 4 * ksub) {
|
|
99
|
+
const uint8_t* c = block + m;
|
|
100
|
+
for (size_t b = 0; b < nb; b++) {
|
|
101
|
+
uint32_t w;
|
|
102
|
+
memcpy(&w, c + b * M, sizeof(w));
|
|
103
|
+
acc[b] += (tab[w & 255] + tab[ksub + ((w >> 8) & 255)]) +
|
|
104
|
+
(tab[2 * ksub + ((w >> 16) & 255)] +
|
|
105
|
+
tab[3 * ksub + (w >> 24)]);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
for (; m < M; m++, tab += ksub) {
|
|
109
|
+
const uint8_t* c = block + m;
|
|
110
|
+
for (size_t b = 0; b < nb; b++) {
|
|
111
|
+
acc[b] += tab[c[b * M]];
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
for (size_t b = 0; b < nb; b++) {
|
|
115
|
+
acc[b] += dis0;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
73
120
|
/*****************************************************
|
|
74
121
|
* Scaning the codes.
|
|
75
122
|
* The scanning functions call their favorite precompute_*
|
|
@@ -411,10 +458,8 @@ struct IVFPQScannerT : QueryTables {
|
|
|
411
458
|
}
|
|
412
459
|
}
|
|
413
460
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
indexIVFPQ_stats.n_hamming_pass += n_hamming_pass;
|
|
417
|
-
}
|
|
461
|
+
detail::atomic_fetch_add_relaxed(
|
|
462
|
+
indexIVFPQ_stats.n_hamming_pass, n_hamming_pass);
|
|
418
463
|
}
|
|
419
464
|
|
|
420
465
|
template <class SearchResultType>
|
|
@@ -487,6 +532,29 @@ struct IVFPQScanner : IVFPQScannerT<idx_t, METRIC_TYPE, PQCodeDist>,
|
|
|
487
532
|
this->pq.M, this->pq.nbits, this->sim_table, code);
|
|
488
533
|
}
|
|
489
534
|
|
|
535
|
+
void distances_to_codes(size_t n, const uint8_t* codes, float* distances)
|
|
536
|
+
const override {
|
|
537
|
+
// Where gathers are fast (Intel), the block kernel is faster at
|
|
538
|
+
// M <= 64, and the per-code gather kernels are faster at M = 128
|
|
539
|
+
// unless all cores are busy.
|
|
540
|
+
if constexpr (
|
|
541
|
+
has_scalar_8bit_kernel<THE_SIMD_LEVEL>() &&
|
|
542
|
+
std::is_same_v<typename PQCodeDist::PQDecoder, PQDecoder8>) {
|
|
543
|
+
if (precompute_mode == 2 &&
|
|
544
|
+
(SIMDConfig::scalar_gather || this->pq.M <= 64)) {
|
|
545
|
+
pq_distances_8bit_by_block<THE_SIMD_LEVEL>(
|
|
546
|
+
this->pq.M,
|
|
547
|
+
this->sim_table,
|
|
548
|
+
this->dis0,
|
|
549
|
+
n,
|
|
550
|
+
codes,
|
|
551
|
+
distances);
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
InvertedListScanner::distances_to_codes(n, codes, distances);
|
|
556
|
+
}
|
|
557
|
+
|
|
490
558
|
size_t scan_codes(
|
|
491
559
|
size_t ncode,
|
|
492
560
|
const uint8_t* codes,
|
|
@@ -560,6 +628,13 @@ InvertedListScanner* make_IVFPQInvertedListScanner<THE_SIMD_LEVEL>(
|
|
|
560
628
|
|
|
561
629
|
auto with_decoder = [&]<bool use_sel>() -> InvertedListScanner* {
|
|
562
630
|
if (ivfpq.pq.nbits == 8) {
|
|
631
|
+
if constexpr (has_scalar_8bit_kernel<THE_SIMD_LEVEL>()) {
|
|
632
|
+
if (use_scalar_8bit_kernel<THE_SIMD_LEVEL>(ivfpq.pq.M)) {
|
|
633
|
+
return make.template operator()<
|
|
634
|
+
PQCodeDistanceScalar8Dist<THE_SIMD_LEVEL>,
|
|
635
|
+
use_sel>();
|
|
636
|
+
}
|
|
637
|
+
}
|
|
563
638
|
return make.template
|
|
564
639
|
operator()<PQCodeDistance<PQDecoder8, THE_SIMD_LEVEL>, use_sel>();
|
|
565
640
|
} else if (ivfpq.pq.nbits == 16) {
|
|
@@ -102,6 +102,12 @@ template <>
|
|
|
102
102
|
FlatCodesDistanceComputer* get_PQFlatCodesDistanceComputer<THE_SIMD_LEVEL>(
|
|
103
103
|
const IndexPQ& index) {
|
|
104
104
|
if (index.pq.nbits == 8) {
|
|
105
|
+
if constexpr (has_scalar_8bit_kernel<THE_SIMD_LEVEL>()) {
|
|
106
|
+
if (use_scalar_8bit_kernel<THE_SIMD_LEVEL>(index.pq.M)) {
|
|
107
|
+
return new PQDistanceComputer<
|
|
108
|
+
PQCodeDistanceScalar8Dist<THE_SIMD_LEVEL>>(index);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
105
111
|
return new PQDistanceComputer<
|
|
106
112
|
PQCodeDistance<PQDecoder8, THE_SIMD_LEVEL>>(index);
|
|
107
113
|
} else if (index.pq.nbits == 16) {
|
|
@@ -5,8 +5,6 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
#ifdef COMPILE_SIMD_AVX2
|
|
9
|
-
|
|
10
8
|
#define THE_SIMD_LEVEL SIMDLevel::AVX2
|
|
11
9
|
|
|
12
10
|
// NOLINTNEXTLINE(facebook-hte-InlineHeader,facebook-unused-include-check)
|
|
@@ -19,5 +17,3 @@
|
|
|
19
17
|
#include <faiss/impl/pq_code_distance/PQDistanceComputer_impl.h>
|
|
20
18
|
// NOLINTNEXTLINE(facebook-hte-InlineHeader,facebook-unused-include-check)
|
|
21
19
|
#include <faiss/impl/pq_code_distance/IVFPQScanner_impl.h>
|
|
22
|
-
|
|
23
|
-
#endif // COMPILE_SIMD_AVX2
|
|
@@ -5,8 +5,6 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
#ifdef COMPILE_SIMD_AVX512
|
|
9
|
-
|
|
10
8
|
#define THE_SIMD_LEVEL SIMDLevel::AVX512
|
|
11
9
|
|
|
12
10
|
// NOLINTNEXTLINE(facebook-hte-InlineHeader)
|
|
@@ -19,5 +17,3 @@
|
|
|
19
17
|
#include <faiss/impl/pq_code_distance/PQDistanceComputer_impl.h>
|
|
20
18
|
// NOLINTNEXTLINE(facebook-hte-InlineHeader)
|
|
21
19
|
#include <faiss/impl/pq_code_distance/IVFPQScanner_impl.h>
|
|
22
|
-
|
|
23
|
-
#endif // COMPILE_SIMD_AVX512
|
|
@@ -5,8 +5,6 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
#ifdef COMPILE_SIMD_ARM_NEON
|
|
9
|
-
|
|
10
8
|
#define THE_SIMD_LEVEL SIMDLevel::ARM_NEON
|
|
11
9
|
|
|
12
10
|
// NOLINTNEXTLINE(facebook-hte-InlineHeader)
|
|
@@ -19,5 +17,3 @@
|
|
|
19
17
|
#include <faiss/impl/pq_code_distance/PQDistanceComputer_impl.h>
|
|
20
18
|
// NOLINTNEXTLINE(facebook-hte-InlineHeader)
|
|
21
19
|
#include <faiss/impl/pq_code_distance/IVFPQScanner_impl.h>
|
|
22
|
-
|
|
23
|
-
#endif // COMPILE_SIMD_ARM_NEON
|
|
@@ -160,6 +160,10 @@ inline void distance_four_codes_avx2_pqdecoder8_m8(
|
|
|
160
160
|
namespace faiss {
|
|
161
161
|
namespace pq_code_distance {
|
|
162
162
|
|
|
163
|
+
// On AMD Zen 3/4/5 (SIMDConfig::scalar_gather) the scalar kernel is 0-48%
|
|
164
|
+
// faster than these gathers at M = 8-384; on Intel the gathers are faster.
|
|
165
|
+
// The callers select it with use_scalar_8bit_kernel().
|
|
166
|
+
|
|
163
167
|
// NOLINTNEXTLINE(facebook-hte-MisplacedTemplateSpecialization)
|
|
164
168
|
template <>
|
|
165
169
|
float pq_code_distance_8bit_single_impl<SIMDLevel::AVX2>(
|