Coverage Report

Created: 2025-10-28 13:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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