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,48 @@
|
|
|
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
|
+
/* QT_8bit reconstruction coefficients.
|
|
11
|
+
*
|
|
12
|
+
* Scalar and portable. A caller on any architecture may include this.
|
|
13
|
+
*
|
|
14
|
+
* For a QT_8bit non-uniform quantizer with trained values vmin and vdiff:
|
|
15
|
+
*
|
|
16
|
+
* a[i] = vdiff[i] / 255
|
|
17
|
+
* rmin[i] = vmin[i] + 0.5 * a[i]
|
|
18
|
+
* e[i] = query[i] - rmin[i]
|
|
19
|
+
*
|
|
20
|
+
* so reconstruct(code)[i] = rmin[i] + a[i] * code[i].
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
#include <cstddef>
|
|
24
|
+
|
|
25
|
+
namespace faiss {
|
|
26
|
+
namespace sq8 {
|
|
27
|
+
|
|
28
|
+
/// Derive the per-dimension scale and offset from a trained quantizer.
|
|
29
|
+
/// @param trained 2*d floats: vmin[0..d) then vdiff[0..d)
|
|
30
|
+
/// @param levels the largest code value: 255 for QT_8bit, 15 for QT_4bit.
|
|
31
|
+
/// Both quantizers reconstruct as rmin[i] + a[i] * code[i],
|
|
32
|
+
/// so only the divisor differs.
|
|
33
|
+
inline void make_coefficients(
|
|
34
|
+
const float* trained,
|
|
35
|
+
size_t d,
|
|
36
|
+
float* a,
|
|
37
|
+
float* rmin,
|
|
38
|
+
float levels = 255.0f) {
|
|
39
|
+
const float* vmin = trained;
|
|
40
|
+
const float* vdiff = trained + d;
|
|
41
|
+
for (size_t i = 0; i < d; i++) {
|
|
42
|
+
a[i] = vdiff[i] / levels;
|
|
43
|
+
rmin[i] = vmin[i] + 0.5f * a[i];
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
} // namespace sq8
|
|
48
|
+
} // namespace faiss
|
|
@@ -0,0 +1,546 @@
|
|
|
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
|
+
/* QT_8bit distance kernel for RISC-V Vector.
|
|
11
|
+
*
|
|
12
|
+
* Free-standing (no exceptions, heap or threads), so a freestanding RISC-V
|
|
13
|
+
* target can compile it. sq-rvv.cpp calls `l2_distance`; the block, strided
|
|
14
|
+
* and 4-bit forms serve callers that store codes transposed, such as the
|
|
15
|
+
* MTIA kernels in faiss/fb/mtia. No Buck target here builds the RISC-V CPU
|
|
16
|
+
* path. See sq8_coefficients.h for the meaning of a and e.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
#include <riscv_vector.h>
|
|
20
|
+
|
|
21
|
+
#include <cstddef>
|
|
22
|
+
#include <cstdint>
|
|
23
|
+
|
|
24
|
+
namespace faiss {
|
|
25
|
+
namespace sq8_rvv {
|
|
26
|
+
|
|
27
|
+
/// Candidates per transposed block. One block fills an f32 LMUL 4 group at
|
|
28
|
+
/// VLEN=512, so every lane holds one candidate. On a smaller VLEN the block
|
|
29
|
+
/// functions loop over the block in pieces of one vector length.
|
|
30
|
+
constexpr size_t kBlockVectors = 64;
|
|
31
|
+
|
|
32
|
+
/// Squared L2 for a whole block, from codes stored transposed: the byte for
|
|
33
|
+
/// dimension i of lane c sits at `block[i * kBlockVectors + c]`. Each lane
|
|
34
|
+
/// accumulates one candidate, so no reduction is needed.
|
|
35
|
+
inline void l2_distance_block(
|
|
36
|
+
const uint8_t* block,
|
|
37
|
+
const float* a,
|
|
38
|
+
const float* e,
|
|
39
|
+
size_t d,
|
|
40
|
+
float* out) {
|
|
41
|
+
for (size_t c = 0; c < kBlockVectors;) {
|
|
42
|
+
const size_t vl = __riscv_vsetvl_e32m4(kBlockVectors - c);
|
|
43
|
+
vfloat32m4_t acc = __riscv_vfmv_v_f_f32m4(0.0f, vl);
|
|
44
|
+
for (size_t i = 0; i < d; i++) {
|
|
45
|
+
vuint8m1_t c8 =
|
|
46
|
+
__riscv_vle8_v_u8m1(block + c + i * kBlockVectors, vl);
|
|
47
|
+
vfloat32m4_t cf = __riscv_vfcvt_f_xu_v_f32m4(
|
|
48
|
+
__riscv_vzext_vf4_u32m4(c8, vl), vl);
|
|
49
|
+
// a[i] and e[i] are the same for every candidate in the block.
|
|
50
|
+
vfloat32m4_t t = __riscv_vfmv_v_f_f32m4(e[i], vl);
|
|
51
|
+
t = __riscv_vfnmsac_vf_f32m4(t, a[i], cf, vl);
|
|
52
|
+
acc = __riscv_vfmacc_vv_f32m4(acc, t, t, vl);
|
|
53
|
+
}
|
|
54
|
+
__riscv_vse32_v_f32m4(out + c, acc, vl);
|
|
55
|
+
c += vl;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/// Squared L2 for two transposed blocks at once.
|
|
60
|
+
///
|
|
61
|
+
/// Issuing the loads of both blocks first keeps two loads in flight. Four
|
|
62
|
+
/// blocks would need 16 of the 32 vector registers for accumulators and
|
|
63
|
+
/// spill.
|
|
64
|
+
inline void l2_distance_block_x2(
|
|
65
|
+
const uint8_t* block0,
|
|
66
|
+
const uint8_t* block1,
|
|
67
|
+
const float* a,
|
|
68
|
+
const float* e,
|
|
69
|
+
size_t d,
|
|
70
|
+
float* out0,
|
|
71
|
+
float* out1) {
|
|
72
|
+
for (size_t c = 0; c < kBlockVectors;) {
|
|
73
|
+
const size_t vl = __riscv_vsetvl_e32m4(kBlockVectors - c);
|
|
74
|
+
vfloat32m4_t acc0 = __riscv_vfmv_v_f_f32m4(0.0f, vl);
|
|
75
|
+
vfloat32m4_t acc1 = __riscv_vfmv_v_f_f32m4(0.0f, vl);
|
|
76
|
+
for (size_t i = 0; i < d; i++) {
|
|
77
|
+
vuint8m1_t v0 =
|
|
78
|
+
__riscv_vle8_v_u8m1(block0 + c + i * kBlockVectors, vl);
|
|
79
|
+
vuint8m1_t v1 =
|
|
80
|
+
__riscv_vle8_v_u8m1(block1 + c + i * kBlockVectors, vl);
|
|
81
|
+
const float ei = e[i];
|
|
82
|
+
const float ai = a[i];
|
|
83
|
+
vfloat32m4_t c0 = __riscv_vfcvt_f_xu_v_f32m4(
|
|
84
|
+
__riscv_vzext_vf4_u32m4(v0, vl), vl);
|
|
85
|
+
vfloat32m4_t t0 = __riscv_vfmv_v_f_f32m4(ei, vl);
|
|
86
|
+
t0 = __riscv_vfnmsac_vf_f32m4(t0, ai, c0, vl);
|
|
87
|
+
acc0 = __riscv_vfmacc_vv_f32m4(acc0, t0, t0, vl);
|
|
88
|
+
vfloat32m4_t c1 = __riscv_vfcvt_f_xu_v_f32m4(
|
|
89
|
+
__riscv_vzext_vf4_u32m4(v1, vl), vl);
|
|
90
|
+
vfloat32m4_t t1 = __riscv_vfmv_v_f_f32m4(ei, vl);
|
|
91
|
+
t1 = __riscv_vfnmsac_vf_f32m4(t1, ai, c1, vl);
|
|
92
|
+
acc1 = __riscv_vfmacc_vv_f32m4(acc1, t1, t1, vl);
|
|
93
|
+
}
|
|
94
|
+
__riscv_vse32_v_f32m4(out0 + c, acc0, vl);
|
|
95
|
+
__riscv_vse32_v_f32m4(out1 + c, acc1, vl);
|
|
96
|
+
c += vl;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/// The code-dependent inner product term for two transposed blocks at once.
|
|
101
|
+
inline void ip_partial_block_x2(
|
|
102
|
+
const uint8_t* block0,
|
|
103
|
+
const uint8_t* block1,
|
|
104
|
+
const float* eq,
|
|
105
|
+
size_t d,
|
|
106
|
+
float* out0,
|
|
107
|
+
float* out1) {
|
|
108
|
+
for (size_t c = 0; c < kBlockVectors;) {
|
|
109
|
+
const size_t vl = __riscv_vsetvl_e32m4(kBlockVectors - c);
|
|
110
|
+
vfloat32m4_t acc0 = __riscv_vfmv_v_f_f32m4(0.0f, vl);
|
|
111
|
+
vfloat32m4_t acc1 = __riscv_vfmv_v_f_f32m4(0.0f, vl);
|
|
112
|
+
for (size_t i = 0; i < d; i++) {
|
|
113
|
+
vuint8m1_t v0 =
|
|
114
|
+
__riscv_vle8_v_u8m1(block0 + c + i * kBlockVectors, vl);
|
|
115
|
+
vuint8m1_t v1 =
|
|
116
|
+
__riscv_vle8_v_u8m1(block1 + c + i * kBlockVectors, vl);
|
|
117
|
+
const float q = eq[i];
|
|
118
|
+
acc0 = __riscv_vfmacc_vf_f32m4(
|
|
119
|
+
acc0,
|
|
120
|
+
q,
|
|
121
|
+
__riscv_vfcvt_f_xu_v_f32m4(
|
|
122
|
+
__riscv_vzext_vf4_u32m4(v0, vl), vl),
|
|
123
|
+
vl);
|
|
124
|
+
acc1 = __riscv_vfmacc_vf_f32m4(
|
|
125
|
+
acc1,
|
|
126
|
+
q,
|
|
127
|
+
__riscv_vfcvt_f_xu_v_f32m4(
|
|
128
|
+
__riscv_vzext_vf4_u32m4(v1, vl), vl),
|
|
129
|
+
vl);
|
|
130
|
+
}
|
|
131
|
+
__riscv_vse32_v_f32m4(out0 + c, acc0, vl);
|
|
132
|
+
__riscv_vse32_v_f32m4(out1 + c, acc1, vl);
|
|
133
|
+
c += vl;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/// The low nibbles of a row of packed QT_4bit codes, as floats.
|
|
138
|
+
inline vfloat32m4_t low_nibbles(vuint8m1_t packed, size_t vl) {
|
|
139
|
+
return __riscv_vfcvt_f_xu_v_f32m4(
|
|
140
|
+
__riscv_vzext_vf4_u32m4(__riscv_vand_vx_u8m1(packed, 0x0F, vl), vl),
|
|
141
|
+
vl);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/// Squared L2 for a transposed block of QT_4bit codes. Faiss packs
|
|
145
|
+
/// dimension i into `code[i / 2]`, even dimensions in the low nibble and odd
|
|
146
|
+
/// in the high one, so d dimensions occupy (d + 1) / 2 bytes. For an odd d
|
|
147
|
+
/// the last byte holds one dimension, in its low nibble.
|
|
148
|
+
inline void l2_distance_4bit_block(
|
|
149
|
+
const uint8_t* block,
|
|
150
|
+
const float* a,
|
|
151
|
+
const float* e,
|
|
152
|
+
size_t d,
|
|
153
|
+
float* out) {
|
|
154
|
+
for (size_t c = 0; c < kBlockVectors;) {
|
|
155
|
+
const size_t vl = __riscv_vsetvl_e32m4(kBlockVectors - c);
|
|
156
|
+
vfloat32m4_t acc = __riscv_vfmv_v_f_f32m4(0.0f, vl);
|
|
157
|
+
for (size_t i = 0; i < d / 2; i++) {
|
|
158
|
+
vuint8m1_t packed =
|
|
159
|
+
__riscv_vle8_v_u8m1(block + c + i * kBlockVectors, vl);
|
|
160
|
+
vfloat32m4_t lo = __riscv_vfcvt_f_xu_v_f32m4(
|
|
161
|
+
__riscv_vzext_vf4_u32m4(
|
|
162
|
+
__riscv_vand_vx_u8m1(packed, 0x0F, vl), vl),
|
|
163
|
+
vl);
|
|
164
|
+
vfloat32m4_t hi = __riscv_vfcvt_f_xu_v_f32m4(
|
|
165
|
+
__riscv_vzext_vf4_u32m4(
|
|
166
|
+
__riscv_vsrl_vx_u8m1(packed, 4, vl), vl),
|
|
167
|
+
vl);
|
|
168
|
+
vfloat32m4_t t = __riscv_vfmv_v_f_f32m4(e[2 * i], vl);
|
|
169
|
+
t = __riscv_vfnmsac_vf_f32m4(t, a[2 * i], lo, vl);
|
|
170
|
+
acc = __riscv_vfmacc_vv_f32m4(acc, t, t, vl);
|
|
171
|
+
t = __riscv_vfmv_v_f_f32m4(e[2 * i + 1], vl);
|
|
172
|
+
t = __riscv_vfnmsac_vf_f32m4(t, a[2 * i + 1], hi, vl);
|
|
173
|
+
acc = __riscv_vfmacc_vv_f32m4(acc, t, t, vl);
|
|
174
|
+
}
|
|
175
|
+
if (d % 2 != 0) {
|
|
176
|
+
vfloat32m4_t lo = low_nibbles(
|
|
177
|
+
__riscv_vle8_v_u8m1(
|
|
178
|
+
block + c + (d / 2) * kBlockVectors, vl),
|
|
179
|
+
vl);
|
|
180
|
+
vfloat32m4_t t = __riscv_vfmv_v_f_f32m4(e[d - 1], vl);
|
|
181
|
+
t = __riscv_vfnmsac_vf_f32m4(t, a[d - 1], lo, vl);
|
|
182
|
+
acc = __riscv_vfmacc_vv_f32m4(acc, t, t, vl);
|
|
183
|
+
}
|
|
184
|
+
__riscv_vse32_v_f32m4(out + c, acc, vl);
|
|
185
|
+
c += vl;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/// The code-dependent inner product term for a transposed QT_4bit block.
|
|
190
|
+
inline void ip_partial_4bit_block(
|
|
191
|
+
const uint8_t* block,
|
|
192
|
+
const float* eq,
|
|
193
|
+
size_t d,
|
|
194
|
+
float* out) {
|
|
195
|
+
for (size_t c = 0; c < kBlockVectors;) {
|
|
196
|
+
const size_t vl = __riscv_vsetvl_e32m4(kBlockVectors - c);
|
|
197
|
+
vfloat32m4_t acc = __riscv_vfmv_v_f_f32m4(0.0f, vl);
|
|
198
|
+
for (size_t i = 0; i < d / 2; i++) {
|
|
199
|
+
vuint8m1_t packed =
|
|
200
|
+
__riscv_vle8_v_u8m1(block + c + i * kBlockVectors, vl);
|
|
201
|
+
vfloat32m4_t lo = __riscv_vfcvt_f_xu_v_f32m4(
|
|
202
|
+
__riscv_vzext_vf4_u32m4(
|
|
203
|
+
__riscv_vand_vx_u8m1(packed, 0x0F, vl), vl),
|
|
204
|
+
vl);
|
|
205
|
+
vfloat32m4_t hi = __riscv_vfcvt_f_xu_v_f32m4(
|
|
206
|
+
__riscv_vzext_vf4_u32m4(
|
|
207
|
+
__riscv_vsrl_vx_u8m1(packed, 4, vl), vl),
|
|
208
|
+
vl);
|
|
209
|
+
acc = __riscv_vfmacc_vf_f32m4(acc, eq[2 * i], lo, vl);
|
|
210
|
+
acc = __riscv_vfmacc_vf_f32m4(acc, eq[2 * i + 1], hi, vl);
|
|
211
|
+
}
|
|
212
|
+
if (d % 2 != 0) {
|
|
213
|
+
vfloat32m4_t lo = low_nibbles(
|
|
214
|
+
__riscv_vle8_v_u8m1(
|
|
215
|
+
block + c + (d / 2) * kBlockVectors, vl),
|
|
216
|
+
vl);
|
|
217
|
+
acc = __riscv_vfmacc_vf_f32m4(acc, eq[d - 1], lo, vl);
|
|
218
|
+
}
|
|
219
|
+
__riscv_vse32_v_f32m4(out + c, acc, vl);
|
|
220
|
+
c += vl;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/// Squared L2 for one QT_4bit candidate in the transposed layout, for the
|
|
225
|
+
/// runs an `IDSelector` produces, which start anywhere.
|
|
226
|
+
inline float l2_distance_4bit_strided(
|
|
227
|
+
const uint8_t* p,
|
|
228
|
+
const float* a,
|
|
229
|
+
const float* e,
|
|
230
|
+
size_t d) {
|
|
231
|
+
float acc = 0.0f;
|
|
232
|
+
for (size_t i = 0; i < d / 2; i++) {
|
|
233
|
+
const uint8_t packed = p[i * kBlockVectors];
|
|
234
|
+
const float t0 =
|
|
235
|
+
e[2 * i] - a[2 * i] * static_cast<float>(packed & 0x0F);
|
|
236
|
+
const float t1 =
|
|
237
|
+
e[2 * i + 1] - a[2 * i + 1] * static_cast<float>(packed >> 4);
|
|
238
|
+
acc += t0 * t0 + t1 * t1;
|
|
239
|
+
}
|
|
240
|
+
if (d % 2 != 0) {
|
|
241
|
+
const uint8_t packed = p[(d / 2) * kBlockVectors];
|
|
242
|
+
const float t = e[d - 1] - a[d - 1] * static_cast<float>(packed & 0x0F);
|
|
243
|
+
acc += t * t;
|
|
244
|
+
}
|
|
245
|
+
return acc;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/// The code-dependent inner product term for one strided QT_4bit candidate.
|
|
249
|
+
inline float ip_partial_4bit_strided(
|
|
250
|
+
const uint8_t* p,
|
|
251
|
+
const float* eq,
|
|
252
|
+
size_t d) {
|
|
253
|
+
float acc = 0.0f;
|
|
254
|
+
for (size_t i = 0; i < d / 2; i++) {
|
|
255
|
+
const uint8_t packed = p[i * kBlockVectors];
|
|
256
|
+
acc += eq[2 * i] * static_cast<float>(packed & 0x0F);
|
|
257
|
+
acc += eq[2 * i + 1] * static_cast<float>(packed >> 4);
|
|
258
|
+
}
|
|
259
|
+
if (d % 2 != 0) {
|
|
260
|
+
const uint8_t packed = p[(d / 2) * kBlockVectors];
|
|
261
|
+
acc += eq[d - 1] * static_cast<float>(packed & 0x0F);
|
|
262
|
+
}
|
|
263
|
+
return acc;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/// Squared L2 for two transposed QT_4bit blocks at once: half the bytes of
|
|
267
|
+
/// QT_8bit and two loads in flight.
|
|
268
|
+
inline void l2_distance_4bit_block_x2(
|
|
269
|
+
const uint8_t* block0,
|
|
270
|
+
const uint8_t* block1,
|
|
271
|
+
const float* a,
|
|
272
|
+
const float* e,
|
|
273
|
+
size_t d,
|
|
274
|
+
float* out0,
|
|
275
|
+
float* out1) {
|
|
276
|
+
for (size_t c = 0; c < kBlockVectors;) {
|
|
277
|
+
const size_t vl = __riscv_vsetvl_e32m4(kBlockVectors - c);
|
|
278
|
+
vfloat32m4_t acc0 = __riscv_vfmv_v_f_f32m4(0.0f, vl);
|
|
279
|
+
vfloat32m4_t acc1 = __riscv_vfmv_v_f_f32m4(0.0f, vl);
|
|
280
|
+
for (size_t i = 0; i < d / 2; i++) {
|
|
281
|
+
vuint8m1_t p0 =
|
|
282
|
+
__riscv_vle8_v_u8m1(block0 + c + i * kBlockVectors, vl);
|
|
283
|
+
vuint8m1_t p1 =
|
|
284
|
+
__riscv_vle8_v_u8m1(block1 + c + i * kBlockVectors, vl);
|
|
285
|
+
const float e0 = e[2 * i];
|
|
286
|
+
const float e1 = e[2 * i + 1];
|
|
287
|
+
const float a0 = a[2 * i];
|
|
288
|
+
const float a1 = a[2 * i + 1];
|
|
289
|
+
auto step = [&](vuint8m1_t p, vfloat32m4_t acc) {
|
|
290
|
+
vfloat32m4_t lo = __riscv_vfcvt_f_xu_v_f32m4(
|
|
291
|
+
__riscv_vzext_vf4_u32m4(
|
|
292
|
+
__riscv_vand_vx_u8m1(p, 0x0F, vl), vl),
|
|
293
|
+
vl);
|
|
294
|
+
vfloat32m4_t hi = __riscv_vfcvt_f_xu_v_f32m4(
|
|
295
|
+
__riscv_vzext_vf4_u32m4(
|
|
296
|
+
__riscv_vsrl_vx_u8m1(p, 4, vl), vl),
|
|
297
|
+
vl);
|
|
298
|
+
vfloat32m4_t t = __riscv_vfmv_v_f_f32m4(e0, vl);
|
|
299
|
+
t = __riscv_vfnmsac_vf_f32m4(t, a0, lo, vl);
|
|
300
|
+
acc = __riscv_vfmacc_vv_f32m4(acc, t, t, vl);
|
|
301
|
+
t = __riscv_vfmv_v_f_f32m4(e1, vl);
|
|
302
|
+
t = __riscv_vfnmsac_vf_f32m4(t, a1, hi, vl);
|
|
303
|
+
return __riscv_vfmacc_vv_f32m4(acc, t, t, vl);
|
|
304
|
+
};
|
|
305
|
+
acc0 = step(p0, acc0);
|
|
306
|
+
acc1 = step(p1, acc1);
|
|
307
|
+
}
|
|
308
|
+
if (d % 2 != 0) {
|
|
309
|
+
const size_t last = (d / 2) * kBlockVectors;
|
|
310
|
+
auto tail = [&](vuint8m1_t p, vfloat32m4_t acc) {
|
|
311
|
+
vfloat32m4_t t = __riscv_vfmv_v_f_f32m4(e[d - 1], vl);
|
|
312
|
+
t = __riscv_vfnmsac_vf_f32m4(
|
|
313
|
+
t, a[d - 1], low_nibbles(p, vl), vl);
|
|
314
|
+
return __riscv_vfmacc_vv_f32m4(acc, t, t, vl);
|
|
315
|
+
};
|
|
316
|
+
acc0 = tail(__riscv_vle8_v_u8m1(block0 + c + last, vl), acc0);
|
|
317
|
+
acc1 = tail(__riscv_vle8_v_u8m1(block1 + c + last, vl), acc1);
|
|
318
|
+
}
|
|
319
|
+
__riscv_vse32_v_f32m4(out0 + c, acc0, vl);
|
|
320
|
+
__riscv_vse32_v_f32m4(out1 + c, acc1, vl);
|
|
321
|
+
c += vl;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/// Squared L2 for one candidate whose code is stored transposed: its d bytes
|
|
326
|
+
/// sit `kBlockVectors` apart. For runs that do not start on a block
|
|
327
|
+
/// boundary, such as the runs an `IDSelector` produces.
|
|
328
|
+
inline float l2_distance_strided(
|
|
329
|
+
const uint8_t* p,
|
|
330
|
+
const float* a,
|
|
331
|
+
const float* e,
|
|
332
|
+
size_t d) {
|
|
333
|
+
const size_t vl = __riscv_vsetvl_e8m1(d > 0 ? d : 1);
|
|
334
|
+
vfloat32m4_t acc = __riscv_vfmv_v_f_f32m4(0.0f, vl);
|
|
335
|
+
size_t i = 0;
|
|
336
|
+
while (i < d) {
|
|
337
|
+
const size_t v = __riscv_vsetvl_e8m1(d - i);
|
|
338
|
+
vuint8m1_t c8 = __riscv_vlse8_v_u8m1(
|
|
339
|
+
p + i * kBlockVectors,
|
|
340
|
+
static_cast<ptrdiff_t>(kBlockVectors),
|
|
341
|
+
v);
|
|
342
|
+
vfloat32m4_t cf =
|
|
343
|
+
__riscv_vfcvt_f_xu_v_f32m4(__riscv_vzext_vf4_u32m4(c8, v), v);
|
|
344
|
+
vfloat32m4_t t = __riscv_vle32_v_f32m4(e + i, v);
|
|
345
|
+
t = __riscv_vfnmsac_vv_f32m4(t, __riscv_vle32_v_f32m4(a + i, v), cf, v);
|
|
346
|
+
acc = __riscv_vfmacc_vv_f32m4_tu(acc, t, t, v);
|
|
347
|
+
i += v;
|
|
348
|
+
}
|
|
349
|
+
vfloat32m1_t red = __riscv_vfredusum_vs_f32m4_f32m1(
|
|
350
|
+
acc, __riscv_vfmv_v_f_f32m1(0.0f, 1), vl);
|
|
351
|
+
return __riscv_vfmv_f_s_f32m1_f32(red);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/// The code-dependent inner product term for one transposed candidate.
|
|
355
|
+
inline float ip_partial_strided(const uint8_t* p, const float* eq, size_t d) {
|
|
356
|
+
const size_t vl = __riscv_vsetvl_e8m1(d > 0 ? d : 1);
|
|
357
|
+
vfloat32m4_t acc = __riscv_vfmv_v_f_f32m4(0.0f, vl);
|
|
358
|
+
size_t i = 0;
|
|
359
|
+
while (i < d) {
|
|
360
|
+
const size_t v = __riscv_vsetvl_e8m1(d - i);
|
|
361
|
+
vuint8m1_t c8 = __riscv_vlse8_v_u8m1(
|
|
362
|
+
p + i * kBlockVectors,
|
|
363
|
+
static_cast<ptrdiff_t>(kBlockVectors),
|
|
364
|
+
v);
|
|
365
|
+
vfloat32m4_t cf =
|
|
366
|
+
__riscv_vfcvt_f_xu_v_f32m4(__riscv_vzext_vf4_u32m4(c8, v), v);
|
|
367
|
+
acc = __riscv_vfmacc_vv_f32m4_tu(
|
|
368
|
+
acc, __riscv_vle32_v_f32m4(eq + i, v), cf, v);
|
|
369
|
+
i += v;
|
|
370
|
+
}
|
|
371
|
+
vfloat32m1_t red = __riscv_vfredusum_vs_f32m4_f32m1(
|
|
372
|
+
acc, __riscv_vfmv_v_f_f32m1(0.0f, 1), vl);
|
|
373
|
+
return __riscv_vfmv_f_s_f32m1_f32(red);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/// Squared L2 on the 8-bit grid for a transposed block, with integer
|
|
377
|
+
/// weights. The host scales the result back.
|
|
378
|
+
inline void l2_distance_int_block(
|
|
379
|
+
const uint8_t* block,
|
|
380
|
+
const uint8_t* qcode,
|
|
381
|
+
const int32_t* w,
|
|
382
|
+
size_t d,
|
|
383
|
+
float* out) {
|
|
384
|
+
for (size_t c = 0; c < kBlockVectors;) {
|
|
385
|
+
const size_t vl = __riscv_vsetvl_e32m4(kBlockVectors - c);
|
|
386
|
+
vint32m4_t acc = __riscv_vmv_v_x_i32m4(0, vl);
|
|
387
|
+
for (size_t i = 0; i < d; i++) {
|
|
388
|
+
vuint8m1_t c8 =
|
|
389
|
+
__riscv_vle8_v_u8m1(block + c + i * kBlockVectors, vl);
|
|
390
|
+
vint32m4_t c = __riscv_vreinterpret_v_u32m4_i32m4(
|
|
391
|
+
__riscv_vzext_vf4_u32m4(c8, vl));
|
|
392
|
+
vint32m4_t diff = __riscv_vsub_vx_i32m4(
|
|
393
|
+
c, static_cast<int32_t>(qcode[i]), vl);
|
|
394
|
+
vint32m4_t sq = __riscv_vmul_vv_i32m4(diff, diff, vl);
|
|
395
|
+
acc = __riscv_vmacc_vx_i32m4(acc, w[i], sq, vl);
|
|
396
|
+
}
|
|
397
|
+
__riscv_vse32_v_f32m4(out + c, __riscv_vfcvt_f_x_v_f32m4(acc, vl), vl);
|
|
398
|
+
c += vl;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/// The code-dependent term of the inner product, for a transposed block.
|
|
403
|
+
inline void ip_partial_block(
|
|
404
|
+
const uint8_t* block,
|
|
405
|
+
const float* eq,
|
|
406
|
+
size_t d,
|
|
407
|
+
float* out) {
|
|
408
|
+
for (size_t c = 0; c < kBlockVectors;) {
|
|
409
|
+
const size_t vl = __riscv_vsetvl_e32m4(kBlockVectors - c);
|
|
410
|
+
vfloat32m4_t acc = __riscv_vfmv_v_f_f32m4(0.0f, vl);
|
|
411
|
+
for (size_t i = 0; i < d; i++) {
|
|
412
|
+
vuint8m1_t c8 =
|
|
413
|
+
__riscv_vle8_v_u8m1(block + c + i * kBlockVectors, vl);
|
|
414
|
+
vfloat32m4_t cf = __riscv_vfcvt_f_xu_v_f32m4(
|
|
415
|
+
__riscv_vzext_vf4_u32m4(c8, vl), vl);
|
|
416
|
+
acc = __riscv_vfmacc_vf_f32m4(acc, eq[i], cf, vl);
|
|
417
|
+
}
|
|
418
|
+
__riscv_vse32_v_f32m4(out + c, acc, vl);
|
|
419
|
+
c += vl;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/// Squared L2 distance between a query and one 8-bit code.
|
|
424
|
+
inline float l2_distance(
|
|
425
|
+
const uint8_t* code,
|
|
426
|
+
const float* a,
|
|
427
|
+
const float* e,
|
|
428
|
+
size_t d) {
|
|
429
|
+
// VLMAX for e8m1 equals the f32 lane count of an m4 group. Guard d == 0,
|
|
430
|
+
// because vsetvl then returns 0 and the chunk loop stalls.
|
|
431
|
+
const size_t vl = __riscv_vsetvl_e8m1(d > 0 ? d : 1);
|
|
432
|
+
vfloat32m4_t acc = __riscv_vfmv_v_f_f32m4(0.0f, vl);
|
|
433
|
+
|
|
434
|
+
size_t i = 0;
|
|
435
|
+
if (i + vl <= d) {
|
|
436
|
+
// Software pipeline: load the next chunk's code bytes at the top.
|
|
437
|
+
vuint8m1_t c8 = __riscv_vle8_v_u8m1(code + i, vl);
|
|
438
|
+
i += vl;
|
|
439
|
+
|
|
440
|
+
for (; i + vl <= d; i += vl) {
|
|
441
|
+
vuint8m1_t c8_next = __riscv_vle8_v_u8m1(code + i, vl);
|
|
442
|
+
vfloat32m4_t cf = __riscv_vfcvt_f_xu_v_f32m4(
|
|
443
|
+
__riscv_vzext_vf4_u32m4(c8, vl), vl);
|
|
444
|
+
vfloat32m4_t t = __riscv_vle32_v_f32m4(e + i - vl, vl);
|
|
445
|
+
t = __riscv_vfnmsac_vv_f32m4(
|
|
446
|
+
t, __riscv_vle32_v_f32m4(a + i - vl, vl), cf, vl);
|
|
447
|
+
acc = __riscv_vfmacc_vv_f32m4(acc, t, t, vl);
|
|
448
|
+
c8 = c8_next;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
vfloat32m4_t cf =
|
|
452
|
+
__riscv_vfcvt_f_xu_v_f32m4(__riscv_vzext_vf4_u32m4(c8, vl), vl);
|
|
453
|
+
vfloat32m4_t t = __riscv_vle32_v_f32m4(e + i - vl, vl);
|
|
454
|
+
t = __riscv_vfnmsac_vv_f32m4(
|
|
455
|
+
t, __riscv_vle32_v_f32m4(a + i - vl, vl), cf, vl);
|
|
456
|
+
acc = __riscv_vfmacc_vv_f32m4(acc, t, t, vl);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// Tail: fewer than vl dimensions remain. The reduction covers every lane.
|
|
460
|
+
if (i < d) {
|
|
461
|
+
const size_t vt = __riscv_vsetvl_e8m1(d - i);
|
|
462
|
+
vuint8m1_t c8 = __riscv_vle8_v_u8m1(code + i, vt);
|
|
463
|
+
vfloat32m4_t cf =
|
|
464
|
+
__riscv_vfcvt_f_xu_v_f32m4(__riscv_vzext_vf4_u32m4(c8, vt), vt);
|
|
465
|
+
vfloat32m4_t t = __riscv_vle32_v_f32m4(e + i, vt);
|
|
466
|
+
t = __riscv_vfnmsac_vv_f32m4(
|
|
467
|
+
t, __riscv_vle32_v_f32m4(a + i, vt), cf, vt);
|
|
468
|
+
acc = __riscv_vfmacc_vv_f32m4_tu(acc, t, t, vt);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
vfloat32m1_t red = __riscv_vfredusum_vs_f32m4_f32m1(
|
|
472
|
+
acc, __riscv_vfmv_v_f_f32m1(0.0f, 1), vl);
|
|
473
|
+
return __riscv_vfmv_f_s_f32m1_f32(red);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/// Inner product between a query and one 8-bit code, without the constant.
|
|
477
|
+
///
|
|
478
|
+
/// Expanding the reconstruction,
|
|
479
|
+
///
|
|
480
|
+
/// sum q[i] * v[i] = sum q[i]*rmin[i] + sum (q[i]*a[i]) * code[i]
|
|
481
|
+
///
|
|
482
|
+
/// the first term does not depend on the code, so the caller adds it. This
|
|
483
|
+
/// computes the second, with u[i] = q[i] * a[i].
|
|
484
|
+
inline float ip_partial(const uint8_t* code, const float* u, size_t d) {
|
|
485
|
+
const size_t vl = __riscv_vsetvl_e8m1(d > 0 ? d : 1);
|
|
486
|
+
vfloat32m4_t acc = __riscv_vfmv_v_f_f32m4(0.0f, vl);
|
|
487
|
+
|
|
488
|
+
size_t i = 0;
|
|
489
|
+
for (; i + vl <= d; i += vl) {
|
|
490
|
+
vuint8m1_t c8 = __riscv_vle8_v_u8m1(code + i, vl);
|
|
491
|
+
vfloat32m4_t cf =
|
|
492
|
+
__riscv_vfcvt_f_xu_v_f32m4(__riscv_vzext_vf4_u32m4(c8, vl), vl);
|
|
493
|
+
acc = __riscv_vfmacc_vv_f32m4(
|
|
494
|
+
acc, cf, __riscv_vle32_v_f32m4(u + i, vl), vl);
|
|
495
|
+
}
|
|
496
|
+
if (i < d) {
|
|
497
|
+
const size_t vt = __riscv_vsetvl_e8m1(d - i);
|
|
498
|
+
vuint8m1_t c8 = __riscv_vle8_v_u8m1(code + i, vt);
|
|
499
|
+
vfloat32m4_t cf =
|
|
500
|
+
__riscv_vfcvt_f_xu_v_f32m4(__riscv_vzext_vf4_u32m4(c8, vt), vt);
|
|
501
|
+
acc = __riscv_vfmacc_vv_f32m4_tu(
|
|
502
|
+
acc, cf, __riscv_vle32_v_f32m4(u + i, vt), vt);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
vfloat32m1_t red = __riscv_vfredusum_vs_f32m4_f32m1(
|
|
506
|
+
acc, __riscv_vfmv_v_f_f32m1(0.0f, 1), vl);
|
|
507
|
+
return __riscv_vfmv_f_s_f32m1_f32(red);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/// Squared L2 distance with the query quantized onto the same 8-bit grid.
|
|
511
|
+
///
|
|
512
|
+
/// sum (q[i] - v[i])^2 = sum a[i]^2 * (qcode[i] - code[i])^2
|
|
513
|
+
///
|
|
514
|
+
/// The weights hold a[i]^2 as integers, so the loop is integer only. The
|
|
515
|
+
/// caller scales the result back and must keep max(w) * 65025 * d inside
|
|
516
|
+
/// int32.
|
|
517
|
+
inline float l2_distance_int(
|
|
518
|
+
const uint8_t* code,
|
|
519
|
+
const uint8_t* qcode,
|
|
520
|
+
const int32_t* w,
|
|
521
|
+
size_t d) {
|
|
522
|
+
// Accumulate at LMUL 4, not 8. A group of eight uses eight of the 32
|
|
523
|
+
// vector registers and leaves only four groups, which is slower.
|
|
524
|
+
vint32m4_t sum = __riscv_vmv_v_x_i32m4(0, __riscv_vsetvlmax_e32m4());
|
|
525
|
+
size_t i = 0;
|
|
526
|
+
while (i < d) {
|
|
527
|
+
const size_t vl = __riscv_vsetvl_e16m2(d - i);
|
|
528
|
+
vint16m2_t c = __riscv_vreinterpret_v_u16m2_i16m2(
|
|
529
|
+
__riscv_vzext_vf2_u16m2(__riscv_vle8_v_u8m1(code + i, vl), vl));
|
|
530
|
+
vint16m2_t q =
|
|
531
|
+
__riscv_vreinterpret_v_u16m2_i16m2(__riscv_vzext_vf2_u16m2(
|
|
532
|
+
__riscv_vle8_v_u8m1(qcode + i, vl), vl));
|
|
533
|
+
vint16m2_t diff = __riscv_vsub_vv_i16m2(q, c, vl);
|
|
534
|
+
// A difference of two bytes fits in int16 and its square in int32.
|
|
535
|
+
vint32m4_t sq = __riscv_vwmul_vv_i32m4(diff, diff, vl);
|
|
536
|
+
sum = __riscv_vmacc_vv_i32m4_tu(
|
|
537
|
+
sum, sq, __riscv_vle32_v_i32m4(w + i, vl), vl);
|
|
538
|
+
i += vl;
|
|
539
|
+
}
|
|
540
|
+
vint32m1_t r = __riscv_vredsum_vs_i32m4_i32m1(
|
|
541
|
+
sum, __riscv_vmv_v_x_i32m1(0, 1), __riscv_vsetvlmax_e32m4());
|
|
542
|
+
return static_cast<float>(__riscv_vmv_x_s_i32m1_i32(r));
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
} // namespace sq8_rvv
|
|
546
|
+
} // namespace faiss
|
|
@@ -366,15 +366,15 @@ void train_NonUniform(
|
|
|
366
366
|
} else {
|
|
367
367
|
// transpose
|
|
368
368
|
std::vector<float> xt(n * d);
|
|
369
|
-
for (idx_t i =
|
|
369
|
+
for (idx_t i = 0; i < n; i++) {
|
|
370
370
|
const float* xi = x + i * d;
|
|
371
371
|
for (int j = 0; j < d; j++) {
|
|
372
372
|
xt[j * n + i] = xi[j];
|
|
373
373
|
}
|
|
374
374
|
}
|
|
375
|
-
std::vector<float> trained_d(2);
|
|
376
375
|
#pragma omp parallel for
|
|
377
376
|
for (int j = 0; j < d; j++) {
|
|
377
|
+
std::vector<float> trained_d(2);
|
|
378
378
|
train_Uniform(rs, rs_arg, n, k, xt.data() + j * n, trained_d);
|
|
379
379
|
vmin[j] = trained_d[0];
|
|
380
380
|
vmax[j] = trained_d[1];
|
|
@@ -36,6 +36,13 @@ constexpr int AVAILABLE_SIMD_LEVELS_AVX2_NEON = AVAILABLE_SIMD_LEVELS_NONE |
|
|
|
36
36
|
constexpr int AVAILABLE_SIMD_LEVELS_BASE = AVAILABLE_SIMD_LEVELS_AVX2_NEON |
|
|
37
37
|
(1 << int(SIMDLevel::AVX512)) | (1 << int(SIMDLevel::RISCV_RVV));
|
|
38
38
|
|
|
39
|
+
// BASE_NO_AVX512: BASE minus AVX512, for functions implemented at NONE,
|
|
40
|
+
// AVX2, ARM_NEON and RISCV_RVV but with no AVX512 specialization. AVX512
|
|
41
|
+
// machines fall through to AVX2, while RISC-V dispatches directly to the
|
|
42
|
+
// native vector-length-agnostic RVV kernels.
|
|
43
|
+
constexpr int AVAILABLE_SIMD_LEVELS_BASE_NO_AVX512 =
|
|
44
|
+
AVAILABLE_SIMD_LEVELS_BASE & ~(1 << int(SIMDLevel::AVX512));
|
|
45
|
+
|
|
39
46
|
// BASE_WITH_VPOPCNT: BASE + AVX512_VPOPCNT, for kernels that need only
|
|
40
47
|
// VPOPCNTDQ on top of baseline AVX-512 (Ice Lake, Zen 4, Zen 5).
|
|
41
48
|
constexpr int AVAILABLE_SIMD_LEVELS_BASE_WITH_VPOPCNT =
|
|
@@ -901,6 +901,20 @@ inline float horizontal_add(const simd8float32_tpl<SIMDLevel::AVX2>& a) {
|
|
|
901
901
|
return _mm_cvtss_f32(v3);
|
|
902
902
|
}
|
|
903
903
|
|
|
904
|
+
/// (s[0] + s[2]) + (s[1] + s[3])
|
|
905
|
+
FAISS_ALWAYS_INLINE float reduce_4(__m128 s) {
|
|
906
|
+
const __m128 h = _mm_add_ps(s, _mm_movehl_ps(s, s));
|
|
907
|
+
return _mm_cvtss_f32(_mm_add_ss(h, _mm_movehdup_ps(h)));
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
/// reduce_4 of four vectors at once, with the same order for each, so a
|
|
911
|
+
/// batched distance is bit-identical to the single one.
|
|
912
|
+
FAISS_ALWAYS_INLINE __m128 reduce_4x4(__m128 a, __m128 b, __m128 c, __m128 d) {
|
|
913
|
+
const __m128 ab = _mm_add_ps(_mm_unpacklo_ps(a, b), _mm_unpackhi_ps(a, b));
|
|
914
|
+
const __m128 cd = _mm_add_ps(_mm_unpacklo_ps(c, d), _mm_unpackhi_ps(c, d));
|
|
915
|
+
return _mm_add_ps(_mm_movelh_ps(ab, cd), _mm_movehl_ps(cd, ab));
|
|
916
|
+
}
|
|
917
|
+
|
|
904
918
|
} // namespace
|
|
905
919
|
|
|
906
920
|
} // namespace faiss
|
|
@@ -16,23 +16,22 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
#include <faiss/impl/simdlib/simdlib.h>
|
|
19
|
+
#include <faiss/utils/simd_levels.h>
|
|
19
20
|
|
|
20
|
-
// Platform specializations — guarded by
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
// specializations. In static mode: only the compiled-in level is available.
|
|
21
|
+
// Platform specializations — guarded by FAISS_SIMD_TU, so that only per-SIMD
|
|
22
|
+
// TUs (compiled with -mavx2 etc.) see them. In static mode: only the
|
|
23
|
+
// compiled-in level is available.
|
|
24
24
|
|
|
25
|
-
#if (
|
|
26
|
-
defined(__AVX512F__)
|
|
25
|
+
#if FAISS_SIMD_TU(AVX512) || FAISS_SIMD_TU(AVX512_SPR)
|
|
27
26
|
|
|
28
27
|
// AVX512 includes AVX2 (simdlib_avx512.h includes simdlib_avx2.h)
|
|
29
28
|
#include <faiss/impl/simdlib/simdlib_avx512.h>
|
|
30
29
|
|
|
31
|
-
#elif
|
|
30
|
+
#elif FAISS_SIMD_TU(AVX2)
|
|
32
31
|
|
|
33
32
|
#include <faiss/impl/simdlib/simdlib_avx2.h>
|
|
34
33
|
|
|
35
|
-
#elif
|
|
34
|
+
#elif FAISS_SIMD_TU(ARM_NEON)
|
|
36
35
|
|
|
37
36
|
#include <faiss/impl/simdlib/simdlib_neon.h>
|
|
38
37
|
|