faiss 0.6.3 → 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 +4 -0
- data/lib/faiss/version.rb +1 -1
- data/vendor/faiss/faiss/Clustering.h +8 -0
- data/vendor/faiss/faiss/Index.h +1 -1
- data/vendor/faiss/faiss/IndexBinaryFromFloat.cpp +23 -2
- data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +12 -140
- data/vendor/faiss/faiss/IndexBinaryHNSW.h +0 -6
- data/vendor/faiss/faiss/IndexBinaryIVF.cpp +6 -14
- data/vendor/faiss/faiss/IndexBinaryIVF.h +8 -1
- data/vendor/faiss/faiss/IndexFlat.cpp +8 -4
- data/vendor/faiss/faiss/IndexFlat.h +2 -2
- data/vendor/faiss/faiss/IndexHNSW.cpp +301 -91
- data/vendor/faiss/faiss/IndexHNSW.h +31 -7
- data/vendor/faiss/faiss/IndexIDMap.cpp +11 -6
- data/vendor/faiss/faiss/IndexIVF.cpp +19 -4
- data/vendor/faiss/faiss/IndexIVFPQ.cpp +9 -1
- data/vendor/faiss/faiss/IndexIVFPQ.h +11 -0
- data/vendor/faiss/faiss/IndexShards.cpp +3 -3
- data/vendor/faiss/faiss/IndexShardsIVF.cpp +4 -3
- data/vendor/faiss/faiss/SuperKMeans.cpp +31 -8
- data/vendor/faiss/faiss/SuperKMeans.h +3 -2
- data/vendor/faiss/faiss/VectorTransform.cpp +38 -0
- data/vendor/faiss/faiss/VectorTransform.h +3 -0
- data/vendor/faiss/faiss/clone_index.cpp +3 -0
- 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 +4 -5
- data/vendor/faiss/faiss/gpu/GpuIndexCagra.h +65 -42
- data/vendor/faiss/faiss/impl/AdditiveQuantizer.cpp +1 -1
- data/vendor/faiss/faiss/impl/ClusteringInitialization.cpp +5 -2
- data/vendor/faiss/faiss/impl/HNSW.cpp +419 -115
- data/vendor/faiss/faiss/impl/HNSW.h +46 -7
- data/vendor/faiss/faiss/impl/IDSelector.h +44 -0
- data/vendor/faiss/faiss/impl/NNDescent.cpp +10 -3
- data/vendor/faiss/faiss/impl/Panorama.h +11 -2
- data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +4 -4
- data/vendor/faiss/faiss/impl/RaBitQUtils.cpp +1 -1
- data/vendor/faiss/faiss/impl/RaBitQuantizer.cpp +74 -8
- data/vendor/faiss/faiss/impl/RaBitQuantizer.h +47 -4
- data/vendor/faiss/faiss/impl/RaBitQuantizerMultiBit.cpp +2 -2
- data/vendor/faiss/faiss/impl/ResultHandler.h +9 -3
- data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +32 -30
- data/vendor/faiss/faiss/impl/ScalarQuantizer.h +6 -10
- data/vendor/faiss/faiss/impl/binary_hamming/IndexBinaryIVF_impl.h +89 -13
- 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/index_read.cpp +130 -29
- data/vendor/faiss/faiss/impl/index_write.cpp +31 -26
- data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQScanner_impl.h +73 -39
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-generic.cpp +4 -4
- data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer.cpp +6 -1
- data/vendor/faiss/faiss/impl/scalar_quantizer/distance_computers.h +2 -2
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx2.cpp +6 -2
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-dispatch.h +37 -17
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-neon.cpp +109 -10
- data/vendor/faiss/faiss/impl/simd_dispatch.h +40 -22
- data/vendor/faiss/faiss/index_factory.cpp +8 -1
- data/vendor/faiss/faiss/invlists/InvertedLists.cpp +7 -4
- data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +10 -4
- data/vendor/faiss/faiss/svs/IndexSVSVamana.cpp +16 -4
- data/vendor/faiss/faiss/svs/IndexSVSVamana.h +8 -1
- 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 +9 -2
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.h +2 -1
- data/vendor/faiss/faiss/utils/distances.cpp +20 -13
- 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/hamming.cpp +15 -9
- 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/simd_impl/distances_arm_sve.cpp +194 -30
- data/vendor/faiss/faiss/utils/simd_impl/distances_rvv.cpp +93 -55
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512.cpp +57 -40
- data/vendor/faiss/faiss/utils/simd_impl/{rabitq_avx512_spr.cpp → rabitq_avx512_vpopcnt.cpp} +21 -24
- 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 +172 -67
- data/vendor/faiss/faiss/utils/simd_levels.h +26 -15
- metadata +6 -5
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512_spr.cpp +0 -15
|
@@ -385,7 +385,7 @@ IndexIVF* parse_IndexIVF(
|
|
|
385
385
|
}
|
|
386
386
|
if (match("FlatPanorama([0-9]+)?(_([0-9]+))?")) {
|
|
387
387
|
int nlevels = mres_to_int(sm[1], 8); // default to 8 levels
|
|
388
|
-
int bs = mres_to_int(sm[3],
|
|
388
|
+
int bs = mres_to_int(sm[3], Panorama::kDefaultBatchSize);
|
|
389
389
|
return new IndexIVFFlatPanorama(
|
|
390
390
|
get_q(), d, nlist, nlevels, mt, own_il, bs);
|
|
391
391
|
}
|
|
@@ -575,6 +575,13 @@ IndexHNSW* parse_IndexHNSW(
|
|
|
575
575
|
if (match(sq_pattern)) {
|
|
576
576
|
return new IndexHNSWSQ(d, sq_types[sm[1].str()], hnsw_M, mt);
|
|
577
577
|
}
|
|
578
|
+
// Keep the bare RaBitQ token consistent with Flat and IVF: it means 1 bit.
|
|
579
|
+
// Use an explicit width such as RaBitQ4 to enable staged refinement.
|
|
580
|
+
if (match("RaBitQ([1-9])?")) {
|
|
581
|
+
// the capture is the bare digit, so no substr offset here
|
|
582
|
+
int nb_bits = mres_to_int(sm[1], 1);
|
|
583
|
+
return new IndexHNSWRaBitQ(d, hnsw_M, nb_bits, mt);
|
|
584
|
+
}
|
|
578
585
|
if (match("([0-9]+)\\+PQ([0-9]+)?")) {
|
|
579
586
|
int ncent = mres_to_int(sm[1]);
|
|
580
587
|
int pq_m = mres_to_int(sm[2]);
|
|
@@ -440,8 +440,11 @@ void ArrayInvertedListsPanorama::resize(size_t list_no, size_t new_size) {
|
|
|
440
440
|
const uint8_t* ArrayInvertedListsPanorama::get_single_code(
|
|
441
441
|
size_t list_no,
|
|
442
442
|
size_t offset) const {
|
|
443
|
-
assert
|
|
444
|
-
|
|
443
|
+
// Throw rather than assert: Panorama::reconstruct takes an unsized
|
|
444
|
+
// pointer, so these are the only bounds available and they must hold
|
|
445
|
+
// in opt builds too.
|
|
446
|
+
FAISS_THROW_IF_NOT(list_no < nlist);
|
|
447
|
+
FAISS_THROW_IF_NOT(offset < ids[list_no].size());
|
|
445
448
|
|
|
446
449
|
uint8_t* recons_buffer = new uint8_t[code_size];
|
|
447
450
|
|
|
@@ -669,10 +672,10 @@ namespace {
|
|
|
669
672
|
int translate_list_no(const VStackInvertedLists* vil, idx_t list_no) {
|
|
670
673
|
FAISS_THROW_IF_NOT(
|
|
671
674
|
list_no >= 0 && static_cast<size_t>(list_no) < vil->nlist);
|
|
672
|
-
|
|
675
|
+
size_t i0 = 0, i1 = vil->ils.size();
|
|
673
676
|
const idx_t* cumsz = vil->cumsz.data();
|
|
674
677
|
while (i0 + 1 < i1) {
|
|
675
|
-
|
|
678
|
+
size_t imed = i0 + (i1 - i0) / 2;
|
|
676
679
|
if (list_no >= cumsz[imed]) {
|
|
677
680
|
i0 = imed;
|
|
678
681
|
} else {
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
#include <pthread.h>
|
|
13
13
|
|
|
14
|
+
#include <memory>
|
|
14
15
|
#include <unordered_set>
|
|
15
16
|
|
|
16
17
|
#include <sys/mman.h>
|
|
@@ -714,12 +715,17 @@ void OnDiskInvertedListsIOHook::write(const InvertedLists* ils, IOWriter* f)
|
|
|
714
715
|
|
|
715
716
|
InvertedLists* OnDiskInvertedListsIOHook::read(IOReader* f, int io_flags)
|
|
716
717
|
const {
|
|
717
|
-
|
|
718
|
+
auto od = std::make_unique<OnDiskInvertedLists>();
|
|
718
719
|
od->read_only = io_flags & IO_FLAG_READ_ONLY;
|
|
719
720
|
READ1(od->nlist);
|
|
720
721
|
READ1(od->code_size);
|
|
721
722
|
// this is a POD object
|
|
722
723
|
READVECTOR(od->lists);
|
|
724
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
725
|
+
od->lists.size() == od->nlist,
|
|
726
|
+
"OnDisk inverted lists: read %zu lists for nlist %zu",
|
|
727
|
+
od->lists.size(),
|
|
728
|
+
od->nlist);
|
|
723
729
|
{
|
|
724
730
|
std::vector<OnDiskInvertedLists::Slot> v;
|
|
725
731
|
READVECTOR(v);
|
|
@@ -759,7 +765,7 @@ InvertedLists* OnDiskInvertedListsIOHook::read(IOReader* f, int io_flags)
|
|
|
759
765
|
if (!(io_flags & IO_FLAG_SKIP_IVF_DATA)) {
|
|
760
766
|
od->do_mmap();
|
|
761
767
|
}
|
|
762
|
-
return od;
|
|
768
|
+
return od.release();
|
|
763
769
|
}
|
|
764
770
|
|
|
765
771
|
/** read from a ArrayInvertedLists into this invertedlist type */
|
|
@@ -769,7 +775,7 @@ InvertedLists* OnDiskInvertedListsIOHook::read_ArrayInvertedLists(
|
|
|
769
775
|
size_t nlist,
|
|
770
776
|
size_t code_size,
|
|
771
777
|
const std::vector<size_t>& sizes) const {
|
|
772
|
-
auto ails =
|
|
778
|
+
auto ails = std::make_unique<OnDiskInvertedLists>();
|
|
773
779
|
ails->nlist = nlist;
|
|
774
780
|
ails->code_size = code_size;
|
|
775
781
|
ails->read_only = true;
|
|
@@ -819,7 +825,7 @@ InvertedLists* OnDiskInvertedListsIOHook::read_ArrayInvertedLists(
|
|
|
819
825
|
// resume normal reading of file
|
|
820
826
|
fseek(fdesc, o, SEEK_SET);
|
|
821
827
|
|
|
822
|
-
return ails;
|
|
828
|
+
return ails.release();
|
|
823
829
|
}
|
|
824
830
|
|
|
825
831
|
} // namespace faiss
|
|
@@ -67,11 +67,13 @@ IndexSVSVamana::IndexSVSVamana(
|
|
|
67
67
|
size_t degree,
|
|
68
68
|
MetricType metric,
|
|
69
69
|
SVSStorageKind storage,
|
|
70
|
-
bool is_static
|
|
70
|
+
bool is_static,
|
|
71
|
+
bool store_vectors)
|
|
71
72
|
: Index(d, metric),
|
|
72
73
|
graph_max_degree{degree},
|
|
73
74
|
is_static{is_static},
|
|
74
|
-
storage_kind{storage}
|
|
75
|
+
storage_kind{storage},
|
|
76
|
+
store_vectors{store_vectors} {
|
|
75
77
|
prune_to = graph_max_degree < 4 ? graph_max_degree : graph_max_degree - 4;
|
|
76
78
|
alpha = metric == METRIC_L2 ? 1.2f : 0.95f;
|
|
77
79
|
|
|
@@ -124,6 +126,14 @@ IndexSVSVamana::~IndexSVSVamana() {
|
|
|
124
126
|
}
|
|
125
127
|
|
|
126
128
|
void IndexSVSVamana::add(idx_t n, const float* x) {
|
|
129
|
+
// Opting out after data has been added would leave stored_vectors
|
|
130
|
+
// misaligned with the ids in the index, so release it instead of growing.
|
|
131
|
+
if (!store_vectors && stored_vectors_valid) {
|
|
132
|
+
stored_vectors.clear();
|
|
133
|
+
stored_vectors.shrink_to_fit();
|
|
134
|
+
stored_vectors_valid = false;
|
|
135
|
+
}
|
|
136
|
+
|
|
127
137
|
if (is_static) {
|
|
128
138
|
FAISS_THROW_IF_MSG(
|
|
129
139
|
impl,
|
|
@@ -167,7 +177,8 @@ void IndexSVSVamana::reconstruct(idx_t key, float* recons) const {
|
|
|
167
177
|
FAISS_THROW_IF_NOT_MSG(
|
|
168
178
|
stored_vectors_valid && !stored_vectors.empty(),
|
|
169
179
|
"IndexSVSVamana::reconstruct: stored_vectors unavailable "
|
|
170
|
-
"(invalidated by remove_ids or not
|
|
180
|
+
"(store_vectors disabled, invalidated by remove_ids, or not "
|
|
181
|
+
"restored after deserialization)");
|
|
171
182
|
std::memcpy(recons, stored_vectors.data() + key * d, sizeof(float) * d);
|
|
172
183
|
}
|
|
173
184
|
|
|
@@ -187,7 +198,8 @@ void IndexSVSVamana::reset() {
|
|
|
187
198
|
}
|
|
188
199
|
}
|
|
189
200
|
stored_vectors.clear();
|
|
190
|
-
|
|
201
|
+
stored_vectors.shrink_to_fit();
|
|
202
|
+
stored_vectors_valid = store_vectors;
|
|
191
203
|
mmap_owner.reset(); // Release the memory mapping
|
|
192
204
|
is_trained = false;
|
|
193
205
|
ntotal = 0;
|
|
@@ -111,7 +111,8 @@ struct IndexSVSVamana : Index {
|
|
|
111
111
|
size_t degree,
|
|
112
112
|
MetricType metric = METRIC_L2,
|
|
113
113
|
SVSStorageKind storage = SVSStorageKind::SVS_FP32,
|
|
114
|
-
bool is_static = false
|
|
114
|
+
bool is_static = false,
|
|
115
|
+
bool store_vectors = true);
|
|
115
116
|
|
|
116
117
|
~IndexSVSVamana() override;
|
|
117
118
|
|
|
@@ -164,6 +165,12 @@ struct IndexSVSVamana : Index {
|
|
|
164
165
|
std::vector<float> stored_vectors;
|
|
165
166
|
bool stored_vectors_valid{true};
|
|
166
167
|
|
|
168
|
+
// Set to false before the first add() to skip the stored_vectors copy,
|
|
169
|
+
// saving ntotal * d * 4 bytes at the cost of reconstruct() support and
|
|
170
|
+
// hence of use as an IVF coarse quantizer. Clearing it after vectors have
|
|
171
|
+
// been added drops the copy, which can no longer be aligned with the ids.
|
|
172
|
+
bool store_vectors{true};
|
|
173
|
+
|
|
167
174
|
protected:
|
|
168
175
|
/* Initializes the implementation. For static indexes the data is consumed
|
|
169
176
|
at build time; for dynamic indexes n/x are ignored and add() populates
|
|
@@ -34,7 +34,9 @@ IndexSVSVamanaLVQ::IndexSVSVamanaLVQ(
|
|
|
34
34
|
size_t degree,
|
|
35
35
|
MetricType metric,
|
|
36
36
|
SVSStorageKind storage,
|
|
37
|
-
bool is_static
|
|
38
|
-
|
|
37
|
+
bool is_static,
|
|
38
|
+
bool store_vectors)
|
|
39
|
+
: IndexSVSVamana(d, degree, metric, storage, is_static, store_vectors) {
|
|
40
|
+
}
|
|
39
41
|
|
|
40
42
|
} // namespace faiss
|
|
@@ -35,7 +35,8 @@ struct IndexSVSVamanaLVQ : IndexSVSVamana {
|
|
|
35
35
|
size_t degree,
|
|
36
36
|
MetricType metric = METRIC_L2,
|
|
37
37
|
SVSStorageKind storage = SVSStorageKind::SVS_LVQ4x0,
|
|
38
|
-
bool is_static = false
|
|
38
|
+
bool is_static = false,
|
|
39
|
+
bool store_vectors = true);
|
|
39
40
|
|
|
40
41
|
~IndexSVSVamanaLVQ() override = default;
|
|
41
42
|
};
|
|
@@ -44,8 +44,15 @@ IndexSVSVamanaLeanVec::IndexSVSVamanaLeanVec(
|
|
|
44
44
|
MetricType metric,
|
|
45
45
|
size_t leanvec_dims,
|
|
46
46
|
SVSStorageKind storage_kind,
|
|
47
|
-
bool is_static
|
|
48
|
-
|
|
47
|
+
bool is_static,
|
|
48
|
+
bool store_vectors)
|
|
49
|
+
: IndexSVSVamana(
|
|
50
|
+
d,
|
|
51
|
+
degree,
|
|
52
|
+
metric,
|
|
53
|
+
storage_kind,
|
|
54
|
+
is_static,
|
|
55
|
+
store_vectors) {
|
|
49
56
|
is_trained = false;
|
|
50
57
|
leanvec_d = leanvec_dims == 0 ? d / 2 : leanvec_dims;
|
|
51
58
|
}
|
|
@@ -36,7 +36,8 @@ struct IndexSVSVamanaLeanVec : IndexSVSVamana {
|
|
|
36
36
|
MetricType metric = METRIC_L2,
|
|
37
37
|
size_t leanvec_dims = 0,
|
|
38
38
|
SVSStorageKind storage = SVSStorageKind::SVS_LeanVec4x4,
|
|
39
|
-
bool is_static = false
|
|
39
|
+
bool is_static = false,
|
|
40
|
+
bool store_vectors = true);
|
|
40
41
|
|
|
41
42
|
~IndexSVSVamanaLeanVec() override;
|
|
42
43
|
|
|
@@ -541,17 +541,19 @@ void exhaustive_L2sqr_blas<Top1BlockResultHandler<CMax<float, int64_t>>>(
|
|
|
541
541
|
return;
|
|
542
542
|
}
|
|
543
543
|
|
|
544
|
-
with_selected_simd_levels<
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
544
|
+
with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_SVE>(
|
|
545
|
+
[&]<SIMDLevel SL>() {
|
|
546
|
+
if constexpr (
|
|
547
|
+
SL == SIMDLevel::AVX2 || SL == SIMDLevel::AVX512 ||
|
|
548
|
+
SL == SIMDLevel::ARM_SVE) {
|
|
549
|
+
exhaustive_L2sqr_blas_cmax<SL>(
|
|
550
|
+
x, y, d, nx, ny, res, y_norms);
|
|
551
|
+
} else {
|
|
552
|
+
exhaustive_L2sqr_blas_default_impl<
|
|
553
|
+
Top1BlockResultHandler<CMax<float, int64_t>>>(
|
|
554
|
+
x, y, d, nx, ny, res, y_norms);
|
|
555
|
+
}
|
|
556
|
+
});
|
|
555
557
|
}
|
|
556
558
|
|
|
557
559
|
struct Run_search_inner_product {
|
|
@@ -563,7 +565,11 @@ struct Run_search_inner_product {
|
|
|
563
565
|
size_t d,
|
|
564
566
|
size_t nx,
|
|
565
567
|
size_t ny) {
|
|
566
|
-
|
|
568
|
+
// ny == 0 goes to the sequential path: it guards only on nx, so its
|
|
569
|
+
// per-query begin()/end() still runs and each handler writes its own
|
|
570
|
+
// neutral distance and -1 label. The BLAS path instead returns early
|
|
571
|
+
// on ny == 0, before the handler is initialized.
|
|
572
|
+
if (res.sel || ny == 0 ||
|
|
567
573
|
nx * d < static_cast<size_t>(distance_compute_blas_threshold)) {
|
|
568
574
|
exhaustive_inner_product_seq(x, y, d, nx, ny, res);
|
|
569
575
|
} else {
|
|
@@ -582,7 +588,8 @@ struct Run_search_L2sqr {
|
|
|
582
588
|
size_t nx,
|
|
583
589
|
size_t ny,
|
|
584
590
|
const float* y_norm2) {
|
|
585
|
-
|
|
591
|
+
// See the note on ny == 0 in Run_search_inner_product.
|
|
592
|
+
if (res.sel || ny == 0 ||
|
|
586
593
|
nx * d < static_cast<size_t>(distance_compute_blas_threshold)) {
|
|
587
594
|
exhaustive_L2sqr_seq(x, y, d, nx, ny, res);
|
|
588
595
|
} else {
|
|
@@ -29,22 +29,22 @@
|
|
|
29
29
|
namespace faiss {
|
|
30
30
|
|
|
31
31
|
inline float fvec_L1_dispatch(const float* x, const float* y, size_t d) {
|
|
32
|
-
return with_selected_simd_levels<
|
|
32
|
+
return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_SVE>(
|
|
33
33
|
[&]<SIMDLevel SL>() { return fvec_L1<SL>(x, y, d); });
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
inline float fvec_Linf_dispatch(const float* x, const float* y, size_t d) {
|
|
37
|
-
return with_selected_simd_levels<
|
|
37
|
+
return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_SVE>(
|
|
38
38
|
[&]<SIMDLevel SL>() { return fvec_Linf<SL>(x, y, d); });
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
inline float fvec_norm_L2sqr_dispatch(const float* x, size_t d) {
|
|
42
|
-
return with_selected_simd_levels<
|
|
42
|
+
return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_SVE>(
|
|
43
43
|
[&]<SIMDLevel SL>() { return fvec_norm_L2sqr<SL>(x, d); });
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
inline float fvec_L2sqr_dispatch(const float* x, const float* y, size_t d) {
|
|
47
|
-
return with_selected_simd_levels<
|
|
47
|
+
return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_SVE>(
|
|
48
48
|
[&]<SIMDLevel SL>() { return fvec_L2sqr<SL>(x, y, d); });
|
|
49
49
|
}
|
|
50
50
|
|
|
@@ -52,7 +52,7 @@ inline float fvec_inner_product_dispatch(
|
|
|
52
52
|
const float* x,
|
|
53
53
|
const float* y,
|
|
54
54
|
size_t d) {
|
|
55
|
-
return with_selected_simd_levels<
|
|
55
|
+
return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_SVE>(
|
|
56
56
|
[&]<SIMDLevel SL>() { return fvec_inner_product<SL>(x, y, d); });
|
|
57
57
|
}
|
|
58
58
|
|
|
@@ -67,10 +67,11 @@ inline void fvec_inner_product_batch_4_dispatch(
|
|
|
67
67
|
float& dis1,
|
|
68
68
|
float& dis2,
|
|
69
69
|
float& dis3) {
|
|
70
|
-
with_selected_simd_levels<
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_SVE>(
|
|
71
|
+
[&]<SIMDLevel SL>() {
|
|
72
|
+
fvec_inner_product_batch_4<SL>(
|
|
73
|
+
x, y0, y1, y2, y3, d, dis0, dis1, dis2, dis3);
|
|
74
|
+
});
|
|
74
75
|
}
|
|
75
76
|
|
|
76
77
|
inline void fvec_L2sqr_batch_4_dispatch(
|
|
@@ -84,9 +85,11 @@ inline void fvec_L2sqr_batch_4_dispatch(
|
|
|
84
85
|
float& dis1,
|
|
85
86
|
float& dis2,
|
|
86
87
|
float& dis3) {
|
|
87
|
-
with_selected_simd_levels<
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_SVE>(
|
|
89
|
+
[&]<SIMDLevel SL>() {
|
|
90
|
+
fvec_L2sqr_batch_4<SL>(
|
|
91
|
+
x, y0, y1, y2, y3, d, dis0, dis1, dis2, dis3);
|
|
92
|
+
});
|
|
90
93
|
}
|
|
91
94
|
|
|
92
95
|
inline void fvec_L2sqr_ny_transposed_dispatch(
|
|
@@ -97,9 +100,11 @@ inline void fvec_L2sqr_ny_transposed_dispatch(
|
|
|
97
100
|
size_t d,
|
|
98
101
|
size_t d_offset,
|
|
99
102
|
size_t ny) {
|
|
100
|
-
with_selected_simd_levels<
|
|
101
|
-
|
|
102
|
-
|
|
103
|
+
with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_SVE>(
|
|
104
|
+
[&]<SIMDLevel SL>() {
|
|
105
|
+
fvec_L2sqr_ny_transposed<SL>(
|
|
106
|
+
dis, x, y, y_sqlen, d, d_offset, ny);
|
|
107
|
+
});
|
|
103
108
|
}
|
|
104
109
|
|
|
105
110
|
inline void fvec_inner_products_ny_dispatch(
|
|
@@ -108,9 +113,10 @@ inline void fvec_inner_products_ny_dispatch(
|
|
|
108
113
|
const float* y,
|
|
109
114
|
size_t d,
|
|
110
115
|
size_t ny) {
|
|
111
|
-
with_selected_simd_levels<
|
|
112
|
-
|
|
113
|
-
|
|
116
|
+
with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_SVE>(
|
|
117
|
+
[&]<SIMDLevel SL>() {
|
|
118
|
+
fvec_inner_products_ny<SL>(ip, x, y, d, ny);
|
|
119
|
+
});
|
|
114
120
|
}
|
|
115
121
|
|
|
116
122
|
inline void fvec_L2sqr_ny_dispatch(
|
|
@@ -119,7 +125,7 @@ inline void fvec_L2sqr_ny_dispatch(
|
|
|
119
125
|
const float* y,
|
|
120
126
|
size_t d,
|
|
121
127
|
size_t ny) {
|
|
122
|
-
with_selected_simd_levels<
|
|
128
|
+
with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_SVE>(
|
|
123
129
|
[&]<SIMDLevel SL>() { fvec_L2sqr_ny<SL>(dis, x, y, d, ny); });
|
|
124
130
|
}
|
|
125
131
|
|
|
@@ -129,7 +135,7 @@ inline size_t fvec_L2sqr_ny_nearest_dispatch(
|
|
|
129
135
|
const float* y,
|
|
130
136
|
size_t d,
|
|
131
137
|
size_t ny) {
|
|
132
|
-
return with_selected_simd_levels<
|
|
138
|
+
return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_SVE>(
|
|
133
139
|
[&]<SIMDLevel SL>() {
|
|
134
140
|
return fvec_L2sqr_ny_nearest<SL>(
|
|
135
141
|
distances_tmp_buffer, x, y, d, ny);
|
|
@@ -144,7 +150,7 @@ inline size_t fvec_L2sqr_ny_nearest_y_transposed_dispatch(
|
|
|
144
150
|
size_t d,
|
|
145
151
|
size_t d_offset,
|
|
146
152
|
size_t ny) {
|
|
147
|
-
return with_selected_simd_levels<
|
|
153
|
+
return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_SVE>(
|
|
148
154
|
[&]<SIMDLevel SL>() {
|
|
149
155
|
return fvec_L2sqr_ny_nearest_y_transposed<SL>(
|
|
150
156
|
distances_tmp_buffer, x, y, y_sqlen, d, d_offset, ny);
|
|
@@ -157,7 +163,7 @@ inline void fvec_madd_dispatch(
|
|
|
157
163
|
float bf,
|
|
158
164
|
const float* b,
|
|
159
165
|
float* c) {
|
|
160
|
-
with_selected_simd_levels<
|
|
166
|
+
with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_SVE>(
|
|
161
167
|
[&]<SIMDLevel SL>() { fvec_madd<SL>(n, a, bf, b, c); });
|
|
162
168
|
}
|
|
163
169
|
|
|
@@ -167,7 +173,7 @@ inline int fvec_madd_and_argmin_dispatch(
|
|
|
167
173
|
float bf,
|
|
168
174
|
const float* b,
|
|
169
175
|
float* c) {
|
|
170
|
-
return with_selected_simd_levels<
|
|
176
|
+
return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE_WITH_SVE>(
|
|
171
177
|
[&]<SIMDLevel SL>() {
|
|
172
178
|
return fvec_madd_and_argmin<SL>(n, a, bf, b, c);
|
|
173
179
|
});
|
|
@@ -241,7 +247,7 @@ auto with_VectorDistance(
|
|
|
241
247
|
if constexpr (!has_simd) {
|
|
242
248
|
return call.template operator()<SIMDLevel::NONE>();
|
|
243
249
|
} else {
|
|
244
|
-
return
|
|
250
|
+
return with_simd_level_with_sve(call);
|
|
245
251
|
}
|
|
246
252
|
};
|
|
247
253
|
return with_metric_type(metric, dispatch_metric);
|
|
@@ -51,7 +51,7 @@ bool exhaustive_L2sqr_fused_cmax(
|
|
|
51
51
|
return true;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
return with_selected_simd_levels<
|
|
54
|
+
return with_selected_simd_levels<AVAILABLE_SIMD_LEVELS_BASE>(
|
|
55
55
|
[&]<SIMDLevel SL>() {
|
|
56
56
|
return exhaustive_L2sqr_fused_cmax<SL>(
|
|
57
57
|
x, y, d, nx, ny, res, y_norms);
|
|
@@ -146,8 +146,14 @@ void hammings(
|
|
|
146
146
|
size_t nb,
|
|
147
147
|
size_t ncodes,
|
|
148
148
|
hamdis_t* __restrict dis) {
|
|
149
|
-
|
|
150
|
-
|
|
149
|
+
with_simd_level_with_vpopcnt([&]<SIMDLevel SL>() {
|
|
150
|
+
// Ragged sizes have their own kernel; keeping it out of
|
|
151
|
+
// hammings_fixSL() leaves the word-level paths untouched.
|
|
152
|
+
if (ncodes % 8 != 0) {
|
|
153
|
+
hammings_ragged_fixSL<SL>(a, b, na, nb, ncodes, dis);
|
|
154
|
+
} else {
|
|
155
|
+
hammings_fixSL<SL>(a, b, na, nb, ncodes, dis);
|
|
156
|
+
}
|
|
151
157
|
});
|
|
152
158
|
}
|
|
153
159
|
|
|
@@ -170,7 +176,7 @@ void hammings_knn_hc(
|
|
|
170
176
|
int order,
|
|
171
177
|
ApproxTopK_mode_t approx_topk_mode,
|
|
172
178
|
const faiss::IDSelector* sel) {
|
|
173
|
-
|
|
179
|
+
with_simd_level_with_vpopcnt([&]<SIMDLevel SL>() {
|
|
174
180
|
hammings_knn_hc_fixSL<SL>(
|
|
175
181
|
ha, a, b, nb, ncodes, order, approx_topk_mode, sel);
|
|
176
182
|
});
|
|
@@ -186,7 +192,7 @@ void hammings_knn_mc(
|
|
|
186
192
|
int32_t* __restrict distances,
|
|
187
193
|
int64_t* __restrict labels,
|
|
188
194
|
const faiss::IDSelector* sel) {
|
|
189
|
-
|
|
195
|
+
with_simd_level_with_vpopcnt([&]<SIMDLevel SL>() {
|
|
190
196
|
hammings_knn_mc_fixSL<SL>(
|
|
191
197
|
a, b, na, nb, k, ncodes, distances, labels, sel);
|
|
192
198
|
});
|
|
@@ -201,7 +207,7 @@ void hamming_range_search(
|
|
|
201
207
|
size_t code_size,
|
|
202
208
|
RangeSearchResult* result,
|
|
203
209
|
const faiss::IDSelector* sel) {
|
|
204
|
-
|
|
210
|
+
with_simd_level_with_vpopcnt([&]<SIMDLevel SL>() {
|
|
205
211
|
hamming_range_search_fixSL<SL>(
|
|
206
212
|
a, b, na, nb, radius, code_size, result, sel);
|
|
207
213
|
});
|
|
@@ -215,7 +221,7 @@ void hamming_count_thres(
|
|
|
215
221
|
hamdis_t ht,
|
|
216
222
|
size_t ncodes,
|
|
217
223
|
size_t* nptr) {
|
|
218
|
-
|
|
224
|
+
with_simd_level_with_vpopcnt([&]<SIMDLevel SL>() {
|
|
219
225
|
hamming_count_thres_fixSL<SL>(bs1, bs2, n1, n2, ht, ncodes, nptr);
|
|
220
226
|
});
|
|
221
227
|
}
|
|
@@ -226,7 +232,7 @@ void crosshamming_count_thres(
|
|
|
226
232
|
hamdis_t ht,
|
|
227
233
|
size_t ncodes,
|
|
228
234
|
size_t* nptr) {
|
|
229
|
-
|
|
235
|
+
with_simd_level_with_vpopcnt([&]<SIMDLevel SL>() {
|
|
230
236
|
crosshamming_count_thres_fixSL<SL>(dbs, n, ht, ncodes, nptr);
|
|
231
237
|
});
|
|
232
238
|
}
|
|
@@ -240,7 +246,7 @@ size_t match_hamming_thres(
|
|
|
240
246
|
size_t ncodes,
|
|
241
247
|
int64_t* idx,
|
|
242
248
|
hamdis_t* dis) {
|
|
243
|
-
return
|
|
249
|
+
return with_simd_level_with_vpopcnt([&]<SIMDLevel SL>() -> size_t {
|
|
244
250
|
return match_hamming_thres_fixSL<SL>(
|
|
245
251
|
bs1, bs2, n1, n2, ht, ncodes, idx, dis);
|
|
246
252
|
});
|
|
@@ -253,7 +259,7 @@ void generalized_hammings_knn_hc(
|
|
|
253
259
|
size_t nb,
|
|
254
260
|
size_t code_size,
|
|
255
261
|
int ordered) {
|
|
256
|
-
|
|
262
|
+
with_simd_level_with_vpopcnt([&]<SIMDLevel SL>() {
|
|
257
263
|
generalized_hammings_knn_hc_fixSL<SL>(ha, a, b, nb, code_size, ordered);
|
|
258
264
|
});
|
|
259
265
|
}
|
|
@@ -111,7 +111,7 @@ FAISS_API extern size_t hamming_batch_size;
|
|
|
111
111
|
*
|
|
112
112
|
* @param a size na * nbytespercode
|
|
113
113
|
* @param b size nb * nbytespercode
|
|
114
|
-
* @param nbytespercode
|
|
114
|
+
* @param nbytespercode any size; multiples of 8 take a faster kernel
|
|
115
115
|
* @param dis output distances, size na * nb
|
|
116
116
|
*/
|
|
117
117
|
void hammings(
|
|
@@ -327,6 +327,15 @@ void hamming_range_search_fixSL(
|
|
|
327
327
|
RangeSearchResult* result,
|
|
328
328
|
const IDSelector* sel);
|
|
329
329
|
|
|
330
|
+
template <SIMDLevel SL>
|
|
331
|
+
void hammings_ragged_fixSL(
|
|
332
|
+
const uint8_t* a,
|
|
333
|
+
const uint8_t* b,
|
|
334
|
+
size_t na,
|
|
335
|
+
size_t nb,
|
|
336
|
+
size_t ncodes,
|
|
337
|
+
hamdis_t* dis);
|
|
338
|
+
|
|
330
339
|
template <SIMDLevel SL>
|
|
331
340
|
void hammings_fixSL(
|
|
332
341
|
const uint8_t* a,
|
|
@@ -210,12 +210,23 @@ inline void hammings_impl(
|
|
|
210
210
|
size_t n2,
|
|
211
211
|
hamdis_t* __restrict dis) {
|
|
212
212
|
size_t i, j;
|
|
213
|
-
|
|
213
|
+
constexpr size_t nwords = nbits / 64;
|
|
214
214
|
for (i = 0; i < n1; i++) {
|
|
215
215
|
const uint64_t* __restrict bs1_ = bs1 + i * nwords;
|
|
216
216
|
hamdis_t* __restrict dis_ = dis + i * n2;
|
|
217
|
-
|
|
218
|
-
|
|
217
|
+
if constexpr (nwords >= 4) {
|
|
218
|
+
// Wide codes are quicker one candidate at a time; otherwise the
|
|
219
|
+
// compiler batches candidates and must gather scattered bytes.
|
|
220
|
+
#if defined(__clang__)
|
|
221
|
+
#pragma clang loop vectorize(disable)
|
|
222
|
+
#endif
|
|
223
|
+
for (j = 0; j < n2; j++) {
|
|
224
|
+
dis_[j] = hamming<nbits>(bs1_, bs2 + j * nwords);
|
|
225
|
+
}
|
|
226
|
+
} else {
|
|
227
|
+
for (j = 0; j < n2; j++) {
|
|
228
|
+
dis_[j] = hamming<nbits>(bs1_, bs2 + j * nwords);
|
|
229
|
+
}
|
|
219
230
|
}
|
|
220
231
|
}
|
|
221
232
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#ifdef COMPILE_SIMD_AVX512_VPOPCNT
|
|
9
|
+
|
|
10
|
+
#define THE_SIMD_LEVEL SIMDLevel::AVX512_VPOPCNT
|
|
11
|
+
#include <faiss/utils/hamming_distance/hamming_computer-avx512_vpopcnt.h>
|
|
12
|
+
#include <faiss/utils/hamming_distance/hamming_impl.h>
|
|
13
|
+
|
|
14
|
+
// Must follow the computer specializations above.
|
|
15
|
+
// clang-format off
|
|
16
|
+
// NOLINTNEXTLINE(facebook-hte-InlineHeader)
|
|
17
|
+
#include <faiss/impl/binary_hamming/IndexBinaryIVF_impl.h>
|
|
18
|
+
// clang-format on
|
|
19
|
+
|
|
20
|
+
// Fails the build if the batch path stops being selected for this computer.
|
|
21
|
+
static_assert(faiss::has_hamming_batch<
|
|
22
|
+
faiss::HammingComputer20_tpl<faiss::SIMDLevel::AVX512_VPOPCNT>>);
|
|
23
|
+
|
|
24
|
+
#endif // COMPILE_SIMD_AVX512_VPOPCNT
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// Types without custom AVX512 code inherit from the NONE specializations
|
|
13
13
|
// in hamming_computer-generic.h. HammingComputer64 and
|
|
14
14
|
// HammingComputerDefault use scalar popcount here; the VPOPCNTDQ fast
|
|
15
|
-
// path lives in hamming_computer-
|
|
15
|
+
// path lives in hamming_computer-avx512_vpopcnt.h (AVX512_VPOPCNT level).
|
|
16
16
|
// GenHammingComputer classes leverage SSE/AVX2 intrinsics.
|
|
17
17
|
|
|
18
18
|
#include <cassert>
|