faiss 0.2.4 → 0.2.5

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.
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