faiss 0.2.4 → 0.2.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (177) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/README.md +23 -21
  4. data/ext/faiss/extconf.rb +11 -0
  5. data/ext/faiss/index.cpp +4 -4
  6. data/ext/faiss/index_binary.cpp +6 -6
  7. data/ext/faiss/product_quantizer.cpp +4 -4
  8. data/lib/faiss/version.rb +1 -1
  9. data/vendor/faiss/faiss/AutoTune.cpp +13 -0
  10. data/vendor/faiss/faiss/IVFlib.cpp +101 -2
  11. data/vendor/faiss/faiss/IVFlib.h +26 -2
  12. data/vendor/faiss/faiss/Index.cpp +36 -3
  13. data/vendor/faiss/faiss/Index.h +43 -6
  14. data/vendor/faiss/faiss/Index2Layer.cpp +6 -2
  15. data/vendor/faiss/faiss/Index2Layer.h +6 -1
  16. data/vendor/faiss/faiss/IndexAdditiveQuantizer.cpp +219 -16
  17. data/vendor/faiss/faiss/IndexAdditiveQuantizer.h +63 -5
  18. data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.cpp +299 -0
  19. data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.h +199 -0
  20. data/vendor/faiss/faiss/IndexBinary.cpp +20 -4
  21. data/vendor/faiss/faiss/IndexBinary.h +18 -3
  22. data/vendor/faiss/faiss/IndexBinaryFlat.cpp +9 -2
  23. data/vendor/faiss/faiss/IndexBinaryFlat.h +4 -2
  24. data/vendor/faiss/faiss/IndexBinaryFromFloat.cpp +4 -1
  25. data/vendor/faiss/faiss/IndexBinaryFromFloat.h +2 -1
  26. data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +5 -1
  27. data/vendor/faiss/faiss/IndexBinaryHNSW.h +2 -1
  28. data/vendor/faiss/faiss/IndexBinaryHash.cpp +17 -4
  29. data/vendor/faiss/faiss/IndexBinaryHash.h +8 -4
  30. data/vendor/faiss/faiss/IndexBinaryIVF.cpp +28 -13
  31. data/vendor/faiss/faiss/IndexBinaryIVF.h +10 -7
  32. data/vendor/faiss/faiss/IndexFastScan.cpp +626 -0
  33. data/vendor/faiss/faiss/IndexFastScan.h +145 -0
  34. data/vendor/faiss/faiss/IndexFlat.cpp +34 -21
  35. data/vendor/faiss/faiss/IndexFlat.h +7 -4
  36. data/vendor/faiss/faiss/IndexFlatCodes.cpp +35 -1
  37. data/vendor/faiss/faiss/IndexFlatCodes.h +12 -0
  38. data/vendor/faiss/faiss/IndexHNSW.cpp +66 -138
  39. data/vendor/faiss/faiss/IndexHNSW.h +4 -2
  40. data/vendor/faiss/faiss/IndexIDMap.cpp +247 -0
  41. data/vendor/faiss/faiss/IndexIDMap.h +107 -0
  42. data/vendor/faiss/faiss/IndexIVF.cpp +121 -33
  43. data/vendor/faiss/faiss/IndexIVF.h +35 -16
  44. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +84 -7
  45. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.h +63 -1
  46. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.cpp +590 -0
  47. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.h +171 -0
  48. data/vendor/faiss/faiss/IndexIVFFastScan.cpp +1290 -0
  49. data/vendor/faiss/faiss/IndexIVFFastScan.h +213 -0
  50. data/vendor/faiss/faiss/IndexIVFFlat.cpp +37 -17
  51. data/vendor/faiss/faiss/IndexIVFFlat.h +4 -2
  52. data/vendor/faiss/faiss/IndexIVFPQ.cpp +234 -50
  53. data/vendor/faiss/faiss/IndexIVFPQ.h +5 -1
  54. data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +23 -852
  55. data/vendor/faiss/faiss/IndexIVFPQFastScan.h +7 -112
  56. data/vendor/faiss/faiss/IndexIVFPQR.cpp +3 -3
  57. data/vendor/faiss/faiss/IndexIVFPQR.h +1 -1
  58. data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +3 -1
  59. data/vendor/faiss/faiss/IndexIVFSpectralHash.h +2 -1
  60. data/vendor/faiss/faiss/IndexLSH.cpp +4 -2
  61. data/vendor/faiss/faiss/IndexLSH.h +2 -1
  62. data/vendor/faiss/faiss/IndexLattice.cpp +7 -1
  63. data/vendor/faiss/faiss/IndexLattice.h +3 -1
  64. data/vendor/faiss/faiss/IndexNNDescent.cpp +4 -3
  65. data/vendor/faiss/faiss/IndexNNDescent.h +2 -1
  66. data/vendor/faiss/faiss/IndexNSG.cpp +37 -3
  67. data/vendor/faiss/faiss/IndexNSG.h +25 -1
  68. data/vendor/faiss/faiss/IndexPQ.cpp +106 -69
  69. data/vendor/faiss/faiss/IndexPQ.h +19 -5
  70. data/vendor/faiss/faiss/IndexPQFastScan.cpp +15 -450
  71. data/vendor/faiss/faiss/IndexPQFastScan.h +15 -78
  72. data/vendor/faiss/faiss/IndexPreTransform.cpp +47 -8
  73. data/vendor/faiss/faiss/IndexPreTransform.h +15 -3
  74. data/vendor/faiss/faiss/IndexRefine.cpp +8 -4
  75. data/vendor/faiss/faiss/IndexRefine.h +4 -2
  76. data/vendor/faiss/faiss/IndexReplicas.cpp +4 -2
  77. data/vendor/faiss/faiss/IndexReplicas.h +2 -1
  78. data/vendor/faiss/faiss/IndexRowwiseMinMax.cpp +438 -0
  79. data/vendor/faiss/faiss/IndexRowwiseMinMax.h +92 -0
  80. data/vendor/faiss/faiss/IndexScalarQuantizer.cpp +26 -15
  81. data/vendor/faiss/faiss/IndexScalarQuantizer.h +6 -7
  82. data/vendor/faiss/faiss/IndexShards.cpp +4 -1
  83. data/vendor/faiss/faiss/IndexShards.h +2 -1
  84. data/vendor/faiss/faiss/MetaIndexes.cpp +5 -178
  85. data/vendor/faiss/faiss/MetaIndexes.h +3 -81
  86. data/vendor/faiss/faiss/VectorTransform.cpp +43 -0
  87. data/vendor/faiss/faiss/VectorTransform.h +22 -4
  88. data/vendor/faiss/faiss/clone_index.cpp +23 -1
  89. data/vendor/faiss/faiss/clone_index.h +3 -0
  90. data/vendor/faiss/faiss/cppcontrib/SaDecodeKernels.h +300 -0
  91. data/vendor/faiss/faiss/cppcontrib/detail/CoarseBitType.h +24 -0
  92. data/vendor/faiss/faiss/cppcontrib/detail/UintReader.h +195 -0
  93. data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-avx2-inl.h +2058 -0
  94. data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-inl.h +408 -0
  95. data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-neon-inl.h +2147 -0
  96. data/vendor/faiss/faiss/cppcontrib/sa_decode/MinMax-inl.h +460 -0
  97. data/vendor/faiss/faiss/cppcontrib/sa_decode/MinMaxFP16-inl.h +465 -0
  98. data/vendor/faiss/faiss/cppcontrib/sa_decode/PQ-avx2-inl.h +1618 -0
  99. data/vendor/faiss/faiss/cppcontrib/sa_decode/PQ-inl.h +251 -0
  100. data/vendor/faiss/faiss/cppcontrib/sa_decode/PQ-neon-inl.h +1452 -0
  101. data/vendor/faiss/faiss/gpu/GpuAutoTune.cpp +1 -0
  102. data/vendor/faiss/faiss/gpu/GpuCloner.cpp +0 -4
  103. data/vendor/faiss/faiss/gpu/GpuIndex.h +28 -4
  104. data/vendor/faiss/faiss/gpu/GpuIndexBinaryFlat.h +2 -1
  105. data/vendor/faiss/faiss/gpu/GpuIndexFlat.h +10 -8
  106. data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +75 -14
  107. data/vendor/faiss/faiss/gpu/GpuIndexIVFFlat.h +19 -32
  108. data/vendor/faiss/faiss/gpu/GpuIndexIVFPQ.h +22 -31
  109. data/vendor/faiss/faiss/gpu/GpuIndexIVFScalarQuantizer.h +22 -28
  110. data/vendor/faiss/faiss/gpu/GpuResources.cpp +14 -0
  111. data/vendor/faiss/faiss/gpu/GpuResources.h +16 -3
  112. data/vendor/faiss/faiss/gpu/StandardGpuResources.cpp +3 -3
  113. data/vendor/faiss/faiss/gpu/impl/IndexUtils.h +32 -0
  114. data/vendor/faiss/faiss/gpu/test/TestGpuIndexBinaryFlat.cpp +1 -0
  115. data/vendor/faiss/faiss/gpu/test/TestGpuIndexFlat.cpp +311 -75
  116. data/vendor/faiss/faiss/gpu/test/TestUtils.cpp +10 -0
  117. data/vendor/faiss/faiss/gpu/test/TestUtils.h +3 -0
  118. data/vendor/faiss/faiss/gpu/test/demo_ivfpq_indexing_gpu.cpp +2 -2
  119. data/vendor/faiss/faiss/gpu/utils/DeviceUtils.h +5 -4
  120. data/vendor/faiss/faiss/impl/AdditiveQuantizer.cpp +116 -47
  121. data/vendor/faiss/faiss/impl/AdditiveQuantizer.h +44 -13
  122. data/vendor/faiss/faiss/impl/AuxIndexStructures.cpp +0 -54
  123. data/vendor/faiss/faiss/impl/AuxIndexStructures.h +0 -76
  124. data/vendor/faiss/faiss/impl/DistanceComputer.h +64 -0
  125. data/vendor/faiss/faiss/impl/HNSW.cpp +123 -27
  126. data/vendor/faiss/faiss/impl/HNSW.h +19 -16
  127. data/vendor/faiss/faiss/impl/IDSelector.cpp +125 -0
  128. data/vendor/faiss/faiss/impl/IDSelector.h +135 -0
  129. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +6 -28
  130. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.h +6 -1
  131. data/vendor/faiss/faiss/impl/LookupTableScaler.h +77 -0
  132. data/vendor/faiss/faiss/impl/NNDescent.cpp +1 -0
  133. data/vendor/faiss/faiss/impl/NSG.cpp +1 -1
  134. data/vendor/faiss/faiss/impl/ProductAdditiveQuantizer.cpp +383 -0
  135. data/vendor/faiss/faiss/impl/ProductAdditiveQuantizer.h +154 -0
  136. data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +225 -145
  137. data/vendor/faiss/faiss/impl/ProductQuantizer.h +29 -10
  138. data/vendor/faiss/faiss/impl/Quantizer.h +43 -0
  139. data/vendor/faiss/faiss/impl/ResidualQuantizer.cpp +192 -36
  140. data/vendor/faiss/faiss/impl/ResidualQuantizer.h +40 -20
  141. data/vendor/faiss/faiss/impl/ResultHandler.h +96 -0
  142. data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +97 -173
  143. data/vendor/faiss/faiss/impl/ScalarQuantizer.h +18 -18
  144. data/vendor/faiss/faiss/impl/index_read.cpp +240 -9
  145. data/vendor/faiss/faiss/impl/index_write.cpp +237 -5
  146. data/vendor/faiss/faiss/impl/kmeans1d.cpp +6 -4
  147. data/vendor/faiss/faiss/impl/pq4_fast_scan.cpp +56 -16
  148. data/vendor/faiss/faiss/impl/pq4_fast_scan.h +25 -8
  149. data/vendor/faiss/faiss/impl/pq4_fast_scan_search_1.cpp +66 -25
  150. data/vendor/faiss/faiss/impl/pq4_fast_scan_search_qbs.cpp +75 -27
  151. data/vendor/faiss/faiss/index_factory.cpp +196 -7
  152. data/vendor/faiss/faiss/index_io.h +5 -0
  153. data/vendor/faiss/faiss/invlists/DirectMap.cpp +1 -0
  154. data/vendor/faiss/faiss/invlists/InvertedLists.cpp +4 -1
  155. data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +2 -1
  156. data/vendor/faiss/faiss/python/python_callbacks.cpp +27 -0
  157. data/vendor/faiss/faiss/python/python_callbacks.h +15 -0
  158. data/vendor/faiss/faiss/utils/Heap.h +31 -15
  159. data/vendor/faiss/faiss/utils/distances.cpp +380 -56
  160. data/vendor/faiss/faiss/utils/distances.h +113 -15
  161. data/vendor/faiss/faiss/utils/distances_simd.cpp +726 -6
  162. data/vendor/faiss/faiss/utils/extra_distances.cpp +12 -7
  163. data/vendor/faiss/faiss/utils/extra_distances.h +3 -1
  164. data/vendor/faiss/faiss/utils/fp16-fp16c.h +21 -0
  165. data/vendor/faiss/faiss/utils/fp16-inl.h +101 -0
  166. data/vendor/faiss/faiss/utils/fp16.h +11 -0
  167. data/vendor/faiss/faiss/utils/hamming-inl.h +54 -0
  168. data/vendor/faiss/faiss/utils/hamming.cpp +0 -48
  169. data/vendor/faiss/faiss/utils/ordered_key_value.h +10 -0
  170. data/vendor/faiss/faiss/utils/quantize_lut.cpp +62 -0
  171. data/vendor/faiss/faiss/utils/quantize_lut.h +20 -0
  172. data/vendor/faiss/faiss/utils/random.cpp +53 -0
  173. data/vendor/faiss/faiss/utils/random.h +5 -0
  174. data/vendor/faiss/faiss/utils/simdlib_avx2.h +4 -0
  175. data/vendor/faiss/faiss/utils/simdlib_emulated.h +6 -1
  176. data/vendor/faiss/faiss/utils/simdlib_neon.h +7 -2
  177. metadata +37 -3
@@ -0,0 +1,77 @@
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 <cstdlib>
12
+
13
+ #include <faiss/utils/simdlib.h>
14
+
15
+ /*******************************************
16
+ * The Scaler objects are used to specialize the handling of the
17
+ * norm components in Additive quantizer fast-scan.
18
+ ********************************************/
19
+
20
+ namespace faiss {
21
+
22
+ /// no-op handler
23
+ struct DummyScaler {
24
+ static constexpr int nscale = 0;
25
+
26
+ inline simd32uint8 lookup(const simd32uint8&, const simd32uint8&) const {
27
+ FAISS_THROW_MSG("DummyScaler::lookup should not be called.");
28
+ return simd32uint8(0);
29
+ }
30
+
31
+ inline simd16uint16 scale_lo(const simd32uint8&) const {
32
+ FAISS_THROW_MSG("DummyScaler::scale_lo should not be called.");
33
+ return simd16uint16(0);
34
+ }
35
+
36
+ inline simd16uint16 scale_hi(const simd32uint8&) const {
37
+ FAISS_THROW_MSG("DummyScaler::scale_hi should not be called.");
38
+ return simd16uint16(0);
39
+ }
40
+
41
+ template <class dist_t>
42
+ inline dist_t scale_one(const dist_t&) const {
43
+ FAISS_THROW_MSG("DummyScaler::scale_one should not be called.");
44
+ return 0;
45
+ }
46
+ };
47
+
48
+ /// consumes 2x4 bits to encode a norm as a scalar additive quantizer
49
+ /// the norm is scaled because its range if larger than other components
50
+ struct NormTableScaler {
51
+ static constexpr int nscale = 2;
52
+ int scale_int;
53
+ simd16uint16 scale_simd;
54
+
55
+ explicit NormTableScaler(int scale) : scale_int(scale), scale_simd(scale) {}
56
+
57
+ inline simd32uint8 lookup(const simd32uint8& lut, const simd32uint8& c)
58
+ const {
59
+ return lut.lookup_2_lanes(c);
60
+ }
61
+
62
+ inline simd16uint16 scale_lo(const simd32uint8& res) const {
63
+ return simd16uint16(res) * scale_simd;
64
+ }
65
+
66
+ inline simd16uint16 scale_hi(const simd32uint8& res) const {
67
+ return (simd16uint16(res) >> 8) * scale_simd;
68
+ }
69
+
70
+ // for non-SIMD implem 2, 3, 4
71
+ template <class dist_t>
72
+ inline dist_t scale_one(const dist_t& x) const {
73
+ return x * scale_int;
74
+ }
75
+ };
76
+
77
+ } // namespace faiss
@@ -13,6 +13,7 @@
13
13
  #include <string>
14
14
 
15
15
  #include <faiss/impl/AuxIndexStructures.h>
16
+ #include <faiss/impl/DistanceComputer.h>
16
17
 
17
18
  namespace faiss {
18
19
 
@@ -14,7 +14,7 @@
14
14
  #include <mutex>
15
15
  #include <stack>
16
16
 
17
- #include <faiss/impl/AuxIndexStructures.h>
17
+ #include <faiss/impl/DistanceComputer.h>
18
18
 
19
19
  namespace faiss {
20
20
 
@@ -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