faiss 0.6.2 → 0.6.4
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/Clustering.h +8 -0
- 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 +24 -4
- data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +16 -145
- data/vendor/faiss/faiss/IndexBinaryHNSW.h +0 -6
- data/vendor/faiss/faiss/IndexBinaryHash.cpp +5 -9
- data/vendor/faiss/faiss/IndexBinaryIVF.cpp +8 -18
- data/vendor/faiss/faiss/IndexBinaryIVF.h +8 -1
- 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 +21 -54
- data/vendor/faiss/faiss/IndexFlat.h +2 -2
- data/vendor/faiss/faiss/IndexHNSW.cpp +311 -102
- data/vendor/faiss/faiss/IndexHNSW.h +31 -7
- data/vendor/faiss/faiss/IndexIDMap.cpp +26 -8
- data/vendor/faiss/faiss/IndexIDMap.h +2 -0
- data/vendor/faiss/faiss/IndexIVF.cpp +36 -10
- data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +1 -1
- 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 +3 -4
- data/vendor/faiss/faiss/IndexIVFIndependentQuantizer.cpp +1 -1
- data/vendor/faiss/faiss/IndexIVFPQ.cpp +49 -23
- data/vendor/faiss/faiss/IndexIVFPQ.h +11 -0
- data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +0 -1
- data/vendor/faiss/faiss/IndexIVFRaBitQ.cpp +19 -49
- 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 +9 -2
- data/vendor/faiss/faiss/IndexNSG.cpp +7 -2
- 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/IndexShards.cpp +5 -5
- data/vendor/faiss/faiss/IndexShardsIVF.cpp +6 -5
- data/vendor/faiss/faiss/MetaIndexes.cpp +2 -4
- data/vendor/faiss/faiss/SuperKMeans.cpp +286 -247
- data/vendor/faiss/faiss/SuperKMeans.h +33 -2
- data/vendor/faiss/faiss/VectorTransform.cpp +71 -2
- data/vendor/faiss/faiss/VectorTransform.h +3 -0
- data/vendor/faiss/faiss/clone_index.cpp +8 -0
- data/vendor/faiss/faiss/factory_tools.cpp +47 -4
- data/vendor/faiss/faiss/gpu/GpuCloner.cpp +11 -11
- data/vendor/faiss/faiss/gpu/GpuClonerOptions.h +1 -5
- data/vendor/faiss/faiss/gpu/GpuDistance.h +2 -5
- data/vendor/faiss/faiss/gpu/GpuIndex.h +38 -16
- data/vendor/faiss/faiss/gpu/GpuIndexCagra.h +71 -1
- data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +17 -0
- data/vendor/faiss/faiss/gpu/GpuIndexIVFScalarQuantizer.h +16 -0
- 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/MetalIndexIVFFlat.h +1 -5
- data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFPQ.h +88 -0
- data/vendor/faiss/faiss/gpu_metal/impl/MetalIVFPQ.h +134 -0
- data/vendor/faiss/faiss/impl/AdditiveQuantizer.cpp +1 -1
- data/vendor/faiss/faiss/impl/ClusteringInitialization.cpp +7 -4
- 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 +528 -267
- data/vendor/faiss/faiss/impl/HNSW.h +46 -7
- data/vendor/faiss/faiss/impl/IDSelector.h +44 -0
- data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +2 -2
- data/vendor/faiss/faiss/impl/NNDescent.cpp +10 -3
- data/vendor/faiss/faiss/impl/NSG.cpp +3 -1
- data/vendor/faiss/faiss/impl/Panorama.h +20 -9
- data/vendor/faiss/faiss/impl/PolysemousTraining.cpp +152 -84
- data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +38 -26
- 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 +239 -72
- data/vendor/faiss/faiss/impl/RaBitQuantizer.h +66 -4
- data/vendor/faiss/faiss/impl/RaBitQuantizerMultiBit.cpp +4 -13
- data/vendor/faiss/faiss/impl/ResultHandler.h +34 -34
- data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +287 -84
- data/vendor/faiss/faiss/impl/ScalarQuantizer.h +26 -10
- data/vendor/faiss/faiss/impl/ThreadedIndex-inl.h +2 -2
- data/vendor/faiss/faiss/impl/VisitedTable.cpp +22 -2
- data/vendor/faiss/faiss/impl/VisitedTable.h +20 -0
- data/vendor/faiss/faiss/impl/binary_hamming/IndexBinaryIVF_impl.h +90 -14
- data/vendor/faiss/faiss/impl/binary_hamming/avx2.cpp +4 -4
- data/vendor/faiss/faiss/impl/expanded_scanners.h +5 -1
- data/vendor/faiss/faiss/impl/fast_scan/decompose_qbs.h +1 -0
- data/vendor/faiss/faiss/impl/fast_scan/dispatching.h +35 -2
- data/vendor/faiss/faiss/impl/hnsw/LockVector.cpp +1 -1
- data/vendor/faiss/faiss/impl/index_read.cpp +491 -50
- data/vendor/faiss/faiss/impl/index_write.cpp +86 -30
- data/vendor/faiss/faiss/impl/lattice_Zn.cpp +8 -9
- data/vendor/faiss/faiss/impl/platform_macros.h +3 -1
- 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/IVFPQScanner_impl.h +73 -39
- 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 +4 -4
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-generic.cpp +4 -4
- 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 +887 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/distance_computers.h +2 -2
- data/vendor/faiss/faiss/impl/scalar_quantizer/quantizers.h +9 -8
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx2.cpp +90 -24
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-impl.h +30 -30
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-spr.cpp +4 -5
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512.cpp +101 -34
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-dispatch.h +169 -13
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-neon.cpp +125 -26
- data/vendor/faiss/faiss/impl/simd_dispatch.h +70 -31
- data/vendor/faiss/faiss/index_factory.cpp +40 -7
- data/vendor/faiss/faiss/invlists/DirectMap.cpp +1 -1
- data/vendor/faiss/faiss/invlists/InvertedLists.cpp +9 -6
- data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +29 -8
- 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 +47 -5
- data/vendor/faiss/faiss/svs/IndexSVSVamana.h +23 -3
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLVQ.cpp +4 -2
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLVQ.h +2 -1
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.cpp +10 -4
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.h +2 -1
- data/vendor/faiss/faiss/utils/approx_topk_hamming/approx_topk_hamming.h +1 -1
- data/vendor/faiss/faiss/utils/distances.cpp +30 -11
- data/vendor/faiss/faiss/utils/distances_dispatch.h +30 -24
- data/vendor/faiss/faiss/utils/distances_fused/distances_fused.cpp +1 -1
- data/vendor/faiss/faiss/utils/distances_simd.cpp +4 -3
- 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 +16 -10
- data/vendor/faiss/faiss/utils/hamming.h +10 -1
- data/vendor/faiss/faiss/utils/hamming_distance/common.h +14 -3
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512_vpopcnt.cpp +24 -0
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-avx512.h +1 -1
- data/vendor/faiss/faiss/utils/hamming_distance/{hamming_computer-avx512_spr.h → hamming_computer-avx512_vpopcnt.h} +85 -24
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_impl.h +141 -0
- 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_arm_sve.cpp +194 -30
- 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 +198 -18
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx2.cpp +245 -0
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512.cpp +330 -40
- data/vendor/faiss/faiss/utils/simd_impl/{rabitq_avx512_spr.cpp → rabitq_avx512_vpopcnt.cpp} +112 -23
- 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_impl/super_kmeans_dispatch.h +2 -7
- data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels.h +6 -1
- data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels_sve.cpp +34 -0
- data/vendor/faiss/faiss/utils/simd_levels.cpp +196 -47
- data/vendor/faiss/faiss/utils/simd_levels.h +33 -8
- data/vendor/faiss/faiss/utils/utils.cpp +9 -27
- metadata +21 -5
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512_spr.cpp +0 -15
|
@@ -8,9 +8,12 @@
|
|
|
8
8
|
#include <faiss/impl/RaBitQuantizer.h>
|
|
9
9
|
|
|
10
10
|
#include <faiss/impl/FaissAssert.h>
|
|
11
|
+
#include <faiss/impl/IDSelector.h>
|
|
11
12
|
#include <faiss/impl/RaBitQUtils.h>
|
|
12
13
|
#include <faiss/impl/RaBitQuantizerMultiBit.h>
|
|
14
|
+
#include <faiss/impl/ResultHandler.h>
|
|
13
15
|
#include <faiss/impl/simd_dispatch.h>
|
|
16
|
+
#include <faiss/invlists/DirectMap.h>
|
|
14
17
|
#include <faiss/utils/distances.h>
|
|
15
18
|
#include <faiss/utils/rabitq_simd.h>
|
|
16
19
|
|
|
@@ -22,6 +25,8 @@
|
|
|
22
25
|
|
|
23
26
|
namespace faiss {
|
|
24
27
|
|
|
28
|
+
RaBitQStats rabitq_stats;
|
|
29
|
+
|
|
25
30
|
// Import shared utilities from RaBitQUtils
|
|
26
31
|
using rabitq_utils::ExtraBitsFactors;
|
|
27
32
|
using rabitq_utils::QueryFactorsData;
|
|
@@ -183,8 +188,10 @@ void RaBitQuantizer::decode_core(
|
|
|
183
188
|
float* x,
|
|
184
189
|
size_t n,
|
|
185
190
|
const float* centroid_in) const {
|
|
186
|
-
|
|
187
|
-
|
|
191
|
+
FAISS_THROW_IF_MSG(
|
|
192
|
+
codes == nullptr, "RaBitQuantizer::decode_core: null codes buffer");
|
|
193
|
+
FAISS_THROW_IF_MSG(
|
|
194
|
+
x == nullptr, "RaBitQuantizer::decode_core: null output buffer");
|
|
188
195
|
|
|
189
196
|
const float inv_d_sqrt = (d == 0) ? 1.0f : (1.0f / std::sqrt((float)d));
|
|
190
197
|
const size_t ex_bits = nb_bits - 1;
|
|
@@ -220,6 +227,51 @@ void RaBitQuantizer::decode_core(
|
|
|
220
227
|
}
|
|
221
228
|
}
|
|
222
229
|
|
|
230
|
+
template <SIMDLevel SL>
|
|
231
|
+
float symmetric_dis_1bit(const RaBitQDistanceComputer& dc, idx_t i, idx_t j) {
|
|
232
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
233
|
+
dc.metric_type == MetricType::METRIC_L2,
|
|
234
|
+
"RaBitQ symmetric distance supports only L2");
|
|
235
|
+
FAISS_ASSERT(i >= 0 && j >= 0);
|
|
236
|
+
FAISS_ASSERT(dc.codes != nullptr);
|
|
237
|
+
|
|
238
|
+
const size_t sign_bytes = (dc.d + 7) / 8;
|
|
239
|
+
const uint8_t* code_i = dc.codes + static_cast<size_t>(i) * dc.code_size;
|
|
240
|
+
const uint8_t* code_j = dc.codes + static_cast<size_t>(j) * dc.code_size;
|
|
241
|
+
const auto* factors_i =
|
|
242
|
+
reinterpret_cast<const SignBitFactors*>(code_i + sign_bytes);
|
|
243
|
+
const auto* factors_j =
|
|
244
|
+
reinterpret_cast<const SignBitFactors*>(code_j + sign_bytes);
|
|
245
|
+
|
|
246
|
+
const uint64_t xor_popcount =
|
|
247
|
+
rabitq::bitwise_xor_dot_product<SL>(code_i, code_j, sign_bytes, 1);
|
|
248
|
+
const float sign_dot =
|
|
249
|
+
static_cast<float>(dc.d) - 2.0f * static_cast<float>(xor_popcount);
|
|
250
|
+
|
|
251
|
+
// The L2-optimal reconstruction of residual r is alpha * sign(r), where
|
|
252
|
+
// alpha = ||r||_1 / d. The stored factors give
|
|
253
|
+
// alpha_i * alpha_j = ||r_i||^2 * ||r_j||^2 /
|
|
254
|
+
// (d * dp_multiplier_i * dp_multiplier_j).
|
|
255
|
+
float cross_term = 0.0f;
|
|
256
|
+
if (factors_i->dp_multiplier != 0.0f && factors_j->dp_multiplier != 0.0f) {
|
|
257
|
+
// Dividing each norm first avoids overflowing the product of two
|
|
258
|
+
// squared norms even when the final distance is representable.
|
|
259
|
+
const float scaled_norm_i =
|
|
260
|
+
factors_i->or_minus_c_l2sqr / factors_i->dp_multiplier;
|
|
261
|
+
const float scaled_norm_j =
|
|
262
|
+
factors_j->or_minus_c_l2sqr / factors_j->dp_multiplier;
|
|
263
|
+
cross_term = (scaled_norm_i * (sign_dot / static_cast<float>(dc.d))) *
|
|
264
|
+
scaled_norm_j;
|
|
265
|
+
}
|
|
266
|
+
const float distance = factors_i->or_minus_c_l2sqr +
|
|
267
|
+
factors_j->or_minus_c_l2sqr - 2.0f * cross_term;
|
|
268
|
+
return std::max(0.0f, distance);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
float RaBitQDistanceComputer::symmetric_dis(idx_t i, idx_t j) {
|
|
272
|
+
return symmetric_dis_1bit<SIMDLevel::NONE>(*this, i, j);
|
|
273
|
+
}
|
|
274
|
+
|
|
223
275
|
namespace {
|
|
224
276
|
|
|
225
277
|
// Distance computers templatized on SIMDLevel to avoid per-call dynamic
|
|
@@ -228,7 +280,7 @@ namespace {
|
|
|
228
280
|
// directly to the SIMD-specialized code.
|
|
229
281
|
|
|
230
282
|
template <SIMDLevel SL>
|
|
231
|
-
struct RaBitQDistanceComputerNotQ : RaBitQDistanceComputer {
|
|
283
|
+
struct RaBitQDistanceComputerNotQ final : RaBitQDistanceComputer {
|
|
232
284
|
// the rotated query (qr - c)
|
|
233
285
|
std::vector<float> rotated_q;
|
|
234
286
|
// some additional numbers for the query
|
|
@@ -236,27 +288,14 @@ struct RaBitQDistanceComputerNotQ : RaBitQDistanceComputer {
|
|
|
236
288
|
|
|
237
289
|
RaBitQDistanceComputerNotQ() = default;
|
|
238
290
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
FAISS_ASSERT(
|
|
243
|
-
(metric_type == MetricType::METRIC_L2 ||
|
|
244
|
-
metric_type == MetricType::METRIC_INNER_PRODUCT));
|
|
245
|
-
FAISS_ASSERT(rotated_q.size() == d);
|
|
246
|
-
|
|
247
|
-
// split the code into parts
|
|
248
|
-
const uint8_t* binary_data = code;
|
|
249
|
-
|
|
250
|
-
// Cast to appropriate type based on nb_bits
|
|
251
|
-
// For 1-bit: use SignBitFactors (8 bytes)
|
|
252
|
-
// For multi-bit: use SignBitFactorsWithError (12 bytes) which includes
|
|
253
|
-
// f_error
|
|
254
|
-
size_t ex_bits = nb_bits - 1;
|
|
255
|
-
const SignBitFactors* base_fac = (ex_bits == 0)
|
|
256
|
-
? reinterpret_cast<const SignBitFactors*>(code + (d + 7) / 8)
|
|
257
|
-
: reinterpret_cast<const SignBitFactorsWithError*>(
|
|
258
|
-
code + (d + 7) / 8);
|
|
291
|
+
float symmetric_dis(idx_t i, idx_t j) final {
|
|
292
|
+
return symmetric_dis_1bit<SL>(*this, i, j);
|
|
293
|
+
}
|
|
259
294
|
|
|
295
|
+
// Compute distance using only 1-bit codes (fast)
|
|
296
|
+
float distance_to_code_1bit_impl(
|
|
297
|
+
const uint8_t* binary_data,
|
|
298
|
+
const SignBitFactors* base_fac) const {
|
|
260
299
|
// this is the baseline code
|
|
261
300
|
//
|
|
262
301
|
// compute <q,o> using floats
|
|
@@ -286,7 +325,7 @@ struct RaBitQDistanceComputerNotQ : RaBitQDistanceComputer {
|
|
|
286
325
|
|
|
287
326
|
if (metric_type == MetricType::METRIC_L2) {
|
|
288
327
|
// ||or - q||^ 2
|
|
289
|
-
return pre_dist;
|
|
328
|
+
return std::max(0.0f, pre_dist);
|
|
290
329
|
} else {
|
|
291
330
|
// metric == MetricType::METRIC_INNER_PRODUCT
|
|
292
331
|
// 2 * (or, q) = (||or - q||^2 - ||q||^2 - ||or||^2)
|
|
@@ -294,8 +333,24 @@ struct RaBitQDistanceComputerNotQ : RaBitQDistanceComputer {
|
|
|
294
333
|
}
|
|
295
334
|
}
|
|
296
335
|
|
|
336
|
+
float distance_to_code_1bit(const uint8_t* code) final {
|
|
337
|
+
FAISS_ASSERT(code != nullptr);
|
|
338
|
+
FAISS_ASSERT(
|
|
339
|
+
(metric_type == MetricType::METRIC_L2 ||
|
|
340
|
+
metric_type == MetricType::METRIC_INNER_PRODUCT));
|
|
341
|
+
FAISS_ASSERT(rotated_q.size() == d);
|
|
342
|
+
|
|
343
|
+
const size_t code_size_base = (d + 7) / 8;
|
|
344
|
+
const size_t ex_bits = nb_bits - 1;
|
|
345
|
+
const SignBitFactors* base_fac = (ex_bits == 0)
|
|
346
|
+
? reinterpret_cast<const SignBitFactors*>(code + code_size_base)
|
|
347
|
+
: reinterpret_cast<const SignBitFactorsWithError*>(
|
|
348
|
+
code + code_size_base);
|
|
349
|
+
return distance_to_code_1bit_impl(code, base_fac);
|
|
350
|
+
}
|
|
351
|
+
|
|
297
352
|
// Compute full distance using 1-bit + ex-bits (accurate)
|
|
298
|
-
float distance_to_code_full(const uint8_t* code)
|
|
353
|
+
float distance_to_code_full(const uint8_t* code) final {
|
|
299
354
|
FAISS_ASSERT(code != nullptr);
|
|
300
355
|
FAISS_ASSERT(
|
|
301
356
|
(metric_type == MetricType::METRIC_L2 ||
|
|
@@ -331,7 +386,7 @@ struct RaBitQDistanceComputerNotQ : RaBitQDistanceComputer {
|
|
|
331
386
|
metric_type);
|
|
332
387
|
}
|
|
333
388
|
|
|
334
|
-
void set_query(const float* x)
|
|
389
|
+
void set_query(const float* x) final {
|
|
335
390
|
q = x;
|
|
336
391
|
FAISS_ASSERT(x != nullptr);
|
|
337
392
|
FAISS_ASSERT(
|
|
@@ -372,10 +427,68 @@ struct RaBitQDistanceComputerNotQ : RaBitQDistanceComputer {
|
|
|
372
427
|
centroid ? fvec_inner_product(x, centroid, d) : 0.0f;
|
|
373
428
|
}
|
|
374
429
|
}
|
|
430
|
+
|
|
431
|
+
size_t scan_codes_multibit(
|
|
432
|
+
size_t list_size,
|
|
433
|
+
const uint8_t* codes,
|
|
434
|
+
const idx_t* ids,
|
|
435
|
+
size_t code_size,
|
|
436
|
+
idx_t list_no,
|
|
437
|
+
bool store_pairs,
|
|
438
|
+
const IDSelector* sel,
|
|
439
|
+
bool keep_max,
|
|
440
|
+
ResultHandler& handler) final {
|
|
441
|
+
const size_t code_size_base = (d + 7) / 8;
|
|
442
|
+
const size_t ex_bits = nb_bits - 1;
|
|
443
|
+
FAISS_ASSERT(ex_bits > 0);
|
|
444
|
+
|
|
445
|
+
// Honor IDSelectorWithContext on the multibit path too, so a RaBitQ
|
|
446
|
+
// index does not silently lose the context hook once nb_bits >= 2 (the
|
|
447
|
+
// 1-bit path already routes through run_scan_codes1).
|
|
448
|
+
const IDSelectorContextDispatch sel_dispatch(sel, store_pairs);
|
|
449
|
+
|
|
450
|
+
size_t nup = 0;
|
|
451
|
+
for (size_t j = 0; j < list_size; j++) {
|
|
452
|
+
if (sel != nullptr) {
|
|
453
|
+
idx_t id = store_pairs ? lo_build(list_no, j) : ids[j];
|
|
454
|
+
if (!sel_dispatch.is_member(
|
|
455
|
+
id, IDScanContext{ids, list_size, j})) {
|
|
456
|
+
codes += code_size;
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
const auto* base_fac =
|
|
462
|
+
reinterpret_cast<const SignBitFactorsWithError*>(
|
|
463
|
+
codes + code_size_base);
|
|
464
|
+
const float est_distance =
|
|
465
|
+
distance_to_code_1bit_impl(codes, base_fac);
|
|
466
|
+
|
|
467
|
+
const bool should_refine = rabitq_utils::should_refine_candidate(
|
|
468
|
+
est_distance,
|
|
469
|
+
base_fac->f_error,
|
|
470
|
+
g_error,
|
|
471
|
+
handler.threshold,
|
|
472
|
+
keep_max);
|
|
473
|
+
if (should_refine) {
|
|
474
|
+
handler.stats.scan_cnt++;
|
|
475
|
+
const float dis = distance_to_code_full(codes);
|
|
476
|
+
idx_t id = store_pairs ? lo_build(list_no, j) : ids[j];
|
|
477
|
+
|
|
478
|
+
if (handler.add_result(dis, id)) {
|
|
479
|
+
handler.stats.nheap_updates++;
|
|
480
|
+
nup++;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
codes += code_size;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
return nup;
|
|
487
|
+
}
|
|
375
488
|
};
|
|
376
489
|
|
|
377
490
|
template <SIMDLevel SL>
|
|
378
|
-
struct RaBitQDistanceComputerQ : RaBitQDistanceComputer {
|
|
491
|
+
struct RaBitQDistanceComputerQ final : RaBitQDistanceComputer {
|
|
379
492
|
// the rotated and quantized query (qr - c)
|
|
380
493
|
std::vector<float> rotated_q;
|
|
381
494
|
// the rotated and quantized query (qr - c) for fast 1-bit computation
|
|
@@ -394,26 +507,15 @@ struct RaBitQDistanceComputerQ : RaBitQDistanceComputer {
|
|
|
394
507
|
|
|
395
508
|
RaBitQDistanceComputerQ() = default;
|
|
396
509
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
FAISS_ASSERT(
|
|
401
|
-
(metric_type == MetricType::METRIC_L2 ||
|
|
402
|
-
metric_type == MetricType::METRIC_INNER_PRODUCT));
|
|
403
|
-
|
|
404
|
-
// split the code into parts
|
|
405
|
-
size_t size = (d + 7) / 8;
|
|
406
|
-
const uint8_t* binary_data = code;
|
|
407
|
-
|
|
408
|
-
// Cast to appropriate type based on nb_bits
|
|
409
|
-
// For 1-bit: use SignBitFactors (8 bytes)
|
|
410
|
-
// For multi-bit: use SignBitFactorsWithError (12 bytes) which
|
|
411
|
-
// includes f_error
|
|
412
|
-
size_t ex_bits = nb_bits - 1;
|
|
413
|
-
const SignBitFactors* base_fac = (ex_bits == 0)
|
|
414
|
-
? reinterpret_cast<const SignBitFactors*>(code + size)
|
|
415
|
-
: reinterpret_cast<const SignBitFactorsWithError*>(code + size);
|
|
510
|
+
float symmetric_dis(idx_t i, idx_t j) final {
|
|
511
|
+
return symmetric_dis_1bit<SL>(*this, i, j);
|
|
512
|
+
}
|
|
416
513
|
|
|
514
|
+
// Compute distance using only 1-bit codes (fast)
|
|
515
|
+
float distance_to_code_1bit_impl(
|
|
516
|
+
const uint8_t* binary_data,
|
|
517
|
+
const SignBitFactors* base_fac,
|
|
518
|
+
size_t size) const {
|
|
417
519
|
// this is ||or - c||^2 - (IP ? ||or||^2 : 0)
|
|
418
520
|
float final_dot = 0;
|
|
419
521
|
if (centered) {
|
|
@@ -428,17 +530,16 @@ struct RaBitQDistanceComputerQ : RaBitQDistanceComputer {
|
|
|
428
530
|
qb);
|
|
429
531
|
final_dot += int_dot * query_fac.int_dot_scale;
|
|
430
532
|
} else {
|
|
431
|
-
auto
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
auto sum_q = rabitq::popcount<SL>(binary_data, size);
|
|
533
|
+
auto bitwise_result =
|
|
534
|
+
rabitq::bitwise_and_dot_product_with_popcount<SL>(
|
|
535
|
+
rearranged_rotated_qq.data(),
|
|
536
|
+
binary_data,
|
|
537
|
+
size,
|
|
538
|
+
qb);
|
|
438
539
|
// dot-product itself
|
|
439
|
-
final_dot += query_fac.c1 *
|
|
540
|
+
final_dot += query_fac.c1 * bitwise_result.dot_product;
|
|
440
541
|
// normalizer coefficients
|
|
441
|
-
final_dot += query_fac.c2 *
|
|
542
|
+
final_dot += query_fac.c2 * bitwise_result.popcount;
|
|
442
543
|
// normalizer coefficients
|
|
443
544
|
final_dot -= query_fac.c34;
|
|
444
545
|
}
|
|
@@ -449,7 +550,7 @@ struct RaBitQDistanceComputerQ : RaBitQDistanceComputer {
|
|
|
449
550
|
|
|
450
551
|
if (metric_type == MetricType::METRIC_L2) {
|
|
451
552
|
// ||or - q||^ 2
|
|
452
|
-
return pre_dist;
|
|
553
|
+
return std::max(0.0f, pre_dist);
|
|
453
554
|
} else {
|
|
454
555
|
// metric == MetricType::METRIC_INNER_PRODUCT
|
|
455
556
|
// 2 * (or, q) = (||or - q||^2 - ||q||^2 - ||or||^2)
|
|
@@ -457,8 +558,22 @@ struct RaBitQDistanceComputerQ : RaBitQDistanceComputer {
|
|
|
457
558
|
}
|
|
458
559
|
}
|
|
459
560
|
|
|
561
|
+
float distance_to_code_1bit(const uint8_t* code) final {
|
|
562
|
+
FAISS_ASSERT(code != nullptr);
|
|
563
|
+
FAISS_ASSERT(
|
|
564
|
+
(metric_type == MetricType::METRIC_L2 ||
|
|
565
|
+
metric_type == MetricType::METRIC_INNER_PRODUCT));
|
|
566
|
+
|
|
567
|
+
const size_t size = (d + 7) / 8;
|
|
568
|
+
const size_t ex_bits = nb_bits - 1;
|
|
569
|
+
const SignBitFactors* base_fac = (ex_bits == 0)
|
|
570
|
+
? reinterpret_cast<const SignBitFactors*>(code + size)
|
|
571
|
+
: reinterpret_cast<const SignBitFactorsWithError*>(code + size);
|
|
572
|
+
return distance_to_code_1bit_impl(code, base_fac, size);
|
|
573
|
+
}
|
|
574
|
+
|
|
460
575
|
// Compute full distance using 1-bit + ex-bits (accurate)
|
|
461
|
-
float distance_to_code_full(const uint8_t* code)
|
|
576
|
+
float distance_to_code_full(const uint8_t* code) final {
|
|
462
577
|
FAISS_ASSERT(code != nullptr);
|
|
463
578
|
FAISS_ASSERT(
|
|
464
579
|
(metric_type == MetricType::METRIC_L2 ||
|
|
@@ -494,7 +609,7 @@ struct RaBitQDistanceComputerQ : RaBitQDistanceComputer {
|
|
|
494
609
|
metric_type);
|
|
495
610
|
}
|
|
496
611
|
|
|
497
|
-
void set_query(const float* x)
|
|
612
|
+
void set_query(const float* x) final {
|
|
498
613
|
q = x;
|
|
499
614
|
FAISS_ASSERT(x != nullptr);
|
|
500
615
|
FAISS_ASSERT(
|
|
@@ -526,16 +641,70 @@ struct RaBitQDistanceComputerQ : RaBitQDistanceComputer {
|
|
|
526
641
|
size_t offset = (d + 7) / 8;
|
|
527
642
|
|
|
528
643
|
rearranged_rotated_qq.resize(offset * qb);
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
644
|
+
with_selected_simd_levels<
|
|
645
|
+
AVAILABLE_SIMD_LEVELS_NONE | (1 << int(SIMDLevel::AVX2)) |
|
|
646
|
+
(1 << int(SIMDLevel::AVX512))>([&]<SIMDLevel RSL>() {
|
|
647
|
+
rabitq::rearrange_bit_planes<RSL>(
|
|
648
|
+
rotated_qq.data(), d, qb, rearranged_rotated_qq.data());
|
|
649
|
+
});
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
size_t scan_codes_multibit(
|
|
653
|
+
size_t list_size,
|
|
654
|
+
const uint8_t* codes,
|
|
655
|
+
const idx_t* ids,
|
|
656
|
+
size_t code_size,
|
|
657
|
+
idx_t list_no,
|
|
658
|
+
bool store_pairs,
|
|
659
|
+
const IDSelector* sel,
|
|
660
|
+
bool keep_max,
|
|
661
|
+
ResultHandler& handler) final {
|
|
662
|
+
const size_t code_size_base = (d + 7) / 8;
|
|
663
|
+
const size_t ex_bits = nb_bits - 1;
|
|
664
|
+
FAISS_ASSERT(ex_bits > 0);
|
|
665
|
+
|
|
666
|
+
// Honor IDSelectorWithContext on the multibit path too, so a RaBitQ
|
|
667
|
+
// index does not silently lose the context hook once nb_bits >= 2 (the
|
|
668
|
+
// 1-bit path already routes through run_scan_codes1).
|
|
669
|
+
const IDSelectorContextDispatch sel_dispatch(sel, store_pairs);
|
|
670
|
+
|
|
671
|
+
size_t nup = 0;
|
|
672
|
+
for (size_t j = 0; j < list_size; j++) {
|
|
673
|
+
if (sel != nullptr) {
|
|
674
|
+
idx_t id = store_pairs ? lo_build(list_no, j) : ids[j];
|
|
675
|
+
if (!sel_dispatch.is_member(
|
|
676
|
+
id, IDScanContext{ids, list_size, j})) {
|
|
677
|
+
codes += code_size;
|
|
678
|
+
continue;
|
|
679
|
+
}
|
|
537
680
|
}
|
|
681
|
+
|
|
682
|
+
const auto* base_fac =
|
|
683
|
+
reinterpret_cast<const SignBitFactorsWithError*>(
|
|
684
|
+
codes + code_size_base);
|
|
685
|
+
const float est_distance =
|
|
686
|
+
distance_to_code_1bit_impl(codes, base_fac, code_size_base);
|
|
687
|
+
|
|
688
|
+
const bool should_refine = rabitq_utils::should_refine_candidate(
|
|
689
|
+
est_distance,
|
|
690
|
+
base_fac->f_error,
|
|
691
|
+
g_error,
|
|
692
|
+
handler.threshold,
|
|
693
|
+
keep_max);
|
|
694
|
+
if (should_refine) {
|
|
695
|
+
handler.stats.scan_cnt++;
|
|
696
|
+
const float dis = distance_to_code_full(codes);
|
|
697
|
+
idx_t id = store_pairs ? lo_build(list_no, j) : ids[j];
|
|
698
|
+
|
|
699
|
+
if (handler.add_result(dis, id)) {
|
|
700
|
+
handler.stats.nheap_updates++;
|
|
701
|
+
nup++;
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
codes += code_size;
|
|
538
705
|
}
|
|
706
|
+
|
|
707
|
+
return nup;
|
|
539
708
|
}
|
|
540
709
|
};
|
|
541
710
|
|
|
@@ -552,12 +721,10 @@ FlatCodesDistanceComputer* RaBitQuantizer::get_distance_computer(
|
|
|
552
721
|
// call the SIMD-specialized rabitq functions directly (no per-call
|
|
553
722
|
// with_simd_level overhead).
|
|
554
723
|
//
|
|
555
|
-
//
|
|
556
|
-
//
|
|
557
|
-
//
|
|
558
|
-
|
|
559
|
-
// specialization in rabitq_avx512.cpp.
|
|
560
|
-
return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_A0_SPR>(
|
|
724
|
+
// VPOPCNT rather than SPR: Ice Lake and Zen 4 have VPOPCNTDQ without the
|
|
725
|
+
// rest of the SPR feature set. Below it, dispatch falls through to
|
|
726
|
+
// rabitq_avx512.cpp.
|
|
727
|
+
return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_VPOPCNT>(
|
|
561
728
|
[&]<SIMDLevel SL>() -> FlatCodesDistanceComputer* {
|
|
562
729
|
if (qb == 0) {
|
|
563
730
|
auto dc =
|
|
@@ -13,9 +13,40 @@
|
|
|
13
13
|
#include <faiss/MetricType.h>
|
|
14
14
|
#include <faiss/impl/DistanceComputer.h>
|
|
15
15
|
#include <faiss/impl/Quantizer.h>
|
|
16
|
+
#include <faiss/impl/RaBitQUtils.h>
|
|
17
|
+
#include <faiss/impl/platform_macros.h>
|
|
16
18
|
|
|
17
19
|
namespace faiss {
|
|
18
20
|
|
|
21
|
+
struct IDSelector;
|
|
22
|
+
template <typename T, typename TI>
|
|
23
|
+
struct ResultHandlerUnordered;
|
|
24
|
+
|
|
25
|
+
/** Statistics for staged RaBitQ distance evaluation.
|
|
26
|
+
*
|
|
27
|
+
* These counters belong to the quantizer rather than to a particular ANN
|
|
28
|
+
* graph. They are currently populated by HNSW's staged search path.
|
|
29
|
+
*/
|
|
30
|
+
struct RaBitQStats {
|
|
31
|
+
uint64_t n_1bit = 0;
|
|
32
|
+
uint64_t n_refine = 0;
|
|
33
|
+
|
|
34
|
+
void reset() {
|
|
35
|
+
n_1bit = n_refine = 0;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
void add(const RaBitQStats& other) {
|
|
39
|
+
n_1bit += other.n_1bit;
|
|
40
|
+
n_refine += other.n_refine;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
double refine_ratio() const {
|
|
44
|
+
return n_1bit ? double(n_refine) / double(n_1bit) : 0.0;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
FAISS_API extern RaBitQStats rabitq_stats;
|
|
49
|
+
|
|
19
50
|
// the reference implementation of the https://arxiv.org/pdf/2405.12497
|
|
20
51
|
// Jianyang Gao, Cheng Long, "RaBitQ: Quantizing High-Dimensional Vectors
|
|
21
52
|
// with a Theoretical Error Bound for Approximate Nearest Neighbor Search".
|
|
@@ -118,10 +149,10 @@ struct RaBitQDistanceComputer : FlatCodesDistanceComputer {
|
|
|
118
149
|
// Used with f_error to compute error bounds for two-stage filtering
|
|
119
150
|
float g_error = 0.0f;
|
|
120
151
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
152
|
+
/// Per-distance-computer counters, aggregated by the owning index.
|
|
153
|
+
RaBitQStats stats;
|
|
154
|
+
|
|
155
|
+
float symmetric_dis(idx_t i, idx_t j) override;
|
|
125
156
|
|
|
126
157
|
// Compute 1-bit distance estimate (fast)
|
|
127
158
|
virtual float distance_to_code_1bit(const uint8_t* code) = 0;
|
|
@@ -129,6 +160,37 @@ struct RaBitQDistanceComputer : FlatCodesDistanceComputer {
|
|
|
129
160
|
// Compute full multi-bit distance (accurate)
|
|
130
161
|
virtual float distance_to_code_full(const uint8_t* code) = 0;
|
|
131
162
|
|
|
163
|
+
/// Apply the RaBitQ error bound without exposing the packed code layout to
|
|
164
|
+
/// ANN consumers. Precondition: nb_bits >= 2.
|
|
165
|
+
#ifndef SWIG
|
|
166
|
+
FAISS_ALWAYS_INLINE bool should_refine(
|
|
167
|
+
const uint8_t* code,
|
|
168
|
+
float estimate,
|
|
169
|
+
float threshold,
|
|
170
|
+
bool is_similarity) const {
|
|
171
|
+
const auto* factors =
|
|
172
|
+
reinterpret_cast<const rabitq_utils::SignBitFactorsWithError*>(
|
|
173
|
+
code + (d + 7) / 8);
|
|
174
|
+
return rabitq_utils::should_refine_candidate(
|
|
175
|
+
estimate, factors->f_error, g_error, threshold, is_similarity);
|
|
176
|
+
}
|
|
177
|
+
#endif
|
|
178
|
+
|
|
179
|
+
virtual void set_centroid(const float* centroid_in) {
|
|
180
|
+
centroid = centroid_in;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
virtual size_t scan_codes_multibit(
|
|
184
|
+
size_t list_size,
|
|
185
|
+
const uint8_t* codes,
|
|
186
|
+
const idx_t* ids,
|
|
187
|
+
size_t code_size,
|
|
188
|
+
idx_t list_no,
|
|
189
|
+
bool store_pairs,
|
|
190
|
+
const IDSelector* sel,
|
|
191
|
+
bool keep_max,
|
|
192
|
+
ResultHandlerUnordered<float, idx_t>& handler) = 0;
|
|
193
|
+
|
|
132
194
|
// Override from FlatCodesDistanceComputer
|
|
133
195
|
// Delegates to distance_to_code_full() for multi-bit distance computation
|
|
134
196
|
float distance_to_code(const uint8_t* code) final {
|
|
@@ -257,8 +257,8 @@ void quantize_ex_bits(
|
|
|
257
257
|
const size_t ex_bits = nb_bits - 1;
|
|
258
258
|
FAISS_THROW_IF_NOT_MSG(
|
|
259
259
|
ex_bits >= 1 && ex_bits <= 8, "ex_bits must be in range [1, 8]");
|
|
260
|
-
|
|
261
|
-
|
|
260
|
+
FAISS_THROW_IF_MSG(residual == nullptr, "residual cannot be null");
|
|
261
|
+
FAISS_THROW_IF_MSG(ex_code == nullptr, "ex_code cannot be null");
|
|
262
262
|
|
|
263
263
|
// Step 1: Compute L2 norm of residual
|
|
264
264
|
float norm_sqr = fvec_norm_L2sqr(residual, d);
|
|
@@ -302,9 +302,9 @@ void quantize_ex_bits(
|
|
|
302
302
|
}
|
|
303
303
|
|
|
304
304
|
// Step 6: Handle negative dimensions (flip bits)
|
|
305
|
-
// For negative residuals, flip all bits: code' = ~code & max_code
|
|
305
|
+
// For negative or zero residuals, flip all bits: code' = ~code & max_code
|
|
306
306
|
for (size_t i = 0; i < d; i++) {
|
|
307
|
-
if (residual[i]
|
|
307
|
+
if (residual[i] <= 0) {
|
|
308
308
|
tmp_code[i] = (~tmp_code[i]) & max_code;
|
|
309
309
|
}
|
|
310
310
|
}
|
|
@@ -312,15 +312,6 @@ void quantize_ex_bits(
|
|
|
312
312
|
// Step 7: Pack codes into byte array
|
|
313
313
|
pack_multibit_codes(tmp_code.data(), ex_code, d, nb_bits);
|
|
314
314
|
|
|
315
|
-
// Step 8: Compute factors for distance computation
|
|
316
|
-
// Reconstruct total_code for factor computation
|
|
317
|
-
std::vector<int> total_code(d);
|
|
318
|
-
for (size_t i = 0; i < d; i++) {
|
|
319
|
-
// Form total_code = (sign << ex_bits) + ex_code
|
|
320
|
-
bool sign_bit = (residual[i] >= 0);
|
|
321
|
-
total_code[i] = tmp_code[i] + ((sign_bit ? 1 : 0) << ex_bits);
|
|
322
|
-
}
|
|
323
|
-
|
|
324
315
|
// Compute ex-factors; centroid is needed for IP metric correction
|
|
325
316
|
compute_ex_factors(
|
|
326
317
|
residual,
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
#include <faiss/impl/InvertedListScannerStats.h>
|
|
19
19
|
#include <faiss/utils/Heap.h>
|
|
20
20
|
#include <faiss/utils/partitioning.h>
|
|
21
|
+
#include <faiss/utils/simd_levels.h>
|
|
21
22
|
#include <algorithm>
|
|
22
23
|
#include <iostream>
|
|
23
24
|
|
|
@@ -122,14 +123,20 @@ struct SingleQueryBlockResultHandler : BlockResultHandler<C, use_sel> {
|
|
|
122
123
|
using ResultHandlerT<C>::threshold;
|
|
123
124
|
|
|
124
125
|
explicit SingleResultHandler(SingleQueryBlockResultHandler& hr)
|
|
125
|
-
: the_handler(hr.the_handler) {
|
|
126
|
+
: the_handler(hr.the_handler) {
|
|
127
|
+
threshold = the_handler.threshold;
|
|
128
|
+
}
|
|
126
129
|
|
|
127
130
|
/// begin results for query # i
|
|
128
|
-
void begin(const size_t /* qid */) {
|
|
131
|
+
void begin(const size_t /* qid */) {
|
|
132
|
+
threshold = the_handler.threshold;
|
|
133
|
+
}
|
|
129
134
|
|
|
130
135
|
/// add one result for query i
|
|
131
136
|
bool add_result(T dis, TI idx) final {
|
|
132
|
-
|
|
137
|
+
bool updated = the_handler.add_result(dis, idx);
|
|
138
|
+
threshold = the_handler.threshold;
|
|
139
|
+
return updated;
|
|
133
140
|
}
|
|
134
141
|
|
|
135
142
|
/// series of results for query i is done
|
|
@@ -234,23 +241,9 @@ struct Top1BlockResultHandler : TopkBlockResultHandler<C, use_sel> {
|
|
|
234
241
|
}
|
|
235
242
|
|
|
236
243
|
/// add results for query i0..i1 and j0..j1
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
auto& min_distance = this->dis_tab[i];
|
|
242
|
-
auto& min_index = this->ids_tab[i];
|
|
243
|
-
|
|
244
|
-
for (size_t j = j0; j < j1; j++) {
|
|
245
|
-
const T distance = dis_tab_i[j];
|
|
246
|
-
|
|
247
|
-
if (C::cmp(min_distance, distance)) {
|
|
248
|
-
min_distance = distance;
|
|
249
|
-
min_index = j;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
}
|
|
244
|
+
/// Implemented in result_handler.cpp; dispatches via
|
|
245
|
+
/// with_selected_simd_levels to top1_add_results_tpl<C, use_sel, SL>.
|
|
246
|
+
void add_results(size_t j0, size_t j1, const T* dis_tab_2) final;
|
|
254
247
|
|
|
255
248
|
void add_result(const size_t i, const T dis, const TI idx) {
|
|
256
249
|
auto& min_distance = this->dis_tab[i];
|
|
@@ -553,20 +546,9 @@ struct ReservoirBlockResultHandler : TopkBlockResultHandler<C, use_sel> {
|
|
|
553
546
|
}
|
|
554
547
|
|
|
555
548
|
/// add results for query i0..i1 and j0..j1
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
i++) {
|
|
560
|
-
ReservoirTopN<C>& reservoir =
|
|
561
|
-
reservoirs[i - static_cast<int64_t>(i0)];
|
|
562
|
-
const T* dis_tab_i =
|
|
563
|
-
dis_in + (j1 - j0) * (i - static_cast<int64_t>(i0)) - j0;
|
|
564
|
-
for (size_t j = j0; j < j1; j++) {
|
|
565
|
-
T dis = dis_tab_i[j];
|
|
566
|
-
reservoir.add_result(dis, j);
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
}
|
|
549
|
+
/// Implemented in result_handler.cpp; dispatches via
|
|
550
|
+
/// with_selected_simd_levels to reservoir_add_results_tpl<C, use_sel, SL>.
|
|
551
|
+
void add_results(size_t j0, size_t j1, const T* dis_in);
|
|
570
552
|
|
|
571
553
|
/// series of results for queries i0..i1 is done
|
|
572
554
|
void end_multiple() final {
|
|
@@ -799,4 +781,22 @@ typename Consumer::T dispatch_range_ResultHandler(
|
|
|
799
781
|
#undef DISPATCH_C_SEL
|
|
800
782
|
}
|
|
801
783
|
|
|
784
|
+
// ------------------------------------------------------------------
|
|
785
|
+
// SIMD-dispatch entry points for Top1 and Reservoir add_results.
|
|
786
|
+
// ------------------------------------------------------------------
|
|
787
|
+
|
|
788
|
+
template <class C, bool use_sel, SIMDLevel SL>
|
|
789
|
+
void top1_add_results_tpl(
|
|
790
|
+
Top1BlockResultHandler<C, use_sel>* self,
|
|
791
|
+
size_t j0,
|
|
792
|
+
size_t j1,
|
|
793
|
+
const typename C::T* dis_tab);
|
|
794
|
+
|
|
795
|
+
template <class C, bool use_sel, SIMDLevel SL>
|
|
796
|
+
void reservoir_add_results_tpl(
|
|
797
|
+
ReservoirBlockResultHandler<C, use_sel>* self,
|
|
798
|
+
size_t j0,
|
|
799
|
+
size_t j1,
|
|
800
|
+
const typename C::T* dis_in);
|
|
801
|
+
|
|
802
802
|
} // namespace faiss
|