/root/doris/contrib/faiss/faiss/IndexAdditiveQuantizer.cpp
Line | Count | Source |
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/IndexAdditiveQuantizer.h> |
9 | | |
10 | | #include <algorithm> |
11 | | #include <cmath> |
12 | | #include <cstring> |
13 | | |
14 | | #include <faiss/impl/FaissAssert.h> |
15 | | #include <faiss/impl/ResidualQuantizer.h> |
16 | | #include <faiss/impl/ResultHandler.h> |
17 | | #include <faiss/utils/distances.h> |
18 | | #include <faiss/utils/extra_distances.h> |
19 | | |
20 | | namespace faiss { |
21 | | |
22 | | /************************************************************************************** |
23 | | * IndexAdditiveQuantizer |
24 | | **************************************************************************************/ |
25 | | |
26 | | IndexAdditiveQuantizer::IndexAdditiveQuantizer( |
27 | | idx_t d, |
28 | | AdditiveQuantizer* aq, |
29 | | MetricType metric) |
30 | 0 | : IndexFlatCodes(aq->code_size, d, metric), aq(aq) { |
31 | 0 | FAISS_THROW_IF_NOT(metric == METRIC_INNER_PRODUCT || metric == METRIC_L2); |
32 | 0 | } |
33 | | |
34 | | namespace { |
35 | | |
36 | | /************************************************************ |
37 | | * DistanceComputer implementation |
38 | | ************************************************************/ |
39 | | |
40 | | template <class VectorDistance> |
41 | | struct AQDistanceComputerDecompress : FlatCodesDistanceComputer { |
42 | | std::vector<float> tmp; |
43 | | const AdditiveQuantizer& aq; |
44 | | VectorDistance vd; |
45 | | size_t d; |
46 | | |
47 | | AQDistanceComputerDecompress( |
48 | | const IndexAdditiveQuantizer& iaq, |
49 | | VectorDistance vd) |
50 | 0 | : FlatCodesDistanceComputer(iaq.codes.data(), iaq.code_size), |
51 | 0 | tmp(iaq.d * 2), |
52 | 0 | aq(*iaq.aq), |
53 | 0 | vd(vd), |
54 | 0 | d(iaq.d) {}Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_128AQDistanceComputerDecompressINS_14VectorDistanceILNS_10MetricTypeE1EEEEC2ERKNS_22IndexAdditiveQuantizerES4_ Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_128AQDistanceComputerDecompressINS_14VectorDistanceILNS_10MetricTypeE0EEEEC2ERKNS_22IndexAdditiveQuantizerES4_ |
55 | | |
56 | | const float* q; |
57 | 0 | void set_query(const float* x) final { |
58 | 0 | q = x; |
59 | 0 | } Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_128AQDistanceComputerDecompressINS_14VectorDistanceILNS_10MetricTypeE1EEEE9set_queryEPKf Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_128AQDistanceComputerDecompressINS_14VectorDistanceILNS_10MetricTypeE0EEEE9set_queryEPKf |
60 | | |
61 | 0 | float symmetric_dis(idx_t i, idx_t j) final { |
62 | 0 | aq.decode(codes + i * d, tmp.data(), 1); |
63 | 0 | aq.decode(codes + j * d, tmp.data() + d, 1); |
64 | 0 | return vd(tmp.data(), tmp.data() + d); |
65 | 0 | } Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_128AQDistanceComputerDecompressINS_14VectorDistanceILNS_10MetricTypeE1EEEE13symmetric_disEll Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_128AQDistanceComputerDecompressINS_14VectorDistanceILNS_10MetricTypeE0EEEE13symmetric_disEll |
66 | | |
67 | 0 | float distance_to_code(const uint8_t* code) final { |
68 | 0 | aq.decode(code, tmp.data(), 1); |
69 | 0 | return vd(q, tmp.data()); |
70 | 0 | } Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_128AQDistanceComputerDecompressINS_14VectorDistanceILNS_10MetricTypeE1EEEE16distance_to_codeEPKh Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_128AQDistanceComputerDecompressINS_14VectorDistanceILNS_10MetricTypeE0EEEE16distance_to_codeEPKh |
71 | | |
72 | 0 | virtual ~AQDistanceComputerDecompress() = default; Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_128AQDistanceComputerDecompressINS_14VectorDistanceILNS_10MetricTypeE1EEEED2Ev Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_128AQDistanceComputerDecompressINS_14VectorDistanceILNS_10MetricTypeE0EEEED2Ev |
73 | | }; |
74 | | |
75 | | template <bool is_IP, AdditiveQuantizer::Search_type_t st> |
76 | | struct AQDistanceComputerLUT : FlatCodesDistanceComputer { |
77 | | std::vector<float> LUT; |
78 | | const AdditiveQuantizer& aq; |
79 | | size_t d; |
80 | | |
81 | | explicit AQDistanceComputerLUT(const IndexAdditiveQuantizer& iaq) |
82 | 0 | : FlatCodesDistanceComputer(iaq.codes.data(), iaq.code_size), |
83 | 0 | LUT(iaq.aq->total_codebook_size + iaq.d * 2), |
84 | 0 | aq(*iaq.aq), |
85 | 0 | d(iaq.d) {}Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb1ELNS_17AdditiveQuantizer13Search_type_tE1EEC2ERKNS_22IndexAdditiveQuantizerE Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb0ELNS_17AdditiveQuantizer13Search_type_tE3EEC2ERKNS_22IndexAdditiveQuantizerE Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb0ELNS_17AdditiveQuantizer13Search_type_tE1EEC2ERKNS_22IndexAdditiveQuantizerE Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb0ELNS_17AdditiveQuantizer13Search_type_tE4EEC2ERKNS_22IndexAdditiveQuantizerE Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb0ELNS_17AdditiveQuantizer13Search_type_tE5EEC2ERKNS_22IndexAdditiveQuantizerE Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb0ELNS_17AdditiveQuantizer13Search_type_tE7EEC2ERKNS_22IndexAdditiveQuantizerE Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb0ELNS_17AdditiveQuantizer13Search_type_tE6EEC2ERKNS_22IndexAdditiveQuantizerE |
86 | | |
87 | | float bias; |
88 | 0 | void set_query(const float* x) final { |
89 | | // this is quite sub-optimal for multiple queries |
90 | 0 | aq.compute_LUT(1, x, LUT.data()); |
91 | 0 | if (is_IP) { |
92 | 0 | bias = 0; |
93 | 0 | } else { |
94 | 0 | bias = fvec_norm_L2sqr(x, d); |
95 | 0 | } |
96 | 0 | } Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb1ELNS_17AdditiveQuantizer13Search_type_tE1EE9set_queryEPKf Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb0ELNS_17AdditiveQuantizer13Search_type_tE3EE9set_queryEPKf Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb0ELNS_17AdditiveQuantizer13Search_type_tE1EE9set_queryEPKf Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb0ELNS_17AdditiveQuantizer13Search_type_tE4EE9set_queryEPKf Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb0ELNS_17AdditiveQuantizer13Search_type_tE5EE9set_queryEPKf Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb0ELNS_17AdditiveQuantizer13Search_type_tE7EE9set_queryEPKf Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb0ELNS_17AdditiveQuantizer13Search_type_tE6EE9set_queryEPKf |
97 | | |
98 | 0 | float symmetric_dis(idx_t i, idx_t j) final { |
99 | 0 | float* tmp = LUT.data(); |
100 | 0 | aq.decode(codes + i * d, tmp, 1); |
101 | 0 | aq.decode(codes + j * d, tmp + d, 1); |
102 | 0 | return fvec_L2sqr(tmp, tmp + d, d); |
103 | 0 | } Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb1ELNS_17AdditiveQuantizer13Search_type_tE1EE13symmetric_disEll Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb0ELNS_17AdditiveQuantizer13Search_type_tE3EE13symmetric_disEll Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb0ELNS_17AdditiveQuantizer13Search_type_tE1EE13symmetric_disEll Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb0ELNS_17AdditiveQuantizer13Search_type_tE4EE13symmetric_disEll Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb0ELNS_17AdditiveQuantizer13Search_type_tE5EE13symmetric_disEll Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb0ELNS_17AdditiveQuantizer13Search_type_tE7EE13symmetric_disEll Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb0ELNS_17AdditiveQuantizer13Search_type_tE6EE13symmetric_disEll |
104 | | |
105 | 0 | float distance_to_code(const uint8_t* code) final { |
106 | 0 | return bias + aq.compute_1_distance_LUT<is_IP, st>(code, LUT.data()); |
107 | 0 | } Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb1ELNS_17AdditiveQuantizer13Search_type_tE1EE16distance_to_codeEPKh Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb0ELNS_17AdditiveQuantizer13Search_type_tE3EE16distance_to_codeEPKh Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb0ELNS_17AdditiveQuantizer13Search_type_tE1EE16distance_to_codeEPKh Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb0ELNS_17AdditiveQuantizer13Search_type_tE4EE16distance_to_codeEPKh Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb0ELNS_17AdditiveQuantizer13Search_type_tE5EE16distance_to_codeEPKh Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb0ELNS_17AdditiveQuantizer13Search_type_tE7EE16distance_to_codeEPKh Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb0ELNS_17AdditiveQuantizer13Search_type_tE6EE16distance_to_codeEPKh |
108 | | |
109 | 0 | virtual ~AQDistanceComputerLUT() = default; Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb1ELNS_17AdditiveQuantizer13Search_type_tE1EED2Ev Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb0ELNS_17AdditiveQuantizer13Search_type_tE3EED2Ev Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb0ELNS_17AdditiveQuantizer13Search_type_tE1EED2Ev Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb0ELNS_17AdditiveQuantizer13Search_type_tE4EED2Ev Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb0ELNS_17AdditiveQuantizer13Search_type_tE5EED2Ev Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb0ELNS_17AdditiveQuantizer13Search_type_tE7EED2Ev Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_121AQDistanceComputerLUTILb0ELNS_17AdditiveQuantizer13Search_type_tE6EED2Ev |
110 | | }; |
111 | | |
112 | | /************************************************************ |
113 | | * scanning implementation for search |
114 | | ************************************************************/ |
115 | | |
116 | | template <class VectorDistance, class BlockResultHandler> |
117 | | void search_with_decompress( |
118 | | const IndexAdditiveQuantizer& ir, |
119 | | const float* xq, |
120 | | VectorDistance& vd, |
121 | 0 | BlockResultHandler& res) { |
122 | 0 | const uint8_t* codes = ir.codes.data(); |
123 | 0 | size_t ntotal = ir.ntotal; |
124 | 0 | size_t code_size = ir.code_size; |
125 | 0 | const AdditiveQuantizer* aq = ir.aq; |
126 | |
|
127 | 0 | using SingleResultHandler = |
128 | 0 | typename BlockResultHandler::SingleResultHandler; |
129 | |
|
130 | 0 | #pragma omp parallel for if (res.nq > 100) |
131 | 0 | for (int64_t q = 0; q < res.nq; q++) { |
132 | 0 | SingleResultHandler resi(res); |
133 | 0 | resi.begin(q); |
134 | 0 | std::vector<float> tmp(ir.d); |
135 | 0 | const float* x = xq + ir.d * q; |
136 | 0 | for (size_t i = 0; i < ntotal; i++) { |
137 | 0 | aq->decode(codes + i * code_size, tmp.data(), 1); |
138 | 0 | float dis = vd(x, tmp.data()); |
139 | 0 | resi.add_result(dis, i); |
140 | 0 | } |
141 | 0 | resi.end(); |
142 | 0 | } Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_122search_with_decompressINS_14VectorDistanceILNS_10MetricTypeE1EEENS_22HeapBlockResultHandlerINS_4CMaxIflEELb0EEEEEvRKNS_22IndexAdditiveQuantizerEPKfRT_RT0_.omp_outlined_debug__ Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_122search_with_decompressINS_14VectorDistanceILNS_10MetricTypeE0EEENS_22HeapBlockResultHandlerINS_4CMinIflEELb0EEEEEvRKNS_22IndexAdditiveQuantizerEPKfRT_RT0_.omp_outlined_debug__ |
143 | 0 | } Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_122search_with_decompressINS_14VectorDistanceILNS_10MetricTypeE1EEENS_22HeapBlockResultHandlerINS_4CMaxIflEELb0EEEEEvRKNS_22IndexAdditiveQuantizerEPKfRT_RT0_ Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_122search_with_decompressINS_14VectorDistanceILNS_10MetricTypeE0EEENS_22HeapBlockResultHandlerINS_4CMinIflEELb0EEEEEvRKNS_22IndexAdditiveQuantizerEPKfRT_RT0_ |
144 | | |
145 | | template < |
146 | | bool is_IP, |
147 | | AdditiveQuantizer::Search_type_t st, |
148 | | class BlockResultHandler> |
149 | | void search_with_LUT( |
150 | | const IndexAdditiveQuantizer& ir, |
151 | | const float* xq, |
152 | 0 | BlockResultHandler& res) { |
153 | 0 | const AdditiveQuantizer& aq = *ir.aq; |
154 | 0 | const uint8_t* codes = ir.codes.data(); |
155 | 0 | size_t ntotal = ir.ntotal; |
156 | 0 | size_t code_size = aq.code_size; |
157 | 0 | size_t nq = res.nq; |
158 | 0 | size_t d = ir.d; |
159 | |
|
160 | 0 | using SingleResultHandler = |
161 | 0 | typename BlockResultHandler::SingleResultHandler; |
162 | 0 | std::unique_ptr<float[]> LUT(new float[nq * aq.total_codebook_size]); |
163 | |
|
164 | 0 | aq.compute_LUT(nq, xq, LUT.get()); |
165 | |
|
166 | 0 | #pragma omp parallel for if (nq > 100) |
167 | 0 | for (int64_t q = 0; q < nq; q++) { |
168 | 0 | SingleResultHandler resi(res); |
169 | 0 | resi.begin(q); |
170 | 0 | std::vector<float> tmp(aq.d); |
171 | 0 | const float* LUT_q = LUT.get() + aq.total_codebook_size * q; |
172 | 0 | float bias = 0; |
173 | 0 | if (!is_IP) { // the LUT function returns ||y||^2 - 2 * <x, y>, need to |
174 | | // add ||x||^2 |
175 | 0 | bias = fvec_norm_L2sqr(xq + q * d, d); |
176 | 0 | } |
177 | 0 | for (size_t i = 0; i < ntotal; i++) { |
178 | 0 | float dis = aq.compute_1_distance_LUT<is_IP, st>( |
179 | 0 | codes + i * code_size, LUT_q); |
180 | 0 | resi.add_result(dis + bias, i); |
181 | 0 | } |
182 | 0 | resi.end(); |
183 | 0 | } Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_115search_with_LUTILb1ELNS_17AdditiveQuantizer13Search_type_tE1ENS_22HeapBlockResultHandlerINS_4CMinIflEELb0EEEEEvRKNS_22IndexAdditiveQuantizerEPKfRT1_.omp_outlined_debug__ Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_115search_with_LUTILb0ELNS_17AdditiveQuantizer13Search_type_tE3ENS_22HeapBlockResultHandlerINS_4CMaxIflEELb0EEEEEvRKNS_22IndexAdditiveQuantizerEPKfRT1_.omp_outlined_debug__ Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_115search_with_LUTILb0ELNS_17AdditiveQuantizer13Search_type_tE1ENS_22HeapBlockResultHandlerINS_4CMaxIflEELb0EEEEEvRKNS_22IndexAdditiveQuantizerEPKfRT1_.omp_outlined_debug__ Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_115search_with_LUTILb0ELNS_17AdditiveQuantizer13Search_type_tE4ENS_22HeapBlockResultHandlerINS_4CMaxIflEELb0EEEEEvRKNS_22IndexAdditiveQuantizerEPKfRT1_.omp_outlined_debug__ Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_115search_with_LUTILb0ELNS_17AdditiveQuantizer13Search_type_tE5ENS_22HeapBlockResultHandlerINS_4CMaxIflEELb0EEEEEvRKNS_22IndexAdditiveQuantizerEPKfRT1_.omp_outlined_debug__ Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_115search_with_LUTILb0ELNS_17AdditiveQuantizer13Search_type_tE7ENS_22HeapBlockResultHandlerINS_4CMaxIflEELb0EEEEEvRKNS_22IndexAdditiveQuantizerEPKfRT1_.omp_outlined_debug__ Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_115search_with_LUTILb0ELNS_17AdditiveQuantizer13Search_type_tE2ENS_22HeapBlockResultHandlerINS_4CMaxIflEELb0EEEEEvRKNS_22IndexAdditiveQuantizerEPKfRT1_.omp_outlined_debug__ Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_115search_with_LUTILb0ELNS_17AdditiveQuantizer13Search_type_tE6ENS_22HeapBlockResultHandlerINS_4CMaxIflEELb0EEEEEvRKNS_22IndexAdditiveQuantizerEPKfRT1_.omp_outlined_debug__ |
184 | 0 | } Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_115search_with_LUTILb1ELNS_17AdditiveQuantizer13Search_type_tE1ENS_22HeapBlockResultHandlerINS_4CMinIflEELb0EEEEEvRKNS_22IndexAdditiveQuantizerEPKfRT1_ Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_115search_with_LUTILb0ELNS_17AdditiveQuantizer13Search_type_tE3ENS_22HeapBlockResultHandlerINS_4CMaxIflEELb0EEEEEvRKNS_22IndexAdditiveQuantizerEPKfRT1_ Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_115search_with_LUTILb0ELNS_17AdditiveQuantizer13Search_type_tE1ENS_22HeapBlockResultHandlerINS_4CMaxIflEELb0EEEEEvRKNS_22IndexAdditiveQuantizerEPKfRT1_ Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_115search_with_LUTILb0ELNS_17AdditiveQuantizer13Search_type_tE4ENS_22HeapBlockResultHandlerINS_4CMaxIflEELb0EEEEEvRKNS_22IndexAdditiveQuantizerEPKfRT1_ Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_115search_with_LUTILb0ELNS_17AdditiveQuantizer13Search_type_tE5ENS_22HeapBlockResultHandlerINS_4CMaxIflEELb0EEEEEvRKNS_22IndexAdditiveQuantizerEPKfRT1_ Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_115search_with_LUTILb0ELNS_17AdditiveQuantizer13Search_type_tE7ENS_22HeapBlockResultHandlerINS_4CMaxIflEELb0EEEEEvRKNS_22IndexAdditiveQuantizerEPKfRT1_ Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_115search_with_LUTILb0ELNS_17AdditiveQuantizer13Search_type_tE2ENS_22HeapBlockResultHandlerINS_4CMaxIflEELb0EEEEEvRKNS_22IndexAdditiveQuantizerEPKfRT1_ Unexecuted instantiation: IndexAdditiveQuantizer.cpp:_ZN5faiss12_GLOBAL__N_115search_with_LUTILb0ELNS_17AdditiveQuantizer13Search_type_tE6ENS_22HeapBlockResultHandlerINS_4CMaxIflEELb0EEEEEvRKNS_22IndexAdditiveQuantizerEPKfRT1_ |
185 | | |
186 | | } // anonymous namespace |
187 | | |
188 | | FlatCodesDistanceComputer* IndexAdditiveQuantizer:: |
189 | 0 | get_FlatCodesDistanceComputer() const { |
190 | 0 | if (aq->search_type == AdditiveQuantizer::ST_decompress) { |
191 | 0 | if (metric_type == METRIC_L2) { |
192 | 0 | using VD = VectorDistance<METRIC_L2>; |
193 | 0 | VD vd = {size_t(d), metric_arg}; |
194 | 0 | return new AQDistanceComputerDecompress<VD>(*this, vd); |
195 | 0 | } else if (metric_type == METRIC_INNER_PRODUCT) { |
196 | 0 | using VD = VectorDistance<METRIC_INNER_PRODUCT>; |
197 | 0 | VD vd = {size_t(d), metric_arg}; |
198 | 0 | return new AQDistanceComputerDecompress<VD>(*this, vd); |
199 | 0 | } else { |
200 | 0 | FAISS_THROW_MSG("unsupported metric"); |
201 | 0 | } |
202 | 0 | } else { |
203 | 0 | if (metric_type == METRIC_INNER_PRODUCT) { |
204 | 0 | return new AQDistanceComputerLUT< |
205 | 0 | true, |
206 | 0 | AdditiveQuantizer::ST_LUT_nonorm>(*this); |
207 | 0 | } else { |
208 | 0 | switch (aq->search_type) { |
209 | 0 | #define DISPATCH(st) \ |
210 | 0 | case AdditiveQuantizer::st: \ |
211 | 0 | return new AQDistanceComputerLUT<false, AdditiveQuantizer::st>(*this); \ |
212 | 0 | break; |
213 | 0 | DISPATCH(ST_norm_float) |
214 | 0 | DISPATCH(ST_LUT_nonorm) |
215 | 0 | DISPATCH(ST_norm_qint8) |
216 | 0 | DISPATCH(ST_norm_qint4) |
217 | 0 | DISPATCH(ST_norm_cqint4) |
218 | 0 | case AdditiveQuantizer::ST_norm_cqint8: |
219 | 0 | case AdditiveQuantizer::ST_norm_lsq2x4: |
220 | 0 | case AdditiveQuantizer::ST_norm_rq2x4: |
221 | 0 | return new AQDistanceComputerLUT< |
222 | 0 | false, |
223 | 0 | AdditiveQuantizer::ST_norm_cqint8>(*this); |
224 | 0 | break; |
225 | 0 | #undef DISPATCH |
226 | 0 | default: |
227 | 0 | FAISS_THROW_FMT( |
228 | 0 | "search type %d not supported", aq->search_type); |
229 | 0 | } |
230 | 0 | } |
231 | 0 | } |
232 | 0 | } |
233 | | |
234 | | void IndexAdditiveQuantizer::search( |
235 | | idx_t n, |
236 | | const float* x, |
237 | | idx_t k, |
238 | | float* distances, |
239 | | idx_t* labels, |
240 | 0 | const SearchParameters* params) const { |
241 | 0 | FAISS_THROW_IF_NOT_MSG( |
242 | 0 | !params, "search params not supported for this index"); |
243 | | |
244 | 0 | if (aq->search_type == AdditiveQuantizer::ST_decompress) { |
245 | 0 | if (metric_type == METRIC_L2) { |
246 | 0 | using VD = VectorDistance<METRIC_L2>; |
247 | 0 | VD vd = {size_t(d), metric_arg}; |
248 | 0 | HeapBlockResultHandler<VD::C> rh(n, distances, labels, k); |
249 | 0 | search_with_decompress(*this, x, vd, rh); |
250 | 0 | } else if (metric_type == METRIC_INNER_PRODUCT) { |
251 | 0 | using VD = VectorDistance<METRIC_INNER_PRODUCT>; |
252 | 0 | VD vd = {size_t(d), metric_arg}; |
253 | 0 | HeapBlockResultHandler<VD::C> rh(n, distances, labels, k); |
254 | 0 | search_with_decompress(*this, x, vd, rh); |
255 | 0 | } |
256 | 0 | } else { |
257 | 0 | if (metric_type == METRIC_INNER_PRODUCT) { |
258 | 0 | HeapBlockResultHandler<CMin<float, idx_t>> rh( |
259 | 0 | n, distances, labels, k); |
260 | 0 | search_with_LUT<true, AdditiveQuantizer::ST_LUT_nonorm>( |
261 | 0 | *this, x, rh); |
262 | 0 | } else { |
263 | 0 | HeapBlockResultHandler<CMax<float, idx_t>> rh( |
264 | 0 | n, distances, labels, k); |
265 | 0 | switch (aq->search_type) { |
266 | 0 | #define DISPATCH(st) \ |
267 | 0 | case AdditiveQuantizer::st: \ |
268 | 0 | search_with_LUT<false, AdditiveQuantizer::st>(*this, x, rh); \ |
269 | 0 | break; |
270 | 0 | DISPATCH(ST_norm_float) |
271 | 0 | DISPATCH(ST_LUT_nonorm) |
272 | 0 | DISPATCH(ST_norm_qint8) |
273 | 0 | DISPATCH(ST_norm_qint4) |
274 | 0 | DISPATCH(ST_norm_cqint4) |
275 | 0 | DISPATCH(ST_norm_from_LUT) |
276 | 0 | case AdditiveQuantizer::ST_norm_cqint8: |
277 | 0 | case AdditiveQuantizer::ST_norm_lsq2x4: |
278 | 0 | case AdditiveQuantizer::ST_norm_rq2x4: |
279 | 0 | search_with_LUT<false, AdditiveQuantizer::ST_norm_cqint8>( |
280 | 0 | *this, x, rh); |
281 | 0 | break; |
282 | 0 | #undef DISPATCH |
283 | 0 | default: |
284 | 0 | FAISS_THROW_FMT( |
285 | 0 | "search type %d not supported", aq->search_type); |
286 | 0 | } |
287 | 0 | } |
288 | 0 | } |
289 | 0 | } |
290 | | |
291 | | void IndexAdditiveQuantizer::sa_encode(idx_t n, const float* x, uint8_t* bytes) |
292 | 0 | const { |
293 | 0 | return aq->compute_codes(x, bytes, n); |
294 | 0 | } |
295 | | |
296 | | void IndexAdditiveQuantizer::sa_decode(idx_t n, const uint8_t* bytes, float* x) |
297 | 0 | const { |
298 | 0 | return aq->decode(bytes, x, n); |
299 | 0 | } |
300 | | |
301 | | /************************************************************************************** |
302 | | * IndexResidualQuantizer |
303 | | **************************************************************************************/ |
304 | | |
305 | | IndexResidualQuantizer::IndexResidualQuantizer( |
306 | | int d, ///< dimensionality of the input vectors |
307 | | size_t M, ///< number of subquantizers |
308 | | size_t nbits, ///< number of bit per subvector index |
309 | | MetricType metric, |
310 | | Search_type_t search_type) |
311 | 0 | : IndexResidualQuantizer( |
312 | 0 | d, |
313 | 0 | std::vector<size_t>(M, nbits), |
314 | 0 | metric, |
315 | 0 | search_type) {} |
316 | | |
317 | | IndexResidualQuantizer::IndexResidualQuantizer( |
318 | | int d, |
319 | | const std::vector<size_t>& nbits, |
320 | | MetricType metric, |
321 | | Search_type_t search_type) |
322 | 0 | : IndexAdditiveQuantizer(d, &rq, metric), rq(d, nbits, search_type) { |
323 | 0 | code_size = rq.code_size; |
324 | 0 | is_trained = false; |
325 | 0 | } |
326 | | |
327 | | IndexResidualQuantizer::IndexResidualQuantizer() |
328 | 0 | : IndexResidualQuantizer(0, 0, 0) {} |
329 | | |
330 | 0 | void IndexResidualQuantizer::train(idx_t n, const float* x) { |
331 | 0 | rq.train(n, x); |
332 | 0 | is_trained = true; |
333 | 0 | } |
334 | | |
335 | | /************************************************************************************** |
336 | | * IndexLocalSearchQuantizer |
337 | | **************************************************************************************/ |
338 | | |
339 | | IndexLocalSearchQuantizer::IndexLocalSearchQuantizer( |
340 | | int d, |
341 | | size_t M, ///< number of subquantizers |
342 | | size_t nbits, ///< number of bit per subvector index |
343 | | MetricType metric, |
344 | | Search_type_t search_type) |
345 | 0 | : IndexAdditiveQuantizer(d, &lsq, metric), |
346 | 0 | lsq(d, M, nbits, search_type) { |
347 | 0 | code_size = lsq.code_size; |
348 | 0 | is_trained = false; |
349 | 0 | } |
350 | | |
351 | | IndexLocalSearchQuantizer::IndexLocalSearchQuantizer() |
352 | 0 | : IndexLocalSearchQuantizer(0, 0, 0) {} |
353 | | |
354 | 0 | void IndexLocalSearchQuantizer::train(idx_t n, const float* x) { |
355 | 0 | lsq.train(n, x); |
356 | 0 | is_trained = true; |
357 | 0 | } |
358 | | |
359 | | /************************************************************************************** |
360 | | * IndexProductResidualQuantizer |
361 | | **************************************************************************************/ |
362 | | |
363 | | IndexProductResidualQuantizer::IndexProductResidualQuantizer( |
364 | | int d, ///< dimensionality of the input vectors |
365 | | size_t nsplits, ///< number of residual quantizers |
366 | | size_t Msub, ///< number of subquantizers per RQ |
367 | | size_t nbits, ///< number of bit per subvector index |
368 | | MetricType metric, |
369 | | Search_type_t search_type) |
370 | 0 | : IndexAdditiveQuantizer(d, &prq, metric), |
371 | 0 | prq(d, nsplits, Msub, nbits, search_type) { |
372 | 0 | code_size = prq.code_size; |
373 | 0 | is_trained = false; |
374 | 0 | } |
375 | | |
376 | | IndexProductResidualQuantizer::IndexProductResidualQuantizer() |
377 | 0 | : IndexProductResidualQuantizer(0, 0, 0, 0) {} |
378 | | |
379 | 0 | void IndexProductResidualQuantizer::train(idx_t n, const float* x) { |
380 | 0 | prq.train(n, x); |
381 | 0 | is_trained = true; |
382 | 0 | } |
383 | | |
384 | | /************************************************************************************** |
385 | | * IndexProductLocalSearchQuantizer |
386 | | **************************************************************************************/ |
387 | | |
388 | | IndexProductLocalSearchQuantizer::IndexProductLocalSearchQuantizer( |
389 | | int d, ///< dimensionality of the input vectors |
390 | | size_t nsplits, ///< number of local search quantizers |
391 | | size_t Msub, ///< number of subquantizers per LSQ |
392 | | size_t nbits, ///< number of bit per subvector index |
393 | | MetricType metric, |
394 | | Search_type_t search_type) |
395 | 0 | : IndexAdditiveQuantizer(d, &plsq, metric), |
396 | 0 | plsq(d, nsplits, Msub, nbits, search_type) { |
397 | 0 | code_size = plsq.code_size; |
398 | 0 | is_trained = false; |
399 | 0 | } |
400 | | |
401 | | IndexProductLocalSearchQuantizer::IndexProductLocalSearchQuantizer() |
402 | 0 | : IndexProductLocalSearchQuantizer(0, 0, 0, 0) {} |
403 | | |
404 | 0 | void IndexProductLocalSearchQuantizer::train(idx_t n, const float* x) { |
405 | 0 | plsq.train(n, x); |
406 | 0 | is_trained = true; |
407 | 0 | } |
408 | | |
409 | | /************************************************************************************** |
410 | | * AdditiveCoarseQuantizer |
411 | | **************************************************************************************/ |
412 | | |
413 | | AdditiveCoarseQuantizer::AdditiveCoarseQuantizer( |
414 | | idx_t d, |
415 | | AdditiveQuantizer* aq, |
416 | | MetricType metric) |
417 | 0 | : Index(d, metric), aq(aq) {} |
418 | | |
419 | 0 | void AdditiveCoarseQuantizer::add(idx_t, const float*) { |
420 | 0 | FAISS_THROW_MSG("not applicable"); |
421 | 0 | } |
422 | | |
423 | 0 | void AdditiveCoarseQuantizer::reconstruct(idx_t key, float* recons) const { |
424 | 0 | aq->decode_64bit(key, recons); |
425 | 0 | } |
426 | | |
427 | 0 | void AdditiveCoarseQuantizer::reset() { |
428 | 0 | FAISS_THROW_MSG("not applicable"); |
429 | 0 | } |
430 | | |
431 | 0 | void AdditiveCoarseQuantizer::train(idx_t n, const float* x) { |
432 | 0 | if (verbose) { |
433 | 0 | printf("AdditiveCoarseQuantizer::train: training on %zd vectors\n", |
434 | 0 | size_t(n)); |
435 | 0 | } |
436 | 0 | size_t norms_size = sizeof(float) << aq->tot_bits; |
437 | |
|
438 | 0 | FAISS_THROW_IF_NOT_MSG( |
439 | 0 | norms_size <= aq->max_mem_distances, |
440 | 0 | "the RCQ norms matrix will become too large, please reduce the number of quantization steps"); |
441 | | |
442 | 0 | aq->train(n, x); |
443 | 0 | is_trained = true; |
444 | 0 | ntotal = (idx_t)1 << aq->tot_bits; |
445 | |
|
446 | 0 | if (metric_type == METRIC_L2) { |
447 | 0 | if (verbose) { |
448 | 0 | printf("AdditiveCoarseQuantizer::train: computing centroid norms for %zd centroids\n", |
449 | 0 | size_t(ntotal)); |
450 | 0 | } |
451 | | // this is not necessary for the residualcoarsequantizer when |
452 | | // using beam search. We'll see if the memory overhead is too high |
453 | 0 | centroid_norms.resize(ntotal); |
454 | 0 | aq->compute_centroid_norms(centroid_norms.data()); |
455 | 0 | } |
456 | 0 | } |
457 | | |
458 | | void AdditiveCoarseQuantizer::search( |
459 | | idx_t n, |
460 | | const float* x, |
461 | | idx_t k, |
462 | | float* distances, |
463 | | idx_t* labels, |
464 | 0 | const SearchParameters* params) const { |
465 | 0 | FAISS_THROW_IF_NOT_MSG( |
466 | 0 | !params, "search params not supported for this index"); |
467 | | |
468 | 0 | if (metric_type == METRIC_INNER_PRODUCT) { |
469 | 0 | aq->knn_centroids_inner_product(n, x, k, distances, labels); |
470 | 0 | } else if (metric_type == METRIC_L2) { |
471 | 0 | FAISS_THROW_IF_NOT(centroid_norms.size() == ntotal); |
472 | 0 | aq->knn_centroids_L2(n, x, k, distances, labels, centroid_norms.data()); |
473 | 0 | } |
474 | 0 | } |
475 | | |
476 | | /************************************************************************************** |
477 | | * ResidualCoarseQuantizer |
478 | | **************************************************************************************/ |
479 | | |
480 | | ResidualCoarseQuantizer::ResidualCoarseQuantizer( |
481 | | int d, ///< dimensionality of the input vectors |
482 | | const std::vector<size_t>& nbits, |
483 | | MetricType metric) |
484 | 0 | : AdditiveCoarseQuantizer(d, &rq, metric), rq(d, nbits) { |
485 | 0 | FAISS_THROW_IF_NOT(rq.tot_bits <= 63); |
486 | 0 | is_trained = false; |
487 | 0 | } |
488 | | |
489 | | ResidualCoarseQuantizer::ResidualCoarseQuantizer( |
490 | | int d, |
491 | | size_t M, ///< number of subquantizers |
492 | | size_t nbits, ///< number of bit per subvector index |
493 | | MetricType metric) |
494 | 0 | : ResidualCoarseQuantizer(d, std::vector<size_t>(M, nbits), metric) {} |
495 | | |
496 | | ResidualCoarseQuantizer::ResidualCoarseQuantizer() |
497 | 0 | : ResidualCoarseQuantizer(0, 0, 0) {} |
498 | | |
499 | 0 | void ResidualCoarseQuantizer::set_beam_factor(float new_beam_factor) { |
500 | 0 | beam_factor = new_beam_factor; |
501 | 0 | if (new_beam_factor > 0) { |
502 | 0 | FAISS_THROW_IF_NOT(new_beam_factor >= 1.0); |
503 | 0 | if (rq.codebook_cross_products.size() == 0) { |
504 | 0 | rq.compute_codebook_tables(); |
505 | 0 | } |
506 | 0 | return; |
507 | 0 | } else { |
508 | | // new_beam_factor = -1: exhaustive computation. |
509 | | // Does not use the cross_products |
510 | 0 | rq.codebook_cross_products.resize(0); |
511 | | // but the centroid norms are necessary! |
512 | 0 | if (metric_type == METRIC_L2 && ntotal != centroid_norms.size()) { |
513 | 0 | if (verbose) { |
514 | 0 | printf("AdditiveCoarseQuantizer::train: computing centroid norms for %zd centroids\n", |
515 | 0 | size_t(ntotal)); |
516 | 0 | } |
517 | 0 | centroid_norms.resize(ntotal); |
518 | 0 | aq->compute_centroid_norms(centroid_norms.data()); |
519 | 0 | } |
520 | 0 | } |
521 | 0 | } |
522 | | |
523 | | void ResidualCoarseQuantizer::search( |
524 | | idx_t n, |
525 | | const float* x, |
526 | | idx_t k, |
527 | | float* distances, |
528 | | idx_t* labels, |
529 | 0 | const SearchParameters* params_in) const { |
530 | 0 | float actual_beam_factor = this->beam_factor; |
531 | 0 | if (params_in) { |
532 | 0 | auto params = |
533 | 0 | dynamic_cast<const SearchParametersResidualCoarseQuantizer*>( |
534 | 0 | params_in); |
535 | 0 | FAISS_THROW_IF_NOT_MSG( |
536 | 0 | params, |
537 | 0 | "need SearchParametersResidualCoarseQuantizer parameters"); |
538 | 0 | actual_beam_factor = params->beam_factor; |
539 | 0 | } |
540 | | |
541 | 0 | if (actual_beam_factor < 0) { |
542 | 0 | AdditiveCoarseQuantizer::search(n, x, k, distances, labels); |
543 | 0 | return; |
544 | 0 | } |
545 | | |
546 | 0 | int beam_size = int(k * actual_beam_factor); |
547 | 0 | if (beam_size > ntotal) { |
548 | 0 | beam_size = ntotal; |
549 | 0 | } |
550 | 0 | size_t memory_per_point = rq.memory_per_point(beam_size); |
551 | | |
552 | | /* |
553 | | |
554 | | printf("mem per point %ld n=%d max_mem_distance=%ld mem_kb=%zd\n", |
555 | | memory_per_point, int(n), rq.max_mem_distances, get_mem_usage_kb()); |
556 | | */ |
557 | 0 | if (n > 1 && memory_per_point * n > rq.max_mem_distances) { |
558 | | // then split queries to reduce temp memory |
559 | 0 | idx_t bs = rq.max_mem_distances / memory_per_point; |
560 | 0 | if (bs == 0) { |
561 | 0 | bs = 1; // otherwise we can't do much |
562 | 0 | } |
563 | 0 | if (verbose) { |
564 | 0 | printf("ResidualCoarseQuantizer::search: run %d searches in batches of size %d\n", |
565 | 0 | int(n), |
566 | 0 | int(bs)); |
567 | 0 | } |
568 | 0 | for (idx_t i0 = 0; i0 < n; i0 += bs) { |
569 | 0 | idx_t i1 = std::min(n, i0 + bs); |
570 | 0 | search(i1 - i0, |
571 | 0 | x + i0 * d, |
572 | 0 | k, |
573 | 0 | distances + i0 * k, |
574 | 0 | labels + i0 * k, |
575 | 0 | params_in); |
576 | 0 | InterruptCallback::check(); |
577 | 0 | } |
578 | 0 | return; |
579 | 0 | } |
580 | | |
581 | 0 | std::vector<int32_t> codes(beam_size * rq.M * n); |
582 | 0 | std::vector<float> beam_distances(n * beam_size); |
583 | |
|
584 | 0 | rq.refine_beam( |
585 | 0 | n, 1, x, beam_size, codes.data(), nullptr, beam_distances.data()); |
586 | | |
587 | | // pack int32 table |
588 | 0 | #pragma omp parallel for if (n > 4000) |
589 | 0 | for (idx_t i = 0; i < n; i++) { |
590 | 0 | memcpy(distances + i * k, |
591 | 0 | beam_distances.data() + beam_size * i, |
592 | 0 | k * sizeof(distances[0])); |
593 | |
|
594 | 0 | const int32_t* codes_i = codes.data() + beam_size * i * rq.M; |
595 | 0 | for (idx_t j = 0; j < k; j++) { |
596 | 0 | idx_t l = 0; |
597 | 0 | int shift = 0; |
598 | 0 | for (int m = 0; m < rq.M; m++) { |
599 | 0 | l |= (*codes_i++) << shift; |
600 | 0 | shift += rq.nbits[m]; |
601 | 0 | } |
602 | 0 | labels[i * k + j] = l; |
603 | 0 | } |
604 | 0 | } |
605 | 0 | } |
606 | | |
607 | | void ResidualCoarseQuantizer::initialize_from( |
608 | 0 | const ResidualCoarseQuantizer& other) { |
609 | 0 | FAISS_THROW_IF_NOT(rq.M <= other.rq.M); |
610 | 0 | rq.initialize_from(other.rq); |
611 | 0 | set_beam_factor(other.beam_factor); |
612 | 0 | is_trained = other.is_trained; |
613 | 0 | ntotal = (idx_t)1 << aq->tot_bits; |
614 | 0 | } |
615 | | |
616 | | /************************************************************************************** |
617 | | * LocalSearchCoarseQuantizer |
618 | | **************************************************************************************/ |
619 | | |
620 | | LocalSearchCoarseQuantizer::LocalSearchCoarseQuantizer( |
621 | | int d, ///< dimensionality of the input vectors |
622 | | size_t M, ///< number of subquantizers |
623 | | size_t nbits, ///< number of bit per subvector index |
624 | | MetricType metric) |
625 | 0 | : AdditiveCoarseQuantizer(d, &lsq, metric), lsq(d, M, nbits) { |
626 | 0 | FAISS_THROW_IF_NOT(lsq.tot_bits <= 63); |
627 | 0 | is_trained = false; |
628 | 0 | } |
629 | | |
630 | 0 | LocalSearchCoarseQuantizer::LocalSearchCoarseQuantizer() { |
631 | 0 | aq = &lsq; |
632 | 0 | } |
633 | | |
634 | | } // namespace faiss |