faiss 0.2.3 → 0.2.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (189) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -0
  3. data/LICENSE.txt +1 -1
  4. data/README.md +23 -21
  5. data/ext/faiss/extconf.rb +11 -0
  6. data/ext/faiss/index.cpp +4 -4
  7. data/ext/faiss/index_binary.cpp +6 -6
  8. data/ext/faiss/product_quantizer.cpp +4 -4
  9. data/lib/faiss/version.rb +1 -1
  10. data/vendor/faiss/faiss/AutoTune.cpp +13 -0
  11. data/vendor/faiss/faiss/Clustering.cpp +32 -0
  12. data/vendor/faiss/faiss/Clustering.h +14 -0
  13. data/vendor/faiss/faiss/IVFlib.cpp +101 -2
  14. data/vendor/faiss/faiss/IVFlib.h +26 -2
  15. data/vendor/faiss/faiss/Index.cpp +36 -3
  16. data/vendor/faiss/faiss/Index.h +43 -6
  17. data/vendor/faiss/faiss/Index2Layer.cpp +24 -93
  18. data/vendor/faiss/faiss/Index2Layer.h +8 -17
  19. data/vendor/faiss/faiss/IndexAdditiveQuantizer.cpp +610 -0
  20. data/vendor/faiss/faiss/IndexAdditiveQuantizer.h +253 -0
  21. data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.cpp +299 -0
  22. data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.h +199 -0
  23. data/vendor/faiss/faiss/IndexBinary.cpp +20 -4
  24. data/vendor/faiss/faiss/IndexBinary.h +18 -3
  25. data/vendor/faiss/faiss/IndexBinaryFlat.cpp +9 -2
  26. data/vendor/faiss/faiss/IndexBinaryFlat.h +4 -2
  27. data/vendor/faiss/faiss/IndexBinaryFromFloat.cpp +4 -1
  28. data/vendor/faiss/faiss/IndexBinaryFromFloat.h +2 -1
  29. data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +5 -1
  30. data/vendor/faiss/faiss/IndexBinaryHNSW.h +2 -1
  31. data/vendor/faiss/faiss/IndexBinaryHash.cpp +17 -4
  32. data/vendor/faiss/faiss/IndexBinaryHash.h +8 -4
  33. data/vendor/faiss/faiss/IndexBinaryIVF.cpp +28 -13
  34. data/vendor/faiss/faiss/IndexBinaryIVF.h +10 -7
  35. data/vendor/faiss/faiss/IndexFastScan.cpp +626 -0
  36. data/vendor/faiss/faiss/IndexFastScan.h +145 -0
  37. data/vendor/faiss/faiss/IndexFlat.cpp +52 -69
  38. data/vendor/faiss/faiss/IndexFlat.h +16 -19
  39. data/vendor/faiss/faiss/IndexFlatCodes.cpp +101 -0
  40. data/vendor/faiss/faiss/IndexFlatCodes.h +59 -0
  41. data/vendor/faiss/faiss/IndexHNSW.cpp +66 -138
  42. data/vendor/faiss/faiss/IndexHNSW.h +4 -2
  43. data/vendor/faiss/faiss/IndexIDMap.cpp +247 -0
  44. data/vendor/faiss/faiss/IndexIDMap.h +107 -0
  45. data/vendor/faiss/faiss/IndexIVF.cpp +200 -40
  46. data/vendor/faiss/faiss/IndexIVF.h +59 -22
  47. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +393 -0
  48. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.h +183 -0
  49. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.cpp +590 -0
  50. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.h +171 -0
  51. data/vendor/faiss/faiss/IndexIVFFastScan.cpp +1290 -0
  52. data/vendor/faiss/faiss/IndexIVFFastScan.h +213 -0
  53. data/vendor/faiss/faiss/IndexIVFFlat.cpp +43 -26
  54. data/vendor/faiss/faiss/IndexIVFFlat.h +4 -2
  55. data/vendor/faiss/faiss/IndexIVFPQ.cpp +238 -53
  56. data/vendor/faiss/faiss/IndexIVFPQ.h +6 -2
  57. data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +23 -852
  58. data/vendor/faiss/faiss/IndexIVFPQFastScan.h +7 -112
  59. data/vendor/faiss/faiss/IndexIVFPQR.cpp +3 -3
  60. data/vendor/faiss/faiss/IndexIVFPQR.h +1 -1
  61. data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +63 -40
  62. data/vendor/faiss/faiss/IndexIVFSpectralHash.h +23 -7
  63. data/vendor/faiss/faiss/IndexLSH.cpp +8 -32
  64. data/vendor/faiss/faiss/IndexLSH.h +4 -16
  65. data/vendor/faiss/faiss/IndexLattice.cpp +7 -1
  66. data/vendor/faiss/faiss/IndexLattice.h +3 -1
  67. data/vendor/faiss/faiss/IndexNNDescent.cpp +4 -5
  68. data/vendor/faiss/faiss/IndexNNDescent.h +2 -1
  69. data/vendor/faiss/faiss/IndexNSG.cpp +37 -5
  70. data/vendor/faiss/faiss/IndexNSG.h +25 -1
  71. data/vendor/faiss/faiss/IndexPQ.cpp +108 -120
  72. data/vendor/faiss/faiss/IndexPQ.h +21 -22
  73. data/vendor/faiss/faiss/IndexPQFastScan.cpp +15 -450
  74. data/vendor/faiss/faiss/IndexPQFastScan.h +15 -78
  75. data/vendor/faiss/faiss/IndexPreTransform.cpp +47 -8
  76. data/vendor/faiss/faiss/IndexPreTransform.h +15 -3
  77. data/vendor/faiss/faiss/IndexRefine.cpp +36 -4
  78. data/vendor/faiss/faiss/IndexRefine.h +14 -2
  79. data/vendor/faiss/faiss/IndexReplicas.cpp +4 -2
  80. data/vendor/faiss/faiss/IndexReplicas.h +2 -1
  81. data/vendor/faiss/faiss/IndexRowwiseMinMax.cpp +438 -0
  82. data/vendor/faiss/faiss/IndexRowwiseMinMax.h +92 -0
  83. data/vendor/faiss/faiss/IndexScalarQuantizer.cpp +28 -43
  84. data/vendor/faiss/faiss/IndexScalarQuantizer.h +8 -23
  85. data/vendor/faiss/faiss/IndexShards.cpp +4 -1
  86. data/vendor/faiss/faiss/IndexShards.h +2 -1
  87. data/vendor/faiss/faiss/MetaIndexes.cpp +5 -178
  88. data/vendor/faiss/faiss/MetaIndexes.h +3 -81
  89. data/vendor/faiss/faiss/VectorTransform.cpp +45 -1
  90. data/vendor/faiss/faiss/VectorTransform.h +25 -4
  91. data/vendor/faiss/faiss/clone_index.cpp +26 -3
  92. data/vendor/faiss/faiss/clone_index.h +3 -0
  93. data/vendor/faiss/faiss/cppcontrib/SaDecodeKernels.h +300 -0
  94. data/vendor/faiss/faiss/cppcontrib/detail/CoarseBitType.h +24 -0
  95. data/vendor/faiss/faiss/cppcontrib/detail/UintReader.h +195 -0
  96. data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-avx2-inl.h +2058 -0
  97. data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-inl.h +408 -0
  98. data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-neon-inl.h +2147 -0
  99. data/vendor/faiss/faiss/cppcontrib/sa_decode/MinMax-inl.h +460 -0
  100. data/vendor/faiss/faiss/cppcontrib/sa_decode/MinMaxFP16-inl.h +465 -0
  101. data/vendor/faiss/faiss/cppcontrib/sa_decode/PQ-avx2-inl.h +1618 -0
  102. data/vendor/faiss/faiss/cppcontrib/sa_decode/PQ-inl.h +251 -0
  103. data/vendor/faiss/faiss/cppcontrib/sa_decode/PQ-neon-inl.h +1452 -0
  104. data/vendor/faiss/faiss/gpu/GpuAutoTune.cpp +1 -0
  105. data/vendor/faiss/faiss/gpu/GpuCloner.cpp +2 -6
  106. data/vendor/faiss/faiss/gpu/GpuIcmEncoder.h +60 -0
  107. data/vendor/faiss/faiss/gpu/GpuIndex.h +28 -4
  108. data/vendor/faiss/faiss/gpu/GpuIndexBinaryFlat.h +2 -1
  109. data/vendor/faiss/faiss/gpu/GpuIndexFlat.h +10 -8
  110. data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +75 -14
  111. data/vendor/faiss/faiss/gpu/GpuIndexIVFFlat.h +19 -32
  112. data/vendor/faiss/faiss/gpu/GpuIndexIVFPQ.h +22 -31
  113. data/vendor/faiss/faiss/gpu/GpuIndexIVFScalarQuantizer.h +22 -28
  114. data/vendor/faiss/faiss/gpu/GpuResources.cpp +14 -0
  115. data/vendor/faiss/faiss/gpu/GpuResources.h +16 -3
  116. data/vendor/faiss/faiss/gpu/StandardGpuResources.cpp +3 -3
  117. data/vendor/faiss/faiss/gpu/impl/IndexUtils.h +32 -0
  118. data/vendor/faiss/faiss/gpu/test/TestGpuIndexBinaryFlat.cpp +1 -0
  119. data/vendor/faiss/faiss/gpu/test/TestGpuIndexFlat.cpp +311 -75
  120. data/vendor/faiss/faiss/gpu/test/TestUtils.cpp +10 -0
  121. data/vendor/faiss/faiss/gpu/test/TestUtils.h +3 -0
  122. data/vendor/faiss/faiss/gpu/test/demo_ivfpq_indexing_gpu.cpp +2 -2
  123. data/vendor/faiss/faiss/gpu/utils/DeviceUtils.h +5 -4
  124. data/vendor/faiss/faiss/impl/AdditiveQuantizer.cpp +331 -29
  125. data/vendor/faiss/faiss/impl/AdditiveQuantizer.h +110 -19
  126. data/vendor/faiss/faiss/impl/AuxIndexStructures.cpp +0 -54
  127. data/vendor/faiss/faiss/impl/AuxIndexStructures.h +0 -76
  128. data/vendor/faiss/faiss/impl/DistanceComputer.h +64 -0
  129. data/vendor/faiss/faiss/impl/HNSW.cpp +133 -32
  130. data/vendor/faiss/faiss/impl/HNSW.h +19 -16
  131. data/vendor/faiss/faiss/impl/IDSelector.cpp +125 -0
  132. data/vendor/faiss/faiss/impl/IDSelector.h +135 -0
  133. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +378 -217
  134. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.h +106 -29
  135. data/vendor/faiss/faiss/impl/LookupTableScaler.h +77 -0
  136. data/vendor/faiss/faiss/impl/NNDescent.cpp +1 -0
  137. data/vendor/faiss/faiss/impl/NSG.cpp +1 -4
  138. data/vendor/faiss/faiss/impl/NSG.h +1 -1
  139. data/vendor/faiss/faiss/impl/ProductAdditiveQuantizer.cpp +383 -0
  140. data/vendor/faiss/faiss/impl/ProductAdditiveQuantizer.h +154 -0
  141. data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +225 -145
  142. data/vendor/faiss/faiss/impl/ProductQuantizer.h +29 -10
  143. data/vendor/faiss/faiss/impl/Quantizer.h +43 -0
  144. data/vendor/faiss/faiss/impl/ResidualQuantizer.cpp +521 -55
  145. data/vendor/faiss/faiss/impl/ResidualQuantizer.h +94 -16
  146. data/vendor/faiss/faiss/impl/ResultHandler.h +96 -0
  147. data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +108 -191
  148. data/vendor/faiss/faiss/impl/ScalarQuantizer.h +18 -18
  149. data/vendor/faiss/faiss/impl/index_read.cpp +338 -24
  150. data/vendor/faiss/faiss/impl/index_write.cpp +300 -18
  151. data/vendor/faiss/faiss/impl/io.cpp +1 -1
  152. data/vendor/faiss/faiss/impl/io_macros.h +20 -0
  153. data/vendor/faiss/faiss/impl/kmeans1d.cpp +303 -0
  154. data/vendor/faiss/faiss/impl/kmeans1d.h +48 -0
  155. data/vendor/faiss/faiss/impl/pq4_fast_scan.cpp +56 -16
  156. data/vendor/faiss/faiss/impl/pq4_fast_scan.h +25 -8
  157. data/vendor/faiss/faiss/impl/pq4_fast_scan_search_1.cpp +66 -25
  158. data/vendor/faiss/faiss/impl/pq4_fast_scan_search_qbs.cpp +75 -27
  159. data/vendor/faiss/faiss/index_factory.cpp +772 -412
  160. data/vendor/faiss/faiss/index_factory.h +3 -0
  161. data/vendor/faiss/faiss/index_io.h +5 -0
  162. data/vendor/faiss/faiss/invlists/DirectMap.cpp +1 -0
  163. data/vendor/faiss/faiss/invlists/InvertedLists.cpp +4 -1
  164. data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +2 -1
  165. data/vendor/faiss/faiss/python/python_callbacks.cpp +27 -0
  166. data/vendor/faiss/faiss/python/python_callbacks.h +15 -0
  167. data/vendor/faiss/faiss/utils/Heap.h +31 -15
  168. data/vendor/faiss/faiss/utils/distances.cpp +384 -58
  169. data/vendor/faiss/faiss/utils/distances.h +149 -18
  170. data/vendor/faiss/faiss/utils/distances_simd.cpp +776 -6
  171. data/vendor/faiss/faiss/utils/extra_distances.cpp +12 -7
  172. data/vendor/faiss/faiss/utils/extra_distances.h +3 -1
  173. data/vendor/faiss/faiss/utils/fp16-fp16c.h +21 -0
  174. data/vendor/faiss/faiss/utils/fp16-inl.h +101 -0
  175. data/vendor/faiss/faiss/utils/fp16.h +11 -0
  176. data/vendor/faiss/faiss/utils/hamming-inl.h +54 -0
  177. data/vendor/faiss/faiss/utils/hamming.cpp +0 -48
  178. data/vendor/faiss/faiss/utils/ordered_key_value.h +10 -0
  179. data/vendor/faiss/faiss/utils/quantize_lut.cpp +62 -0
  180. data/vendor/faiss/faiss/utils/quantize_lut.h +20 -0
  181. data/vendor/faiss/faiss/utils/random.cpp +53 -0
  182. data/vendor/faiss/faiss/utils/random.h +5 -0
  183. data/vendor/faiss/faiss/utils/simdlib_avx2.h +4 -0
  184. data/vendor/faiss/faiss/utils/simdlib_emulated.h +6 -1
  185. data/vendor/faiss/faiss/utils/simdlib_neon.h +7 -2
  186. data/vendor/faiss/faiss/utils/utils.h +1 -1
  187. metadata +46 -5
  188. data/vendor/faiss/faiss/IndexResidual.cpp +0 -291
  189. data/vendor/faiss/faiss/IndexResidual.h +0 -152
@@ -0,0 +1,383 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its 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/ProductAdditiveQuantizer.h>
9
+
10
+ #include <cstddef>
11
+ #include <cstdio>
12
+ #include <cstring>
13
+ #include <memory>
14
+ #include <random>
15
+
16
+ #include <algorithm>
17
+
18
+ #include <faiss/clone_index.h>
19
+ #include <faiss/impl/AuxIndexStructures.h>
20
+ #include <faiss/impl/FaissAssert.h>
21
+ #include <faiss/utils/distances.h>
22
+ #include <faiss/utils/hamming.h>
23
+ #include <faiss/utils/utils.h>
24
+
25
+ extern "C" {
26
+
27
+ // general matrix multiplication
28
+ int sgemm_(
29
+ const char* transa,
30
+ const char* transb,
31
+ FINTEGER* m,
32
+ FINTEGER* n,
33
+ FINTEGER* k,
34
+ const float* alpha,
35
+ const float* a,
36
+ FINTEGER* lda,
37
+ const float* b,
38
+ FINTEGER* ldb,
39
+ float* beta,
40
+ float* c,
41
+ FINTEGER* ldc);
42
+ }
43
+
44
+ namespace faiss {
45
+
46
+ ProductAdditiveQuantizer::ProductAdditiveQuantizer(
47
+ size_t d,
48
+ const std::vector<AdditiveQuantizer*>& aqs,
49
+ Search_type_t search_type) {
50
+ init(d, aqs, search_type);
51
+ }
52
+
53
+ ProductAdditiveQuantizer::ProductAdditiveQuantizer()
54
+ : ProductAdditiveQuantizer(0, {}) {}
55
+
56
+ void ProductAdditiveQuantizer::init(
57
+ size_t d,
58
+ const std::vector<AdditiveQuantizer*>& aqs,
59
+ Search_type_t search_type) {
60
+ // AdditiveQuantizer constructor
61
+ this->d = d;
62
+ this->search_type = search_type;
63
+ M = 0;
64
+ for (const auto& q : aqs) {
65
+ M += q->M;
66
+ nbits.insert(nbits.end(), q->nbits.begin(), q->nbits.end());
67
+ }
68
+ verbose = false;
69
+ is_trained = false;
70
+ norm_max = norm_min = NAN;
71
+ code_size = 0;
72
+ tot_bits = 0;
73
+ total_codebook_size = 0;
74
+ only_8bit = false;
75
+ set_derived_values();
76
+
77
+ // ProductAdditiveQuantizer
78
+ nsplits = aqs.size();
79
+
80
+ FAISS_THROW_IF_NOT(quantizers.empty());
81
+ for (const auto& q : aqs) {
82
+ auto aq = dynamic_cast<AdditiveQuantizer*>(clone_Quantizer(q));
83
+ quantizers.push_back(aq);
84
+ }
85
+ }
86
+
87
+ ProductAdditiveQuantizer::~ProductAdditiveQuantizer() {
88
+ for (auto& q : quantizers) {
89
+ delete q;
90
+ }
91
+ }
92
+
93
+ AdditiveQuantizer* ProductAdditiveQuantizer::subquantizer(size_t s) const {
94
+ return quantizers[s];
95
+ }
96
+
97
+ void ProductAdditiveQuantizer::train(size_t n, const float* x) {
98
+ if (is_trained) {
99
+ return;
100
+ }
101
+
102
+ // copy the subvectors into contiguous memory
103
+ size_t offset_d = 0;
104
+ std::vector<float> xt;
105
+ for (size_t s = 0; s < nsplits; s++) {
106
+ auto q = quantizers[s];
107
+ xt.resize(q->d * n);
108
+
109
+ #pragma omp parallel for if (n > 1000)
110
+ for (idx_t i = 0; i < n; i++) {
111
+ memcpy(xt.data() + i * q->d,
112
+ x + i * d + offset_d,
113
+ q->d * sizeof(*x));
114
+ }
115
+
116
+ q->train(n, xt.data());
117
+ offset_d += q->d;
118
+ }
119
+
120
+ // compute codebook size
121
+ size_t codebook_size = 0;
122
+ for (const auto& q : quantizers) {
123
+ codebook_size += q->total_codebook_size * q->d;
124
+ }
125
+
126
+ // copy codebook from sub-quantizers
127
+ codebooks.resize(codebook_size); // size (M * ksub, dsub)
128
+ float* cb = codebooks.data();
129
+ for (size_t s = 0; s < nsplits; s++) {
130
+ auto q = quantizers[s];
131
+ size_t sub_codebook_size = q->total_codebook_size * q->d;
132
+ memcpy(cb, q->codebooks.data(), sub_codebook_size * sizeof(float));
133
+ cb += sub_codebook_size;
134
+ }
135
+
136
+ is_trained = true;
137
+
138
+ // train norm
139
+ std::vector<int32_t> codes(n * M);
140
+ compute_unpacked_codes(x, codes.data(), n);
141
+ std::vector<float> x_recons(n * d);
142
+ std::vector<float> norms(n);
143
+ decode_unpacked(codes.data(), x_recons.data(), n);
144
+ fvec_norms_L2sqr(norms.data(), x_recons.data(), d, n);
145
+ train_norm(n, norms.data());
146
+ }
147
+
148
+ void ProductAdditiveQuantizer::compute_codes_add_centroids(
149
+ const float* x,
150
+ uint8_t* codes_out,
151
+ size_t n,
152
+ const float* centroids) const {
153
+ // size (n, M)
154
+ std::vector<int32_t> unpacked_codes(n * M);
155
+ compute_unpacked_codes(x, unpacked_codes.data(), n, centroids);
156
+
157
+ // pack
158
+ pack_codes(n, unpacked_codes.data(), codes_out, -1, nullptr, centroids);
159
+ }
160
+
161
+ void ProductAdditiveQuantizer::compute_unpacked_codes(
162
+ const float* x,
163
+ int32_t* unpacked_codes,
164
+ size_t n,
165
+ const float* centroids) const {
166
+ /// TODO: actuallly we do not need to unpack and pack
167
+ size_t offset_d = 0, offset_m = 0;
168
+ std::vector<float> xsub;
169
+ std::vector<uint8_t> codes;
170
+
171
+ for (size_t s = 0; s < nsplits; s++) {
172
+ const auto q = quantizers[s];
173
+ xsub.resize(n * q->d);
174
+ codes.resize(n * q->code_size);
175
+
176
+ #pragma omp parallel for if (n > 1000)
177
+ for (idx_t i = 0; i < n; i++) {
178
+ memcpy(xsub.data() + i * q->d,
179
+ x + i * d + offset_d,
180
+ q->d * sizeof(float));
181
+ }
182
+
183
+ q->compute_codes(xsub.data(), codes.data(), n);
184
+
185
+ // unpack
186
+ #pragma omp parallel for if (n > 1000)
187
+ for (idx_t i = 0; i < n; i++) {
188
+ uint8_t* code = codes.data() + i * q->code_size;
189
+ BitstringReader bsr(code, q->code_size);
190
+
191
+ // unpacked_codes[i][s][m] = codes[i][m]
192
+ for (size_t m = 0; m < q->M; m++) {
193
+ unpacked_codes[i * M + offset_m + m] = bsr.read(q->nbits[m]);
194
+ }
195
+ }
196
+
197
+ offset_d += q->d;
198
+ offset_m += q->M;
199
+ }
200
+ }
201
+
202
+ void ProductAdditiveQuantizer::decode_unpacked(
203
+ const int32_t* codes,
204
+ float* x,
205
+ size_t n,
206
+ int64_t ld_codes) const {
207
+ FAISS_THROW_IF_NOT_MSG(
208
+ is_trained, "The product additive quantizer is not trained yet.");
209
+
210
+ if (ld_codes == -1) {
211
+ ld_codes = M;
212
+ }
213
+
214
+ // product additive quantizer decoding
215
+ #pragma omp parallel for if (n > 1000)
216
+ for (int64_t i = 0; i < n; i++) {
217
+ const int32_t* codesi = codes + i * ld_codes;
218
+
219
+ size_t offset_m = 0, offset_d = 0;
220
+ for (size_t s = 0; s < nsplits; s++) {
221
+ const auto q = quantizers[s];
222
+ float* xi = x + i * d + offset_d;
223
+
224
+ for (int m = 0; m < q->M; m++) {
225
+ int idx = codesi[offset_m + m];
226
+ const float* c = codebooks.data() +
227
+ q->d * (codebook_offsets[offset_m + m] + idx);
228
+ if (m == 0) {
229
+ memcpy(xi, c, sizeof(*x) * q->d);
230
+ } else {
231
+ fvec_add(q->d, xi, c, xi);
232
+ }
233
+ }
234
+
235
+ offset_m += q->M;
236
+ offset_d += q->d;
237
+ }
238
+ }
239
+ }
240
+
241
+ void ProductAdditiveQuantizer::decode(const uint8_t* codes, float* x, size_t n)
242
+ const {
243
+ FAISS_THROW_IF_NOT_MSG(
244
+ is_trained, "The product additive quantizer is not trained yet.");
245
+
246
+ #pragma omp parallel for if (n > 1000)
247
+ for (int64_t i = 0; i < n; i++) {
248
+ BitstringReader bsr(codes + i * code_size, code_size);
249
+
250
+ size_t offset_m = 0, offset_d = 0;
251
+ for (size_t s = 0; s < nsplits; s++) {
252
+ const auto q = quantizers[s];
253
+ float* xi = x + i * d + offset_d;
254
+
255
+ for (int m = 0; m < q->M; m++) {
256
+ int idx = bsr.read(q->nbits[m]);
257
+ const float* c = codebooks.data() +
258
+ q->d * (codebook_offsets[offset_m + m] + idx);
259
+ if (m == 0) {
260
+ memcpy(xi, c, sizeof(*x) * q->d);
261
+ } else {
262
+ fvec_add(q->d, xi, c, xi);
263
+ }
264
+ }
265
+
266
+ offset_m += q->M;
267
+ offset_d += q->d;
268
+ }
269
+ }
270
+ }
271
+
272
+ void ProductAdditiveQuantizer::compute_LUT(
273
+ size_t n,
274
+ const float* xq,
275
+ float* LUT,
276
+ float alpha,
277
+ long ld_lut) const {
278
+ // codebooks: size (M * ksub, dsub)
279
+ // xq: size (n, d)
280
+ // output LUT: size (n, M * ksub)
281
+
282
+ FINTEGER nqi = n;
283
+ // leading dimension of 'LUT' and 'xq'
284
+ FINTEGER ld_LUT = ld_lut > 0 ? ld_lut : total_codebook_size;
285
+ FINTEGER ld_xq = d;
286
+
287
+ float zero = 0;
288
+ size_t offset_d = 0;
289
+ size_t offset_cb = 0;
290
+ size_t offset_lut = 0;
291
+
292
+ for (size_t s = 0; s < nsplits; s++) {
293
+ const auto q = quantizers[s];
294
+
295
+ FINTEGER ncenti = q->total_codebook_size;
296
+ FINTEGER ld_cb = q->d; // leading dimension of 'codebooks'
297
+
298
+ auto codebooksi = codebooks.data() + offset_cb;
299
+ auto xqi = xq + offset_d;
300
+ auto LUTi = LUT + offset_lut;
301
+
302
+ sgemm_("Transposed",
303
+ "Not transposed",
304
+ &ncenti,
305
+ &nqi,
306
+ &ld_cb,
307
+ &alpha,
308
+ codebooksi,
309
+ &ld_cb,
310
+ xqi,
311
+ &ld_xq,
312
+ &zero,
313
+ LUTi,
314
+ &ld_LUT);
315
+
316
+ offset_d += q->d;
317
+ offset_cb += q->total_codebook_size * q->d;
318
+ offset_lut += q->total_codebook_size;
319
+ }
320
+ }
321
+
322
+ /*************************************
323
+ * Product Local Search Quantizer
324
+ ************************************/
325
+
326
+ ProductLocalSearchQuantizer::ProductLocalSearchQuantizer(
327
+ size_t d,
328
+ size_t nsplits,
329
+ size_t Msub,
330
+ size_t nbits,
331
+ Search_type_t search_type) {
332
+ std::vector<AdditiveQuantizer*> aqs;
333
+
334
+ if (nsplits > 0) {
335
+ FAISS_THROW_IF_NOT(d % nsplits == 0);
336
+ size_t dsub = d / nsplits;
337
+
338
+ for (size_t i = 0; i < nsplits; i++) {
339
+ auto lsq =
340
+ new LocalSearchQuantizer(dsub, Msub, nbits, ST_decompress);
341
+ aqs.push_back(lsq);
342
+ }
343
+ }
344
+ init(d, aqs, search_type);
345
+ for (auto& q : aqs) {
346
+ delete q;
347
+ }
348
+ }
349
+
350
+ ProductLocalSearchQuantizer::ProductLocalSearchQuantizer()
351
+ : ProductLocalSearchQuantizer(0, 0, 0, 0) {}
352
+
353
+ /*************************************
354
+ * Product Residual Quantizer
355
+ ************************************/
356
+
357
+ ProductResidualQuantizer::ProductResidualQuantizer(
358
+ size_t d,
359
+ size_t nsplits,
360
+ size_t Msub,
361
+ size_t nbits,
362
+ Search_type_t search_type) {
363
+ std::vector<AdditiveQuantizer*> aqs;
364
+
365
+ if (nsplits > 0) {
366
+ FAISS_THROW_IF_NOT(d % nsplits == 0);
367
+ size_t dsub = d / nsplits;
368
+
369
+ for (size_t i = 0; i < nsplits; i++) {
370
+ auto rq = new ResidualQuantizer(dsub, Msub, nbits, ST_decompress);
371
+ aqs.push_back(rq);
372
+ }
373
+ }
374
+ init(d, aqs, search_type);
375
+ for (auto& q : aqs) {
376
+ delete q;
377
+ }
378
+ }
379
+
380
+ ProductResidualQuantizer::ProductResidualQuantizer()
381
+ : ProductResidualQuantizer(0, 0, 0, 0) {}
382
+
383
+ } // namespace faiss
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its 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 <cstdint>
11
+ #include <vector>
12
+
13
+ #include <faiss/Index.h>
14
+ #include <faiss/impl/AdditiveQuantizer.h>
15
+ #include <faiss/impl/LocalSearchQuantizer.h>
16
+ #include <faiss/impl/ResidualQuantizer.h>
17
+
18
+ namespace faiss {
19
+
20
+ /** Product Additive Quantizers
21
+ *
22
+ * The product additive quantizer is a variant of AQ and PQ.
23
+ * It first splits the vector space into multiple orthogonal sub-spaces
24
+ * just like PQ does. And then it quantizes each sub-space by an independent
25
+ * additive quantizer.
26
+ *
27
+ */
28
+ struct ProductAdditiveQuantizer : AdditiveQuantizer {
29
+ size_t nsplits; ///< number of sub-vectors we split a vector into
30
+
31
+ std::vector<AdditiveQuantizer*> quantizers;
32
+
33
+ /** Construct a product additive quantizer.
34
+ *
35
+ * The additive quantizers passed in will be cloned into the
36
+ * ProductAdditiveQuantizer object.
37
+ *
38
+ * @param d dimensionality of the input vectors
39
+ * @param aqs sub-additive quantizers
40
+ * @param search_type AQ search type
41
+ */
42
+ ProductAdditiveQuantizer(
43
+ size_t d,
44
+ const std::vector<AdditiveQuantizer*>& aqs,
45
+ Search_type_t search_type = ST_decompress);
46
+
47
+ ProductAdditiveQuantizer();
48
+
49
+ virtual ~ProductAdditiveQuantizer();
50
+
51
+ void init(
52
+ size_t d,
53
+ const std::vector<AdditiveQuantizer*>& aqs,
54
+ Search_type_t search_type);
55
+
56
+ AdditiveQuantizer* subquantizer(size_t m) const;
57
+
58
+ ///< Train the product additive quantizer
59
+ void train(size_t n, const float* x) override;
60
+
61
+ /** Encode a set of vectors
62
+ *
63
+ * @param x vectors to encode, size n * d
64
+ * @param codes output codes, size n * code_size
65
+ * @param centroids centroids to be added to x, size n * d
66
+ */
67
+ void compute_codes_add_centroids(
68
+ const float* x,
69
+ uint8_t* codes,
70
+ size_t n,
71
+ const float* centroids = nullptr) const override;
72
+
73
+ void compute_unpacked_codes(
74
+ const float* x,
75
+ int32_t* codes,
76
+ size_t n,
77
+ const float* centroids = nullptr) const;
78
+
79
+ /** Decode a set of vectors in non-packed format
80
+ *
81
+ * @param codes codes to decode, size n * ld_codes
82
+ * @param x output vectors, size n * d
83
+ */
84
+ void decode_unpacked(
85
+ const int32_t* codes,
86
+ float* x,
87
+ size_t n,
88
+ int64_t ld_codes = -1) const override;
89
+
90
+ /** Decode a set of vectors
91
+ *
92
+ * @param codes codes to decode, size n * code_size
93
+ * @param x output vectors, size n * d
94
+ */
95
+ void decode(const uint8_t* codes, float* x, size_t n) const override;
96
+
97
+ /** Compute inner-product look-up tables. Used in the search functions.
98
+ *
99
+ * @param xq query vector, size (n, d)
100
+ * @param LUT look-up table, size (n, total_codebook_size)
101
+ * @param alpha compute alpha * inner-product
102
+ * @param ld_lut leading dimension of LUT
103
+ */
104
+ void compute_LUT(
105
+ size_t n,
106
+ const float* xq,
107
+ float* LUT,
108
+ float alpha = 1.0f,
109
+ long ld_lut = -1) const override;
110
+ };
111
+
112
+ /** Product Local Search Quantizer
113
+ */
114
+ struct ProductLocalSearchQuantizer : ProductAdditiveQuantizer {
115
+ /** Construct a product LSQ object.
116
+ *
117
+ * @param d dimensionality of the input vectors
118
+ * @param nsplits number of sub-vectors we split a vector into
119
+ * @param Msub number of codebooks of each LSQ
120
+ * @param nbits bits for each step
121
+ * @param search_type AQ search type
122
+ */
123
+ ProductLocalSearchQuantizer(
124
+ size_t d,
125
+ size_t nsplits,
126
+ size_t Msub,
127
+ size_t nbits,
128
+ Search_type_t search_type = ST_decompress);
129
+
130
+ ProductLocalSearchQuantizer();
131
+ };
132
+
133
+ /** Product Residual Quantizer
134
+ */
135
+ struct ProductResidualQuantizer : ProductAdditiveQuantizer {
136
+ /** Construct a product RQ object.
137
+ *
138
+ * @param d dimensionality of the input vectors
139
+ * @param nsplits number of sub-vectors we split a vector into
140
+ * @param Msub number of codebooks of each RQ
141
+ * @param nbits bits for each step
142
+ * @param search_type AQ search type
143
+ */
144
+ ProductResidualQuantizer(
145
+ size_t d,
146
+ size_t nsplits,
147
+ size_t Msub,
148
+ size_t nbits,
149
+ Search_type_t search_type = ST_decompress);
150
+
151
+ ProductResidualQuantizer();
152
+ };
153
+
154
+ }; // namespace faiss