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
|
@@ -0,0 +1,882 @@
|
|
|
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/impl/EDENQuantizer.h>
|
|
9
|
+
|
|
10
|
+
#include <faiss/impl/FaissAssert.h>
|
|
11
|
+
#include <faiss/impl/simd_dispatch.h>
|
|
12
|
+
#include <faiss/utils/distances.h>
|
|
13
|
+
#include <faiss/utils/hamming.h>
|
|
14
|
+
#include <algorithm>
|
|
15
|
+
#include <cmath>
|
|
16
|
+
#include <cstring>
|
|
17
|
+
#include <limits>
|
|
18
|
+
#include <memory>
|
|
19
|
+
#include <vector>
|
|
20
|
+
|
|
21
|
+
namespace faiss {
|
|
22
|
+
|
|
23
|
+
namespace eden_distance {
|
|
24
|
+
|
|
25
|
+
namespace {
|
|
26
|
+
|
|
27
|
+
enum class CodeDotLUTKind {
|
|
28
|
+
None,
|
|
29
|
+
Byte,
|
|
30
|
+
HalfByte,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
using CodeDotLUTBatch8Fn = void (*)(
|
|
34
|
+
const uint8_t* const code[8],
|
|
35
|
+
const float* lut,
|
|
36
|
+
int lut_kind,
|
|
37
|
+
size_t packed_size,
|
|
38
|
+
float dots[8]);
|
|
39
|
+
|
|
40
|
+
using CodeDotLUTBatch16Fn = void (*)(
|
|
41
|
+
const uint8_t* const code[16],
|
|
42
|
+
const float* lut,
|
|
43
|
+
int lut_kind,
|
|
44
|
+
size_t packed_size,
|
|
45
|
+
float dots[16]);
|
|
46
|
+
|
|
47
|
+
float compute_code_dot_reference(
|
|
48
|
+
const uint8_t* code,
|
|
49
|
+
const float* query,
|
|
50
|
+
size_t d,
|
|
51
|
+
size_t nb_bits,
|
|
52
|
+
const float* scalar_centroids) {
|
|
53
|
+
BitstringReader reader(code, eden_utils::packed_code_size(d, nb_bits));
|
|
54
|
+
float dot = 0.0f;
|
|
55
|
+
for (size_t i = 0; i < d; i++) {
|
|
56
|
+
dot += query[i] * scalar_centroids[reader.read(nb_bits)];
|
|
57
|
+
}
|
|
58
|
+
return dot;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
bool supports_byte_lut(size_t nb_bits) {
|
|
62
|
+
return nb_bits == 1 || nb_bits == 2 || nb_bits == 4 || nb_bits == 8;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
bool use_half_byte_lut(size_t nb_bits, size_t num_bytes) {
|
|
66
|
+
if (nb_bits == 1) {
|
|
67
|
+
return num_bytes >= 32;
|
|
68
|
+
}
|
|
69
|
+
if (nb_bits == 2) {
|
|
70
|
+
return num_bytes >= 16;
|
|
71
|
+
}
|
|
72
|
+
if (nb_bits == 4) {
|
|
73
|
+
return num_bytes >= 128;
|
|
74
|
+
}
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
void build_code_dot_lut(
|
|
79
|
+
const float* query,
|
|
80
|
+
size_t d,
|
|
81
|
+
size_t nb_bits,
|
|
82
|
+
const float* scalar_centroids,
|
|
83
|
+
std::vector<float>& lut,
|
|
84
|
+
CodeDotLUTKind& lut_kind) {
|
|
85
|
+
if (!supports_byte_lut(nb_bits)) {
|
|
86
|
+
lut.clear();
|
|
87
|
+
lut_kind = CodeDotLUTKind::None;
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const size_t values_per_byte = 8 / nb_bits;
|
|
92
|
+
const size_t num_bytes = (d + values_per_byte - 1) / values_per_byte;
|
|
93
|
+
const uint8_t mask = static_cast<uint8_t>((1u << nb_bits) - 1);
|
|
94
|
+
|
|
95
|
+
if (use_half_byte_lut(nb_bits, num_bytes)) {
|
|
96
|
+
lut_kind = CodeDotLUTKind::HalfByte;
|
|
97
|
+
lut.resize(num_bytes * 32);
|
|
98
|
+
|
|
99
|
+
if (nb_bits == 1) {
|
|
100
|
+
for (size_t byte_no = 0; byte_no < num_bytes; byte_no++) {
|
|
101
|
+
const size_t dim0 = byte_no * 8;
|
|
102
|
+
float* table = lut.data() + byte_no * 32;
|
|
103
|
+
const float q0 = dim0 < d ? query[dim0] : 0.0f;
|
|
104
|
+
const float q1 = dim0 + 1 < d ? query[dim0 + 1] : 0.0f;
|
|
105
|
+
const float q2 = dim0 + 2 < d ? query[dim0 + 2] : 0.0f;
|
|
106
|
+
const float q3 = dim0 + 3 < d ? query[dim0 + 3] : 0.0f;
|
|
107
|
+
const float q4 = dim0 + 4 < d ? query[dim0 + 4] : 0.0f;
|
|
108
|
+
const float q5 = dim0 + 5 < d ? query[dim0 + 5] : 0.0f;
|
|
109
|
+
const float q6 = dim0 + 6 < d ? query[dim0 + 6] : 0.0f;
|
|
110
|
+
const float q7 = dim0 + 7 < d ? query[dim0 + 7] : 0.0f;
|
|
111
|
+
for (size_t half_byte_value = 0; half_byte_value < 16;
|
|
112
|
+
half_byte_value++) {
|
|
113
|
+
const float c0 = scalar_centroids[half_byte_value & 0x01];
|
|
114
|
+
const float c1 =
|
|
115
|
+
scalar_centroids[(half_byte_value >> 1) & 0x01];
|
|
116
|
+
const float c2 =
|
|
117
|
+
scalar_centroids[(half_byte_value >> 2) & 0x01];
|
|
118
|
+
const float c3 =
|
|
119
|
+
scalar_centroids[(half_byte_value >> 3) & 0x01];
|
|
120
|
+
table[half_byte_value] =
|
|
121
|
+
((q0 * c0 + q1 * c1) + q2 * c2) + q3 * c3;
|
|
122
|
+
table[16 + half_byte_value] =
|
|
123
|
+
((q4 * c0 + q5 * c1) + q6 * c2) + q7 * c3;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (nb_bits == 2) {
|
|
130
|
+
for (size_t byte_no = 0; byte_no < num_bytes; byte_no++) {
|
|
131
|
+
const size_t dim0 = byte_no * 4;
|
|
132
|
+
float* table = lut.data() + byte_no * 32;
|
|
133
|
+
const float q0 = dim0 < d ? query[dim0] : 0.0f;
|
|
134
|
+
const float q1 = dim0 + 1 < d ? query[dim0 + 1] : 0.0f;
|
|
135
|
+
const float q2 = dim0 + 2 < d ? query[dim0 + 2] : 0.0f;
|
|
136
|
+
const float q3 = dim0 + 3 < d ? query[dim0 + 3] : 0.0f;
|
|
137
|
+
for (size_t half_byte_value = 0; half_byte_value < 16;
|
|
138
|
+
half_byte_value++) {
|
|
139
|
+
const float c0 = scalar_centroids[half_byte_value & 0x03];
|
|
140
|
+
const float c1 =
|
|
141
|
+
scalar_centroids[(half_byte_value >> 2) & 0x03];
|
|
142
|
+
table[half_byte_value] = q0 * c0 + q1 * c1;
|
|
143
|
+
table[16 + half_byte_value] = q2 * c0 + q3 * c1;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (nb_bits == 4) {
|
|
150
|
+
for (size_t byte_no = 0; byte_no < num_bytes; byte_no++) {
|
|
151
|
+
const size_t dim0 = byte_no * 2;
|
|
152
|
+
float* table = lut.data() + byte_no * 32;
|
|
153
|
+
const float q0 = dim0 < d ? query[dim0] : 0.0f;
|
|
154
|
+
const float q1 = dim0 + 1 < d ? query[dim0 + 1] : 0.0f;
|
|
155
|
+
for (size_t assignment = 0; assignment < 16; assignment++) {
|
|
156
|
+
const float centroid = scalar_centroids[assignment];
|
|
157
|
+
table[assignment] = q0 * centroid;
|
|
158
|
+
table[16 + assignment] = q1 * centroid;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const size_t values_per_half_byte = values_per_byte / 2;
|
|
165
|
+
for (size_t byte_no = 0; byte_no < num_bytes; byte_no++) {
|
|
166
|
+
const size_t dim0 = byte_no * values_per_byte;
|
|
167
|
+
float* table = lut.data() + byte_no * 32;
|
|
168
|
+
for (size_t half_byte_value = 0; half_byte_value < 16;
|
|
169
|
+
half_byte_value++) {
|
|
170
|
+
float low_dot = 0.0f;
|
|
171
|
+
float high_dot = 0.0f;
|
|
172
|
+
for (size_t j = 0; j < values_per_half_byte; j++) {
|
|
173
|
+
uint8_t assignment = static_cast<uint8_t>(
|
|
174
|
+
(half_byte_value >> (j * nb_bits)) & mask);
|
|
175
|
+
size_t dim = dim0 + j;
|
|
176
|
+
if (dim < d) {
|
|
177
|
+
low_dot += query[dim] * scalar_centroids[assignment];
|
|
178
|
+
}
|
|
179
|
+
dim += values_per_half_byte;
|
|
180
|
+
if (dim < d) {
|
|
181
|
+
high_dot += query[dim] * scalar_centroids[assignment];
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
table[half_byte_value] = low_dot;
|
|
185
|
+
table[16 + half_byte_value] = high_dot;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
lut_kind = CodeDotLUTKind::Byte;
|
|
192
|
+
lut.resize(num_bytes * 256);
|
|
193
|
+
for (size_t byte_no = 0; byte_no < num_bytes; byte_no++) {
|
|
194
|
+
const size_t dim0 = byte_no * values_per_byte;
|
|
195
|
+
float* table = lut.data() + byte_no * 256;
|
|
196
|
+
for (size_t byte_value = 0; byte_value < 256; byte_value++) {
|
|
197
|
+
float dot = 0.0f;
|
|
198
|
+
for (size_t j = 0; j < values_per_byte; j++) {
|
|
199
|
+
const size_t dim = dim0 + j;
|
|
200
|
+
if (dim >= d) {
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
const uint8_t assignment = static_cast<uint8_t>(
|
|
204
|
+
(byte_value >> (j * nb_bits)) & mask);
|
|
205
|
+
dot += query[dim] * scalar_centroids[assignment];
|
|
206
|
+
}
|
|
207
|
+
table[byte_value] = dot;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
float compute_code_dot_lut(
|
|
213
|
+
const uint8_t* __restrict code,
|
|
214
|
+
const std::vector<float>& lut,
|
|
215
|
+
CodeDotLUTKind lut_kind,
|
|
216
|
+
size_t packed_size) {
|
|
217
|
+
const float* __restrict table = lut.data();
|
|
218
|
+
size_t i = 0;
|
|
219
|
+
float acc0 = 0.0f;
|
|
220
|
+
float acc1 = 0.0f;
|
|
221
|
+
float acc2 = 0.0f;
|
|
222
|
+
float acc3 = 0.0f;
|
|
223
|
+
if (lut_kind == CodeDotLUTKind::HalfByte) {
|
|
224
|
+
for (; i + 4 <= packed_size; i += 4) {
|
|
225
|
+
uint8_t byte0 = code[i];
|
|
226
|
+
uint8_t byte1 = code[i + 1];
|
|
227
|
+
uint8_t byte2 = code[i + 2];
|
|
228
|
+
uint8_t byte3 = code[i + 3];
|
|
229
|
+
acc0 += table[byte0 & 0x0f] + table[16 + (byte0 >> 4)];
|
|
230
|
+
acc1 += table[32 + (byte1 & 0x0f)] + table[48 + (byte1 >> 4)];
|
|
231
|
+
acc2 += table[64 + (byte2 & 0x0f)] + table[80 + (byte2 >> 4)];
|
|
232
|
+
acc3 += table[96 + (byte3 & 0x0f)] + table[112 + (byte3 >> 4)];
|
|
233
|
+
table += 128;
|
|
234
|
+
}
|
|
235
|
+
float dot = (acc0 + acc1) + (acc2 + acc3);
|
|
236
|
+
for (; i < packed_size; i++) {
|
|
237
|
+
const uint8_t byte = code[i];
|
|
238
|
+
dot += table[byte & 0x0f] + table[16 + (byte >> 4)];
|
|
239
|
+
table += 32;
|
|
240
|
+
}
|
|
241
|
+
return dot;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
for (; i + 4 <= packed_size; i += 4) {
|
|
245
|
+
acc0 += table[code[i]];
|
|
246
|
+
acc1 += table[256 + code[i + 1]];
|
|
247
|
+
acc2 += table[512 + code[i + 2]];
|
|
248
|
+
acc3 += table[768 + code[i + 3]];
|
|
249
|
+
table += 1024;
|
|
250
|
+
}
|
|
251
|
+
float dot = (acc0 + acc1) + (acc2 + acc3);
|
|
252
|
+
for (; i < packed_size; i++) {
|
|
253
|
+
dot += table[code[i]];
|
|
254
|
+
table += 256;
|
|
255
|
+
}
|
|
256
|
+
return dot;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
void compute_code_dot_lut_batch_8_scalar(
|
|
260
|
+
const uint8_t* const code[8],
|
|
261
|
+
const float* __restrict table,
|
|
262
|
+
int lut_kind,
|
|
263
|
+
size_t packed_size,
|
|
264
|
+
float dots[8]) {
|
|
265
|
+
std::fill(dots, dots + 8, 0.0f);
|
|
266
|
+
if (static_cast<CodeDotLUTKind>(lut_kind) == CodeDotLUTKind::HalfByte) {
|
|
267
|
+
for (size_t i = 0; i < packed_size; i++) {
|
|
268
|
+
for (size_t j = 0; j < 8; j++) {
|
|
269
|
+
const uint8_t byte = code[j][i];
|
|
270
|
+
dots[j] += table[byte & 0x0f] + table[16 + (byte >> 4)];
|
|
271
|
+
}
|
|
272
|
+
table += 32;
|
|
273
|
+
}
|
|
274
|
+
} else {
|
|
275
|
+
for (size_t i = 0; i < packed_size; i++) {
|
|
276
|
+
for (size_t j = 0; j < 8; j++) {
|
|
277
|
+
dots[j] += table[code[j][i]];
|
|
278
|
+
}
|
|
279
|
+
table += 256;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
struct EDENDistanceComputerBase : EDENFlatCodesDistanceComputer {
|
|
285
|
+
size_t d = 0;
|
|
286
|
+
size_t nb_bits = 1;
|
|
287
|
+
const float* scalar_centroids = nullptr;
|
|
288
|
+
const float* centroid = nullptr;
|
|
289
|
+
MetricType metric_type = MetricType::METRIC_L2;
|
|
290
|
+
|
|
291
|
+
size_t packed_size = 0;
|
|
292
|
+
std::vector<float> dot_query;
|
|
293
|
+
float query_base = 0.0f;
|
|
294
|
+
|
|
295
|
+
float symmetric_dis(idx_t /*i*/, idx_t /*j*/) override {
|
|
296
|
+
FAISS_THROW_MSG("Not implemented");
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
void set_query_common(const float* x) {
|
|
300
|
+
q = x;
|
|
301
|
+
FAISS_ASSERT(x != nullptr);
|
|
302
|
+
|
|
303
|
+
dot_query.resize(d);
|
|
304
|
+
if (metric_type == MetricType::METRIC_L2) {
|
|
305
|
+
query_base = centroid ? fvec_L2sqr(x, centroid, d)
|
|
306
|
+
: fvec_norm_L2sqr(x, d);
|
|
307
|
+
for (size_t i = 0; i < d; i++) {
|
|
308
|
+
dot_query[i] = x[i] - (centroid ? centroid[i] : 0.0f);
|
|
309
|
+
}
|
|
310
|
+
} else if (metric_type == MetricType::METRIC_INNER_PRODUCT) {
|
|
311
|
+
query_base = centroid ? fvec_inner_product(x, centroid, d) : 0.0f;
|
|
312
|
+
memcpy(dot_query.data(), x, d * sizeof(float));
|
|
313
|
+
} else {
|
|
314
|
+
FAISS_THROW_MSG("EDEN supports only L2 and inner-product metrics");
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
float distance_from_code_dot(
|
|
319
|
+
const EDENCodeFactors* factors,
|
|
320
|
+
float code_dot_query) const {
|
|
321
|
+
if (metric_type == MetricType::METRIC_L2) {
|
|
322
|
+
return query_base + factors->l2_norm_term -
|
|
323
|
+
2.0f * factors->scale * code_dot_query;
|
|
324
|
+
}
|
|
325
|
+
return query_base + factors->scale * code_dot_query;
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
struct EDENReferenceDistanceComputer : EDENDistanceComputerBase {
|
|
330
|
+
void set_query(const float* x) override {
|
|
331
|
+
set_query_common(x);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
float distance_to_code(const uint8_t* code) final {
|
|
335
|
+
const EDENCodeFactors* factors =
|
|
336
|
+
reinterpret_cast<const EDENCodeFactors*>(code + packed_size);
|
|
337
|
+
const float code_dot_query = compute_code_dot_reference(
|
|
338
|
+
code, dot_query.data(), d, nb_bits, scalar_centroids);
|
|
339
|
+
return distance_from_code_dot(factors, code_dot_query);
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
struct EDENOptimizedDistanceComputer : EDENDistanceComputerBase {
|
|
344
|
+
std::vector<float> code_dot_lut;
|
|
345
|
+
CodeDotLUTKind code_dot_lut_kind = CodeDotLUTKind::None;
|
|
346
|
+
CodeDotLUTBatch8Fn code_dot_batch_8 = compute_code_dot_lut_batch_8_scalar;
|
|
347
|
+
CodeDotLUTBatch16Fn code_dot_batch_16 = nullptr;
|
|
348
|
+
|
|
349
|
+
void set_query(const float* x) override {
|
|
350
|
+
set_query_common(x);
|
|
351
|
+
build_code_dot_lut(
|
|
352
|
+
dot_query.data(),
|
|
353
|
+
d,
|
|
354
|
+
nb_bits,
|
|
355
|
+
scalar_centroids,
|
|
356
|
+
code_dot_lut,
|
|
357
|
+
code_dot_lut_kind);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
float distance_to_code(const uint8_t* code) final {
|
|
361
|
+
const EDENCodeFactors* factors =
|
|
362
|
+
reinterpret_cast<const EDENCodeFactors*>(code + packed_size);
|
|
363
|
+
const float code_dot_query = code_dot_lut.empty()
|
|
364
|
+
? compute_code_dot_reference(
|
|
365
|
+
code, dot_query.data(), d, nb_bits, scalar_centroids)
|
|
366
|
+
: compute_code_dot_lut(
|
|
367
|
+
code, code_dot_lut, code_dot_lut_kind, packed_size);
|
|
368
|
+
return distance_from_code_dot(factors, code_dot_query);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
void distances_batch_4(
|
|
372
|
+
idx_t idx0,
|
|
373
|
+
idx_t idx1,
|
|
374
|
+
idx_t idx2,
|
|
375
|
+
idx_t idx3,
|
|
376
|
+
float& dis0,
|
|
377
|
+
float& dis1,
|
|
378
|
+
float& dis2,
|
|
379
|
+
float& dis3) final {
|
|
380
|
+
const uint8_t* code0 = codes + idx0 * code_size;
|
|
381
|
+
const uint8_t* code1 = codes + idx1 * code_size;
|
|
382
|
+
const uint8_t* code2 = codes + idx2 * code_size;
|
|
383
|
+
const uint8_t* code3 = codes + idx3 * code_size;
|
|
384
|
+
|
|
385
|
+
if (code_dot_lut.empty()) {
|
|
386
|
+
dis0 = distance_to_code(code0);
|
|
387
|
+
dis1 = distance_to_code(code1);
|
|
388
|
+
dis2 = distance_to_code(code2);
|
|
389
|
+
dis3 = distance_to_code(code3);
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
const uint8_t* code_batch[8] = {
|
|
394
|
+
code0, code1, code2, code3, code0, code1, code2, code3};
|
|
395
|
+
float dots[8];
|
|
396
|
+
code_dot_batch_8(
|
|
397
|
+
code_batch,
|
|
398
|
+
code_dot_lut.data(),
|
|
399
|
+
static_cast<int>(code_dot_lut_kind),
|
|
400
|
+
packed_size,
|
|
401
|
+
dots);
|
|
402
|
+
|
|
403
|
+
dis0 = distance_from_code_dot(
|
|
404
|
+
reinterpret_cast<const EDENCodeFactors*>(code0 + packed_size),
|
|
405
|
+
dots[0]);
|
|
406
|
+
dis1 = distance_from_code_dot(
|
|
407
|
+
reinterpret_cast<const EDENCodeFactors*>(code1 + packed_size),
|
|
408
|
+
dots[1]);
|
|
409
|
+
dis2 = distance_from_code_dot(
|
|
410
|
+
reinterpret_cast<const EDENCodeFactors*>(code2 + packed_size),
|
|
411
|
+
dots[2]);
|
|
412
|
+
dis3 = distance_from_code_dot(
|
|
413
|
+
reinterpret_cast<const EDENCodeFactors*>(code3 + packed_size),
|
|
414
|
+
dots[3]);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
void consecutive_distances_batch_8(idx_t first, float* distances) final {
|
|
418
|
+
const uint8_t* code[8];
|
|
419
|
+
for (size_t i = 0; i < 8; i++) {
|
|
420
|
+
code[i] = codes + (first + idx_t(i)) * code_size;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
if (code_dot_lut.empty()) {
|
|
424
|
+
distances_batch_4(
|
|
425
|
+
first,
|
|
426
|
+
first + 1,
|
|
427
|
+
first + 2,
|
|
428
|
+
first + 3,
|
|
429
|
+
distances[0],
|
|
430
|
+
distances[1],
|
|
431
|
+
distances[2],
|
|
432
|
+
distances[3]);
|
|
433
|
+
distances_batch_4(
|
|
434
|
+
first + 4,
|
|
435
|
+
first + 5,
|
|
436
|
+
first + 6,
|
|
437
|
+
first + 7,
|
|
438
|
+
distances[4],
|
|
439
|
+
distances[5],
|
|
440
|
+
distances[6],
|
|
441
|
+
distances[7]);
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
float dots[8];
|
|
446
|
+
code_dot_batch_8(
|
|
447
|
+
code,
|
|
448
|
+
code_dot_lut.data(),
|
|
449
|
+
static_cast<int>(code_dot_lut_kind),
|
|
450
|
+
packed_size,
|
|
451
|
+
dots);
|
|
452
|
+
|
|
453
|
+
for (size_t i = 0; i < 8; i++) {
|
|
454
|
+
const EDENCodeFactors* factors =
|
|
455
|
+
reinterpret_cast<const EDENCodeFactors*>(
|
|
456
|
+
code[i] + packed_size);
|
|
457
|
+
distances[i] = distance_from_code_dot(factors, dots[i]);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
void consecutive_distances_batch_16(idx_t first, float* distances) final {
|
|
462
|
+
if (code_dot_lut.empty() || code_dot_batch_16 == nullptr) {
|
|
463
|
+
consecutive_distances_batch_8(first, distances);
|
|
464
|
+
consecutive_distances_batch_8(first + 8, distances + 8);
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
const uint8_t* code[16];
|
|
469
|
+
for (size_t i = 0; i < 16; i++) {
|
|
470
|
+
code[i] = codes + (first + idx_t(i)) * code_size;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
float dots[16];
|
|
474
|
+
code_dot_batch_16(
|
|
475
|
+
code,
|
|
476
|
+
code_dot_lut.data(),
|
|
477
|
+
static_cast<int>(code_dot_lut_kind),
|
|
478
|
+
packed_size,
|
|
479
|
+
dots);
|
|
480
|
+
|
|
481
|
+
for (size_t i = 0; i < 16; i++) {
|
|
482
|
+
const EDENCodeFactors* factors =
|
|
483
|
+
reinterpret_cast<const EDENCodeFactors*>(
|
|
484
|
+
code[i] + packed_size);
|
|
485
|
+
distances[i] = distance_from_code_dot(factors, dots[i]);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
};
|
|
489
|
+
|
|
490
|
+
EDENFlatCodesDistanceComputer* make_reference_distance_computer(
|
|
491
|
+
MetricType metric_type,
|
|
492
|
+
size_t d,
|
|
493
|
+
size_t nb_bits,
|
|
494
|
+
const float* scalar_centroids,
|
|
495
|
+
const float* centroid) {
|
|
496
|
+
auto dc = std::make_unique<EDENReferenceDistanceComputer>();
|
|
497
|
+
dc->metric_type = metric_type;
|
|
498
|
+
dc->d = d;
|
|
499
|
+
dc->nb_bits = nb_bits;
|
|
500
|
+
dc->scalar_centroids = scalar_centroids;
|
|
501
|
+
dc->centroid = centroid;
|
|
502
|
+
dc->packed_size = eden_utils::packed_code_size(d, nb_bits);
|
|
503
|
+
return dc.release();
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
EDENFlatCodesDistanceComputer* make_optimized_distance_computer(
|
|
507
|
+
MetricType metric_type,
|
|
508
|
+
size_t d,
|
|
509
|
+
size_t nb_bits,
|
|
510
|
+
const float* scalar_centroids,
|
|
511
|
+
const float* centroid,
|
|
512
|
+
CodeDotLUTBatch8Fn code_dot_batch_8,
|
|
513
|
+
CodeDotLUTBatch16Fn code_dot_batch_16 = nullptr) {
|
|
514
|
+
auto dc = std::make_unique<EDENOptimizedDistanceComputer>();
|
|
515
|
+
dc->metric_type = metric_type;
|
|
516
|
+
dc->d = d;
|
|
517
|
+
dc->nb_bits = nb_bits;
|
|
518
|
+
dc->scalar_centroids = scalar_centroids;
|
|
519
|
+
dc->centroid = centroid;
|
|
520
|
+
dc->packed_size = eden_utils::packed_code_size(d, nb_bits);
|
|
521
|
+
dc->code_dot_batch_8 = code_dot_batch_8;
|
|
522
|
+
dc->code_dot_batch_16 = code_dot_batch_16;
|
|
523
|
+
return dc.release();
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
} // namespace
|
|
527
|
+
|
|
528
|
+
#ifdef COMPILE_SIMD_AVX2
|
|
529
|
+
void compute_code_dot_lut_batch_8_avx2(
|
|
530
|
+
const uint8_t* const code[8],
|
|
531
|
+
const float* lut,
|
|
532
|
+
int lut_kind,
|
|
533
|
+
size_t packed_size,
|
|
534
|
+
float dots[8]);
|
|
535
|
+
#endif
|
|
536
|
+
|
|
537
|
+
#ifdef COMPILE_SIMD_AVX512
|
|
538
|
+
void compute_code_dot_lut_batch_8_avx512(
|
|
539
|
+
const uint8_t* const code[8],
|
|
540
|
+
const float* lut,
|
|
541
|
+
int lut_kind,
|
|
542
|
+
size_t packed_size,
|
|
543
|
+
float dots[8]);
|
|
544
|
+
|
|
545
|
+
void compute_code_dot_lut_batch_16_avx512(
|
|
546
|
+
const uint8_t* const code[16],
|
|
547
|
+
const float* lut,
|
|
548
|
+
int lut_kind,
|
|
549
|
+
size_t packed_size,
|
|
550
|
+
float dots[16]);
|
|
551
|
+
#endif
|
|
552
|
+
|
|
553
|
+
template <SIMDLevel SL>
|
|
554
|
+
EDENFlatCodesDistanceComputer* make_distance_computer_for_level(
|
|
555
|
+
MetricType metric_type,
|
|
556
|
+
size_t d,
|
|
557
|
+
size_t nb_bits,
|
|
558
|
+
const float* scalar_centroids,
|
|
559
|
+
const float* centroid) {
|
|
560
|
+
return make_reference_distance_computer(
|
|
561
|
+
metric_type, d, nb_bits, scalar_centroids, centroid);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
#ifdef COMPILE_SIMD_AVX2
|
|
565
|
+
template <>
|
|
566
|
+
EDENFlatCodesDistanceComputer* make_distance_computer_for_level<
|
|
567
|
+
SIMDLevel::AVX2>(
|
|
568
|
+
MetricType metric_type,
|
|
569
|
+
size_t d,
|
|
570
|
+
size_t nb_bits,
|
|
571
|
+
const float* scalar_centroids,
|
|
572
|
+
const float* centroid) {
|
|
573
|
+
return make_optimized_distance_computer(
|
|
574
|
+
metric_type,
|
|
575
|
+
d,
|
|
576
|
+
nb_bits,
|
|
577
|
+
scalar_centroids,
|
|
578
|
+
centroid,
|
|
579
|
+
compute_code_dot_lut_batch_8_avx2);
|
|
580
|
+
}
|
|
581
|
+
#endif
|
|
582
|
+
|
|
583
|
+
#ifdef COMPILE_SIMD_AVX512
|
|
584
|
+
template <>
|
|
585
|
+
EDENFlatCodesDistanceComputer* make_distance_computer_for_level<
|
|
586
|
+
SIMDLevel::AVX512>(
|
|
587
|
+
MetricType metric_type,
|
|
588
|
+
size_t d,
|
|
589
|
+
size_t nb_bits,
|
|
590
|
+
const float* scalar_centroids,
|
|
591
|
+
const float* centroid) {
|
|
592
|
+
return make_optimized_distance_computer(
|
|
593
|
+
metric_type,
|
|
594
|
+
d,
|
|
595
|
+
nb_bits,
|
|
596
|
+
scalar_centroids,
|
|
597
|
+
centroid,
|
|
598
|
+
compute_code_dot_lut_batch_8_avx512,
|
|
599
|
+
compute_code_dot_lut_batch_16_avx512);
|
|
600
|
+
}
|
|
601
|
+
#endif
|
|
602
|
+
|
|
603
|
+
#ifdef COMPILE_SIMD_ARM_NEON
|
|
604
|
+
template <>
|
|
605
|
+
EDENFlatCodesDistanceComputer* make_distance_computer_for_level<
|
|
606
|
+
SIMDLevel::ARM_NEON>(
|
|
607
|
+
MetricType metric_type,
|
|
608
|
+
size_t d,
|
|
609
|
+
size_t nb_bits,
|
|
610
|
+
const float* scalar_centroids,
|
|
611
|
+
const float* centroid) {
|
|
612
|
+
return make_optimized_distance_computer(
|
|
613
|
+
metric_type,
|
|
614
|
+
d,
|
|
615
|
+
nb_bits,
|
|
616
|
+
scalar_centroids,
|
|
617
|
+
centroid,
|
|
618
|
+
compute_code_dot_lut_batch_8_scalar);
|
|
619
|
+
}
|
|
620
|
+
#endif
|
|
621
|
+
|
|
622
|
+
#ifdef COMPILE_SIMD_RISCV_RVV
|
|
623
|
+
template <>
|
|
624
|
+
EDENFlatCodesDistanceComputer* make_distance_computer_for_level<
|
|
625
|
+
SIMDLevel::RISCV_RVV>(
|
|
626
|
+
MetricType metric_type,
|
|
627
|
+
size_t d,
|
|
628
|
+
size_t nb_bits,
|
|
629
|
+
const float* scalar_centroids,
|
|
630
|
+
const float* centroid) {
|
|
631
|
+
return make_optimized_distance_computer(
|
|
632
|
+
metric_type,
|
|
633
|
+
d,
|
|
634
|
+
nb_bits,
|
|
635
|
+
scalar_centroids,
|
|
636
|
+
centroid,
|
|
637
|
+
compute_code_dot_lut_batch_8_scalar);
|
|
638
|
+
}
|
|
639
|
+
#endif
|
|
640
|
+
|
|
641
|
+
} // namespace eden_distance
|
|
642
|
+
|
|
643
|
+
namespace eden_utils {
|
|
644
|
+
|
|
645
|
+
ScalarQuantizer::QuantizerType quantizer_type_for_bits(size_t nb_bits) {
|
|
646
|
+
switch (nb_bits) {
|
|
647
|
+
case 1:
|
|
648
|
+
return ScalarQuantizer::QT_1bit_eden;
|
|
649
|
+
case 2:
|
|
650
|
+
return ScalarQuantizer::QT_2bit_eden;
|
|
651
|
+
case 3:
|
|
652
|
+
return ScalarQuantizer::QT_3bit_eden;
|
|
653
|
+
case 4:
|
|
654
|
+
return ScalarQuantizer::QT_4bit_eden;
|
|
655
|
+
case 5:
|
|
656
|
+
return ScalarQuantizer::QT_5bit_eden;
|
|
657
|
+
case 6:
|
|
658
|
+
return ScalarQuantizer::QT_6bit_eden;
|
|
659
|
+
case 7:
|
|
660
|
+
return ScalarQuantizer::QT_7bit_eden;
|
|
661
|
+
case 8:
|
|
662
|
+
return ScalarQuantizer::QT_8bit_eden;
|
|
663
|
+
default:
|
|
664
|
+
FAISS_THROW_MSG("EDEN nb_bits must be in [1, 8]");
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
bool is_eden_quantizer_type(ScalarQuantizer::QuantizerType qtype) {
|
|
669
|
+
return qtype >= ScalarQuantizer::QT_1bit_eden &&
|
|
670
|
+
qtype <= ScalarQuantizer::QT_8bit_eden;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
size_t nb_bits_for_qtype(ScalarQuantizer::QuantizerType qtype) {
|
|
674
|
+
switch (qtype) {
|
|
675
|
+
case ScalarQuantizer::QT_1bit_eden:
|
|
676
|
+
return 1;
|
|
677
|
+
case ScalarQuantizer::QT_2bit_eden:
|
|
678
|
+
return 2;
|
|
679
|
+
case ScalarQuantizer::QT_3bit_eden:
|
|
680
|
+
return 3;
|
|
681
|
+
case ScalarQuantizer::QT_4bit_eden:
|
|
682
|
+
return 4;
|
|
683
|
+
case ScalarQuantizer::QT_5bit_eden:
|
|
684
|
+
return 5;
|
|
685
|
+
case ScalarQuantizer::QT_6bit_eden:
|
|
686
|
+
return 6;
|
|
687
|
+
case ScalarQuantizer::QT_7bit_eden:
|
|
688
|
+
return 7;
|
|
689
|
+
case ScalarQuantizer::QT_8bit_eden:
|
|
690
|
+
return 8;
|
|
691
|
+
default:
|
|
692
|
+
FAISS_THROW_MSG("expected an EDEN ScalarQuantizer qtype");
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
size_t packed_code_size(size_t d, size_t nb_bits) {
|
|
697
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
698
|
+
nb_bits >= 1 && nb_bits <= 8, "EDEN nb_bits must be in [1, 8]");
|
|
699
|
+
return (d * nb_bits + 7) / 8;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
size_t code_size(size_t d, size_t nb_bits) {
|
|
703
|
+
return packed_code_size(d, nb_bits) + sizeof(EDENCodeFactors);
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
uint8_t extract_code(const uint8_t* codes, size_t index, size_t nb_bits) {
|
|
707
|
+
if (nb_bits == 8) {
|
|
708
|
+
return codes[index];
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
const size_t bit_pos = index * nb_bits;
|
|
712
|
+
BitstringReader reader(codes, (bit_pos + nb_bits + 7) / 8);
|
|
713
|
+
reader.i = bit_pos;
|
|
714
|
+
return static_cast<uint8_t>(reader.read(nb_bits));
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
void compute_codes(
|
|
718
|
+
const ScalarQuantizer& sq,
|
|
719
|
+
MetricType metric_type,
|
|
720
|
+
EDENScaleType scale_type,
|
|
721
|
+
const float* x,
|
|
722
|
+
uint8_t* codes,
|
|
723
|
+
size_t n,
|
|
724
|
+
const float* centroid) {
|
|
725
|
+
FAISS_ASSERT(x != nullptr);
|
|
726
|
+
FAISS_ASSERT(codes != nullptr);
|
|
727
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
728
|
+
is_eden_quantizer_type(sq.qtype),
|
|
729
|
+
"expected an EDEN ScalarQuantizer qtype");
|
|
730
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
731
|
+
metric_type == MetricType::METRIC_L2 ||
|
|
732
|
+
metric_type == MetricType::METRIC_INNER_PRODUCT,
|
|
733
|
+
"EDEN supports only L2 and inner-product metrics");
|
|
734
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
735
|
+
scale_type == EDENScaleType_UNBIASED ||
|
|
736
|
+
scale_type == EDENScaleType_BIASED,
|
|
737
|
+
"invalid EDEN scale type");
|
|
738
|
+
|
|
739
|
+
if (n == 0) {
|
|
740
|
+
return;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
const size_t d = sq.d;
|
|
744
|
+
const size_t nb_bits = sq.bits;
|
|
745
|
+
const size_t packed_size = sq.code_size;
|
|
746
|
+
const size_t full_code_size = code_size(d, nb_bits);
|
|
747
|
+
const float sqrt_d = std::sqrt(static_cast<float>(d));
|
|
748
|
+
|
|
749
|
+
#pragma omp parallel if (n > 1000)
|
|
750
|
+
{
|
|
751
|
+
std::unique_ptr<ScalarQuantizer::SQuantizer> squant(
|
|
752
|
+
sq.select_quantizer());
|
|
753
|
+
std::vector<float> normalized(d);
|
|
754
|
+
std::vector<float> decoded(d);
|
|
755
|
+
|
|
756
|
+
#pragma omp for
|
|
757
|
+
for (int64_t i = 0; i < static_cast<int64_t>(n); i++) {
|
|
758
|
+
const float* xi = x + i * d;
|
|
759
|
+
uint8_t* code = codes + i * full_code_size;
|
|
760
|
+
memset(code, 0, full_code_size);
|
|
761
|
+
|
|
762
|
+
float norm_sqr = 0.0f;
|
|
763
|
+
for (size_t j = 0; j < d; j++) {
|
|
764
|
+
const float c = centroid ? centroid[j] : 0.0f;
|
|
765
|
+
const float r = xi[j] - c;
|
|
766
|
+
norm_sqr += r * r;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
EDENCodeFactors* factors =
|
|
770
|
+
reinterpret_cast<EDENCodeFactors*>(code + packed_size);
|
|
771
|
+
if (norm_sqr <= std::numeric_limits<float>::epsilon()) {
|
|
772
|
+
factors->l2_norm_term = 0.0f;
|
|
773
|
+
factors->scale = 0.0f;
|
|
774
|
+
continue;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
const float norm = std::sqrt(norm_sqr);
|
|
778
|
+
const float inv_norm = 1.0f / norm;
|
|
779
|
+
for (size_t j = 0; j < d; j++) {
|
|
780
|
+
const float c = centroid ? centroid[j] : 0.0f;
|
|
781
|
+
normalized[j] = (xi[j] - c) * sqrt_d * inv_norm;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
squant->encode_vector(normalized.data(), code);
|
|
785
|
+
squant->decode_vector(code, decoded.data());
|
|
786
|
+
|
|
787
|
+
double code_norm_sqr = 0.0;
|
|
788
|
+
double code_residual_ip = 0.0;
|
|
789
|
+
for (size_t j = 0; j < d; j++) {
|
|
790
|
+
const float c = centroid ? centroid[j] : 0.0f;
|
|
791
|
+
const float r = xi[j] - c;
|
|
792
|
+
const float q = decoded[j];
|
|
793
|
+
code_norm_sqr += double(q) * q;
|
|
794
|
+
code_residual_ip += double(q) * r;
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
float scale = 0.0f;
|
|
798
|
+
float l2_norm_term = 0.0f;
|
|
799
|
+
// Unbiased EDEN uses ||r||^2 / <q, r>. The biased scale follows
|
|
800
|
+
// DRIVE (NeurIPS 2021): <q, r> / ||q||^2.
|
|
801
|
+
if (scale_type == EDENScaleType_BIASED) {
|
|
802
|
+
scale = static_cast<float>(code_residual_ip / code_norm_sqr);
|
|
803
|
+
l2_norm_term = static_cast<float>(
|
|
804
|
+
double(scale) * scale * code_norm_sqr);
|
|
805
|
+
} else {
|
|
806
|
+
scale = static_cast<float>(double(norm_sqr) / code_residual_ip);
|
|
807
|
+
l2_norm_term = norm_sqr;
|
|
808
|
+
}
|
|
809
|
+
if (!std::isfinite(scale)) {
|
|
810
|
+
scale = 0.0f;
|
|
811
|
+
l2_norm_term = 0.0f;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
factors->scale = scale;
|
|
815
|
+
factors->l2_norm_term = l2_norm_term;
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
void decode(
|
|
821
|
+
const ScalarQuantizer& sq,
|
|
822
|
+
const uint8_t* codes,
|
|
823
|
+
float* x,
|
|
824
|
+
size_t n,
|
|
825
|
+
const float* centroid) {
|
|
826
|
+
FAISS_ASSERT(codes != nullptr);
|
|
827
|
+
FAISS_ASSERT(x != nullptr);
|
|
828
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
829
|
+
is_eden_quantizer_type(sq.qtype),
|
|
830
|
+
"expected an EDEN ScalarQuantizer qtype");
|
|
831
|
+
|
|
832
|
+
const size_t d = sq.d;
|
|
833
|
+
const size_t packed_size = sq.code_size;
|
|
834
|
+
const size_t full_code_size = code_size(d, sq.bits);
|
|
835
|
+
|
|
836
|
+
#pragma omp parallel if (n > 1000)
|
|
837
|
+
{
|
|
838
|
+
std::unique_ptr<ScalarQuantizer::SQuantizer> squant(
|
|
839
|
+
sq.select_quantizer());
|
|
840
|
+
std::vector<float> decoded(d);
|
|
841
|
+
|
|
842
|
+
#pragma omp for
|
|
843
|
+
for (int64_t i = 0; i < static_cast<int64_t>(n); i++) {
|
|
844
|
+
const uint8_t* code = codes + i * full_code_size;
|
|
845
|
+
const EDENCodeFactors* factors =
|
|
846
|
+
reinterpret_cast<const EDENCodeFactors*>(
|
|
847
|
+
code + packed_size);
|
|
848
|
+
float* xi = x + i * d;
|
|
849
|
+
|
|
850
|
+
squant->decode_vector(code, decoded.data());
|
|
851
|
+
for (size_t j = 0; j < d; j++) {
|
|
852
|
+
const float c = centroid ? centroid[j] : 0.0f;
|
|
853
|
+
xi[j] = c + factors->scale * decoded[j];
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
} // namespace eden_utils
|
|
860
|
+
|
|
861
|
+
namespace eden_utils {
|
|
862
|
+
|
|
863
|
+
EDENFlatCodesDistanceComputer* get_distance_computer(
|
|
864
|
+
const ScalarQuantizer& sq,
|
|
865
|
+
MetricType metric_type,
|
|
866
|
+
const float* centroid) {
|
|
867
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
868
|
+
is_eden_quantizer_type(sq.qtype),
|
|
869
|
+
"expected an EDEN ScalarQuantizer qtype");
|
|
870
|
+
const size_t centroid_count = size_t{1} << sq.bits;
|
|
871
|
+
FAISS_THROW_IF_NOT(sq.trained.size() >= centroid_count);
|
|
872
|
+
const float* scalar_centroids = sq.trained.data();
|
|
873
|
+
return with_simd_level(
|
|
874
|
+
[&]<SIMDLevel SL>() -> EDENFlatCodesDistanceComputer* {
|
|
875
|
+
return eden_distance::make_distance_computer_for_level<SL>(
|
|
876
|
+
metric_type, sq.d, sq.bits, scalar_centroids, centroid);
|
|
877
|
+
});
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
} // namespace eden_utils
|
|
881
|
+
|
|
882
|
+
} // namespace faiss
|