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
|
@@ -13,12 +13,15 @@
|
|
|
13
13
|
#include <cstdio>
|
|
14
14
|
#include <cstring>
|
|
15
15
|
#include <memory>
|
|
16
|
+
#include <type_traits>
|
|
16
17
|
|
|
17
18
|
#include <algorithm>
|
|
18
19
|
|
|
19
20
|
#include <faiss/IndexFlat.h>
|
|
20
21
|
#include <faiss/VectorTransform.h>
|
|
21
22
|
#include <faiss/impl/FaissAssert.h>
|
|
23
|
+
// NOLINTNEXTLINE(facebook-hte-InlineHeader)
|
|
24
|
+
#include <faiss/impl/pq_code_distance/pq_code_distance-inl.h>
|
|
22
25
|
#include <faiss/impl/simd_dispatch.h>
|
|
23
26
|
#include <faiss/utils/distances.h>
|
|
24
27
|
|
|
@@ -719,8 +722,28 @@ void pq_knn_search_with_tables(
|
|
|
719
722
|
|
|
720
723
|
switch (nbits) {
|
|
721
724
|
case 8:
|
|
722
|
-
|
|
723
|
-
|
|
725
|
+
if (ksub == 256) {
|
|
726
|
+
constexpr bool max_heap =
|
|
727
|
+
std::is_same_v<C, CMax<float, int64_t>>;
|
|
728
|
+
pq_code_distance::pq_scan_8bit(
|
|
729
|
+
M,
|
|
730
|
+
dis_table,
|
|
731
|
+
codes,
|
|
732
|
+
ncodes,
|
|
733
|
+
k,
|
|
734
|
+
heap_dis,
|
|
735
|
+
heap_ids,
|
|
736
|
+
max_heap);
|
|
737
|
+
} else {
|
|
738
|
+
pq_estimators_from_tables<uint8_t, C>(
|
|
739
|
+
pq,
|
|
740
|
+
codes,
|
|
741
|
+
ncodes,
|
|
742
|
+
dis_table,
|
|
743
|
+
k,
|
|
744
|
+
heap_dis,
|
|
745
|
+
heap_ids);
|
|
746
|
+
}
|
|
724
747
|
break;
|
|
725
748
|
|
|
726
749
|
case 16:
|
|
@@ -839,32 +862,44 @@ void ProductQuantizer::search_sdc(
|
|
|
839
862
|
size_t k = res->k;
|
|
840
863
|
int64_t nq_signed = nq;
|
|
841
864
|
|
|
842
|
-
#pragma omp parallel
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
865
|
+
#pragma omp parallel
|
|
866
|
+
{
|
|
867
|
+
// One allocation per OMP thread instead of one per query.
|
|
868
|
+
std::vector<const float*> q_row(M);
|
|
869
|
+
#pragma omp for
|
|
870
|
+
for (int64_t i = 0; i < nq_signed; i++) {
|
|
871
|
+
idx_t* heap_ids = res->ids + i * k;
|
|
872
|
+
float* heap_dis = res->val + i * k;
|
|
873
|
+
const uint8_t* qcode = qcodes + i * code_size;
|
|
874
|
+
|
|
875
|
+
if (init_finalize_heap)
|
|
876
|
+
maxheap_heapify(k, heap_dis, heap_ids);
|
|
877
|
+
|
|
878
|
+
// Precompute per-subquantizer row pointers: q_row[m] points to
|
|
879
|
+
// sdc_table[m*ksub^2 + qcode[m]*ksub], eliminating M
|
|
880
|
+
// multiplications and M pointer advances per database vector in the
|
|
881
|
+
// j-loop.
|
|
882
|
+
const float* sdc = sdc_table.data();
|
|
856
883
|
for (size_t m = 0; m < M; m++) {
|
|
857
|
-
|
|
858
|
-
|
|
884
|
+
q_row[m] = sdc + m * (size_t)(ksub * ksub) +
|
|
885
|
+
(size_t)qcode[m] * ksub;
|
|
859
886
|
}
|
|
860
|
-
|
|
861
|
-
|
|
887
|
+
|
|
888
|
+
const uint8_t* bcode = bcodes;
|
|
889
|
+
for (size_t j = 0; j < nb; j++) {
|
|
890
|
+
float dis = 0;
|
|
891
|
+
for (size_t m = 0; m < M; m++) {
|
|
892
|
+
dis += q_row[m][bcode[m]];
|
|
893
|
+
}
|
|
894
|
+
if (dis < heap_dis[0]) {
|
|
895
|
+
maxheap_replace_top(k, heap_dis, heap_ids, dis, j);
|
|
896
|
+
}
|
|
897
|
+
bcode += code_size;
|
|
862
898
|
}
|
|
863
|
-
bcode += code_size;
|
|
864
|
-
}
|
|
865
899
|
|
|
866
|
-
|
|
867
|
-
|
|
900
|
+
if (init_finalize_heap)
|
|
901
|
+
maxheap_reorder(k, heap_dis, heap_ids);
|
|
902
|
+
}
|
|
868
903
|
}
|
|
869
904
|
}
|
|
870
905
|
|
|
@@ -188,46 +188,54 @@ QueryFactorsData compute_query_factors(
|
|
|
188
188
|
|
|
189
189
|
const float inv_d_sqrt = 1.0f / std::sqrt(static_cast<float>(d));
|
|
190
190
|
|
|
191
|
-
// Compute quantization range
|
|
192
|
-
float v_min = std::numeric_limits<float>::max();
|
|
193
|
-
float v_max = std::numeric_limits<float>::lowest();
|
|
194
|
-
|
|
195
191
|
const float* rq = rotated_q.data();
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
v_min = -v_radius;
|
|
200
|
-
v_max = v_radius;
|
|
201
|
-
} else {
|
|
202
|
-
for (size_t i = 0; i < d; i++) {
|
|
203
|
-
const float v_q = rq[i];
|
|
204
|
-
v_min = std::min(v_min, v_q);
|
|
205
|
-
v_max = std::max(v_max, v_q);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// Quantize the query
|
|
210
|
-
const uint8_t max_code = (1 << qb) - 1;
|
|
211
|
-
const float delta = (v_max - v_min) / max_code;
|
|
212
|
-
const float inv_delta = 1.0f / delta;
|
|
213
|
-
|
|
214
|
-
rotated_qq.resize(d);
|
|
192
|
+
float v_min;
|
|
193
|
+
float v_max;
|
|
194
|
+
float delta;
|
|
215
195
|
size_t sum_qq = 0;
|
|
216
196
|
int64_t sum2_signed_odd_int = 0;
|
|
217
|
-
|
|
197
|
+
const uint8_t max_code = (1 << qb) - 1;
|
|
198
|
+
rotated_qq.resize(d);
|
|
218
199
|
uint8_t* rqq = rotated_qq.data();
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
200
|
+
|
|
201
|
+
// Select the SIMD implementation once for both range computation and
|
|
202
|
+
// quantization. This function runs once per query/probe pair.
|
|
203
|
+
with_selected_simd_levels<rabitq::RABITQ_QUANTIZATION_SIMD_LEVELS>(
|
|
204
|
+
[&]<SIMDLevel SL>() {
|
|
205
|
+
if (centered) {
|
|
206
|
+
const float z_max = Z_MAX_BY_QB[qb - 1];
|
|
207
|
+
const float v_radius =
|
|
208
|
+
z_max * std::sqrt(query_factors.qr_to_c_L2sqr / d);
|
|
209
|
+
v_min = -v_radius;
|
|
210
|
+
v_max = v_radius;
|
|
211
|
+
} else {
|
|
212
|
+
v_min = std::numeric_limits<float>::max();
|
|
213
|
+
v_max = std::numeric_limits<float>::lowest();
|
|
214
|
+
rabitq::minmax_values<SL>(rq, d, v_min, v_max);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
delta = (v_max - v_min) / max_code;
|
|
218
|
+
// A constant (or zero-norm) query has delta == 0. Preserve the
|
|
219
|
+
// scalar path's centered correction terms while avoiding
|
|
220
|
+
// 0 * inf during quantization.
|
|
221
|
+
if (delta <= 0.0f) {
|
|
222
|
+
memset(rqq, 0, d * sizeof(uint8_t));
|
|
223
|
+
if (centered) {
|
|
224
|
+
sum2_signed_odd_int = int64_t(d) * max_code * max_code;
|
|
225
|
+
}
|
|
226
|
+
} else {
|
|
227
|
+
rabitq::quantize_query_values<SL>(
|
|
228
|
+
rq,
|
|
229
|
+
d,
|
|
230
|
+
v_min,
|
|
231
|
+
1.0f / delta,
|
|
232
|
+
max_code,
|
|
233
|
+
centered,
|
|
234
|
+
rqq,
|
|
235
|
+
sum_qq,
|
|
236
|
+
sum2_signed_odd_int);
|
|
237
|
+
}
|
|
238
|
+
});
|
|
231
239
|
|
|
232
240
|
// Compute query factors
|
|
233
241
|
query_factors.c1 = 2 * delta * inv_d_sqrt;
|
|
@@ -321,7 +329,7 @@ float compute_full_multibit_distance(
|
|
|
321
329
|
size_t d,
|
|
322
330
|
size_t ex_bits,
|
|
323
331
|
MetricType metric_type) {
|
|
324
|
-
return with_selected_simd_levels<
|
|
332
|
+
return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_A0_SPR>(
|
|
325
333
|
[&]<SIMDLevel SL>() {
|
|
326
334
|
return compute_full_multibit_distance<SL>(
|
|
327
335
|
sign_bits,
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
#include <faiss/utils/rabitq_simd.h>
|
|
14
14
|
#include <faiss/utils/simd_levels.h>
|
|
15
15
|
#include <algorithm>
|
|
16
|
+
#include <cassert>
|
|
16
17
|
#include <cstddef>
|
|
17
18
|
#include <cstdint>
|
|
18
19
|
#include <cstring>
|
|
@@ -86,6 +87,40 @@ struct QueryFactorsData {
|
|
|
86
87
|
*/
|
|
87
88
|
FAISS_API extern const float Z_MAX_BY_QB[8];
|
|
88
89
|
|
|
90
|
+
/** Fast half-away rounding for non-negative RaBitQ quantization values.
|
|
91
|
+
*
|
|
92
|
+
* Contract: x must be finite, non-NaN, and in [0, 255.5). This is not a
|
|
93
|
+
* bit-exact replacement for roundf within a few ulps below k + 0.5, where the
|
|
94
|
+
* addition may round across the tie. It is intended only for RaBitQ LUT
|
|
95
|
+
* quantization paths where a +/- 1 code difference at those boundaries is
|
|
96
|
+
* acceptable.
|
|
97
|
+
*/
|
|
98
|
+
inline uint8_t round_nonnegative_to_uint8(float x) {
|
|
99
|
+
assert(x == x);
|
|
100
|
+
assert(x >= 0.0f);
|
|
101
|
+
assert(x < 255.5f);
|
|
102
|
+
return rabitq::round_nonnegative_byte_scalar(x);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Same as round_nonnegative_to_uint8 for uint16 RaBitQ bias values. */
|
|
106
|
+
inline uint16_t round_nonnegative_to_uint16(float x) {
|
|
107
|
+
assert(x == x);
|
|
108
|
+
assert(x >= 0.0f);
|
|
109
|
+
assert(x < 65535.5f);
|
|
110
|
+
return static_cast<uint16_t>(static_cast<int>(x + 0.5f));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Fast clamped rounding for query-byte quantization.
|
|
114
|
+
*
|
|
115
|
+
* Contract: x must be non-NaN. Values outside [0, max_code] are clamped before
|
|
116
|
+
* applying the same non-bit-exact rounding used by
|
|
117
|
+
* round_nonnegative_to_uint8().
|
|
118
|
+
*/
|
|
119
|
+
inline uint8_t round_clamped_to_uint8(float x, uint8_t max_code) {
|
|
120
|
+
assert(x == x);
|
|
121
|
+
return rabitq::round_clamped_byte_scalar(x, max_code);
|
|
122
|
+
}
|
|
123
|
+
|
|
89
124
|
/** Compute factors for a single database vector using RaBitQ algorithm.
|
|
90
125
|
* This function consolidates the mathematical logic that was duplicated
|
|
91
126
|
* between IndexRaBitQ and IndexRaBitQFastScan.
|
|
@@ -8,13 +8,15 @@
|
|
|
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
|
|
|
17
|
-
#include <algorithm>
|
|
18
20
|
#include <cmath>
|
|
19
21
|
#include <cstring>
|
|
20
22
|
#include <memory>
|
|
@@ -183,8 +185,10 @@ void RaBitQuantizer::decode_core(
|
|
|
183
185
|
float* x,
|
|
184
186
|
size_t n,
|
|
185
187
|
const float* centroid_in) const {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
+
FAISS_THROW_IF_MSG(
|
|
189
|
+
codes == nullptr, "RaBitQuantizer::decode_core: null codes buffer");
|
|
190
|
+
FAISS_THROW_IF_MSG(
|
|
191
|
+
x == nullptr, "RaBitQuantizer::decode_core: null output buffer");
|
|
188
192
|
|
|
189
193
|
const float inv_d_sqrt = (d == 0) ? 1.0f : (1.0f / std::sqrt((float)d));
|
|
190
194
|
const size_t ex_bits = nb_bits - 1;
|
|
@@ -228,7 +232,7 @@ namespace {
|
|
|
228
232
|
// directly to the SIMD-specialized code.
|
|
229
233
|
|
|
230
234
|
template <SIMDLevel SL>
|
|
231
|
-
struct RaBitQDistanceComputerNotQ : RaBitQDistanceComputer {
|
|
235
|
+
struct RaBitQDistanceComputerNotQ final : RaBitQDistanceComputer {
|
|
232
236
|
// the rotated query (qr - c)
|
|
233
237
|
std::vector<float> rotated_q;
|
|
234
238
|
// some additional numbers for the query
|
|
@@ -237,26 +241,9 @@ struct RaBitQDistanceComputerNotQ : RaBitQDistanceComputer {
|
|
|
237
241
|
RaBitQDistanceComputerNotQ() = default;
|
|
238
242
|
|
|
239
243
|
// Compute distance using only 1-bit codes (fast)
|
|
240
|
-
float
|
|
241
|
-
|
|
242
|
-
|
|
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);
|
|
259
|
-
|
|
244
|
+
float distance_to_code_1bit_impl(
|
|
245
|
+
const uint8_t* binary_data,
|
|
246
|
+
const SignBitFactors* base_fac) const {
|
|
260
247
|
// this is the baseline code
|
|
261
248
|
//
|
|
262
249
|
// compute <q,o> using floats
|
|
@@ -286,7 +273,7 @@ struct RaBitQDistanceComputerNotQ : RaBitQDistanceComputer {
|
|
|
286
273
|
|
|
287
274
|
if (metric_type == MetricType::METRIC_L2) {
|
|
288
275
|
// ||or - q||^ 2
|
|
289
|
-
return pre_dist;
|
|
276
|
+
return std::max(0.0f, pre_dist);
|
|
290
277
|
} else {
|
|
291
278
|
// metric == MetricType::METRIC_INNER_PRODUCT
|
|
292
279
|
// 2 * (or, q) = (||or - q||^2 - ||q||^2 - ||or||^2)
|
|
@@ -294,8 +281,24 @@ struct RaBitQDistanceComputerNotQ : RaBitQDistanceComputer {
|
|
|
294
281
|
}
|
|
295
282
|
}
|
|
296
283
|
|
|
284
|
+
float distance_to_code_1bit(const uint8_t* code) final {
|
|
285
|
+
FAISS_ASSERT(code != nullptr);
|
|
286
|
+
FAISS_ASSERT(
|
|
287
|
+
(metric_type == MetricType::METRIC_L2 ||
|
|
288
|
+
metric_type == MetricType::METRIC_INNER_PRODUCT));
|
|
289
|
+
FAISS_ASSERT(rotated_q.size() == d);
|
|
290
|
+
|
|
291
|
+
const size_t code_size_base = (d + 7) / 8;
|
|
292
|
+
const size_t ex_bits = nb_bits - 1;
|
|
293
|
+
const SignBitFactors* base_fac = (ex_bits == 0)
|
|
294
|
+
? reinterpret_cast<const SignBitFactors*>(code + code_size_base)
|
|
295
|
+
: reinterpret_cast<const SignBitFactorsWithError*>(
|
|
296
|
+
code + code_size_base);
|
|
297
|
+
return distance_to_code_1bit_impl(code, base_fac);
|
|
298
|
+
}
|
|
299
|
+
|
|
297
300
|
// Compute full distance using 1-bit + ex-bits (accurate)
|
|
298
|
-
float distance_to_code_full(const uint8_t* code)
|
|
301
|
+
float distance_to_code_full(const uint8_t* code) final {
|
|
299
302
|
FAISS_ASSERT(code != nullptr);
|
|
300
303
|
FAISS_ASSERT(
|
|
301
304
|
(metric_type == MetricType::METRIC_L2 ||
|
|
@@ -331,7 +334,7 @@ struct RaBitQDistanceComputerNotQ : RaBitQDistanceComputer {
|
|
|
331
334
|
metric_type);
|
|
332
335
|
}
|
|
333
336
|
|
|
334
|
-
void set_query(const float* x)
|
|
337
|
+
void set_query(const float* x) final {
|
|
335
338
|
q = x;
|
|
336
339
|
FAISS_ASSERT(x != nullptr);
|
|
337
340
|
FAISS_ASSERT(
|
|
@@ -372,10 +375,62 @@ struct RaBitQDistanceComputerNotQ : RaBitQDistanceComputer {
|
|
|
372
375
|
centroid ? fvec_inner_product(x, centroid, d) : 0.0f;
|
|
373
376
|
}
|
|
374
377
|
}
|
|
378
|
+
|
|
379
|
+
size_t scan_codes_multibit(
|
|
380
|
+
size_t list_size,
|
|
381
|
+
const uint8_t* codes,
|
|
382
|
+
const idx_t* ids,
|
|
383
|
+
size_t code_size,
|
|
384
|
+
idx_t list_no,
|
|
385
|
+
bool store_pairs,
|
|
386
|
+
const IDSelector* sel,
|
|
387
|
+
bool keep_max,
|
|
388
|
+
ResultHandler& handler) final {
|
|
389
|
+
const size_t code_size_base = (d + 7) / 8;
|
|
390
|
+
const size_t ex_bits = nb_bits - 1;
|
|
391
|
+
FAISS_ASSERT(ex_bits > 0);
|
|
392
|
+
|
|
393
|
+
size_t nup = 0;
|
|
394
|
+
for (size_t j = 0; j < list_size; j++) {
|
|
395
|
+
if (sel != nullptr) {
|
|
396
|
+
idx_t id = store_pairs ? lo_build(list_no, j) : ids[j];
|
|
397
|
+
if (!sel->is_member(id)) {
|
|
398
|
+
codes += code_size;
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
const auto* base_fac =
|
|
404
|
+
reinterpret_cast<const SignBitFactorsWithError*>(
|
|
405
|
+
codes + code_size_base);
|
|
406
|
+
const float est_distance =
|
|
407
|
+
distance_to_code_1bit_impl(codes, base_fac);
|
|
408
|
+
|
|
409
|
+
const bool should_refine = rabitq_utils::should_refine_candidate(
|
|
410
|
+
est_distance,
|
|
411
|
+
base_fac->f_error,
|
|
412
|
+
g_error,
|
|
413
|
+
handler.threshold,
|
|
414
|
+
keep_max);
|
|
415
|
+
if (should_refine) {
|
|
416
|
+
handler.stats.scan_cnt++;
|
|
417
|
+
const float dis = distance_to_code_full(codes);
|
|
418
|
+
idx_t id = store_pairs ? lo_build(list_no, j) : ids[j];
|
|
419
|
+
|
|
420
|
+
if (handler.add_result(dis, id)) {
|
|
421
|
+
handler.stats.nheap_updates++;
|
|
422
|
+
nup++;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
codes += code_size;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
return nup;
|
|
429
|
+
}
|
|
375
430
|
};
|
|
376
431
|
|
|
377
432
|
template <SIMDLevel SL>
|
|
378
|
-
struct RaBitQDistanceComputerQ : RaBitQDistanceComputer {
|
|
433
|
+
struct RaBitQDistanceComputerQ final : RaBitQDistanceComputer {
|
|
379
434
|
// the rotated and quantized query (qr - c)
|
|
380
435
|
std::vector<float> rotated_q;
|
|
381
436
|
// the rotated and quantized query (qr - c) for fast 1-bit computation
|
|
@@ -395,25 +450,10 @@ struct RaBitQDistanceComputerQ : RaBitQDistanceComputer {
|
|
|
395
450
|
RaBitQDistanceComputerQ() = default;
|
|
396
451
|
|
|
397
452
|
// Compute distance using only 1-bit codes (fast)
|
|
398
|
-
float
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
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);
|
|
416
|
-
|
|
453
|
+
float distance_to_code_1bit_impl(
|
|
454
|
+
const uint8_t* binary_data,
|
|
455
|
+
const SignBitFactors* base_fac,
|
|
456
|
+
size_t size) const {
|
|
417
457
|
// this is ||or - c||^2 - (IP ? ||or||^2 : 0)
|
|
418
458
|
float final_dot = 0;
|
|
419
459
|
if (centered) {
|
|
@@ -428,17 +468,16 @@ struct RaBitQDistanceComputerQ : RaBitQDistanceComputer {
|
|
|
428
468
|
qb);
|
|
429
469
|
final_dot += int_dot * query_fac.int_dot_scale;
|
|
430
470
|
} else {
|
|
431
|
-
auto
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
auto sum_q = rabitq::popcount<SL>(binary_data, size);
|
|
471
|
+
auto bitwise_result =
|
|
472
|
+
rabitq::bitwise_and_dot_product_with_popcount<SL>(
|
|
473
|
+
rearranged_rotated_qq.data(),
|
|
474
|
+
binary_data,
|
|
475
|
+
size,
|
|
476
|
+
qb);
|
|
438
477
|
// dot-product itself
|
|
439
|
-
final_dot += query_fac.c1 *
|
|
478
|
+
final_dot += query_fac.c1 * bitwise_result.dot_product;
|
|
440
479
|
// normalizer coefficients
|
|
441
|
-
final_dot += query_fac.c2 *
|
|
480
|
+
final_dot += query_fac.c2 * bitwise_result.popcount;
|
|
442
481
|
// normalizer coefficients
|
|
443
482
|
final_dot -= query_fac.c34;
|
|
444
483
|
}
|
|
@@ -449,7 +488,7 @@ struct RaBitQDistanceComputerQ : RaBitQDistanceComputer {
|
|
|
449
488
|
|
|
450
489
|
if (metric_type == MetricType::METRIC_L2) {
|
|
451
490
|
// ||or - q||^ 2
|
|
452
|
-
return pre_dist;
|
|
491
|
+
return std::max(0.0f, pre_dist);
|
|
453
492
|
} else {
|
|
454
493
|
// metric == MetricType::METRIC_INNER_PRODUCT
|
|
455
494
|
// 2 * (or, q) = (||or - q||^2 - ||q||^2 - ||or||^2)
|
|
@@ -457,8 +496,22 @@ struct RaBitQDistanceComputerQ : RaBitQDistanceComputer {
|
|
|
457
496
|
}
|
|
458
497
|
}
|
|
459
498
|
|
|
499
|
+
float distance_to_code_1bit(const uint8_t* code) final {
|
|
500
|
+
FAISS_ASSERT(code != nullptr);
|
|
501
|
+
FAISS_ASSERT(
|
|
502
|
+
(metric_type == MetricType::METRIC_L2 ||
|
|
503
|
+
metric_type == MetricType::METRIC_INNER_PRODUCT));
|
|
504
|
+
|
|
505
|
+
const size_t size = (d + 7) / 8;
|
|
506
|
+
const size_t ex_bits = nb_bits - 1;
|
|
507
|
+
const SignBitFactors* base_fac = (ex_bits == 0)
|
|
508
|
+
? reinterpret_cast<const SignBitFactors*>(code + size)
|
|
509
|
+
: reinterpret_cast<const SignBitFactorsWithError*>(code + size);
|
|
510
|
+
return distance_to_code_1bit_impl(code, base_fac, size);
|
|
511
|
+
}
|
|
512
|
+
|
|
460
513
|
// Compute full distance using 1-bit + ex-bits (accurate)
|
|
461
|
-
float distance_to_code_full(const uint8_t* code)
|
|
514
|
+
float distance_to_code_full(const uint8_t* code) final {
|
|
462
515
|
FAISS_ASSERT(code != nullptr);
|
|
463
516
|
FAISS_ASSERT(
|
|
464
517
|
(metric_type == MetricType::METRIC_L2 ||
|
|
@@ -494,7 +547,7 @@ struct RaBitQDistanceComputerQ : RaBitQDistanceComputer {
|
|
|
494
547
|
metric_type);
|
|
495
548
|
}
|
|
496
549
|
|
|
497
|
-
void set_query(const float* x)
|
|
550
|
+
void set_query(const float* x) final {
|
|
498
551
|
q = x;
|
|
499
552
|
FAISS_ASSERT(x != nullptr);
|
|
500
553
|
FAISS_ASSERT(
|
|
@@ -526,16 +579,64 @@ struct RaBitQDistanceComputerQ : RaBitQDistanceComputer {
|
|
|
526
579
|
size_t offset = (d + 7) / 8;
|
|
527
580
|
|
|
528
581
|
rearranged_rotated_qq.resize(offset * qb);
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
582
|
+
with_selected_simd_levels<
|
|
583
|
+
AVAILABLE_SIMD_LEVELS_NONE | (1 << int(SIMDLevel::AVX2)) |
|
|
584
|
+
(1 << int(SIMDLevel::AVX512))>([&]<SIMDLevel RSL>() {
|
|
585
|
+
rabitq::rearrange_bit_planes<RSL>(
|
|
586
|
+
rotated_qq.data(), d, qb, rearranged_rotated_qq.data());
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
size_t scan_codes_multibit(
|
|
591
|
+
size_t list_size,
|
|
592
|
+
const uint8_t* codes,
|
|
593
|
+
const idx_t* ids,
|
|
594
|
+
size_t code_size,
|
|
595
|
+
idx_t list_no,
|
|
596
|
+
bool store_pairs,
|
|
597
|
+
const IDSelector* sel,
|
|
598
|
+
bool keep_max,
|
|
599
|
+
ResultHandler& handler) final {
|
|
600
|
+
const size_t code_size_base = (d + 7) / 8;
|
|
601
|
+
const size_t ex_bits = nb_bits - 1;
|
|
602
|
+
FAISS_ASSERT(ex_bits > 0);
|
|
603
|
+
|
|
604
|
+
size_t nup = 0;
|
|
605
|
+
for (size_t j = 0; j < list_size; j++) {
|
|
606
|
+
if (sel != nullptr) {
|
|
607
|
+
idx_t id = store_pairs ? lo_build(list_no, j) : ids[j];
|
|
608
|
+
if (!sel->is_member(id)) {
|
|
609
|
+
codes += code_size;
|
|
610
|
+
continue;
|
|
611
|
+
}
|
|
537
612
|
}
|
|
613
|
+
|
|
614
|
+
const auto* base_fac =
|
|
615
|
+
reinterpret_cast<const SignBitFactorsWithError*>(
|
|
616
|
+
codes + code_size_base);
|
|
617
|
+
const float est_distance =
|
|
618
|
+
distance_to_code_1bit_impl(codes, base_fac, code_size_base);
|
|
619
|
+
|
|
620
|
+
const bool should_refine = rabitq_utils::should_refine_candidate(
|
|
621
|
+
est_distance,
|
|
622
|
+
base_fac->f_error,
|
|
623
|
+
g_error,
|
|
624
|
+
handler.threshold,
|
|
625
|
+
keep_max);
|
|
626
|
+
if (should_refine) {
|
|
627
|
+
handler.stats.scan_cnt++;
|
|
628
|
+
const float dis = distance_to_code_full(codes);
|
|
629
|
+
idx_t id = store_pairs ? lo_build(list_no, j) : ids[j];
|
|
630
|
+
|
|
631
|
+
if (handler.add_result(dis, id)) {
|
|
632
|
+
handler.stats.nheap_updates++;
|
|
633
|
+
nup++;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
codes += code_size;
|
|
538
637
|
}
|
|
638
|
+
|
|
639
|
+
return nup;
|
|
539
640
|
}
|
|
540
641
|
};
|
|
541
642
|
|
|
@@ -551,7 +652,13 @@ FlatCodesDistanceComputer* RaBitQuantizer::get_distance_computer(
|
|
|
551
652
|
// Dispatch on SIMDLevel once here so the distance computer methods
|
|
552
653
|
// call the SIMD-specialized rabitq functions directly (no per-call
|
|
553
654
|
// with_simd_level overhead).
|
|
554
|
-
|
|
655
|
+
//
|
|
656
|
+
// Use A0_SPR (which includes AVX512_SPR) so that on Sapphire Rapids
|
|
657
|
+
// and later x86 microarchitectures the VPOPCNTDQ-based RaBitQ
|
|
658
|
+
// specialization in rabitq_avx512_spr.cpp is selected. On AVX-512
|
|
659
|
+
// CPUs without VPOPCNTDQ, dispatch falls through to the AVX512
|
|
660
|
+
// specialization in rabitq_avx512.cpp.
|
|
661
|
+
return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_A0_SPR>(
|
|
555
662
|
[&]<SIMDLevel SL>() -> FlatCodesDistanceComputer* {
|
|
556
663
|
if (qb == 0) {
|
|
557
664
|
auto dc =
|
|
@@ -16,6 +16,10 @@
|
|
|
16
16
|
|
|
17
17
|
namespace faiss {
|
|
18
18
|
|
|
19
|
+
struct IDSelector;
|
|
20
|
+
template <typename T, typename TI>
|
|
21
|
+
struct ResultHandlerUnordered;
|
|
22
|
+
|
|
19
23
|
// the reference implementation of the https://arxiv.org/pdf/2405.12497
|
|
20
24
|
// Jianyang Gao, Cheng Long, "RaBitQ: Quantizing High-Dimensional Vectors
|
|
21
25
|
// with a Theoretical Error Bound for Approximate Nearest Neighbor Search".
|
|
@@ -129,6 +133,21 @@ struct RaBitQDistanceComputer : FlatCodesDistanceComputer {
|
|
|
129
133
|
// Compute full multi-bit distance (accurate)
|
|
130
134
|
virtual float distance_to_code_full(const uint8_t* code) = 0;
|
|
131
135
|
|
|
136
|
+
virtual void set_centroid(const float* centroid_in) {
|
|
137
|
+
centroid = centroid_in;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
virtual size_t scan_codes_multibit(
|
|
141
|
+
size_t list_size,
|
|
142
|
+
const uint8_t* codes,
|
|
143
|
+
const idx_t* ids,
|
|
144
|
+
size_t code_size,
|
|
145
|
+
idx_t list_no,
|
|
146
|
+
bool store_pairs,
|
|
147
|
+
const IDSelector* sel,
|
|
148
|
+
bool keep_max,
|
|
149
|
+
ResultHandlerUnordered<float, idx_t>& handler) = 0;
|
|
150
|
+
|
|
132
151
|
// Override from FlatCodesDistanceComputer
|
|
133
152
|
// Delegates to distance_to_code_full() for multi-bit distance computation
|
|
134
153
|
float distance_to_code(const uint8_t* code) final {
|