faiss 0.4.3 → 0.5.1
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 +10 -0
- data/README.md +2 -0
- data/ext/faiss/index.cpp +33 -6
- data/ext/faiss/index_binary.cpp +17 -4
- data/ext/faiss/kmeans.cpp +6 -6
- data/lib/faiss/version.rb +1 -1
- data/vendor/faiss/faiss/AutoTune.cpp +2 -3
- data/vendor/faiss/faiss/AutoTune.h +1 -1
- data/vendor/faiss/faiss/Clustering.cpp +2 -2
- data/vendor/faiss/faiss/Clustering.h +2 -2
- data/vendor/faiss/faiss/IVFlib.cpp +26 -51
- data/vendor/faiss/faiss/IVFlib.h +1 -1
- data/vendor/faiss/faiss/Index.cpp +11 -0
- data/vendor/faiss/faiss/Index.h +34 -11
- data/vendor/faiss/faiss/Index2Layer.cpp +1 -1
- data/vendor/faiss/faiss/Index2Layer.h +2 -2
- data/vendor/faiss/faiss/IndexAdditiveQuantizer.cpp +1 -0
- data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.cpp +9 -4
- data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.h +5 -1
- data/vendor/faiss/faiss/IndexBinary.h +7 -7
- data/vendor/faiss/faiss/IndexBinaryFromFloat.h +1 -1
- data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +8 -2
- data/vendor/faiss/faiss/IndexBinaryHNSW.h +1 -1
- data/vendor/faiss/faiss/IndexBinaryHash.cpp +3 -3
- data/vendor/faiss/faiss/IndexBinaryHash.h +5 -5
- data/vendor/faiss/faiss/IndexBinaryIVF.cpp +7 -6
- data/vendor/faiss/faiss/IndexFastScan.cpp +125 -49
- data/vendor/faiss/faiss/IndexFastScan.h +102 -7
- data/vendor/faiss/faiss/IndexFlat.cpp +374 -4
- data/vendor/faiss/faiss/IndexFlat.h +81 -1
- data/vendor/faiss/faiss/IndexHNSW.cpp +93 -2
- data/vendor/faiss/faiss/IndexHNSW.h +58 -2
- data/vendor/faiss/faiss/IndexIDMap.cpp +14 -13
- data/vendor/faiss/faiss/IndexIDMap.h +6 -6
- data/vendor/faiss/faiss/IndexIVF.cpp +1 -1
- data/vendor/faiss/faiss/IndexIVF.h +5 -5
- data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +1 -1
- data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.cpp +9 -3
- data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.h +3 -1
- data/vendor/faiss/faiss/IndexIVFFastScan.cpp +176 -90
- data/vendor/faiss/faiss/IndexIVFFastScan.h +173 -18
- data/vendor/faiss/faiss/IndexIVFFlat.cpp +1 -0
- data/vendor/faiss/faiss/IndexIVFFlatPanorama.cpp +251 -0
- data/vendor/faiss/faiss/IndexIVFFlatPanorama.h +64 -0
- data/vendor/faiss/faiss/IndexIVFPQ.cpp +3 -1
- data/vendor/faiss/faiss/IndexIVFPQ.h +1 -1
- data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +134 -2
- data/vendor/faiss/faiss/IndexIVFPQFastScan.h +7 -1
- data/vendor/faiss/faiss/IndexIVFRaBitQ.cpp +99 -8
- data/vendor/faiss/faiss/IndexIVFRaBitQ.h +4 -1
- data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.cpp +828 -0
- data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.h +252 -0
- data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +1 -1
- data/vendor/faiss/faiss/IndexIVFSpectralHash.h +1 -1
- data/vendor/faiss/faiss/IndexNNDescent.cpp +1 -1
- data/vendor/faiss/faiss/IndexNSG.cpp +1 -1
- data/vendor/faiss/faiss/IndexNeuralNetCodec.h +1 -1
- data/vendor/faiss/faiss/IndexPQ.cpp +4 -1
- data/vendor/faiss/faiss/IndexPQ.h +1 -1
- data/vendor/faiss/faiss/IndexPQFastScan.cpp +6 -2
- data/vendor/faiss/faiss/IndexPQFastScan.h +5 -1
- data/vendor/faiss/faiss/IndexPreTransform.cpp +14 -0
- data/vendor/faiss/faiss/IndexPreTransform.h +9 -0
- data/vendor/faiss/faiss/IndexRaBitQ.cpp +96 -13
- data/vendor/faiss/faiss/IndexRaBitQ.h +11 -2
- data/vendor/faiss/faiss/IndexRaBitQFastScan.cpp +731 -0
- data/vendor/faiss/faiss/IndexRaBitQFastScan.h +175 -0
- data/vendor/faiss/faiss/IndexRefine.cpp +49 -0
- data/vendor/faiss/faiss/IndexRefine.h +17 -0
- data/vendor/faiss/faiss/IndexShards.cpp +1 -1
- data/vendor/faiss/faiss/MatrixStats.cpp +3 -3
- data/vendor/faiss/faiss/MetricType.h +1 -1
- data/vendor/faiss/faiss/VectorTransform.h +2 -2
- data/vendor/faiss/faiss/clone_index.cpp +5 -1
- data/vendor/faiss/faiss/gpu/GpuCloner.cpp +1 -1
- data/vendor/faiss/faiss/gpu/GpuClonerOptions.h +3 -1
- data/vendor/faiss/faiss/gpu/GpuIndex.h +11 -11
- data/vendor/faiss/faiss/gpu/GpuIndexBinaryCagra.h +1 -1
- data/vendor/faiss/faiss/gpu/GpuIndexBinaryFlat.h +1 -1
- data/vendor/faiss/faiss/gpu/GpuIndexCagra.h +11 -7
- data/vendor/faiss/faiss/gpu/StandardGpuResources.cpp +1 -1
- data/vendor/faiss/faiss/gpu/perf/IndexWrapper-inl.h +2 -0
- data/vendor/faiss/faiss/gpu/test/TestGpuIcmEncoder.cpp +7 -0
- data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFFlat.cpp +1 -1
- data/vendor/faiss/faiss/impl/AdditiveQuantizer.cpp +1 -1
- data/vendor/faiss/faiss/impl/AdditiveQuantizer.h +1 -1
- data/vendor/faiss/faiss/impl/AuxIndexStructures.cpp +2 -2
- data/vendor/faiss/faiss/impl/AuxIndexStructures.h +1 -1
- data/vendor/faiss/faiss/impl/CodePacker.h +2 -2
- data/vendor/faiss/faiss/impl/DistanceComputer.h +77 -6
- data/vendor/faiss/faiss/impl/FastScanDistancePostProcessing.h +53 -0
- data/vendor/faiss/faiss/impl/HNSW.cpp +295 -16
- data/vendor/faiss/faiss/impl/HNSW.h +35 -6
- data/vendor/faiss/faiss/impl/IDSelector.cpp +2 -2
- data/vendor/faiss/faiss/impl/IDSelector.h +4 -4
- data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +4 -4
- data/vendor/faiss/faiss/impl/LocalSearchQuantizer.h +1 -1
- data/vendor/faiss/faiss/impl/LookupTableScaler.h +1 -1
- data/vendor/faiss/faiss/impl/NNDescent.cpp +1 -1
- data/vendor/faiss/faiss/impl/NNDescent.h +2 -2
- data/vendor/faiss/faiss/impl/NSG.cpp +1 -1
- data/vendor/faiss/faiss/impl/Panorama.cpp +193 -0
- data/vendor/faiss/faiss/impl/Panorama.h +204 -0
- data/vendor/faiss/faiss/impl/PanoramaStats.cpp +33 -0
- data/vendor/faiss/faiss/impl/PanoramaStats.h +38 -0
- data/vendor/faiss/faiss/impl/PolysemousTraining.cpp +5 -5
- data/vendor/faiss/faiss/impl/ProductAdditiveQuantizer.cpp +1 -1
- data/vendor/faiss/faiss/impl/ProductAdditiveQuantizer.h +1 -1
- data/vendor/faiss/faiss/impl/ProductQuantizer-inl.h +2 -0
- data/vendor/faiss/faiss/impl/ProductQuantizer.h +1 -1
- data/vendor/faiss/faiss/impl/RaBitQStats.cpp +29 -0
- data/vendor/faiss/faiss/impl/RaBitQStats.h +56 -0
- data/vendor/faiss/faiss/impl/RaBitQUtils.cpp +294 -0
- data/vendor/faiss/faiss/impl/RaBitQUtils.h +330 -0
- data/vendor/faiss/faiss/impl/RaBitQuantizer.cpp +304 -223
- data/vendor/faiss/faiss/impl/RaBitQuantizer.h +72 -4
- data/vendor/faiss/faiss/impl/RaBitQuantizerMultiBit.cpp +362 -0
- data/vendor/faiss/faiss/impl/RaBitQuantizerMultiBit.h +112 -0
- data/vendor/faiss/faiss/impl/ResidualQuantizer.h +1 -1
- data/vendor/faiss/faiss/impl/ResultHandler.h +4 -4
- data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +7 -10
- data/vendor/faiss/faiss/impl/ScalarQuantizer.h +2 -4
- data/vendor/faiss/faiss/impl/ThreadedIndex-inl.h +7 -4
- data/vendor/faiss/faiss/impl/index_read.cpp +238 -10
- data/vendor/faiss/faiss/impl/index_write.cpp +212 -19
- data/vendor/faiss/faiss/impl/io.cpp +2 -2
- data/vendor/faiss/faiss/impl/io.h +4 -4
- data/vendor/faiss/faiss/impl/kmeans1d.cpp +1 -1
- data/vendor/faiss/faiss/impl/kmeans1d.h +1 -1
- data/vendor/faiss/faiss/impl/lattice_Zn.h +2 -2
- data/vendor/faiss/faiss/impl/mapped_io.cpp +2 -2
- data/vendor/faiss/faiss/impl/mapped_io.h +4 -3
- data/vendor/faiss/faiss/impl/maybe_owned_vector.h +8 -1
- data/vendor/faiss/faiss/impl/platform_macros.h +12 -0
- data/vendor/faiss/faiss/impl/pq4_fast_scan.cpp +30 -4
- data/vendor/faiss/faiss/impl/pq4_fast_scan.h +14 -8
- data/vendor/faiss/faiss/impl/pq4_fast_scan_search_qbs.cpp +5 -6
- data/vendor/faiss/faiss/impl/simd_result_handlers.h +55 -11
- data/vendor/faiss/faiss/impl/svs_io.cpp +86 -0
- data/vendor/faiss/faiss/impl/svs_io.h +67 -0
- data/vendor/faiss/faiss/impl/zerocopy_io.h +1 -1
- data/vendor/faiss/faiss/index_factory.cpp +217 -8
- data/vendor/faiss/faiss/index_factory.h +1 -1
- data/vendor/faiss/faiss/index_io.h +1 -1
- data/vendor/faiss/faiss/invlists/BlockInvertedLists.h +1 -1
- data/vendor/faiss/faiss/invlists/DirectMap.cpp +1 -1
- data/vendor/faiss/faiss/invlists/InvertedLists.cpp +115 -1
- data/vendor/faiss/faiss/invlists/InvertedLists.h +46 -0
- data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +1 -1
- data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.h +1 -1
- data/vendor/faiss/faiss/svs/IndexSVSFaissUtils.h +261 -0
- data/vendor/faiss/faiss/svs/IndexSVSFlat.cpp +117 -0
- data/vendor/faiss/faiss/svs/IndexSVSFlat.h +66 -0
- data/vendor/faiss/faiss/svs/IndexSVSVamana.cpp +245 -0
- data/vendor/faiss/faiss/svs/IndexSVSVamana.h +137 -0
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLVQ.cpp +39 -0
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLVQ.h +42 -0
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.cpp +149 -0
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.h +58 -0
- data/vendor/faiss/faiss/utils/AlignedTable.h +1 -1
- data/vendor/faiss/faiss/utils/Heap.cpp +2 -2
- data/vendor/faiss/faiss/utils/Heap.h +3 -3
- data/vendor/faiss/faiss/utils/NeuralNet.cpp +1 -1
- data/vendor/faiss/faiss/utils/NeuralNet.h +3 -3
- data/vendor/faiss/faiss/utils/approx_topk/approx_topk.h +2 -2
- data/vendor/faiss/faiss/utils/approx_topk/avx2-inl.h +2 -2
- data/vendor/faiss/faiss/utils/approx_topk/mode.h +1 -1
- data/vendor/faiss/faiss/utils/distances.cpp +0 -3
- data/vendor/faiss/faiss/utils/distances.h +2 -2
- data/vendor/faiss/faiss/utils/extra_distances-inl.h +3 -1
- data/vendor/faiss/faiss/utils/hamming-inl.h +2 -0
- data/vendor/faiss/faiss/utils/hamming.cpp +7 -6
- data/vendor/faiss/faiss/utils/hamming.h +1 -1
- data/vendor/faiss/faiss/utils/hamming_distance/common.h +1 -2
- data/vendor/faiss/faiss/utils/partitioning.cpp +5 -5
- data/vendor/faiss/faiss/utils/partitioning.h +2 -2
- data/vendor/faiss/faiss/utils/rabitq_simd.h +222 -336
- data/vendor/faiss/faiss/utils/random.cpp +1 -1
- data/vendor/faiss/faiss/utils/simdlib_avx2.h +1 -1
- data/vendor/faiss/faiss/utils/simdlib_avx512.h +1 -1
- data/vendor/faiss/faiss/utils/simdlib_neon.h +2 -2
- data/vendor/faiss/faiss/utils/transpose/transpose-avx512-inl.h +1 -1
- data/vendor/faiss/faiss/utils/utils.cpp +9 -2
- data/vendor/faiss/faiss/utils/utils.h +2 -2
- metadata +29 -1
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
#include <vector>
|
|
14
14
|
|
|
15
15
|
#include <faiss/IndexFlatCodes.h>
|
|
16
|
+
#include <faiss/impl/Panorama.h>
|
|
16
17
|
|
|
17
18
|
namespace faiss {
|
|
18
19
|
|
|
@@ -66,7 +67,7 @@ struct IndexFlat : IndexFlatCodes {
|
|
|
66
67
|
|
|
67
68
|
FlatCodesDistanceComputer* get_FlatCodesDistanceComputer() const override;
|
|
68
69
|
|
|
69
|
-
/* The
|
|
70
|
+
/* The standalone codec interface (just memcopies in this case) */
|
|
70
71
|
void sa_encode(idx_t n, const float* x, uint8_t* bytes) const override;
|
|
71
72
|
|
|
72
73
|
void sa_decode(idx_t n, const uint8_t* bytes, float* x) const override;
|
|
@@ -99,6 +100,85 @@ struct IndexFlatL2 : IndexFlat {
|
|
|
99
100
|
void clear_l2norms();
|
|
100
101
|
};
|
|
101
102
|
|
|
103
|
+
struct IndexFlatPanorama : IndexFlat {
|
|
104
|
+
const size_t batch_size;
|
|
105
|
+
const size_t n_levels;
|
|
106
|
+
std::vector<float> cum_sums;
|
|
107
|
+
Panorama pano;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* @param d dimensionality of the input vectors
|
|
111
|
+
* @param metric metric type
|
|
112
|
+
* @param n_levels number of Panorama levels
|
|
113
|
+
* @param batch_size batch size for Panorama storage
|
|
114
|
+
*/
|
|
115
|
+
explicit IndexFlatPanorama(
|
|
116
|
+
idx_t d,
|
|
117
|
+
MetricType metric,
|
|
118
|
+
size_t n_levels,
|
|
119
|
+
size_t batch_size)
|
|
120
|
+
: IndexFlat(d, metric),
|
|
121
|
+
batch_size(batch_size),
|
|
122
|
+
n_levels(n_levels),
|
|
123
|
+
pano(code_size, n_levels, batch_size) {
|
|
124
|
+
FAISS_THROW_IF_NOT(metric == METRIC_L2);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
void add(idx_t n, const float* x) override;
|
|
128
|
+
|
|
129
|
+
void search(
|
|
130
|
+
idx_t n,
|
|
131
|
+
const float* x,
|
|
132
|
+
idx_t k,
|
|
133
|
+
float* distances,
|
|
134
|
+
idx_t* labels,
|
|
135
|
+
const SearchParameters* params = nullptr) const override;
|
|
136
|
+
|
|
137
|
+
void range_search(
|
|
138
|
+
idx_t n,
|
|
139
|
+
const float* x,
|
|
140
|
+
float radius,
|
|
141
|
+
RangeSearchResult* result,
|
|
142
|
+
const SearchParameters* params = nullptr) const override;
|
|
143
|
+
|
|
144
|
+
void search_subset(
|
|
145
|
+
idx_t n,
|
|
146
|
+
const float* x,
|
|
147
|
+
idx_t k_base,
|
|
148
|
+
const idx_t* base_labels,
|
|
149
|
+
idx_t k,
|
|
150
|
+
float* distances,
|
|
151
|
+
idx_t* labels) const override;
|
|
152
|
+
|
|
153
|
+
void reset() override;
|
|
154
|
+
|
|
155
|
+
void reconstruct(idx_t key, float* recons) const override;
|
|
156
|
+
|
|
157
|
+
void reconstruct_n(idx_t i, idx_t n, float* recons) const override;
|
|
158
|
+
|
|
159
|
+
size_t remove_ids(const IDSelector& sel) override;
|
|
160
|
+
|
|
161
|
+
void merge_from(Index& otherIndex, idx_t add_id) override;
|
|
162
|
+
|
|
163
|
+
void add_sa_codes(idx_t n, const uint8_t* codes_in, const idx_t* xids)
|
|
164
|
+
override;
|
|
165
|
+
|
|
166
|
+
void permute_entries(const idx_t* perm);
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
struct IndexFlatL2Panorama : IndexFlatPanorama {
|
|
170
|
+
/**
|
|
171
|
+
* @param d dimensionality of the input vectors
|
|
172
|
+
* @param n_levels number of Panorama levels
|
|
173
|
+
* @param batch_size batch size for Panorama storage
|
|
174
|
+
*/
|
|
175
|
+
explicit IndexFlatL2Panorama(
|
|
176
|
+
idx_t d,
|
|
177
|
+
size_t n_levels,
|
|
178
|
+
size_t batch_size = 512)
|
|
179
|
+
: IndexFlatPanorama(d, METRIC_L2, n_levels, batch_size) {}
|
|
180
|
+
};
|
|
181
|
+
|
|
102
182
|
/// optimized version for 1D "vectors".
|
|
103
183
|
struct IndexFlat1D : IndexFlatL2 {
|
|
104
184
|
bool continuous_update = true; ///< is the permutation updated continuously?
|
|
@@ -276,7 +276,7 @@ void hnsw_search(
|
|
|
276
276
|
res.begin(i);
|
|
277
277
|
dis->set_query(x + i * index->d);
|
|
278
278
|
|
|
279
|
-
HNSWStats stats = hnsw.search(*dis, res, vt, params);
|
|
279
|
+
HNSWStats stats = hnsw.search(*dis, index, res, vt, params);
|
|
280
280
|
n1 += stats.n1;
|
|
281
281
|
n2 += stats.n2;
|
|
282
282
|
ndis += stats.ndis;
|
|
@@ -450,7 +450,9 @@ void IndexHNSW::search_level_0(
|
|
|
450
450
|
vt.advance();
|
|
451
451
|
}
|
|
452
452
|
#pragma omp critical
|
|
453
|
-
{
|
|
453
|
+
{
|
|
454
|
+
hnsw_stats.combine(search_stats);
|
|
455
|
+
}
|
|
454
456
|
}
|
|
455
457
|
if (is_similarity_metric(this->metric_type)) {
|
|
456
458
|
// we need to revert the negated distances
|
|
@@ -647,6 +649,95 @@ IndexHNSWFlat::IndexHNSWFlat(int d, int M, MetricType metric)
|
|
|
647
649
|
is_trained = true;
|
|
648
650
|
}
|
|
649
651
|
|
|
652
|
+
/**************************************************************
|
|
653
|
+
* IndexHNSWFlatPanorama implementation
|
|
654
|
+
**************************************************************/
|
|
655
|
+
|
|
656
|
+
void IndexHNSWFlatPanorama::compute_cum_sums(
|
|
657
|
+
const float* x,
|
|
658
|
+
float* dst_cum_sums,
|
|
659
|
+
int d,
|
|
660
|
+
int num_panorama_levels,
|
|
661
|
+
int panorama_level_width) {
|
|
662
|
+
// Iterate backwards through levels, accumulating sum as we go.
|
|
663
|
+
// This avoids computing the suffix sum for each vector, which takes
|
|
664
|
+
// extra memory.
|
|
665
|
+
|
|
666
|
+
float sum = 0.0f;
|
|
667
|
+
dst_cum_sums[num_panorama_levels] = 0.0f;
|
|
668
|
+
for (int level = num_panorama_levels - 1; level >= 0; level--) {
|
|
669
|
+
int start_idx = level * panorama_level_width;
|
|
670
|
+
int end_idx = std::min(start_idx + panorama_level_width, d);
|
|
671
|
+
for (int j = start_idx; j < end_idx; j++) {
|
|
672
|
+
sum += x[j] * x[j];
|
|
673
|
+
}
|
|
674
|
+
dst_cum_sums[level] = std::sqrt(sum);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
IndexHNSWFlatPanorama::IndexHNSWFlatPanorama()
|
|
679
|
+
: IndexHNSWFlat(),
|
|
680
|
+
cum_sums(),
|
|
681
|
+
panorama_level_width(0),
|
|
682
|
+
num_panorama_levels(0) {}
|
|
683
|
+
|
|
684
|
+
IndexHNSWFlatPanorama::IndexHNSWFlatPanorama(
|
|
685
|
+
int d,
|
|
686
|
+
int M,
|
|
687
|
+
int num_panorama_levels,
|
|
688
|
+
MetricType metric)
|
|
689
|
+
: IndexHNSWFlat(d, M, metric),
|
|
690
|
+
cum_sums(),
|
|
691
|
+
panorama_level_width(
|
|
692
|
+
(d + num_panorama_levels - 1) / num_panorama_levels),
|
|
693
|
+
num_panorama_levels(num_panorama_levels) {
|
|
694
|
+
// For now, we only support L2 distance.
|
|
695
|
+
// Supporting dot product and cosine distance is a trivial addition
|
|
696
|
+
// left for future work.
|
|
697
|
+
FAISS_THROW_IF_NOT(metric == METRIC_L2);
|
|
698
|
+
|
|
699
|
+
// Enable Panorama search mode.
|
|
700
|
+
// This is not ideal, but is still more simple than making a subclass of
|
|
701
|
+
// HNSW and overriding the search logic.
|
|
702
|
+
hnsw.is_panorama = true;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
void IndexHNSWFlatPanorama::add(idx_t n, const float* x) {
|
|
706
|
+
idx_t n0 = ntotal;
|
|
707
|
+
cum_sums.resize((ntotal + n) * (num_panorama_levels + 1));
|
|
708
|
+
|
|
709
|
+
for (size_t idx = 0; idx < n; idx++) {
|
|
710
|
+
const float* vector = x + idx * d;
|
|
711
|
+
compute_cum_sums(
|
|
712
|
+
vector,
|
|
713
|
+
&cum_sums[(n0 + idx) * (num_panorama_levels + 1)],
|
|
714
|
+
d,
|
|
715
|
+
num_panorama_levels,
|
|
716
|
+
panorama_level_width);
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
IndexHNSWFlat::add(n, x);
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
void IndexHNSWFlatPanorama::reset() {
|
|
723
|
+
cum_sums.clear();
|
|
724
|
+
IndexHNSWFlat::reset();
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
void IndexHNSWFlatPanorama::permute_entries(const idx_t* perm) {
|
|
728
|
+
std::vector<float> new_cum_sums(ntotal * (num_panorama_levels + 1));
|
|
729
|
+
|
|
730
|
+
for (idx_t i = 0; i < ntotal; i++) {
|
|
731
|
+
idx_t src = perm[i];
|
|
732
|
+
memcpy(&new_cum_sums[i * (num_panorama_levels + 1)],
|
|
733
|
+
&cum_sums[src * (num_panorama_levels + 1)],
|
|
734
|
+
(num_panorama_levels + 1) * sizeof(float));
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
std::swap(cum_sums, new_cum_sums);
|
|
738
|
+
IndexHNSWFlat::permute_entries(perm);
|
|
739
|
+
}
|
|
740
|
+
|
|
650
741
|
/**************************************************************
|
|
651
742
|
* IndexHNSWPQ implementation
|
|
652
743
|
**************************************************************/
|
|
@@ -43,7 +43,7 @@ struct IndexHNSW : Index {
|
|
|
43
43
|
|
|
44
44
|
// When set to true, all neighbors in level 0 are filled up
|
|
45
45
|
// to the maximum size allowed (2 * M). This option is used by
|
|
46
|
-
//
|
|
46
|
+
// IndexHNSWCagra to create a full base layer graph that is
|
|
47
47
|
// used when GpuIndexCagra::copyFrom(IndexHNSWCagra*) is invoked.
|
|
48
48
|
bool keep_max_size_level0 = false;
|
|
49
49
|
|
|
@@ -111,7 +111,7 @@ struct IndexHNSW : Index {
|
|
|
111
111
|
|
|
112
112
|
void link_singletons();
|
|
113
113
|
|
|
114
|
-
void permute_entries(const idx_t* perm);
|
|
114
|
+
virtual void permute_entries(const idx_t* perm);
|
|
115
115
|
|
|
116
116
|
DistanceComputer* get_distance_computer() const override;
|
|
117
117
|
};
|
|
@@ -125,6 +125,62 @@ struct IndexHNSWFlat : IndexHNSW {
|
|
|
125
125
|
IndexHNSWFlat(int d, int M, MetricType metric = METRIC_L2);
|
|
126
126
|
};
|
|
127
127
|
|
|
128
|
+
/** Panorama implementation of IndexHNSWFlat following
|
|
129
|
+
* https://www.arxiv.org/pdf/2510.00566.
|
|
130
|
+
*
|
|
131
|
+
* Unlike cluster-based Panorama, the vectors have to be higher dimensional
|
|
132
|
+
* (i.e. typically d > 512) and/or be able to compress a lot of their energy in
|
|
133
|
+
* the early dimensions to be effective. This is because HNSW accesses vectors
|
|
134
|
+
* in a random order, which makes cache misses dominate the distance computation
|
|
135
|
+
* time.
|
|
136
|
+
*
|
|
137
|
+
* The `num_panorama_levels` parameter controls the granularity of progressive
|
|
138
|
+
* distance refinement, allowing candidates to be eliminated early using partial
|
|
139
|
+
* distance computations rather than computing full distances.
|
|
140
|
+
*
|
|
141
|
+
* NOTE: This version of HNSW handles search slightly differently than the
|
|
142
|
+
* vanilla HNSW, as it uses partial distance computations with progressive
|
|
143
|
+
* refinement bounds. Instead of computing full distances immediately for all
|
|
144
|
+
* candidates, Panorama maintains lower and upper bounds that are incrementally
|
|
145
|
+
* tightened across refinement levels. Candidates are inserted into the search
|
|
146
|
+
* beam using approximate distance estimates (LB+UB)/2 and are only fully
|
|
147
|
+
* evaluated when they survive pruning and enter the result heap. This allows
|
|
148
|
+
* the algorithm to prune unpromising candidates early using Cauchy-Schwarz
|
|
149
|
+
* bounds on partial inner products. Hence, recall is not guaranteed to be the
|
|
150
|
+
* same as vanilla HNSW due to the heterogeneous precision within the search
|
|
151
|
+
* beam (exact vs. partial distance estimates affecting traversal order).
|
|
152
|
+
*/
|
|
153
|
+
struct IndexHNSWFlatPanorama : IndexHNSWFlat {
|
|
154
|
+
IndexHNSWFlatPanorama();
|
|
155
|
+
IndexHNSWFlatPanorama(
|
|
156
|
+
int d,
|
|
157
|
+
int M,
|
|
158
|
+
int num_panorama_levels,
|
|
159
|
+
MetricType metric = METRIC_L2);
|
|
160
|
+
|
|
161
|
+
void add(idx_t n, const float* x) override;
|
|
162
|
+
void reset() override;
|
|
163
|
+
void permute_entries(const idx_t* perm) override;
|
|
164
|
+
|
|
165
|
+
/// Inline for performance - called frequently in search hot path.
|
|
166
|
+
const float* get_cum_sum(idx_t i) const {
|
|
167
|
+
return cum_sums.data() + i * (num_panorama_levels + 1);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/// Compute cumulative sums for a vector (used both for database points and
|
|
171
|
+
/// queries).
|
|
172
|
+
static void compute_cum_sums(
|
|
173
|
+
const float* x,
|
|
174
|
+
float* dst_cum_sums,
|
|
175
|
+
int d,
|
|
176
|
+
int num_panorama_levels,
|
|
177
|
+
int panorama_level_width);
|
|
178
|
+
|
|
179
|
+
std::vector<float> cum_sums;
|
|
180
|
+
const size_t panorama_level_width;
|
|
181
|
+
const size_t num_panorama_levels;
|
|
182
|
+
};
|
|
183
|
+
|
|
128
184
|
/** PQ index topped with with a HNSW structure to access elements
|
|
129
185
|
* more efficiently.
|
|
130
186
|
*/
|
|
@@ -59,7 +59,7 @@ IndexIDMapTemplate<IndexT>::IndexIDMapTemplate(IndexT* index) : index(index) {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
template <typename IndexT>
|
|
62
|
-
void IndexIDMapTemplate<IndexT>::
|
|
62
|
+
void IndexIDMapTemplate<IndexT>::add_ex(
|
|
63
63
|
idx_t,
|
|
64
64
|
const void*,
|
|
65
65
|
NumericType numeric_type) {
|
|
@@ -78,11 +78,11 @@ void IndexIDMapTemplate<IndexT>::add(
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
template <typename IndexT>
|
|
81
|
-
void IndexIDMapTemplate<IndexT>::
|
|
81
|
+
void IndexIDMapTemplate<IndexT>::train_ex(
|
|
82
82
|
idx_t n,
|
|
83
83
|
const void* x,
|
|
84
84
|
NumericType numeric_type) {
|
|
85
|
-
index->
|
|
85
|
+
index->train_ex(n, x, numeric_type);
|
|
86
86
|
this->is_trained = index->is_trained;
|
|
87
87
|
}
|
|
88
88
|
|
|
@@ -90,7 +90,8 @@ template <typename IndexT>
|
|
|
90
90
|
void IndexIDMapTemplate<IndexT>::train(
|
|
91
91
|
idx_t n,
|
|
92
92
|
const typename IndexT::component_t* x) {
|
|
93
|
-
|
|
93
|
+
train_ex(
|
|
94
|
+
n,
|
|
94
95
|
static_cast<const void*>(x),
|
|
95
96
|
component_t_to_numeric<typename IndexT::component_t>());
|
|
96
97
|
}
|
|
@@ -103,12 +104,12 @@ void IndexIDMapTemplate<IndexT>::reset() {
|
|
|
103
104
|
}
|
|
104
105
|
|
|
105
106
|
template <typename IndexT>
|
|
106
|
-
void IndexIDMapTemplate<IndexT>::
|
|
107
|
+
void IndexIDMapTemplate<IndexT>::add_with_ids_ex(
|
|
107
108
|
idx_t n,
|
|
108
109
|
const void* x,
|
|
109
110
|
NumericType numeric_type,
|
|
110
111
|
const idx_t* xids) {
|
|
111
|
-
index->
|
|
112
|
+
index->add_ex(n, x, numeric_type);
|
|
112
113
|
for (idx_t i = 0; i < n; i++) {
|
|
113
114
|
id_map.push_back(xids[i]);
|
|
114
115
|
}
|
|
@@ -120,7 +121,7 @@ void IndexIDMapTemplate<IndexT>::add_with_ids(
|
|
|
120
121
|
idx_t n,
|
|
121
122
|
const typename IndexT::component_t* x,
|
|
122
123
|
const idx_t* xids) {
|
|
123
|
-
|
|
124
|
+
add_with_ids_ex(
|
|
124
125
|
n,
|
|
125
126
|
static_cast<const void*>(x),
|
|
126
127
|
component_t_to_numeric<typename IndexT::component_t>(),
|
|
@@ -166,7 +167,7 @@ struct ScopedSelChange {
|
|
|
166
167
|
} // namespace
|
|
167
168
|
|
|
168
169
|
template <typename IndexT>
|
|
169
|
-
void IndexIDMapTemplate<IndexT>::
|
|
170
|
+
void IndexIDMapTemplate<IndexT>::search_ex(
|
|
170
171
|
idx_t n,
|
|
171
172
|
const void* x,
|
|
172
173
|
NumericType numeric_type,
|
|
@@ -193,7 +194,7 @@ void IndexIDMapTemplate<IndexT>::searchEx(
|
|
|
193
194
|
sel_change.set(params_non_const, &this_idtrans);
|
|
194
195
|
}
|
|
195
196
|
}
|
|
196
|
-
index->
|
|
197
|
+
index->search_ex(n, x, numeric_type, k, distances, labels, params);
|
|
197
198
|
idx_t* li = labels;
|
|
198
199
|
#pragma omp parallel for
|
|
199
200
|
for (idx_t i = 0; i < n * k; i++) {
|
|
@@ -209,7 +210,7 @@ void IndexIDMapTemplate<IndexT>::search(
|
|
|
209
210
|
typename IndexT::distance_t* distances,
|
|
210
211
|
idx_t* labels,
|
|
211
212
|
const SearchParameters* params) const {
|
|
212
|
-
|
|
213
|
+
search_ex(
|
|
213
214
|
n,
|
|
214
215
|
static_cast<const void*>(x),
|
|
215
216
|
component_t_to_numeric<typename IndexT::component_t>(),
|
|
@@ -301,13 +302,13 @@ IndexIDMap2Template<IndexT>::IndexIDMap2Template(IndexT* index)
|
|
|
301
302
|
: IndexIDMapTemplate<IndexT>(index) {}
|
|
302
303
|
|
|
303
304
|
template <typename IndexT>
|
|
304
|
-
void IndexIDMap2Template<IndexT>::
|
|
305
|
+
void IndexIDMap2Template<IndexT>::add_with_ids_ex(
|
|
305
306
|
idx_t n,
|
|
306
307
|
const void* x,
|
|
307
308
|
NumericType numeric_type,
|
|
308
309
|
const idx_t* xids) {
|
|
309
310
|
size_t prev_ntotal = this->ntotal;
|
|
310
|
-
IndexIDMapTemplate<IndexT>::
|
|
311
|
+
IndexIDMapTemplate<IndexT>::add_with_ids_ex(n, x, numeric_type, xids);
|
|
311
312
|
for (size_t i = prev_ntotal; i < this->ntotal; i++) {
|
|
312
313
|
rev_map[this->id_map[i]] = i;
|
|
313
314
|
}
|
|
@@ -318,7 +319,7 @@ void IndexIDMap2Template<IndexT>::add_with_ids(
|
|
|
318
319
|
idx_t n,
|
|
319
320
|
const typename IndexT::component_t* x,
|
|
320
321
|
const idx_t* xids) {
|
|
321
|
-
|
|
322
|
+
add_with_ids_ex(
|
|
322
323
|
n,
|
|
323
324
|
static_cast<const void*>(x),
|
|
324
325
|
component_t_to_numeric<typename IndexT::component_t>(),
|
|
@@ -23,7 +23,7 @@ struct IndexIDMapTemplate : IndexT {
|
|
|
23
23
|
using distance_t = typename IndexT::distance_t;
|
|
24
24
|
|
|
25
25
|
IndexT* index = nullptr; ///! the sub-index
|
|
26
|
-
bool own_fields = false; ///! whether pointers are deleted in
|
|
26
|
+
bool own_fields = false; ///! whether pointers are deleted in destructor
|
|
27
27
|
std::vector<idx_t> id_map;
|
|
28
28
|
|
|
29
29
|
explicit IndexIDMapTemplate(IndexT* index);
|
|
@@ -31,7 +31,7 @@ struct IndexIDMapTemplate : IndexT {
|
|
|
31
31
|
/// @param xids if non-null, ids to store for the vectors (size n)
|
|
32
32
|
void add_with_ids(idx_t n, const component_t* x, const idx_t* xids)
|
|
33
33
|
override;
|
|
34
|
-
void
|
|
34
|
+
void add_with_ids_ex(
|
|
35
35
|
idx_t n,
|
|
36
36
|
const void* x,
|
|
37
37
|
NumericType numeric_type,
|
|
@@ -39,7 +39,7 @@ struct IndexIDMapTemplate : IndexT {
|
|
|
39
39
|
|
|
40
40
|
/// this will fail. Use add_with_ids
|
|
41
41
|
void add(idx_t n, const component_t* x) override;
|
|
42
|
-
void
|
|
42
|
+
void add_ex(idx_t n, const void* x, NumericType numeric_type) override;
|
|
43
43
|
|
|
44
44
|
void search(
|
|
45
45
|
idx_t n,
|
|
@@ -48,7 +48,7 @@ struct IndexIDMapTemplate : IndexT {
|
|
|
48
48
|
distance_t* distances,
|
|
49
49
|
idx_t* labels,
|
|
50
50
|
const SearchParameters* params = nullptr) const override;
|
|
51
|
-
void
|
|
51
|
+
void search_ex(
|
|
52
52
|
idx_t n,
|
|
53
53
|
const void* x,
|
|
54
54
|
NumericType numeric_type,
|
|
@@ -58,7 +58,7 @@ struct IndexIDMapTemplate : IndexT {
|
|
|
58
58
|
const SearchParameters* params = nullptr) const override;
|
|
59
59
|
|
|
60
60
|
void train(idx_t n, const component_t* x) override;
|
|
61
|
-
void
|
|
61
|
+
void train_ex(idx_t n, const void* x, NumericType numeric_type) override;
|
|
62
62
|
|
|
63
63
|
void reset() override;
|
|
64
64
|
|
|
@@ -104,7 +104,7 @@ struct IndexIDMap2Template : IndexIDMapTemplate<IndexT> {
|
|
|
104
104
|
|
|
105
105
|
void add_with_ids(idx_t n, const component_t* x, const idx_t* xids)
|
|
106
106
|
override;
|
|
107
|
-
void
|
|
107
|
+
void add_with_ids_ex(
|
|
108
108
|
idx_t n,
|
|
109
109
|
const void* x,
|
|
110
110
|
NumericType numeric_type,
|
|
@@ -506,7 +506,7 @@ void IndexIVF::search_preassigned(
|
|
|
506
506
|
};
|
|
507
507
|
|
|
508
508
|
// single list scan using the current scanner (with query
|
|
509
|
-
// set
|
|
509
|
+
// set properly) and storing results in simi and idxi
|
|
510
510
|
auto scan_one_list = [&](idx_t key,
|
|
511
511
|
float coarse_dis_i,
|
|
512
512
|
float* simi,
|
|
@@ -160,7 +160,7 @@ struct IndexIVFInterface : Level1Quantizer {
|
|
|
160
160
|
* index maps to a list (aka inverted list or posting list), where the
|
|
161
161
|
* id of the vector is stored.
|
|
162
162
|
*
|
|
163
|
-
* The inverted list object is required only after
|
|
163
|
+
* The inverted list object is required only after training. If none is
|
|
164
164
|
* set externally, an ArrayInvertedLists is used automatically.
|
|
165
165
|
*
|
|
166
166
|
* At search time, the vector to be searched is also quantized, and
|
|
@@ -171,7 +171,7 @@ struct IndexIVFInterface : Level1Quantizer {
|
|
|
171
171
|
* lists are visited.
|
|
172
172
|
*
|
|
173
173
|
* Sub-classes implement a post-filtering of the index that refines
|
|
174
|
-
* the distance estimation from the query to
|
|
174
|
+
* the distance estimation from the query to database vectors.
|
|
175
175
|
*/
|
|
176
176
|
struct IndexIVF : Index, IndexIVFInterface {
|
|
177
177
|
/// Access to the actual data
|
|
@@ -497,12 +497,12 @@ struct InvertedListScanner {
|
|
|
497
497
|
/// compute a single query-to-code distance
|
|
498
498
|
virtual float distance_to_code(const uint8_t* code) const = 0;
|
|
499
499
|
|
|
500
|
-
/** scan a set of codes, compute distances to current query and
|
|
500
|
+
/** scan a set of codes, compute distances to current query, and
|
|
501
501
|
* update heap of results if necessary. Default implementation
|
|
502
502
|
* calls distance_to_code.
|
|
503
503
|
*
|
|
504
|
-
* @param n
|
|
505
|
-
* @param codes
|
|
504
|
+
* @param n number of codes to scan
|
|
505
|
+
* @param codes codes to scan (n * code_size)
|
|
506
506
|
* @param ids corresponding ids (ignored if store_pairs)
|
|
507
507
|
* @param distances heap distances (size k)
|
|
508
508
|
* @param labels heap labels (size k)
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
#include <faiss/impl/AuxIndexStructures.h>
|
|
16
16
|
#include <faiss/impl/FaissAssert.h>
|
|
17
|
+
#include <faiss/impl/FastScanDistancePostProcessing.h>
|
|
17
18
|
#include <faiss/impl/LookupTableScaler.h>
|
|
18
19
|
#include <faiss/impl/pq4_fast_scan.h>
|
|
19
20
|
#include <faiss/invlists/BlockInvertedLists.h>
|
|
@@ -212,7 +213,9 @@ void IndexIVFAdditiveQuantizerFastScan::estimate_norm_scale(
|
|
|
212
213
|
size_t index_nprobe = nprobe;
|
|
213
214
|
nprobe = 1;
|
|
214
215
|
CoarseQuantized cq{index_nprobe, coarse_dis.data(), coarse_ids.data()};
|
|
215
|
-
|
|
216
|
+
FastScanDistancePostProcessing empty_context{};
|
|
217
|
+
|
|
218
|
+
compute_LUT(n, x, cq, dis_tables, biases, empty_context);
|
|
216
219
|
nprobe = index_nprobe;
|
|
217
220
|
|
|
218
221
|
float scale = 0;
|
|
@@ -314,8 +317,10 @@ void IndexIVFAdditiveQuantizerFastScan::search(
|
|
|
314
317
|
}
|
|
315
318
|
|
|
316
319
|
NormTableScaler scaler(norm_scale);
|
|
320
|
+
FastScanDistancePostProcessing context;
|
|
321
|
+
context.norm_scaler = &scaler;
|
|
317
322
|
IndexIVFFastScan::CoarseQuantized cq{nprobe};
|
|
318
|
-
search_dispatch_implem(n, x, k, distances, labels, cq,
|
|
323
|
+
search_dispatch_implem(n, x, k, distances, labels, cq, context);
|
|
319
324
|
}
|
|
320
325
|
|
|
321
326
|
/*********************************************************
|
|
@@ -383,7 +388,8 @@ void IndexIVFAdditiveQuantizerFastScan::compute_LUT(
|
|
|
383
388
|
const float* x,
|
|
384
389
|
const CoarseQuantized& cq,
|
|
385
390
|
AlignedTable<float>& dis_tables,
|
|
386
|
-
AlignedTable<float>& biases
|
|
391
|
+
AlignedTable<float>& biases,
|
|
392
|
+
const FastScanDistancePostProcessing&) const {
|
|
387
393
|
const size_t dim12 = ksub * M;
|
|
388
394
|
const size_t ip_dim12 = aq->M * ksub;
|
|
389
395
|
const size_t nprobe = cq.nprobe;
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
#include <faiss/IndexIVFAdditiveQuantizer.h>
|
|
13
13
|
#include <faiss/IndexIVFFastScan.h>
|
|
14
14
|
#include <faiss/impl/AdditiveQuantizer.h>
|
|
15
|
+
#include <faiss/impl/FastScanDistancePostProcessing.h>
|
|
15
16
|
#include <faiss/impl/ProductAdditiveQuantizer.h>
|
|
16
17
|
#include <faiss/utils/AlignedTable.h>
|
|
17
18
|
|
|
@@ -101,7 +102,8 @@ struct IndexIVFAdditiveQuantizerFastScan : IndexIVFFastScan {
|
|
|
101
102
|
const float* x,
|
|
102
103
|
const CoarseQuantized& cq,
|
|
103
104
|
AlignedTable<float>& dis_tables,
|
|
104
|
-
AlignedTable<float>& biases
|
|
105
|
+
AlignedTable<float>& biases,
|
|
106
|
+
const FastScanDistancePostProcessing& context) const override;
|
|
105
107
|
};
|
|
106
108
|
|
|
107
109
|
struct IndexIVFLocalSearchQuantizerFastScan
|