faiss 0.6.1 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/lib/faiss/version.rb +1 -1
- data/vendor/faiss/faiss/AutoTune.cpp +3 -1
- data/vendor/faiss/faiss/Clustering.cpp +9 -1
- data/vendor/faiss/faiss/IVFlib.cpp +14 -3
- data/vendor/faiss/faiss/Index.h +2 -2
- data/vendor/faiss/faiss/IndexAdditiveQuantizer.cpp +9 -10
- data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.cpp +2 -3
- data/vendor/faiss/faiss/IndexBinaryFromFloat.cpp +1 -2
- data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +10 -12
- data/vendor/faiss/faiss/IndexBinaryHash.cpp +5 -9
- data/vendor/faiss/faiss/IndexBinaryIVF.cpp +5 -7
- data/vendor/faiss/faiss/IndexEDEN.cpp +273 -0
- data/vendor/faiss/faiss/IndexEDEN.h +57 -0
- data/vendor/faiss/faiss/IndexFastScan.cpp +15 -4
- data/vendor/faiss/faiss/IndexFlat.cpp +13 -50
- data/vendor/faiss/faiss/IndexHNSW.cpp +177 -148
- data/vendor/faiss/faiss/IndexIDMap.cpp +16 -3
- data/vendor/faiss/faiss/IndexIDMap.h +2 -0
- data/vendor/faiss/faiss/IndexIVF.cpp +19 -8
- data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +3 -3
- data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.cpp +3 -4
- data/vendor/faiss/faiss/IndexIVFEDEN.cpp +302 -0
- data/vendor/faiss/faiss/IndexIVFEDEN.h +70 -0
- data/vendor/faiss/faiss/IndexIVFFastScan.cpp +5 -6
- data/vendor/faiss/faiss/IndexIVFFlat.cpp +6 -5
- data/vendor/faiss/faiss/IndexIVFFlatPanorama.cpp +3 -3
- data/vendor/faiss/faiss/IndexIVFIndependentQuantizer.cpp +1 -1
- data/vendor/faiss/faiss/IndexIVFPQ.cpp +42 -25
- data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +0 -1
- data/vendor/faiss/faiss/IndexIVFPQR.cpp +2 -3
- data/vendor/faiss/faiss/IndexIVFRaBitQ.cpp +23 -62
- data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.cpp +180 -76
- data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.h +5 -4
- data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +8 -6
- data/vendor/faiss/faiss/IndexLSH.cpp +2 -3
- data/vendor/faiss/faiss/IndexLattice.cpp +5 -0
- data/vendor/faiss/faiss/IndexNNDescent.cpp +10 -3
- data/vendor/faiss/faiss/IndexNSG.cpp +8 -4
- data/vendor/faiss/faiss/IndexPQ.cpp +6 -8
- data/vendor/faiss/faiss/IndexPreTransform.cpp +15 -0
- data/vendor/faiss/faiss/IndexRaBitQ.cpp +2 -2
- data/vendor/faiss/faiss/IndexRaBitQFastScan.cpp +1 -2
- data/vendor/faiss/faiss/IndexRaBitQFastScan.h +5 -1
- data/vendor/faiss/faiss/IndexRefine.cpp +30 -1
- data/vendor/faiss/faiss/IndexReplicas.cpp +1 -2
- data/vendor/faiss/faiss/IndexScalarQuantizer.cpp +68 -6
- data/vendor/faiss/faiss/IndexScalarQuantizer.h +10 -0
- data/vendor/faiss/faiss/IndexShards.cpp +2 -2
- data/vendor/faiss/faiss/IndexShardsIVF.cpp +2 -2
- data/vendor/faiss/faiss/MetaIndexes.cpp +2 -4
- data/vendor/faiss/faiss/SuperKMeans.cpp +256 -240
- data/vendor/faiss/faiss/SuperKMeans.h +30 -0
- data/vendor/faiss/faiss/VectorTransform.cpp +33 -2
- data/vendor/faiss/faiss/clone_index.cpp +5 -0
- data/vendor/faiss/faiss/cppcontrib/SaDecodeKernels.h +1 -1
- data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-neon-inl.h +902 -12
- data/vendor/faiss/faiss/cppcontrib/sa_decode/PQ-neon-inl.h +702 -10
- data/vendor/faiss/faiss/factory_tools.cpp +51 -4
- data/vendor/faiss/faiss/gpu/GpuCloner.cpp +11 -11
- data/vendor/faiss/faiss/gpu/GpuIndex.h +34 -11
- data/vendor/faiss/faiss/gpu/GpuIndexCagra.h +47 -0
- data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +17 -0
- data/vendor/faiss/faiss/gpu/GpuIndexIVFScalarQuantizer.h +16 -0
- data/vendor/faiss/faiss/gpu/GpuResources.h +3 -2
- data/vendor/faiss/faiss/gpu/StandardGpuResources.cpp +11 -12
- data/vendor/faiss/faiss/gpu/StandardGpuResources.h +3 -3
- data/vendor/faiss/faiss/gpu/perf/PerfClustering.cpp +1 -1
- data/vendor/faiss/faiss/gpu/perf/PerfIVFPQAdd.cpp +2 -2
- data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFScalarQuantizer.cpp +180 -0
- data/vendor/faiss/faiss/gpu_metal/MetalDistance.h +87 -0
- data/vendor/faiss/faiss/gpu_metal/MetalIndex.h +7 -0
- data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFFlat.h +177 -0
- data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFPQ.h +88 -0
- data/vendor/faiss/faiss/gpu_metal/MetalKernels.h +48 -3
- data/vendor/faiss/faiss/gpu_metal/MetalPythonBridge.h +45 -0
- data/vendor/faiss/faiss/gpu_metal/impl/MetalIVFFlat.h +193 -0
- data/vendor/faiss/faiss/gpu_metal/impl/MetalIVFPQ.h +134 -0
- data/vendor/faiss/faiss/impl/ClusteringInitialization.cpp +2 -2
- data/vendor/faiss/faiss/impl/DistanceComputer.h +34 -0
- data/vendor/faiss/faiss/impl/EDENQuantizer.h +119 -0
- data/vendor/faiss/faiss/impl/HNSW.cpp +658 -344
- data/vendor/faiss/faiss/impl/HNSW.h +51 -13
- data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +2 -2
- data/vendor/faiss/faiss/impl/NSG.cpp +18 -12
- data/vendor/faiss/faiss/impl/Panorama.h +20 -7
- data/vendor/faiss/faiss/impl/PolysemousTraining.cpp +152 -84
- data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +59 -24
- data/vendor/faiss/faiss/impl/RaBitQUtils.cpp +45 -37
- data/vendor/faiss/faiss/impl/RaBitQUtils.h +35 -0
- data/vendor/faiss/faiss/impl/RaBitQuantizer.cpp +175 -68
- data/vendor/faiss/faiss/impl/RaBitQuantizer.h +19 -0
- data/vendor/faiss/faiss/impl/RaBitQuantizerMultiBit.cpp +2 -11
- data/vendor/faiss/faiss/impl/ResultHandler.h +26 -31
- data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +522 -58
- data/vendor/faiss/faiss/impl/ScalarQuantizer.h +70 -0
- data/vendor/faiss/faiss/impl/ThreadedIndex-inl.h +2 -2
- data/vendor/faiss/faiss/impl/VisitedTable.cpp +33 -13
- data/vendor/faiss/faiss/impl/VisitedTable.h +88 -33
- data/vendor/faiss/faiss/impl/binary_hamming/IndexBinaryIVF_impl.h +1 -1
- data/vendor/faiss/faiss/impl/binary_hamming/avx2.cpp +4 -4
- data/vendor/faiss/faiss/impl/fast_scan/dispatching.h +38 -3
- data/vendor/faiss/faiss/impl/hnsw/LockVector.cpp +1 -1
- data/vendor/faiss/faiss/impl/hnsw/MinimaxHeap.cpp +35 -43
- data/vendor/faiss/faiss/impl/hnsw/MinimaxHeap.h +64 -15
- data/vendor/faiss/faiss/impl/hnsw/avx2.cpp +86 -40
- data/vendor/faiss/faiss/impl/hnsw/avx512.cpp +81 -50
- data/vendor/faiss/faiss/impl/index_read.cpp +476 -75
- data/vendor/faiss/faiss/impl/index_write.cpp +56 -4
- data/vendor/faiss/faiss/impl/io_macros.h +25 -0
- data/vendor/faiss/faiss/impl/lattice_Zn.cpp +8 -9
- data/vendor/faiss/faiss/impl/platform_macros.h +15 -9
- data/vendor/faiss/faiss/impl/polysemous_training/avx512.cpp +284 -0
- data/vendor/faiss/faiss/impl/polysemous_training/dispatch.h +115 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQ_QueryTables.cpp +0 -1
- data/vendor/faiss/faiss/impl/pq_code_distance/PQDistanceComputer_impl.h +26 -15
- data/vendor/faiss/faiss/impl/pq_code_distance/avx2.cpp +6 -4
- data/vendor/faiss/faiss/impl/pq_code_distance/avx512.cpp +2 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/neon.cpp +2 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-generic.cpp +20 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-inl.h +36 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-sve.cpp +5 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_scan_impl.h +105 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/rvv.cpp +2 -0
- data/vendor/faiss/faiss/impl/result_handler/ResultHandler.cpp +195 -0
- data/vendor/faiss/faiss/impl/result_handler/avx2.cpp +133 -0
- data/vendor/faiss/faiss/impl/result_handler/avx512.cpp +281 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx2.cpp +72 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx512.cpp +228 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer.cpp +882 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/distance_computers.h +6 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/quantizers.h +336 -26
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx2.cpp +331 -32
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-impl.h +553 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-spr.cpp +558 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512.cpp +284 -45
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-dispatch.h +502 -3
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-neon.cpp +157 -32
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-rvv.cpp +26 -0
- data/vendor/faiss/faiss/impl/simd_dispatch.h +86 -8
- data/vendor/faiss/faiss/index_factory.cpp +37 -7
- data/vendor/faiss/faiss/index_io.h +16 -0
- data/vendor/faiss/faiss/invlists/DirectMap.cpp +5 -2
- data/vendor/faiss/faiss/invlists/InvertedLists.cpp +15 -15
- data/vendor/faiss/faiss/invlists/InvertedLists.h +2 -2
- data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +19 -4
- data/vendor/faiss/faiss/python/python_callbacks.cpp +3 -1
- data/vendor/faiss/faiss/svs/IndexSVSFaissUtils.h +60 -0
- data/vendor/faiss/faiss/svs/IndexSVSFlat.cpp +26 -1
- data/vendor/faiss/faiss/svs/IndexSVSFlat.h +13 -0
- data/vendor/faiss/faiss/svs/IndexSVSIVF.cpp +1 -1
- data/vendor/faiss/faiss/svs/IndexSVSIVFLeanVec.cpp +1 -1
- data/vendor/faiss/faiss/svs/IndexSVSVamana.cpp +150 -23
- data/vendor/faiss/faiss/svs/IndexSVSVamana.h +30 -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 +65 -25
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.h +3 -2
- data/vendor/faiss/faiss/utils/approx_topk_hamming/approx_topk_hamming.h +1 -1
- data/vendor/faiss/faiss/utils/bf16.h +34 -0
- data/vendor/faiss/faiss/utils/distances.cpp +14 -2
- data/vendor/faiss/faiss/utils/distances_simd.cpp +4 -4
- data/vendor/faiss/faiss/utils/extra_distances.cpp +4 -14
- data/vendor/faiss/faiss/utils/extra_distances.h +1 -2
- data/vendor/faiss/faiss/utils/hamming.cpp +9 -9
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx2.cpp +2 -1
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512_spr.cpp +15 -0
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-avx512.h +6 -30
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-avx512_spr.h +171 -0
- data/vendor/faiss/faiss/utils/partitioning.cpp +0 -2
- data/vendor/faiss/faiss/utils/quantize_lut.cpp +29 -8
- data/vendor/faiss/faiss/utils/rabitq_simd.h +202 -0
- data/vendor/faiss/faiss/utils/simd_impl/distances_avx2.cpp +0 -1
- data/vendor/faiss/faiss/utils/simd_impl/distances_avx512.cpp +263 -15
- data/vendor/faiss/faiss/utils/simd_impl/distances_rvv.cpp +160 -18
- data/vendor/faiss/faiss/utils/simd_impl/partitioning_simdlib256.h +14 -68
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx2.cpp +245 -0
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512.cpp +273 -0
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512_spr.cpp +435 -0
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_neon.cpp +11 -0
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_rvv.cpp +143 -6
- data/vendor/faiss/faiss/utils/simd_levels.cpp +56 -2
- data/vendor/faiss/faiss/utils/simd_levels.h +14 -0
- data/vendor/faiss/faiss/utils/utils.cpp +9 -27
- metadata +27 -2
|
@@ -75,7 +75,7 @@ void round_uint8_per_column(
|
|
|
75
75
|
max_span = span;
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
|
-
float a = 255 / max_span;
|
|
78
|
+
float a = max_span > 0 ? 255.0f / max_span : 0.0f;
|
|
79
79
|
float b = 0;
|
|
80
80
|
for (size_t i = 0; i < n; i++) {
|
|
81
81
|
b += mins[i];
|
|
@@ -111,7 +111,7 @@ void round_uint8_per_column_multi(
|
|
|
111
111
|
max_span = span;
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
|
-
float a = 255 / max_span;
|
|
114
|
+
float a = max_span > 0 ? 255.0f / max_span : 0.0f;
|
|
115
115
|
float b = 0;
|
|
116
116
|
for (size_t i = 0; i < n; i++) {
|
|
117
117
|
b += mins[i];
|
|
@@ -143,7 +143,8 @@ void quantize_LUT_and_bias(
|
|
|
143
143
|
float* b_out) {
|
|
144
144
|
float a, b;
|
|
145
145
|
if (!bias) {
|
|
146
|
-
|
|
146
|
+
FAISS_THROW_IF_MSG(
|
|
147
|
+
lut_is_3d, "3d LUT is not supported when bias is null");
|
|
147
148
|
std::vector<float> mins(M);
|
|
148
149
|
float max_span_LUT = -HUGE_VAL, max_span_dis = 0;
|
|
149
150
|
b = 0;
|
|
@@ -154,7 +155,12 @@ void quantize_LUT_and_bias(
|
|
|
154
155
|
max_span_dis += span;
|
|
155
156
|
b += mins[i];
|
|
156
157
|
}
|
|
157
|
-
a = std::min(
|
|
158
|
+
a = std::min(
|
|
159
|
+
max_span_LUT > 0 ? 255.0f / max_span_LUT : HUGE_VALF,
|
|
160
|
+
max_span_dis > 0 ? 65535.0f / max_span_dis : HUGE_VALF);
|
|
161
|
+
if (!std::isfinite(a)) {
|
|
162
|
+
a = 0.0f;
|
|
163
|
+
}
|
|
158
164
|
|
|
159
165
|
for (size_t i = 0; i < M; i++) {
|
|
160
166
|
round_tab(LUT + i * ksub, ksub, a, mins[i], LUTq + i * ksub);
|
|
@@ -174,7 +180,12 @@ void quantize_LUT_and_bias(
|
|
|
174
180
|
max_span_dis += span;
|
|
175
181
|
b += mins[i];
|
|
176
182
|
}
|
|
177
|
-
a = std::min(
|
|
183
|
+
a = std::min(
|
|
184
|
+
max_span_LUT > 0 ? 255.0f / max_span_LUT : HUGE_VALF,
|
|
185
|
+
max_span_dis > 0 ? 65535.0f / max_span_dis : HUGE_VALF);
|
|
186
|
+
if (!std::isfinite(a)) {
|
|
187
|
+
a = 0.0f;
|
|
188
|
+
}
|
|
178
189
|
b += bias_min;
|
|
179
190
|
|
|
180
191
|
for (size_t i = 0; i < M; i++) {
|
|
@@ -208,7 +219,12 @@ void quantize_LUT_and_bias(
|
|
|
208
219
|
b = std::min(b, b2j);
|
|
209
220
|
}
|
|
210
221
|
|
|
211
|
-
a = std::min(
|
|
222
|
+
a = std::min(
|
|
223
|
+
max_span_LUT > 0 ? 255.0f / max_span_LUT : HUGE_VALF,
|
|
224
|
+
max_span_dis > 0 ? 65535.0f / max_span_dis : HUGE_VALF);
|
|
225
|
+
if (!std::isfinite(a)) {
|
|
226
|
+
a = 0.0f;
|
|
227
|
+
}
|
|
212
228
|
|
|
213
229
|
ij = 0;
|
|
214
230
|
size_t ij_2 = 0;
|
|
@@ -256,7 +272,7 @@ void quantize_LUT_and_bias(
|
|
|
256
272
|
max_span = std::max(max_span, span);
|
|
257
273
|
b += mins[i];
|
|
258
274
|
}
|
|
259
|
-
a = 255 / max_span;
|
|
275
|
+
a = max_span > 0 ? 255.0f / max_span : 0.0f;
|
|
260
276
|
ij = 0;
|
|
261
277
|
size_t ij_2 = 0;
|
|
262
278
|
for (size_t j = 0; j < nprobe; j++) {
|
|
@@ -305,7 +321,12 @@ void aq_quantize_LUT_and_bias(
|
|
|
305
321
|
max_span_dis += (i >= M - M_norm ? span * norm_scale : span);
|
|
306
322
|
b += mins[i];
|
|
307
323
|
}
|
|
308
|
-
a = std::min(
|
|
324
|
+
a = std::min(
|
|
325
|
+
max_span_LUT > 0 ? 255.0f / max_span_LUT : HUGE_VALF,
|
|
326
|
+
max_span_dis > 0 ? 65535.0f / max_span_dis : HUGE_VALF);
|
|
327
|
+
if (!std::isfinite(a)) {
|
|
328
|
+
a = 0.0f;
|
|
329
|
+
}
|
|
309
330
|
b += bias_min;
|
|
310
331
|
|
|
311
332
|
for (size_t i = 0; i < M; i++) {
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
#pragma once
|
|
9
9
|
|
|
10
|
+
#include <algorithm>
|
|
10
11
|
#include <cstddef>
|
|
11
12
|
#include <cstdint>
|
|
12
13
|
#include <cstring>
|
|
@@ -16,6 +17,15 @@
|
|
|
16
17
|
|
|
17
18
|
namespace faiss::rabitq {
|
|
18
19
|
|
|
20
|
+
/// SIMD levels with RaBitQ query/LUT quantization implementations.
|
|
21
|
+
constexpr int RABITQ_QUANTIZATION_SIMD_LEVELS = (1 << int(SIMDLevel::NONE)) |
|
|
22
|
+
(1 << int(SIMDLevel::AVX2)) | (1 << int(SIMDLevel::AVX512));
|
|
23
|
+
|
|
24
|
+
struct BitwiseAndDotProductResult {
|
|
25
|
+
uint64_t dot_product;
|
|
26
|
+
uint64_t popcount;
|
|
27
|
+
};
|
|
28
|
+
|
|
19
29
|
/**
|
|
20
30
|
* Compute dot product between query and binary data using popcount on AND.
|
|
21
31
|
*
|
|
@@ -32,6 +42,17 @@ uint64_t bitwise_and_dot_product(
|
|
|
32
42
|
size_t size,
|
|
33
43
|
size_t qb);
|
|
34
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Compute bitwise_and_dot_product(query, data, size, qb) and popcount(data,
|
|
47
|
+
* size) in one pass over data.
|
|
48
|
+
*/
|
|
49
|
+
template <SIMDLevel SL = SINGLE_SIMD_LEVEL>
|
|
50
|
+
BitwiseAndDotProductResult bitwise_and_dot_product_with_popcount(
|
|
51
|
+
const uint8_t* query,
|
|
52
|
+
const uint8_t* data,
|
|
53
|
+
size_t size,
|
|
54
|
+
size_t qb);
|
|
55
|
+
|
|
35
56
|
/**
|
|
36
57
|
* Compute dot product between query and binary data using popcount on XOR.
|
|
37
58
|
*
|
|
@@ -58,6 +79,56 @@ uint64_t bitwise_xor_dot_product(
|
|
|
58
79
|
template <SIMDLevel SL = SINGLE_SIMD_LEVEL>
|
|
59
80
|
uint64_t popcount(const uint8_t* data, size_t size);
|
|
60
81
|
|
|
82
|
+
/**
|
|
83
|
+
* Rearrange per-dimension quantized query codes into bit-plane layout.
|
|
84
|
+
*
|
|
85
|
+
* @p rotated_qq holds one qb-bit code per dimension (one byte each, value in
|
|
86
|
+
* [0, 2^qb)). @p out receives qb bit-planes of ((d + 7) / 8) bytes each:
|
|
87
|
+
* bit-plane j packs bit j of code i into bit (i % 8) of byte (i / 8). @p out
|
|
88
|
+
* must have room for qb * ((d + 7) / 8) bytes and is fully overwritten.
|
|
89
|
+
*
|
|
90
|
+
* @param rotated_qq per-dimension codes (d bytes)
|
|
91
|
+
* @param d dimensionality
|
|
92
|
+
* @param qb quantization bits per dimension (1..8)
|
|
93
|
+
* @param out bit-plane output buffer (qb * ((d + 7) / 8) bytes)
|
|
94
|
+
*/
|
|
95
|
+
template <SIMDLevel SL = SINGLE_SIMD_LEVEL>
|
|
96
|
+
void rearrange_bit_planes(
|
|
97
|
+
const uint8_t* rotated_qq,
|
|
98
|
+
size_t d,
|
|
99
|
+
size_t qb,
|
|
100
|
+
uint8_t* out);
|
|
101
|
+
|
|
102
|
+
/// Find min/max of one 16-entry FastScan LUT row.
|
|
103
|
+
template <SIMDLevel SL = SINGLE_SIMD_LEVEL>
|
|
104
|
+
void lut_minmax_16(const float* tab, float& mn, float& mx);
|
|
105
|
+
|
|
106
|
+
/// Find min/max of an arbitrary-length float vector. For n == 0, mn and mx
|
|
107
|
+
/// are left unchanged.
|
|
108
|
+
template <SIMDLevel SL = SINGLE_SIMD_LEVEL>
|
|
109
|
+
void minmax_values(const float* values, size_t n, float& mn, float& mx);
|
|
110
|
+
|
|
111
|
+
/// Quantize one 16-entry FastScan LUT row with non-negative half-up rounding.
|
|
112
|
+
template <SIMDLevel SL = SINGLE_SIMD_LEVEL>
|
|
113
|
+
void lut_quantize_16_to_uint8(
|
|
114
|
+
const float* tab,
|
|
115
|
+
float mn,
|
|
116
|
+
float a,
|
|
117
|
+
uint8_t* out);
|
|
118
|
+
|
|
119
|
+
/// Quantize rotated query values and accumulate query correction terms.
|
|
120
|
+
template <SIMDLevel SL = SINGLE_SIMD_LEVEL>
|
|
121
|
+
void quantize_query_values(
|
|
122
|
+
const float* rq,
|
|
123
|
+
size_t d,
|
|
124
|
+
float v_min,
|
|
125
|
+
float inv_delta,
|
|
126
|
+
uint8_t max_code,
|
|
127
|
+
bool centered,
|
|
128
|
+
uint8_t* rqq,
|
|
129
|
+
size_t& sum_qq,
|
|
130
|
+
int64_t& sum2_signed_odd_int);
|
|
131
|
+
|
|
61
132
|
// NONE specializations — scalar fallbacks
|
|
62
133
|
|
|
63
134
|
template <>
|
|
@@ -85,6 +156,35 @@ inline uint64_t bitwise_and_dot_product<SIMDLevel::NONE>(
|
|
|
85
156
|
return sum;
|
|
86
157
|
}
|
|
87
158
|
|
|
159
|
+
template <>
|
|
160
|
+
inline BitwiseAndDotProductResult bitwise_and_dot_product_with_popcount<
|
|
161
|
+
SIMDLevel::NONE>(
|
|
162
|
+
const uint8_t* query,
|
|
163
|
+
const uint8_t* data,
|
|
164
|
+
size_t size,
|
|
165
|
+
size_t qb) {
|
|
166
|
+
uint64_t dot_product = 0;
|
|
167
|
+
uint64_t popcount_sum = 0;
|
|
168
|
+
size_t offset = 0;
|
|
169
|
+
for (size_t step = 64 / 8; offset + step <= size; offset += step) {
|
|
170
|
+
const auto yv = *(const uint64_t*)(data + offset);
|
|
171
|
+
popcount_sum += popcount64(yv);
|
|
172
|
+
for (int j = 0; j < qb; j++) {
|
|
173
|
+
const auto qv = *(const uint64_t*)(query + j * size + offset);
|
|
174
|
+
dot_product += popcount64(qv & yv) << j;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
for (; offset < size; ++offset) {
|
|
178
|
+
const auto yv = *(data + offset);
|
|
179
|
+
popcount_sum += popcount32(yv);
|
|
180
|
+
for (int j = 0; j < qb; j++) {
|
|
181
|
+
const auto qv = *(query + j * size + offset);
|
|
182
|
+
dot_product += popcount32(qv & yv) << j;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return {dot_product, popcount_sum};
|
|
186
|
+
}
|
|
187
|
+
|
|
88
188
|
template <>
|
|
89
189
|
inline uint64_t bitwise_xor_dot_product<SIMDLevel::NONE>(
|
|
90
190
|
const uint8_t* query,
|
|
@@ -125,6 +225,108 @@ inline uint64_t popcount<SIMDLevel::NONE>(const uint8_t* data, size_t size) {
|
|
|
125
225
|
return sum;
|
|
126
226
|
}
|
|
127
227
|
|
|
228
|
+
template <>
|
|
229
|
+
inline void rearrange_bit_planes<SIMDLevel::NONE>(
|
|
230
|
+
const uint8_t* rotated_qq,
|
|
231
|
+
size_t d,
|
|
232
|
+
size_t qb,
|
|
233
|
+
uint8_t* out) {
|
|
234
|
+
const size_t offset = (d + 7) / 8;
|
|
235
|
+
memset(out, 0, offset * qb);
|
|
236
|
+
for (size_t idim = 0; idim < d; idim++) {
|
|
237
|
+
for (size_t iv = 0; iv < qb; iv++) {
|
|
238
|
+
const bool bit = ((rotated_qq[idim] & (1 << iv)) != 0);
|
|
239
|
+
out[iv * offset + idim / 8] |= bit ? (1 << (idim % 8)) : 0;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
inline uint8_t round_clamped_byte_scalar(float x, uint8_t max_code) {
|
|
245
|
+
if (x <= 0.0f) {
|
|
246
|
+
return 0;
|
|
247
|
+
}
|
|
248
|
+
if (x >= max_code) {
|
|
249
|
+
return max_code;
|
|
250
|
+
}
|
|
251
|
+
return static_cast<uint8_t>(static_cast<int>(x + 0.5f));
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
inline uint8_t round_nonnegative_byte_scalar(float x) {
|
|
255
|
+
return round_clamped_byte_scalar(x, 255);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
template <>
|
|
259
|
+
inline void lut_minmax_16<SIMDLevel::NONE>(
|
|
260
|
+
const float* tab,
|
|
261
|
+
float& mn,
|
|
262
|
+
float& mx) {
|
|
263
|
+
mn = tab[0];
|
|
264
|
+
mx = tab[0];
|
|
265
|
+
for (size_t s = 1; s < 16; s++) {
|
|
266
|
+
mn = std::min(mn, tab[s]);
|
|
267
|
+
mx = std::max(mx, tab[s]);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
template <>
|
|
272
|
+
inline void minmax_values<SIMDLevel::NONE>(
|
|
273
|
+
const float* values,
|
|
274
|
+
size_t n,
|
|
275
|
+
float& mn,
|
|
276
|
+
float& mx) {
|
|
277
|
+
if (n == 0) {
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
mn = values[0];
|
|
281
|
+
mx = values[0];
|
|
282
|
+
for (size_t i = 1; i < n; i++) {
|
|
283
|
+
mn = std::min(mn, values[i]);
|
|
284
|
+
mx = std::max(mx, values[i]);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
template <>
|
|
289
|
+
inline void lut_quantize_16_to_uint8<SIMDLevel::NONE>(
|
|
290
|
+
const float* tab,
|
|
291
|
+
float mn,
|
|
292
|
+
float a,
|
|
293
|
+
uint8_t* out) {
|
|
294
|
+
for (size_t s = 0; s < 16; s++) {
|
|
295
|
+
out[s] = round_nonnegative_byte_scalar(a * (tab[s] - mn));
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
template <>
|
|
300
|
+
inline void quantize_query_values<SIMDLevel::NONE>(
|
|
301
|
+
const float* rq,
|
|
302
|
+
size_t d,
|
|
303
|
+
float v_min,
|
|
304
|
+
float inv_delta,
|
|
305
|
+
uint8_t max_code,
|
|
306
|
+
bool centered,
|
|
307
|
+
uint8_t* rqq,
|
|
308
|
+
size_t& sum_qq,
|
|
309
|
+
int64_t& sum2_signed_odd_int) {
|
|
310
|
+
if (centered) {
|
|
311
|
+
for (size_t i = 0; i < d; i++) {
|
|
312
|
+
const uint8_t v_qq = round_clamped_byte_scalar(
|
|
313
|
+
(rq[i] - v_min) * inv_delta, max_code);
|
|
314
|
+
rqq[i] = v_qq;
|
|
315
|
+
sum_qq += v_qq;
|
|
316
|
+
|
|
317
|
+
const int64_t signed_odd_int = int64_t(v_qq) * 2 - max_code;
|
|
318
|
+
sum2_signed_odd_int += signed_odd_int * signed_odd_int;
|
|
319
|
+
}
|
|
320
|
+
} else {
|
|
321
|
+
for (size_t i = 0; i < d; i++) {
|
|
322
|
+
const uint8_t v_qq = round_clamped_byte_scalar(
|
|
323
|
+
(rq[i] - v_min) * inv_delta, max_code);
|
|
324
|
+
rqq[i] = v_qq;
|
|
325
|
+
sum_qq += v_qq;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
128
330
|
} // namespace faiss::rabitq
|
|
129
331
|
|
|
130
332
|
/*********************************************************
|
|
@@ -9,6 +9,35 @@
|
|
|
9
9
|
|
|
10
10
|
#include <immintrin.h>
|
|
11
11
|
|
|
12
|
+
#include <memory>
|
|
13
|
+
|
|
14
|
+
#include <faiss/impl/AuxIndexStructures.h>
|
|
15
|
+
#include <faiss/impl/ResultHandler.h>
|
|
16
|
+
#include <faiss/utils/distances_fused/distances_fused.h>
|
|
17
|
+
#include <faiss/utils/simd_impl/exhaustive_L2sqr_blas_cmax.h>
|
|
18
|
+
|
|
19
|
+
#ifndef FINTEGER
|
|
20
|
+
#define FINTEGER long
|
|
21
|
+
#endif
|
|
22
|
+
|
|
23
|
+
extern "C" {
|
|
24
|
+
|
|
25
|
+
int sgemm_(
|
|
26
|
+
const char* transa,
|
|
27
|
+
const char* transb,
|
|
28
|
+
FINTEGER* m,
|
|
29
|
+
FINTEGER* n,
|
|
30
|
+
FINTEGER* k,
|
|
31
|
+
const float* alpha,
|
|
32
|
+
const float* a,
|
|
33
|
+
FINTEGER* lda,
|
|
34
|
+
const float* b,
|
|
35
|
+
FINTEGER* ldb,
|
|
36
|
+
float* beta,
|
|
37
|
+
float* c,
|
|
38
|
+
FINTEGER* ldc);
|
|
39
|
+
}
|
|
40
|
+
|
|
12
41
|
#define THE_SIMD_LEVEL SIMDLevel::AVX512
|
|
13
42
|
#include <faiss/utils/simd_impl/distances_autovec-inl.h>
|
|
14
43
|
// NOLINTNEXTLINE(facebook-hte-InlineHeader)
|
|
@@ -954,21 +983,6 @@ size_t fvec_L2sqr_ny_nearest<SIMDLevel::AVX512>(
|
|
|
954
983
|
&fvec_L2sqr_ny_nearest_D8<SIMDLevel::AVX512>);
|
|
955
984
|
}
|
|
956
985
|
|
|
957
|
-
template <>
|
|
958
|
-
size_t fvec_L2sqr_ny_nearest_y_transposed<SIMDLevel::AVX512>(
|
|
959
|
-
float* distances_tmp_buffer,
|
|
960
|
-
const float* x,
|
|
961
|
-
const float* y,
|
|
962
|
-
const float* y_sqlen,
|
|
963
|
-
size_t d,
|
|
964
|
-
size_t d_offset,
|
|
965
|
-
size_t ny) {
|
|
966
|
-
return fvec_L2sqr_ny_nearest_y_transposed<SIMDLevel::NONE>(
|
|
967
|
-
distances_tmp_buffer, x, y, y_sqlen, d, d_offset, ny);
|
|
968
|
-
}
|
|
969
|
-
|
|
970
|
-
// TODO: Following functions are not used in the current codebase. Check AVX2 ,
|
|
971
|
-
// respective implementation has been used
|
|
972
986
|
template <size_t DIM>
|
|
973
987
|
size_t fvec_L2sqr_ny_nearest_y_transposed_D(
|
|
974
988
|
float* /* distances_tmp_buffer */,
|
|
@@ -1082,6 +1096,33 @@ size_t fvec_L2sqr_ny_nearest_y_transposed_D(
|
|
|
1082
1096
|
return current_min_index;
|
|
1083
1097
|
}
|
|
1084
1098
|
|
|
1099
|
+
template <>
|
|
1100
|
+
size_t fvec_L2sqr_ny_nearest_y_transposed<SIMDLevel::AVX512>(
|
|
1101
|
+
float* distances_tmp_buffer,
|
|
1102
|
+
const float* x,
|
|
1103
|
+
const float* y,
|
|
1104
|
+
const float* y_sqlen,
|
|
1105
|
+
size_t d,
|
|
1106
|
+
size_t d_offset,
|
|
1107
|
+
size_t ny) {
|
|
1108
|
+
// optimized for a few special cases
|
|
1109
|
+
#define DISPATCH(dval) \
|
|
1110
|
+
case dval: \
|
|
1111
|
+
return fvec_L2sqr_ny_nearest_y_transposed_D<dval>( \
|
|
1112
|
+
distances_tmp_buffer, x, y, y_sqlen, d_offset, ny);
|
|
1113
|
+
|
|
1114
|
+
switch (d) {
|
|
1115
|
+
DISPATCH(1)
|
|
1116
|
+
DISPATCH(2)
|
|
1117
|
+
DISPATCH(4)
|
|
1118
|
+
DISPATCH(8)
|
|
1119
|
+
default:
|
|
1120
|
+
return fvec_L2sqr_ny_nearest_y_transposed<SIMDLevel::NONE>(
|
|
1121
|
+
distances_tmp_buffer, x, y, y_sqlen, d, d_offset, ny);
|
|
1122
|
+
}
|
|
1123
|
+
#undef DISPATCH
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1085
1126
|
template <>
|
|
1086
1127
|
int fvec_madd_and_argmin<SIMDLevel::AVX512>(
|
|
1087
1128
|
size_t n,
|
|
@@ -1092,4 +1133,211 @@ int fvec_madd_and_argmin<SIMDLevel::AVX512>(
|
|
|
1092
1133
|
return fvec_madd_and_argmin_sse(n, a, bf, b, c);
|
|
1093
1134
|
}
|
|
1094
1135
|
|
|
1136
|
+
template <>
|
|
1137
|
+
void exhaustive_L2sqr_blas_cmax<SIMDLevel::AVX512>(
|
|
1138
|
+
const float* x,
|
|
1139
|
+
const float* y,
|
|
1140
|
+
size_t d,
|
|
1141
|
+
size_t nx,
|
|
1142
|
+
size_t ny,
|
|
1143
|
+
Top1BlockResultHandler<CMax<float, int64_t>>& res,
|
|
1144
|
+
const float* y_norms) {
|
|
1145
|
+
// BLAS does not like empty matrices
|
|
1146
|
+
if (nx == 0 || ny == 0) {
|
|
1147
|
+
return;
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
/* block sizes */
|
|
1151
|
+
const size_t bs_x = distance_compute_blas_query_bs;
|
|
1152
|
+
const size_t bs_y = distance_compute_blas_database_bs;
|
|
1153
|
+
std::unique_ptr<float[]> ip_block(new float[bs_x * bs_y]);
|
|
1154
|
+
std::unique_ptr<float[]> x_norms(new float[nx]);
|
|
1155
|
+
std::unique_ptr<float[]> del2;
|
|
1156
|
+
|
|
1157
|
+
fvec_norms_L2sqr(x_norms.get(), x, d, nx);
|
|
1158
|
+
|
|
1159
|
+
if (!y_norms) {
|
|
1160
|
+
float* y_norms2 = new float[ny];
|
|
1161
|
+
del2.reset(y_norms2);
|
|
1162
|
+
fvec_norms_L2sqr(y_norms2, y, d, ny);
|
|
1163
|
+
y_norms = y_norms2;
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
for (size_t i0 = 0; i0 < nx; i0 += bs_x) {
|
|
1167
|
+
size_t i1 = i0 + bs_x;
|
|
1168
|
+
if (i1 > nx) {
|
|
1169
|
+
i1 = nx;
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
res.begin_multiple(i0, i1);
|
|
1173
|
+
|
|
1174
|
+
for (size_t j0 = 0; j0 < ny; j0 += bs_y) {
|
|
1175
|
+
size_t j1 = j0 + bs_y;
|
|
1176
|
+
if (j1 > ny) {
|
|
1177
|
+
j1 = ny;
|
|
1178
|
+
}
|
|
1179
|
+
/* compute the actual dot products */
|
|
1180
|
+
{
|
|
1181
|
+
float one = 1, zero = 0;
|
|
1182
|
+
FINTEGER nyi = j1 - j0, nxi = i1 - i0, di = d;
|
|
1183
|
+
sgemm_("Transpose",
|
|
1184
|
+
"Not transpose",
|
|
1185
|
+
&nyi,
|
|
1186
|
+
&nxi,
|
|
1187
|
+
&di,
|
|
1188
|
+
&one,
|
|
1189
|
+
y + j0 * d,
|
|
1190
|
+
&di,
|
|
1191
|
+
x + i0 * d,
|
|
1192
|
+
&di,
|
|
1193
|
+
&zero,
|
|
1194
|
+
ip_block.get(),
|
|
1195
|
+
&nyi);
|
|
1196
|
+
}
|
|
1197
|
+
#pragma omp parallel for schedule(static) if ((i1 - i0) >= 16)
|
|
1198
|
+
for (int64_t i = static_cast<int64_t>(i0);
|
|
1199
|
+
i < static_cast<int64_t>(i1);
|
|
1200
|
+
i++) {
|
|
1201
|
+
float* ip_line = ip_block.get() + (i - i0) * (j1 - j0);
|
|
1202
|
+
|
|
1203
|
+
_mm_prefetch((const char*)ip_line, _MM_HINT_NTA);
|
|
1204
|
+
_mm_prefetch((const char*)(ip_line + 16), _MM_HINT_NTA);
|
|
1205
|
+
|
|
1206
|
+
// constant
|
|
1207
|
+
const __m512 mul_minus2 = _mm512_set1_ps(-2);
|
|
1208
|
+
|
|
1209
|
+
// Track 16 min distances + 16 min indices.
|
|
1210
|
+
// All the distances tracked do not take x_norms[i]
|
|
1211
|
+
// into account in order to get rid of extra
|
|
1212
|
+
// _mm512_add_ps(x_norms[i], ...) instructions
|
|
1213
|
+
// in distance computations.
|
|
1214
|
+
__m512 min_distances =
|
|
1215
|
+
_mm512_set1_ps(res.dis_tab[i] - x_norms[i]);
|
|
1216
|
+
|
|
1217
|
+
// these indices are local and are relative to j0.
|
|
1218
|
+
// so, value 0 means j0.
|
|
1219
|
+
__m512i min_indices = _mm512_set1_epi32(0);
|
|
1220
|
+
|
|
1221
|
+
__m512i current_indices = _mm512_setr_epi32(
|
|
1222
|
+
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
|
|
1223
|
+
const __m512i indices_delta = _mm512_set1_epi32(16);
|
|
1224
|
+
|
|
1225
|
+
// current j index
|
|
1226
|
+
size_t idx_j = 0;
|
|
1227
|
+
size_t count = j1 - j0;
|
|
1228
|
+
|
|
1229
|
+
// process 32 elements per loop
|
|
1230
|
+
for (; idx_j < (count / 32) * 32; idx_j += 32, ip_line += 32) {
|
|
1231
|
+
_mm_prefetch((const char*)(ip_line + 32), _MM_HINT_NTA);
|
|
1232
|
+
_mm_prefetch((const char*)(ip_line + 48), _MM_HINT_NTA);
|
|
1233
|
+
|
|
1234
|
+
// load values for norms
|
|
1235
|
+
const __m512 y_norm_0 =
|
|
1236
|
+
_mm512_loadu_ps(y_norms + idx_j + j0 + 0);
|
|
1237
|
+
const __m512 y_norm_1 =
|
|
1238
|
+
_mm512_loadu_ps(y_norms + idx_j + j0 + 16);
|
|
1239
|
+
|
|
1240
|
+
// load values for dot products
|
|
1241
|
+
const __m512 ip_0 = _mm512_loadu_ps(ip_line + 0);
|
|
1242
|
+
const __m512 ip_1 = _mm512_loadu_ps(ip_line + 16);
|
|
1243
|
+
|
|
1244
|
+
// compute dis = y_norm[j] - 2 * dot(x_norm[i], y_norm[j]).
|
|
1245
|
+
// x_norm[i] was dropped off because it is a constant for a
|
|
1246
|
+
// given i.
|
|
1247
|
+
__m512 distances_0 =
|
|
1248
|
+
_mm512_fmadd_ps(ip_0, mul_minus2, y_norm_0);
|
|
1249
|
+
__m512 distances_1 =
|
|
1250
|
+
_mm512_fmadd_ps(ip_1, mul_minus2, y_norm_1);
|
|
1251
|
+
|
|
1252
|
+
// compare the new distances to the min distances
|
|
1253
|
+
// for each of the first group of 16 AVX512 components.
|
|
1254
|
+
const __mmask16 comparison_0 = _mm512_cmp_ps_mask(
|
|
1255
|
+
min_distances, distances_0, _CMP_LE_OS);
|
|
1256
|
+
|
|
1257
|
+
// update min distances and indices with closest vectors if
|
|
1258
|
+
// needed.
|
|
1259
|
+
min_distances = _mm512_mask_blend_ps(
|
|
1260
|
+
comparison_0, distances_0, min_distances);
|
|
1261
|
+
min_indices = _mm512_mask_blend_epi32(
|
|
1262
|
+
comparison_0, current_indices, min_indices);
|
|
1263
|
+
current_indices =
|
|
1264
|
+
_mm512_add_epi32(current_indices, indices_delta);
|
|
1265
|
+
|
|
1266
|
+
// compare the new distances to the min distances
|
|
1267
|
+
// for each of the second group of 16 AVX512 components.
|
|
1268
|
+
const __mmask16 comparison_1 = _mm512_cmp_ps_mask(
|
|
1269
|
+
min_distances, distances_1, _CMP_LE_OS);
|
|
1270
|
+
|
|
1271
|
+
// update min distances and indices with closest vectors if
|
|
1272
|
+
// needed.
|
|
1273
|
+
min_distances = _mm512_mask_blend_ps(
|
|
1274
|
+
comparison_1, distances_1, min_distances);
|
|
1275
|
+
min_indices = _mm512_mask_blend_epi32(
|
|
1276
|
+
comparison_1, current_indices, min_indices);
|
|
1277
|
+
current_indices =
|
|
1278
|
+
_mm512_add_epi32(current_indices, indices_delta);
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
// dump values and find the minimum distance / minimum index
|
|
1282
|
+
float min_distances_scalar[16];
|
|
1283
|
+
uint32_t min_indices_scalar[16];
|
|
1284
|
+
_mm512_storeu_ps(min_distances_scalar, min_distances);
|
|
1285
|
+
_mm512_storeu_si512(
|
|
1286
|
+
(__m512i*)(min_indices_scalar), min_indices);
|
|
1287
|
+
|
|
1288
|
+
float current_min_distance = res.dis_tab[i];
|
|
1289
|
+
uint32_t current_min_index = res.ids_tab[i];
|
|
1290
|
+
|
|
1291
|
+
// if two indices are represented with equal distance values,
|
|
1292
|
+
// then the index with the min value is returned.
|
|
1293
|
+
for (size_t jv = 0; jv < 16; jv++) {
|
|
1294
|
+
// add missing x_norms[i]
|
|
1295
|
+
float distance_candidate =
|
|
1296
|
+
min_distances_scalar[jv] + x_norms[i];
|
|
1297
|
+
|
|
1298
|
+
// negative values can occur for identical vectors
|
|
1299
|
+
// due to roundoff errors.
|
|
1300
|
+
if (distance_candidate < 0) {
|
|
1301
|
+
distance_candidate = 0;
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
int64_t index_candidate = min_indices_scalar[jv] + j0;
|
|
1305
|
+
|
|
1306
|
+
if (current_min_distance > distance_candidate) {
|
|
1307
|
+
current_min_distance = distance_candidate;
|
|
1308
|
+
current_min_index = index_candidate;
|
|
1309
|
+
} else if (
|
|
1310
|
+
current_min_distance == distance_candidate &&
|
|
1311
|
+
current_min_index > index_candidate) {
|
|
1312
|
+
current_min_index = index_candidate;
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
// process leftovers
|
|
1317
|
+
for (; idx_j < count; idx_j++, ip_line++) {
|
|
1318
|
+
float ip = *ip_line;
|
|
1319
|
+
float dis = x_norms[i] + y_norms[idx_j + j0] - 2 * ip;
|
|
1320
|
+
// negative values can occur for identical vectors
|
|
1321
|
+
// due to roundoff errors.
|
|
1322
|
+
if (dis < 0) {
|
|
1323
|
+
dis = 0;
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
if (current_min_distance > dis) {
|
|
1327
|
+
current_min_distance = dis;
|
|
1328
|
+
current_min_index = idx_j + j0;
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
//
|
|
1333
|
+
res.add_result(i, current_min_distance, current_min_index);
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
// Does nothing for SingleBestResultHandler, but
|
|
1337
|
+
// keeping the call for the consistency.
|
|
1338
|
+
res.end_multiple();
|
|
1339
|
+
InterruptCallback::check();
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1095
1343
|
} // namespace faiss
|