faiss 0.6.2 → 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 +4 -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 +4 -5
- data/vendor/faiss/faiss/IndexBinaryHash.cpp +5 -9
- data/vendor/faiss/faiss/IndexBinaryIVF.cpp +2 -4
- 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 +10 -11
- data/vendor/faiss/faiss/IndexIDMap.cpp +16 -3
- data/vendor/faiss/faiss/IndexIDMap.h +2 -0
- data/vendor/faiss/faiss/IndexIVF.cpp +17 -6
- 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 +40 -22
- 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 +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/factory_tools.cpp +47 -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/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/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 +109 -152
- data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +2 -2
- data/vendor/faiss/faiss/impl/NSG.cpp +3 -1
- data/vendor/faiss/faiss/impl/Panorama.h +9 -7
- data/vendor/faiss/faiss/impl/PolysemousTraining.cpp +152 -84
- data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +34 -22
- data/vendor/faiss/faiss/impl/RaBitQUtils.cpp +44 -36
- data/vendor/faiss/faiss/impl/RaBitQUtils.h +35 -0
- data/vendor/faiss/faiss/impl/RaBitQuantizer.cpp +168 -67
- 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 +25 -31
- data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +258 -57
- data/vendor/faiss/faiss/impl/ScalarQuantizer.h +20 -0
- 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 +1 -1
- data/vendor/faiss/faiss/impl/binary_hamming/avx2.cpp +4 -4
- 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 +376 -36
- data/vendor/faiss/faiss/impl/index_write.cpp +55 -4
- 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/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/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/quantizers.h +9 -8
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx2.cpp +85 -23
- 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 +136 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-neon.cpp +16 -16
- data/vendor/faiss/faiss/impl/simd_dispatch.h +30 -9
- data/vendor/faiss/faiss/index_factory.cpp +32 -6
- data/vendor/faiss/faiss/invlists/DirectMap.cpp +1 -1
- data/vendor/faiss/faiss/invlists/InvertedLists.cpp +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 +31 -1
- data/vendor/faiss/faiss/svs/IndexSVSVamana.h +15 -2
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.cpp +1 -2
- data/vendor/faiss/faiss/utils/approx_topk_hamming/approx_topk_hamming.h +1 -1
- data/vendor/faiss/faiss/utils/distances.cpp +14 -2
- 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 +1 -1
- 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/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 +92 -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 +44 -0
- data/vendor/faiss/faiss/utils/simd_levels.h +14 -0
- data/vendor/faiss/faiss/utils/utils.cpp +9 -27
- metadata +16 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0ab0ef0079ca7056c6d303b95882757645a81bee9b4c13862f4337dbec1b105a
|
|
4
|
+
data.tar.gz: d61339d723153ed333a6719001de98fa1742606334684b0f7db26f26ad001b09
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 20ce33982905751c82f05241b94ca500b241ac15f18245e8e14dad29d2fe5f162c7d4fe4e5441e92f79e06eb9519538831fa2c857050e6b3ea8ad5d0b8e63366
|
|
7
|
+
data.tar.gz: cfd073d25d3067488fdde88e06c5c68eeec6840ea57b9e6222129f4594279a27148b62361bcbd0dcc57727053acd35e4f202558adef03de648d0c8179f05ce07
|
data/CHANGELOG.md
CHANGED
data/lib/faiss/version.rb
CHANGED
|
@@ -45,6 +45,8 @@ void AutoTuneCriterion::set_groundtruth(
|
|
|
45
45
|
gt_D.resize(nq * gt_nnn_in);
|
|
46
46
|
memcpy(gt_D.data(), gt_D_in, sizeof(gt_D[0]) * nq * gt_nnn_in);
|
|
47
47
|
}
|
|
48
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
49
|
+
gt_I_in != nullptr, "set_groundtruth: gt_I must be non-null");
|
|
48
50
|
gt_I.resize(nq * gt_nnn_in);
|
|
49
51
|
memcpy(gt_I.data(), gt_I_in, sizeof(gt_I[0]) * nq * gt_nnn_in);
|
|
50
52
|
}
|
|
@@ -148,7 +150,7 @@ bool OperatingPoints::add(
|
|
|
148
150
|
}
|
|
149
151
|
// remove non-optimal points from array
|
|
150
152
|
for (size_t i = a.size() - 1; i > 0; --i) {
|
|
151
|
-
if (a[i].t
|
|
153
|
+
if (a[i].t <= a[i - 1].t) {
|
|
152
154
|
a.erase(a.begin() + (i - 1));
|
|
153
155
|
}
|
|
154
156
|
}
|
|
@@ -367,7 +367,7 @@ void Clustering::train_encoded(
|
|
|
367
367
|
? std::numeric_limits<double>::max()
|
|
368
368
|
: std::abs(prev_obj - obj) / std::abs(prev_obj);
|
|
369
369
|
|
|
370
|
-
if (change
|
|
370
|
+
if (change <= early_stop_threshold) {
|
|
371
371
|
if (verbose) {
|
|
372
372
|
printf("\n Converged at iteration %d: "
|
|
373
373
|
"objective did not change\n",
|
|
@@ -439,6 +439,14 @@ float kmeans_clustering(
|
|
|
439
439
|
size_t k,
|
|
440
440
|
const float* x,
|
|
441
441
|
float* centroids) {
|
|
442
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
443
|
+
d <= static_cast<size_t>(std::numeric_limits<int>::max()),
|
|
444
|
+
"kmeans_clustering: d=%zu exceeds INT_MAX",
|
|
445
|
+
d);
|
|
446
|
+
FAISS_THROW_IF_NOT_FMT(
|
|
447
|
+
k <= static_cast<size_t>(std::numeric_limits<int>::max()),
|
|
448
|
+
"kmeans_clustering: k=%zu exceeds INT_MAX",
|
|
449
|
+
k);
|
|
442
450
|
Clustering clus(static_cast<int>(d), static_cast<int>(k));
|
|
443
451
|
clus.verbose = d * n * k > (size_t(1) << 30);
|
|
444
452
|
// display logs if > 1Gflop per iteration
|
|
@@ -592,8 +592,12 @@ void handle_ivf(
|
|
|
592
592
|
static_cast<faiss::IndexIVF*>(faiss::clone_index(clone));
|
|
593
593
|
if (generate_ids) {
|
|
594
594
|
// Assume the quantizer does not natively support add_with_ids.
|
|
595
|
-
|
|
596
|
-
|
|
595
|
+
// The IDMap wraps the cloned quantizer; own_fields makes it delete
|
|
596
|
+
// that quantizer when sharded_index (which owns the IDMap) is
|
|
597
|
+
// freed.
|
|
598
|
+
auto* id_quantizer = new IndexIDMap2(sharded_index->quantizer);
|
|
599
|
+
id_quantizer->own_fields = true;
|
|
600
|
+
sharded_index->quantizer = id_quantizer;
|
|
597
601
|
sharded_index->quantizer->add_with_ids(
|
|
598
602
|
sharded_centroids[i].size() / index->quantizer->d,
|
|
599
603
|
sharded_centroids[i].data(),
|
|
@@ -615,6 +619,7 @@ void handle_ivf(
|
|
|
615
619
|
faiss::write_index(sharded_index, fname);
|
|
616
620
|
delete sharded_index;
|
|
617
621
|
}
|
|
622
|
+
delete clone;
|
|
618
623
|
}
|
|
619
624
|
|
|
620
625
|
void handle_binary_ivf(
|
|
@@ -650,8 +655,13 @@ void handle_binary_ivf(
|
|
|
650
655
|
faiss::clone_binary_index(clone));
|
|
651
656
|
if (generate_ids) {
|
|
652
657
|
// Assume the quantizer does not natively support add_with_ids.
|
|
653
|
-
|
|
658
|
+
// The IDMap wraps the cloned quantizer; own_fields makes it delete
|
|
659
|
+
// that quantizer when sharded_index (which owns the IDMap) is
|
|
660
|
+
// freed.
|
|
661
|
+
auto* id_quantizer =
|
|
654
662
|
new IndexBinaryIDMap2(sharded_index->quantizer);
|
|
663
|
+
id_quantizer->own_fields = true;
|
|
664
|
+
sharded_index->quantizer = id_quantizer;
|
|
655
665
|
sharded_index->quantizer->add_with_ids(
|
|
656
666
|
sharded_centroids[i].size() / reconstruction_size,
|
|
657
667
|
sharded_centroids[i].data(),
|
|
@@ -673,6 +683,7 @@ void handle_binary_ivf(
|
|
|
673
683
|
faiss::write_index_binary(sharded_index, fname);
|
|
674
684
|
delete sharded_index;
|
|
675
685
|
}
|
|
686
|
+
delete clone;
|
|
676
687
|
}
|
|
677
688
|
|
|
678
689
|
template <typename IndexType>
|
data/vendor/faiss/faiss/Index.h
CHANGED
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
#include <cstdio>
|
|
17
17
|
|
|
18
18
|
#define FAISS_VERSION_MAJOR 1
|
|
19
|
-
#define FAISS_VERSION_MINOR
|
|
20
|
-
#define FAISS_VERSION_PATCH
|
|
19
|
+
#define FAISS_VERSION_MINOR 15
|
|
20
|
+
#define FAISS_VERSION_PATCH 0
|
|
21
21
|
|
|
22
22
|
// Macro to combine the version components into a single string
|
|
23
23
|
#ifndef FAISS_STRINGIFY
|
|
@@ -58,8 +58,8 @@ struct AQDistanceComputerDecompress : FlatCodesDistanceComputer {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
float symmetric_dis(idx_t i, idx_t j) final {
|
|
61
|
-
aq.decode(codes + i *
|
|
62
|
-
aq.decode(codes + j *
|
|
61
|
+
aq.decode(codes + i * code_size, tmp.data(), 1);
|
|
62
|
+
aq.decode(codes + j * code_size, tmp.data() + d, 1);
|
|
63
63
|
return vd(tmp.data(), tmp.data() + d);
|
|
64
64
|
}
|
|
65
65
|
|
|
@@ -79,7 +79,8 @@ struct AQDistanceComputerLUT : FlatCodesDistanceComputer {
|
|
|
79
79
|
|
|
80
80
|
explicit AQDistanceComputerLUT(const IndexAdditiveQuantizer& iaq)
|
|
81
81
|
: FlatCodesDistanceComputer(iaq.codes.data(), iaq.code_size),
|
|
82
|
-
LUT(iaq.aq->total_codebook_size
|
|
82
|
+
LUT(iaq.aq->total_codebook_size // Storage for LUT.
|
|
83
|
+
+ size_t(iaq.d) * 2), // tmp storage for symmetric distance.
|
|
83
84
|
aq(*iaq.aq),
|
|
84
85
|
d(iaq.d) {}
|
|
85
86
|
|
|
@@ -96,9 +97,9 @@ struct AQDistanceComputerLUT : FlatCodesDistanceComputer {
|
|
|
96
97
|
}
|
|
97
98
|
|
|
98
99
|
float symmetric_dis(idx_t i, idx_t j) final {
|
|
99
|
-
float* tmp = LUT.data();
|
|
100
|
-
aq.decode(codes + i *
|
|
101
|
-
aq.decode(codes + j *
|
|
100
|
+
float* tmp = LUT.data() + aq.total_codebook_size;
|
|
101
|
+
aq.decode(codes + i * code_size, tmp, 1);
|
|
102
|
+
aq.decode(codes + j * code_size, tmp + d, 1);
|
|
102
103
|
return fvec_L2sqr(tmp, tmp + d, d);
|
|
103
104
|
}
|
|
104
105
|
|
|
@@ -234,8 +235,7 @@ void IndexAdditiveQuantizer::search(
|
|
|
234
235
|
float* distances,
|
|
235
236
|
idx_t* labels,
|
|
236
237
|
const SearchParameters* params) const {
|
|
237
|
-
|
|
238
|
-
!params, "search params not supported for this index");
|
|
238
|
+
FAISS_THROW_IF_MSG(params, "search params not supported for this index");
|
|
239
239
|
|
|
240
240
|
if (aq->search_type == AdditiveQuantizer::ST_decompress) {
|
|
241
241
|
with_VectorDistance(d, metric_type, metric_arg, [&](auto vd) {
|
|
@@ -458,8 +458,7 @@ void AdditiveCoarseQuantizer::search(
|
|
|
458
458
|
float* distances,
|
|
459
459
|
idx_t* labels,
|
|
460
460
|
const SearchParameters* params) const {
|
|
461
|
-
|
|
462
|
-
!params, "search params not supported for this index");
|
|
461
|
+
FAISS_THROW_IF_MSG(params, "search params not supported for this index");
|
|
463
462
|
|
|
464
463
|
if (metric_type == METRIC_INNER_PRODUCT) {
|
|
465
464
|
aq->knn_centroids_inner_product(n, x, k, distances, labels);
|
|
@@ -36,7 +36,7 @@ void IndexAdditiveQuantizerFastScan::init(
|
|
|
36
36
|
MetricType metric,
|
|
37
37
|
int bbs_) {
|
|
38
38
|
FAISS_THROW_IF_NOT(aq_init != nullptr);
|
|
39
|
-
|
|
39
|
+
FAISS_THROW_IF_MSG(aq_init->nbits.empty(), "nbits must not be empty");
|
|
40
40
|
FAISS_THROW_IF_NOT(aq_init->nbits[0] == 4);
|
|
41
41
|
if (metric == METRIC_INNER_PRODUCT) {
|
|
42
42
|
FAISS_THROW_IF_NOT_MSG(
|
|
@@ -192,8 +192,7 @@ void IndexAdditiveQuantizerFastScan::search(
|
|
|
192
192
|
float* distances,
|
|
193
193
|
idx_t* labels,
|
|
194
194
|
const SearchParameters* params) const {
|
|
195
|
-
|
|
196
|
-
!params, "search params not supported for this index");
|
|
195
|
+
FAISS_THROW_IF_MSG(params, "search params not supported for this index");
|
|
197
196
|
FAISS_THROW_IF_NOT(k > 0);
|
|
198
197
|
bool rescale = (rescale_norm && norm_scale > 1 && metric_type == METRIC_L2);
|
|
199
198
|
if (!rescale) {
|
|
@@ -55,8 +55,7 @@ void IndexBinaryFromFloat::search(
|
|
|
55
55
|
int32_t* distances,
|
|
56
56
|
idx_t* labels,
|
|
57
57
|
const SearchParameters* params) const {
|
|
58
|
-
|
|
59
|
-
!params, "search params not supported for this index");
|
|
58
|
+
FAISS_THROW_IF_MSG(params, "search params not supported for this index");
|
|
60
59
|
FAISS_THROW_IF_NOT(k > 0);
|
|
61
60
|
|
|
62
61
|
constexpr idx_t bs = 32768;
|
|
@@ -24,7 +24,6 @@
|
|
|
24
24
|
#include <faiss/impl/ResultHandler.h>
|
|
25
25
|
#include <faiss/impl/VisitedTable.h>
|
|
26
26
|
#include <faiss/utils/Heap.h>
|
|
27
|
-
#include <faiss/utils/hamming.h>
|
|
28
27
|
#include <faiss/utils/random.h>
|
|
29
28
|
|
|
30
29
|
#include <faiss/impl/simd_dispatch.h>
|
|
@@ -293,8 +292,8 @@ void IndexBinaryHNSW::reconstruct(idx_t key, uint8_t* recons) const {
|
|
|
293
292
|
|
|
294
293
|
DistanceComputer* IndexBinaryHNSW::get_distance_computer() const {
|
|
295
294
|
IndexBinaryFlat* flat_storage = dynamic_cast<IndexBinaryFlat*>(storage);
|
|
296
|
-
|
|
297
|
-
flat_storage
|
|
295
|
+
FAISS_THROW_IF_MSG(
|
|
296
|
+
flat_storage == nullptr,
|
|
298
297
|
"IndexBinaryHNSW requires IndexBinaryFlat storage");
|
|
299
298
|
return with_simd_level([&]<SIMDLevel SL>() {
|
|
300
299
|
return make_binary_hnsw_distance_computer_fixSL<SL>(
|
|
@@ -317,8 +316,8 @@ IndexBinaryHNSWCagra::IndexBinaryHNSWCagra(int d_, int M)
|
|
|
317
316
|
}
|
|
318
317
|
|
|
319
318
|
void IndexBinaryHNSWCagra::add(idx_t n, const uint8_t* x) {
|
|
320
|
-
|
|
321
|
-
|
|
319
|
+
FAISS_THROW_IF_MSG(
|
|
320
|
+
base_level_only,
|
|
322
321
|
"Cannot add vectors when base_level_only is set to True");
|
|
323
322
|
|
|
324
323
|
IndexBinaryHNSW::add(n, x);
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
// NOLINTNEXTLINE(facebook-hte-InlineHeader)
|
|
28
28
|
// NOLINTNEXTLINE(facebook-hte-InlineHeader)
|
|
29
29
|
#include <faiss/impl/binary_hamming/IndexBinaryHash_impl.h>
|
|
30
|
-
#include <faiss/utils/hamming_distance/hamming_computer-generic.h>
|
|
30
|
+
#include <faiss/utils/hamming_distance/hamming_computer-generic.h> // IWYU pragma: keep
|
|
31
31
|
#undef THE_SIMD_LEVEL
|
|
32
32
|
|
|
33
33
|
namespace faiss {
|
|
@@ -83,8 +83,7 @@ void IndexBinaryHash::range_search(
|
|
|
83
83
|
int radius,
|
|
84
84
|
RangeSearchResult* result,
|
|
85
85
|
const SearchParameters* params) const {
|
|
86
|
-
|
|
87
|
-
!params, "search params not supported for this index");
|
|
86
|
+
FAISS_THROW_IF_MSG(params, "search params not supported for this index");
|
|
88
87
|
size_t nlist = 0, ndis = 0, n0 = 0;
|
|
89
88
|
|
|
90
89
|
#pragma omp parallel if (n > 100) reduction(+ : ndis, n0, nlist)
|
|
@@ -116,8 +115,7 @@ void IndexBinaryHash::search(
|
|
|
116
115
|
int32_t* distances,
|
|
117
116
|
idx_t* labels,
|
|
118
117
|
const SearchParameters* params) const {
|
|
119
|
-
|
|
120
|
-
!params, "search params not supported for this index");
|
|
118
|
+
FAISS_THROW_IF_MSG(params, "search params not supported for this index");
|
|
121
119
|
FAISS_THROW_IF_NOT(k > 0);
|
|
122
120
|
|
|
123
121
|
using HeapForL2 = CMax<int32_t, idx_t>;
|
|
@@ -216,8 +214,7 @@ void IndexBinaryMultiHash::range_search(
|
|
|
216
214
|
int radius,
|
|
217
215
|
RangeSearchResult* result,
|
|
218
216
|
const SearchParameters* params) const {
|
|
219
|
-
|
|
220
|
-
!params, "search params not supported for this index");
|
|
217
|
+
FAISS_THROW_IF_MSG(params, "search params not supported for this index");
|
|
221
218
|
size_t nlist = 0, ndis = 0, n0 = 0;
|
|
222
219
|
|
|
223
220
|
#pragma omp parallel if (n > 100) reduction(+ : ndis, n0, nlist)
|
|
@@ -249,8 +246,7 @@ void IndexBinaryMultiHash::search(
|
|
|
249
246
|
int32_t* distances,
|
|
250
247
|
idx_t* labels,
|
|
251
248
|
const SearchParameters* params) const {
|
|
252
|
-
|
|
253
|
-
!params, "search params not supported for this index");
|
|
249
|
+
FAISS_THROW_IF_MSG(params, "search params not supported for this index");
|
|
254
250
|
FAISS_THROW_IF_NOT(k > 0);
|
|
255
251
|
|
|
256
252
|
using HeapForL2 = CMax<int32_t, idx_t>;
|
|
@@ -206,8 +206,7 @@ void IndexBinaryIVF::search_and_reconstruct(
|
|
|
206
206
|
idx_t* __restrict labels,
|
|
207
207
|
uint8_t* __restrict recons,
|
|
208
208
|
const SearchParameters* params) const {
|
|
209
|
-
|
|
210
|
-
!params, "search params not supported for this index");
|
|
209
|
+
FAISS_THROW_IF_MSG(params, "search params not supported for this index");
|
|
211
210
|
const size_t nprobe_2 = std::min(nlist, this->nprobe);
|
|
212
211
|
FAISS_THROW_IF_NOT(k > 0);
|
|
213
212
|
FAISS_THROW_IF_NOT(nprobe_2 > 0);
|
|
@@ -524,8 +523,7 @@ void IndexBinaryIVF::range_search(
|
|
|
524
523
|
int radius,
|
|
525
524
|
RangeSearchResult* __restrict res,
|
|
526
525
|
const SearchParameters* params) const {
|
|
527
|
-
|
|
528
|
-
!params, "search params not supported for this index");
|
|
526
|
+
FAISS_THROW_IF_MSG(params, "search params not supported for this index");
|
|
529
527
|
const size_t nprobe_2 = std::min(nlist, this->nprobe);
|
|
530
528
|
std::unique_ptr<idx_t[]> idx(new idx_t[n * nprobe_2]);
|
|
531
529
|
std::unique_ptr<int32_t[]> coarse_dis(new int32_t[n * nprobe_2]);
|
|
@@ -0,0 +1,273 @@
|
|
|
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
|
+
#include <faiss/IndexEDEN.h>
|
|
9
|
+
|
|
10
|
+
#include <faiss/impl/FaissAssert.h>
|
|
11
|
+
#include <faiss/impl/ResultHandler.h>
|
|
12
|
+
#include <memory>
|
|
13
|
+
|
|
14
|
+
namespace faiss {
|
|
15
|
+
|
|
16
|
+
IndexEDEN::IndexEDEN() = default;
|
|
17
|
+
|
|
18
|
+
IndexEDEN::IndexEDEN(
|
|
19
|
+
idx_t d_in,
|
|
20
|
+
MetricType metric,
|
|
21
|
+
uint8_t nb_bits_in,
|
|
22
|
+
EDENScaleType scale_type_in)
|
|
23
|
+
: IndexFlatCodes(0, d_in, metric),
|
|
24
|
+
sq(d_in, eden_utils::quantizer_type_for_bits(nb_bits_in)),
|
|
25
|
+
scale_type(scale_type_in) {
|
|
26
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
27
|
+
scale_type == EDENScaleType_UNBIASED ||
|
|
28
|
+
scale_type == EDENScaleType_BIASED,
|
|
29
|
+
"invalid EDEN scale type");
|
|
30
|
+
sq.train(0, nullptr);
|
|
31
|
+
code_size = eden_utils::code_size(d, sq.bits);
|
|
32
|
+
is_trained = false;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
void IndexEDEN::train(idx_t n, const float* x) {
|
|
36
|
+
std::vector<float> centroid(d, 0.0f);
|
|
37
|
+
for (idx_t i = 0; i < n; i++) {
|
|
38
|
+
for (size_t j = 0; j < static_cast<size_t>(d); j++) {
|
|
39
|
+
centroid[j] += x[i * d + j];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (n != 0) {
|
|
44
|
+
for (size_t j = 0; j < static_cast<size_t>(d); j++) {
|
|
45
|
+
centroid[j] /= static_cast<float>(n);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
center = std::move(centroid);
|
|
50
|
+
sq.train(n, x);
|
|
51
|
+
is_trained = true;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
void IndexEDEN::sa_encode(idx_t n, const float* x, uint8_t* bytes) const {
|
|
55
|
+
FAISS_THROW_IF_NOT(is_trained);
|
|
56
|
+
eden_utils::compute_codes(
|
|
57
|
+
sq, metric_type, scale_type, x, bytes, n, center.data());
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
void IndexEDEN::sa_decode(idx_t n, const uint8_t* bytes, float* x) const {
|
|
61
|
+
FAISS_THROW_IF_NOT(is_trained);
|
|
62
|
+
eden_utils::decode(sq, bytes, x, n, center.data());
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
FlatCodesDistanceComputer* IndexEDEN::get_FlatCodesDistanceComputer() const {
|
|
66
|
+
FlatCodesDistanceComputer* dc =
|
|
67
|
+
eden_utils::get_distance_computer(sq, metric_type, center.data());
|
|
68
|
+
dc->code_size = code_size;
|
|
69
|
+
dc->codes = codes.data();
|
|
70
|
+
return dc;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
namespace {
|
|
74
|
+
|
|
75
|
+
bool use_eden_batch_scan(size_t d, size_t nb_bits) {
|
|
76
|
+
const size_t values_per_byte = 8 / nb_bits;
|
|
77
|
+
const size_t num_bytes = (d + values_per_byte - 1) / values_per_byte;
|
|
78
|
+
if (nb_bits == 1) {
|
|
79
|
+
return num_bytes >= 32;
|
|
80
|
+
}
|
|
81
|
+
if (nb_bits == 2) {
|
|
82
|
+
return num_bytes >= 16;
|
|
83
|
+
}
|
|
84
|
+
if (nb_bits == 4) {
|
|
85
|
+
return num_bytes >= 128;
|
|
86
|
+
}
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
struct Run_search_with_eden_dc {
|
|
91
|
+
using T = void;
|
|
92
|
+
|
|
93
|
+
template <class BlockResultHandler>
|
|
94
|
+
void f(BlockResultHandler& res, const IndexEDEN* index, const float* xq) {
|
|
95
|
+
const size_t ntotal = index->ntotal;
|
|
96
|
+
using SingleResultHandler =
|
|
97
|
+
typename BlockResultHandler::SingleResultHandler;
|
|
98
|
+
const int d = index->d;
|
|
99
|
+
const bool use_batch_scan = use_eden_batch_scan(d, index->sq.bits);
|
|
100
|
+
|
|
101
|
+
#pragma omp parallel
|
|
102
|
+
{
|
|
103
|
+
std::unique_ptr<EDENFlatCodesDistanceComputer> dc(
|
|
104
|
+
eden_utils::get_distance_computer(
|
|
105
|
+
index->sq,
|
|
106
|
+
index->metric_type,
|
|
107
|
+
index->center.data()));
|
|
108
|
+
dc->code_size = index->code_size;
|
|
109
|
+
dc->codes = index->codes.data();
|
|
110
|
+
SingleResultHandler resi(res);
|
|
111
|
+
|
|
112
|
+
#pragma omp for
|
|
113
|
+
for (int64_t q = 0; q < static_cast<int64_t>(res.nq); q++) {
|
|
114
|
+
resi.begin(q);
|
|
115
|
+
dc->set_query(xq + d * q);
|
|
116
|
+
|
|
117
|
+
if (use_batch_scan) {
|
|
118
|
+
size_t i = 0;
|
|
119
|
+
for (; i + 16 <= ntotal; i += 16) {
|
|
120
|
+
bool keep[16];
|
|
121
|
+
bool keep_all = true;
|
|
122
|
+
for (size_t j = 0; j < 16; j++) {
|
|
123
|
+
keep[j] = res.is_in_selection(i + j);
|
|
124
|
+
keep_all &= keep[j];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (keep_all) {
|
|
128
|
+
float dis[16];
|
|
129
|
+
dc->consecutive_distances_batch_16(i, dis);
|
|
130
|
+
for (size_t j = 0; j < 16; j++) {
|
|
131
|
+
resi.add_result(dis[j], i + j);
|
|
132
|
+
}
|
|
133
|
+
} else {
|
|
134
|
+
for (size_t j = 0; j < 16; j++) {
|
|
135
|
+
if (keep[j]) {
|
|
136
|
+
resi.add_result((*dc)(i + j), i + j);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
for (; i + 8 <= ntotal; i += 8) {
|
|
142
|
+
const bool keep0 = res.is_in_selection(i);
|
|
143
|
+
const bool keep1 = res.is_in_selection(i + 1);
|
|
144
|
+
const bool keep2 = res.is_in_selection(i + 2);
|
|
145
|
+
const bool keep3 = res.is_in_selection(i + 3);
|
|
146
|
+
const bool keep4 = res.is_in_selection(i + 4);
|
|
147
|
+
const bool keep5 = res.is_in_selection(i + 5);
|
|
148
|
+
const bool keep6 = res.is_in_selection(i + 6);
|
|
149
|
+
const bool keep7 = res.is_in_selection(i + 7);
|
|
150
|
+
if (keep0 && keep1 && keep2 && keep3 && keep4 &&
|
|
151
|
+
keep5 && keep6 && keep7) {
|
|
152
|
+
float dis[8];
|
|
153
|
+
dc->consecutive_distances_batch_8(i, dis);
|
|
154
|
+
resi.add_result(dis[0], i);
|
|
155
|
+
resi.add_result(dis[1], i + 1);
|
|
156
|
+
resi.add_result(dis[2], i + 2);
|
|
157
|
+
resi.add_result(dis[3], i + 3);
|
|
158
|
+
resi.add_result(dis[4], i + 4);
|
|
159
|
+
resi.add_result(dis[5], i + 5);
|
|
160
|
+
resi.add_result(dis[6], i + 6);
|
|
161
|
+
resi.add_result(dis[7], i + 7);
|
|
162
|
+
} else {
|
|
163
|
+
if (keep0) {
|
|
164
|
+
resi.add_result((*dc)(i), i);
|
|
165
|
+
}
|
|
166
|
+
if (keep1) {
|
|
167
|
+
resi.add_result((*dc)(i + 1), i + 1);
|
|
168
|
+
}
|
|
169
|
+
if (keep2) {
|
|
170
|
+
resi.add_result((*dc)(i + 2), i + 2);
|
|
171
|
+
}
|
|
172
|
+
if (keep3) {
|
|
173
|
+
resi.add_result((*dc)(i + 3), i + 3);
|
|
174
|
+
}
|
|
175
|
+
if (keep4) {
|
|
176
|
+
resi.add_result((*dc)(i + 4), i + 4);
|
|
177
|
+
}
|
|
178
|
+
if (keep5) {
|
|
179
|
+
resi.add_result((*dc)(i + 5), i + 5);
|
|
180
|
+
}
|
|
181
|
+
if (keep6) {
|
|
182
|
+
resi.add_result((*dc)(i + 6), i + 6);
|
|
183
|
+
}
|
|
184
|
+
if (keep7) {
|
|
185
|
+
resi.add_result((*dc)(i + 7), i + 7);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
for (; i + 4 <= ntotal; i += 4) {
|
|
190
|
+
const bool keep0 = res.is_in_selection(i);
|
|
191
|
+
const bool keep1 = res.is_in_selection(i + 1);
|
|
192
|
+
const bool keep2 = res.is_in_selection(i + 2);
|
|
193
|
+
const bool keep3 = res.is_in_selection(i + 3);
|
|
194
|
+
if (keep0 && keep1 && keep2 && keep3) {
|
|
195
|
+
float dis0;
|
|
196
|
+
float dis1;
|
|
197
|
+
float dis2;
|
|
198
|
+
float dis3;
|
|
199
|
+
dc->distances_batch_4(
|
|
200
|
+
i,
|
|
201
|
+
i + 1,
|
|
202
|
+
i + 2,
|
|
203
|
+
i + 3,
|
|
204
|
+
dis0,
|
|
205
|
+
dis1,
|
|
206
|
+
dis2,
|
|
207
|
+
dis3);
|
|
208
|
+
resi.add_result(dis0, i);
|
|
209
|
+
resi.add_result(dis1, i + 1);
|
|
210
|
+
resi.add_result(dis2, i + 2);
|
|
211
|
+
resi.add_result(dis3, i + 3);
|
|
212
|
+
} else {
|
|
213
|
+
if (keep0) {
|
|
214
|
+
resi.add_result((*dc)(i), i);
|
|
215
|
+
}
|
|
216
|
+
if (keep1) {
|
|
217
|
+
resi.add_result((*dc)(i + 1), i + 1);
|
|
218
|
+
}
|
|
219
|
+
if (keep2) {
|
|
220
|
+
resi.add_result((*dc)(i + 2), i + 2);
|
|
221
|
+
}
|
|
222
|
+
if (keep3) {
|
|
223
|
+
resi.add_result((*dc)(i + 3), i + 3);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
for (; i < ntotal; i++) {
|
|
228
|
+
if (res.is_in_selection(i)) {
|
|
229
|
+
resi.add_result((*dc)(i), i);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
} else {
|
|
233
|
+
for (size_t i = 0; i < ntotal; i++) {
|
|
234
|
+
if (res.is_in_selection(i)) {
|
|
235
|
+
resi.add_result((*dc)(i), i);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
resi.end();
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
} // namespace
|
|
247
|
+
|
|
248
|
+
void IndexEDEN::search(
|
|
249
|
+
idx_t n,
|
|
250
|
+
const float* x,
|
|
251
|
+
idx_t k,
|
|
252
|
+
float* distances,
|
|
253
|
+
idx_t* labels,
|
|
254
|
+
const SearchParameters* params) const {
|
|
255
|
+
FAISS_THROW_IF_NOT(is_trained);
|
|
256
|
+
const IDSelector* sel = params != nullptr ? params->sel : nullptr;
|
|
257
|
+
Run_search_with_eden_dc r;
|
|
258
|
+
dispatch_knn_ResultHandler(
|
|
259
|
+
n, distances, labels, k, metric_type, sel, r, this, x);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
void IndexEDEN::range_search(
|
|
263
|
+
idx_t /*n*/,
|
|
264
|
+
const float* x,
|
|
265
|
+
float radius,
|
|
266
|
+
RangeSearchResult* result,
|
|
267
|
+
const SearchParameters* params) const {
|
|
268
|
+
const IDSelector* sel = params != nullptr ? params->sel : nullptr;
|
|
269
|
+
Run_search_with_eden_dc r;
|
|
270
|
+
dispatch_range_ResultHandler(result, radius, metric_type, sel, r, this, x);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
} // namespace faiss
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#include <faiss/IndexFlatCodes.h>
|
|
11
|
+
#include <faiss/impl/EDENQuantizer.h>
|
|
12
|
+
|
|
13
|
+
namespace faiss {
|
|
14
|
+
|
|
15
|
+
struct IndexEDEN : IndexFlatCodes {
|
|
16
|
+
ScalarQuantizer sq;
|
|
17
|
+
EDENScaleType scale_type = EDENScaleType_UNBIASED;
|
|
18
|
+
|
|
19
|
+
// Center of all training points. Random rotation, if desired, is expected
|
|
20
|
+
// to be supplied externally via IndexPreTransform.
|
|
21
|
+
std::vector<float> center;
|
|
22
|
+
|
|
23
|
+
IndexEDEN();
|
|
24
|
+
|
|
25
|
+
// Factory strings: EDEN, EDEN<n>, EDENBIASED, EDEN<n>BIASED.
|
|
26
|
+
// <n> is the Lloyd-Max bit budget, 1..8. The default is EDEN's original
|
|
27
|
+
// unbiased scale; the BIASED suffix selects the MSE-minimizing scale.
|
|
28
|
+
explicit IndexEDEN(
|
|
29
|
+
idx_t d,
|
|
30
|
+
MetricType metric = METRIC_L2,
|
|
31
|
+
uint8_t nb_bits = 1,
|
|
32
|
+
EDENScaleType scale_type = EDENScaleType_UNBIASED);
|
|
33
|
+
|
|
34
|
+
void train(idx_t n, const float* x) override;
|
|
35
|
+
|
|
36
|
+
void sa_encode(idx_t n, const float* x, uint8_t* bytes) const override;
|
|
37
|
+
void sa_decode(idx_t n, const uint8_t* bytes, float* x) const override;
|
|
38
|
+
|
|
39
|
+
FlatCodesDistanceComputer* get_FlatCodesDistanceComputer() const override;
|
|
40
|
+
|
|
41
|
+
void search(
|
|
42
|
+
idx_t n,
|
|
43
|
+
const float* x,
|
|
44
|
+
idx_t k,
|
|
45
|
+
float* distances,
|
|
46
|
+
idx_t* labels,
|
|
47
|
+
const SearchParameters* params = nullptr) const override;
|
|
48
|
+
|
|
49
|
+
void range_search(
|
|
50
|
+
idx_t n,
|
|
51
|
+
const float* x,
|
|
52
|
+
float radius,
|
|
53
|
+
RangeSearchResult* result,
|
|
54
|
+
const SearchParameters* params = nullptr) const override;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
} // namespace faiss
|