Coverage Report

Created: 2025-09-16 07:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/root/doris/contrib/faiss/faiss/IndexBinaryIVF.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
// -*- c++ -*-
9
10
#include <faiss/IndexBinaryIVF.h>
11
12
#include <omp.h>
13
#include <cinttypes>
14
#include <cstdio>
15
16
#include <algorithm>
17
#include <memory>
18
19
#include <faiss/IndexFlat.h>
20
#include <faiss/IndexLSH.h>
21
#include <faiss/impl/AuxIndexStructures.h>
22
#include <faiss/impl/FaissAssert.h>
23
#include <faiss/utils/hamming.h>
24
#include <faiss/utils/sorting.h>
25
#include <faiss/utils/utils.h>
26
27
namespace faiss {
28
29
IndexBinaryIVF::IndexBinaryIVF(IndexBinary* quantizer, size_t d, size_t nlist)
30
0
        : IndexBinary(d),
31
0
          invlists(new ArrayInvertedLists(nlist, code_size)),
32
0
          quantizer(quantizer),
33
0
          nlist(nlist) {
34
0
    FAISS_THROW_IF_NOT(d == quantizer->d);
35
0
    is_trained = quantizer->is_trained && (quantizer->ntotal == nlist);
36
0
    cp.niter = 10;
37
0
}
38
39
0
IndexBinaryIVF::IndexBinaryIVF() = default;
40
41
0
void IndexBinaryIVF::add(idx_t n, const uint8_t* x) {
42
0
    add_with_ids(n, x, nullptr);
43
0
}
44
45
void IndexBinaryIVF::add_with_ids(
46
        idx_t n,
47
        const uint8_t* x,
48
0
        const idx_t* xids) {
49
0
    add_core(n, x, xids, nullptr);
50
0
}
51
52
void IndexBinaryIVF::add_core(
53
        idx_t n,
54
        const uint8_t* x,
55
        const idx_t* xids,
56
0
        const idx_t* precomputed_idx) {
57
0
    FAISS_THROW_IF_NOT(is_trained);
58
0
    assert(invlists);
59
0
    direct_map.check_can_add(xids);
60
61
0
    const idx_t* idx;
62
63
0
    std::unique_ptr<idx_t[]> scoped_idx;
64
65
0
    if (precomputed_idx) {
66
0
        idx = precomputed_idx;
67
0
    } else {
68
0
        scoped_idx.reset(new idx_t[n]);
69
0
        quantizer->assign(n, x, scoped_idx.get());
70
0
        idx = scoped_idx.get();
71
0
    }
72
73
0
    idx_t n_add = 0;
74
0
    for (size_t i = 0; i < n; i++) {
75
0
        idx_t id = xids ? xids[i] : ntotal + i;
76
0
        idx_t list_no = idx[i];
77
78
0
        if (list_no < 0) {
79
0
            direct_map.add_single_id(id, -1, 0);
80
0
        } else {
81
0
            const uint8_t* xi = x + i * code_size;
82
0
            size_t offset = invlists->add_entry(list_no, id, xi);
83
84
0
            direct_map.add_single_id(id, list_no, offset);
85
0
        }
86
87
0
        n_add++;
88
0
    }
89
0
    if (verbose) {
90
0
        printf("IndexBinaryIVF::add_with_ids: added "
91
0
               "%" PRId64 " / %" PRId64 " vectors\n",
92
0
               n_add,
93
0
               n);
94
0
    }
95
0
    ntotal += n_add;
96
0
}
97
98
0
void IndexBinaryIVF::make_direct_map(bool b) {
99
0
    if (b) {
100
0
        direct_map.set_type(DirectMap::Array, invlists, ntotal);
101
0
    } else {
102
0
        direct_map.set_type(DirectMap::NoMap, invlists, ntotal);
103
0
    }
104
0
}
105
106
0
void IndexBinaryIVF::set_direct_map_type(DirectMap::Type type) {
107
0
    direct_map.set_type(type, invlists, ntotal);
108
0
}
109
110
void IndexBinaryIVF::search(
111
        idx_t n,
112
        const uint8_t* x,
113
        idx_t k,
114
        int32_t* distances,
115
        idx_t* labels,
116
0
        const SearchParameters* params) const {
117
0
    FAISS_THROW_IF_NOT_MSG(
118
0
            !params, "search params not supported for this index");
119
0
    FAISS_THROW_IF_NOT(k > 0);
120
0
    FAISS_THROW_IF_NOT(nprobe > 0);
121
122
0
    const size_t nprobe_2 = std::min(nlist, this->nprobe);
123
0
    std::unique_ptr<idx_t[]> idx(new idx_t[n * nprobe_2]);
124
0
    std::unique_ptr<int32_t[]> coarse_dis(new int32_t[n * nprobe_2]);
125
126
0
    double t0 = getmillisecs();
127
0
    quantizer->search(n, x, nprobe_2, coarse_dis.get(), idx.get());
128
0
    indexIVF_stats.quantization_time += getmillisecs() - t0;
129
130
0
    t0 = getmillisecs();
131
0
    invlists->prefetch_lists(idx.get(), n * nprobe_2);
132
133
0
    search_preassigned(
134
0
            n, x, k, idx.get(), coarse_dis.get(), distances, labels, false);
135
0
    indexIVF_stats.search_time += getmillisecs() - t0;
136
0
}
137
138
0
void IndexBinaryIVF::reconstruct(idx_t key, uint8_t* recons) const {
139
0
    idx_t lo = direct_map.get(key);
140
0
    reconstruct_from_offset(lo_listno(lo), lo_offset(lo), recons);
141
0
}
142
143
0
void IndexBinaryIVF::reconstruct_n(idx_t i0, idx_t ni, uint8_t* recons) const {
144
0
    FAISS_THROW_IF_NOT(ni == 0 || (i0 >= 0 && i0 + ni <= ntotal));
145
146
0
    for (idx_t list_no = 0; list_no < nlist; list_no++) {
147
0
        size_t list_size = invlists->list_size(list_no);
148
0
        const idx_t* idlist = invlists->get_ids(list_no);
149
150
0
        for (idx_t offset = 0; offset < list_size; offset++) {
151
0
            idx_t id = idlist[offset];
152
0
            if (!(id >= i0 && id < i0 + ni)) {
153
0
                continue;
154
0
            }
155
156
0
            uint8_t* reconstructed = recons + (id - i0) * d;
157
0
            reconstruct_from_offset(list_no, offset, reconstructed);
158
0
        }
159
0
    }
160
0
}
161
162
void IndexBinaryIVF::search_and_reconstruct(
163
        idx_t n,
164
        const uint8_t* __restrict x,
165
        idx_t k,
166
        int32_t* __restrict distances,
167
        idx_t* __restrict labels,
168
        uint8_t* __restrict recons,
169
0
        const SearchParameters* params) const {
170
0
    FAISS_THROW_IF_NOT_MSG(
171
0
            !params, "search params not supported for this index");
172
0
    const size_t nprobe_2 = std::min(nlist, this->nprobe);
173
0
    FAISS_THROW_IF_NOT(k > 0);
174
0
    FAISS_THROW_IF_NOT(nprobe_2 > 0);
175
176
0
    std::unique_ptr<idx_t[]> idx(new idx_t[n * nprobe_2]);
177
0
    std::unique_ptr<int32_t[]> coarse_dis(new int32_t[n * nprobe_2]);
178
179
0
    quantizer->search(n, x, nprobe_2, coarse_dis.get(), idx.get());
180
181
0
    invlists->prefetch_lists(idx.get(), n * nprobe_2);
182
183
    // search_preassigned() with `store_pairs` enabled to obtain the list_no
184
    // and offset into `codes` for reconstruction
185
0
    search_preassigned(
186
0
            n,
187
0
            x,
188
0
            k,
189
0
            idx.get(),
190
0
            coarse_dis.get(),
191
0
            distances,
192
0
            labels,
193
0
            /* store_pairs */ true);
194
0
    for (idx_t i = 0; i < n; ++i) {
195
0
        for (idx_t j = 0; j < k; ++j) {
196
0
            idx_t ij = i * k + j;
197
0
            idx_t key = labels[ij];
198
0
            uint8_t* reconstructed = recons + ij * d;
199
0
            if (key < 0) {
200
                // Fill with NaNs
201
0
                memset(reconstructed, -1, sizeof(*reconstructed) * d);
202
0
            } else {
203
0
                int list_no = key >> 32;
204
0
                int offset = key & 0xffffffff;
205
206
                // Update label to the actual id
207
0
                labels[ij] = invlists->get_single_id(list_no, offset);
208
209
0
                reconstruct_from_offset(list_no, offset, reconstructed);
210
0
            }
211
0
        }
212
0
    }
213
0
}
214
215
void IndexBinaryIVF::reconstruct_from_offset(
216
        idx_t list_no,
217
        idx_t offset,
218
0
        uint8_t* recons) const {
219
0
    memcpy(recons, invlists->get_single_code(list_no, offset), code_size);
220
0
}
221
222
0
void IndexBinaryIVF::reset() {
223
0
    direct_map.clear();
224
0
    invlists->reset();
225
0
    ntotal = 0;
226
0
}
227
228
0
size_t IndexBinaryIVF::remove_ids(const IDSelector& sel) {
229
0
    size_t nremove = direct_map.remove_ids(sel, invlists);
230
0
    ntotal -= nremove;
231
0
    return nremove;
232
0
}
233
234
0
void IndexBinaryIVF::train(idx_t n, const uint8_t* x) {
235
0
    if (verbose) {
236
0
        printf("Training quantizer\n");
237
0
    }
238
239
0
    if (quantizer->is_trained && (quantizer->ntotal == nlist)) {
240
0
        if (verbose) {
241
0
            printf("IVF quantizer does not need training.\n");
242
0
        }
243
0
    } else {
244
0
        if (verbose) {
245
0
            printf("Training quantizer on %" PRId64 " vectors in %dD\n", n, d);
246
0
        }
247
248
0
        Clustering clus(d, nlist, cp);
249
0
        quantizer->reset();
250
251
0
        IndexFlatL2 index_tmp(d);
252
253
0
        if (clustering_index && verbose) {
254
0
            printf("using clustering_index of dimension %d to do the clustering\n",
255
0
                   clustering_index->d);
256
0
        }
257
258
        // LSH codec that is able to convert the binary vectors to floats.
259
0
        IndexLSH codec(d, d, false, false);
260
261
0
        clus.train_encoded(
262
0
                n, x, &codec, clustering_index ? *clustering_index : index_tmp);
263
264
        // convert clusters to binary
265
0
        std::unique_ptr<uint8_t[]> x_b(new uint8_t[clus.k * code_size]);
266
0
        real_to_binary(d * clus.k, clus.centroids.data(), x_b.get());
267
268
0
        quantizer->add(clus.k, x_b.get());
269
0
        quantizer->is_trained = true;
270
0
    }
271
272
0
    is_trained = true;
273
0
}
274
275
void IndexBinaryIVF::check_compatible_for_merge(
276
0
        const IndexBinary& otherIndex) const {
277
0
    auto other = dynamic_cast<const IndexBinaryIVF*>(&otherIndex);
278
0
    FAISS_THROW_IF_NOT(other);
279
0
    FAISS_THROW_IF_NOT(other->d == d);
280
0
    FAISS_THROW_IF_NOT(other->nlist == nlist);
281
0
    FAISS_THROW_IF_NOT(other->code_size == code_size);
282
0
    FAISS_THROW_IF_NOT_MSG(
283
0
            direct_map.no() && other->direct_map.no(),
284
0
            "direct map copy not implemented");
285
0
    FAISS_THROW_IF_NOT_MSG(
286
0
            typeid(*this) == typeid(other),
287
0
            "can only merge indexes of the same type");
288
0
}
289
290
0
void IndexBinaryIVF::merge_from(IndexBinary& otherIndex, idx_t add_id) {
291
    // minimal sanity checks
292
0
    check_compatible_for_merge(otherIndex);
293
0
    auto other = static_cast<IndexBinaryIVF*>(&otherIndex);
294
0
    invlists->merge_from(other->invlists, add_id);
295
0
    ntotal += other->ntotal;
296
0
    other->ntotal = 0;
297
0
}
298
299
0
void IndexBinaryIVF::replace_invlists(InvertedLists* il, bool own) {
300
0
    FAISS_THROW_IF_NOT(il->nlist == nlist && il->code_size == code_size);
301
0
    if (own_invlists) {
302
0
        delete invlists;
303
0
    }
304
0
    invlists = il;
305
0
    own_invlists = own;
306
0
}
307
308
namespace {
309
310
template <class HammingComputer>
311
struct IVFBinaryScannerL2 : BinaryInvertedListScanner {
312
    HammingComputer hc;
313
    size_t code_size;
314
    bool store_pairs;
315
316
    IVFBinaryScannerL2(size_t code_size, bool store_pairs)
317
0
            : code_size(code_size), store_pairs(store_pairs) {}
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_16HammingComputer4EEC2Emb
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_16HammingComputer8EEC2Emb
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_17HammingComputer16EEC2Emb
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_17HammingComputer20EEC2Emb
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_17HammingComputer32EEC2Emb
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_17HammingComputer64EEC2Emb
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_22HammingComputerDefaultEEC2Emb
318
319
0
    void set_query(const uint8_t* query_vector) override {
320
0
        hc.set(query_vector, code_size);
321
0
    }
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_16HammingComputer4EE9set_queryEPKh
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_16HammingComputer8EE9set_queryEPKh
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_17HammingComputer16EE9set_queryEPKh
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_17HammingComputer20EE9set_queryEPKh
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_17HammingComputer32EE9set_queryEPKh
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_17HammingComputer64EE9set_queryEPKh
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_22HammingComputerDefaultEE9set_queryEPKh
322
323
    idx_t list_no;
324
0
    void set_list(idx_t list_no_2, uint8_t /* coarse_dis */) override {
325
0
        this->list_no = list_no_2;
326
0
    }
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_16HammingComputer4EE8set_listElh
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_16HammingComputer8EE8set_listElh
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_17HammingComputer16EE8set_listElh
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_17HammingComputer20EE8set_listElh
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_17HammingComputer32EE8set_listElh
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_17HammingComputer64EE8set_listElh
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_22HammingComputerDefaultEE8set_listElh
327
328
0
    uint32_t distance_to_code(const uint8_t* code) const override {
329
0
        return hc.hamming(code);
330
0
    }
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZNK5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_16HammingComputer4EE16distance_to_codeEPKh
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZNK5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_16HammingComputer8EE16distance_to_codeEPKh
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZNK5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_17HammingComputer16EE16distance_to_codeEPKh
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZNK5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_17HammingComputer20EE16distance_to_codeEPKh
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZNK5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_17HammingComputer32EE16distance_to_codeEPKh
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZNK5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_17HammingComputer64EE16distance_to_codeEPKh
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZNK5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_22HammingComputerDefaultEE16distance_to_codeEPKh
331
332
    size_t scan_codes(
333
            size_t n,
334
            const uint8_t* __restrict codes,
335
            const idx_t* __restrict ids,
336
            int32_t* __restrict simi,
337
            idx_t* __restrict idxi,
338
0
            size_t k) const override {
339
0
        using C = CMax<int32_t, idx_t>;
340
341
0
        size_t nup = 0;
342
0
        for (size_t j = 0; j < n; j++) {
343
0
            uint32_t dis = hc.hamming(codes);
344
0
            if (dis < simi[0]) {
345
0
                idx_t id = store_pairs ? lo_build(list_no, j) : ids[j];
346
0
                heap_replace_top<C>(k, simi, idxi, dis, id);
347
0
                nup++;
348
0
            }
349
0
            codes += code_size;
350
0
        }
351
0
        return nup;
352
0
    }
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZNK5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_16HammingComputer4EE10scan_codesEmPKhPKlPiPlm
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZNK5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_16HammingComputer8EE10scan_codesEmPKhPKlPiPlm
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZNK5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_17HammingComputer16EE10scan_codesEmPKhPKlPiPlm
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZNK5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_17HammingComputer20EE10scan_codesEmPKhPKlPiPlm
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZNK5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_17HammingComputer32EE10scan_codesEmPKhPKlPiPlm
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZNK5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_17HammingComputer64EE10scan_codesEmPKhPKlPiPlm
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZNK5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_22HammingComputerDefaultEE10scan_codesEmPKhPKlPiPlm
353
354
    void scan_codes_range(
355
            size_t n,
356
            const uint8_t* __restrict codes,
357
            const idx_t* __restrict ids,
358
            int radius,
359
0
            RangeQueryResult& result) const override {
360
0
        for (size_t j = 0; j < n; j++) {
361
0
            uint32_t dis = hc.hamming(codes);
362
0
            if (dis < radius) {
363
0
                int64_t id = store_pairs ? lo_build(list_no, j) : ids[j];
364
0
                result.add(dis, id);
365
0
            }
366
0
            codes += code_size;
367
0
        }
368
0
    }
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZNK5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_16HammingComputer4EE16scan_codes_rangeEmPKhPKliRNS_16RangeQueryResultE
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZNK5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_16HammingComputer8EE16scan_codes_rangeEmPKhPKliRNS_16RangeQueryResultE
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZNK5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_17HammingComputer16EE16scan_codes_rangeEmPKhPKliRNS_16RangeQueryResultE
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZNK5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_17HammingComputer20EE16scan_codes_rangeEmPKhPKliRNS_16RangeQueryResultE
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZNK5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_17HammingComputer32EE16scan_codes_rangeEmPKhPKliRNS_16RangeQueryResultE
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZNK5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_17HammingComputer64EE16scan_codes_rangeEmPKhPKliRNS_16RangeQueryResultE
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZNK5faiss12_GLOBAL__N_118IVFBinaryScannerL2INS_22HammingComputerDefaultEE16scan_codes_rangeEmPKhPKliRNS_16RangeQueryResultE
369
};
370
371
void search_knn_hamming_heap(
372
        const IndexBinaryIVF* ivf,
373
        size_t n,
374
        const uint8_t* __restrict x,
375
        idx_t k,
376
        const idx_t* __restrict keys,
377
        const int32_t* __restrict coarse_dis,
378
        int32_t* __restrict distances,
379
        idx_t* __restrict labels,
380
        bool store_pairs,
381
0
        const IVFSearchParameters* params) {
382
0
    idx_t nprobe = params ? params->nprobe : ivf->nprobe;
383
0
    nprobe = std::min((idx_t)ivf->nlist, nprobe);
384
0
    idx_t max_codes = params ? params->max_codes : ivf->max_codes;
385
0
    MetricType metric_type = ivf->metric_type;
386
387
    // almost verbatim copy from IndexIVF::search_preassigned
388
389
0
    size_t nlistv = 0, ndis = 0, nheap = 0;
390
0
    using HeapForIP = CMin<int32_t, idx_t>;
391
0
    using HeapForL2 = CMax<int32_t, idx_t>;
392
393
0
#pragma omp parallel if (n > 1) reduction(+ : nlistv, ndis, nheap)
394
0
    {
395
0
        std::unique_ptr<BinaryInvertedListScanner> scanner(
396
0
                ivf->get_InvertedListScanner(store_pairs));
397
398
0
#pragma omp for
399
0
        for (idx_t i = 0; i < n; i++) {
400
0
            const uint8_t* xi = x + i * ivf->code_size;
401
0
            scanner->set_query(xi);
402
403
0
            const idx_t* keysi = keys + i * nprobe;
404
0
            int32_t* simi = distances + k * i;
405
0
            idx_t* idxi = labels + k * i;
406
407
0
            if (metric_type == METRIC_INNER_PRODUCT) {
408
0
                heap_heapify<HeapForIP>(k, simi, idxi);
409
0
            } else {
410
0
                heap_heapify<HeapForL2>(k, simi, idxi);
411
0
            }
412
413
0
            size_t nscan = 0;
414
415
0
            for (size_t ik = 0; ik < nprobe; ik++) {
416
0
                idx_t key = keysi[ik]; /* select the list  */
417
0
                if (key < 0) {
418
                    // not enough centroids for multiprobe
419
0
                    continue;
420
0
                }
421
0
                FAISS_THROW_IF_NOT_FMT(
422
0
                        key < (idx_t)ivf->nlist,
423
0
                        "Invalid key=%" PRId64 " at ik=%zd nlist=%zd\n",
424
0
                        key,
425
0
                        ik,
426
0
                        ivf->nlist);
427
428
0
                scanner->set_list(key, coarse_dis[i * nprobe + ik]);
429
430
0
                nlistv++;
431
432
0
                size_t list_size = ivf->invlists->list_size(key);
433
0
                InvertedLists::ScopedCodes scodes(ivf->invlists, key);
434
0
                std::unique_ptr<InvertedLists::ScopedIds> sids;
435
0
                const idx_t* ids = nullptr;
436
437
0
                if (!store_pairs) {
438
0
                    sids = std::make_unique<InvertedLists::ScopedIds>(
439
0
                            ivf->invlists, key);
440
0
                    ids = sids->get();
441
0
                }
442
443
0
                nheap += scanner->scan_codes(
444
0
                        list_size, scodes.get(), ids, simi, idxi, k);
445
446
0
                nscan += list_size;
447
0
                if (max_codes && nscan >= max_codes)
448
0
                    break;
449
0
            }
450
451
0
            ndis += nscan;
452
0
            if (metric_type == METRIC_INNER_PRODUCT) {
453
0
                heap_reorder<HeapForIP>(k, simi, idxi);
454
0
            } else {
455
0
                heap_reorder<HeapForL2>(k, simi, idxi);
456
0
            }
457
458
0
        } // parallel for
459
0
    } // parallel
460
461
0
    indexIVF_stats.nq += n;
462
0
    indexIVF_stats.nlist += nlistv;
463
0
    indexIVF_stats.ndis += ndis;
464
0
    indexIVF_stats.nheap_updates += nheap;
465
0
}
466
467
template <class HammingComputer, bool store_pairs>
468
void search_knn_hamming_count(
469
        const IndexBinaryIVF* ivf,
470
        size_t nx,
471
        const uint8_t* __restrict x,
472
        const idx_t* __restrict keys,
473
        int k,
474
        int32_t* __restrict distances,
475
        idx_t* __restrict labels,
476
0
        const IVFSearchParameters* params) {
477
0
    const int nBuckets = ivf->d + 1;
478
0
    std::vector<int> all_counters(nx * nBuckets, 0);
479
0
    std::unique_ptr<idx_t[]> all_ids_per_dis(new idx_t[nx * nBuckets * k]);
480
481
0
    idx_t nprobe = params ? params->nprobe : ivf->nprobe;
482
0
    nprobe = std::min((idx_t)ivf->nlist, nprobe);
483
0
    idx_t max_codes = params ? params->max_codes : ivf->max_codes;
484
485
0
    std::vector<HCounterState<HammingComputer>> cs;
486
0
    for (size_t i = 0; i < nx; ++i) {
487
0
        cs.push_back(HCounterState<HammingComputer>(
488
0
                all_counters.data() + i * nBuckets,
489
0
                all_ids_per_dis.get() + i * nBuckets * k,
490
0
                x + i * ivf->code_size,
491
0
                ivf->d,
492
0
                k));
493
0
    }
494
495
0
    size_t nlistv = 0, ndis = 0;
496
497
0
#pragma omp parallel for reduction(+ : nlistv, ndis)
498
0
    for (int64_t i = 0; i < nx; i++) {
499
0
        const idx_t* keysi = keys + i * nprobe;
500
0
        HCounterState<HammingComputer>& csi = cs[i];
501
502
0
        size_t nscan = 0;
503
504
0
        for (size_t ik = 0; ik < nprobe; ik++) {
505
0
            idx_t key = keysi[ik]; /* select the list  */
506
0
            if (key < 0) {
507
                // not enough centroids for multiprobe
508
0
                continue;
509
0
            }
510
0
            FAISS_THROW_IF_NOT_FMT(
511
0
                    key < (idx_t)ivf->nlist,
512
0
                    "Invalid key=%" PRId64 " at ik=%zd nlist=%zd\n",
513
0
                    key,
514
0
                    ik,
515
0
                    ivf->nlist);
516
517
0
            nlistv++;
518
0
            size_t list_size = ivf->invlists->list_size(key);
519
0
            InvertedLists::ScopedCodes scodes(ivf->invlists, key);
520
0
            const uint8_t* list_vecs = scodes.get();
521
0
            const idx_t* ids =
522
0
                    store_pairs ? nullptr : ivf->invlists->get_ids(key);
523
524
0
            for (size_t j = 0; j < list_size; j++) {
525
0
                const uint8_t* yj = list_vecs + ivf->code_size * j;
526
527
0
                idx_t id = store_pairs ? (key << 32 | j) : ids[j];
528
0
                csi.update_counter(yj, id);
529
0
            }
530
0
            if (ids) {
531
0
                ivf->invlists->release_ids(key, ids);
532
0
            }
533
534
0
            nscan += list_size;
535
0
            if (max_codes && nscan >= max_codes)
536
0
                break;
537
0
        }
538
0
        ndis += nscan;
539
540
0
        int nres = 0;
541
0
        for (int b = 0; b < nBuckets && nres < k; b++) {
542
0
            for (int l = 0; l < csi.counters[b] && nres < k; l++) {
543
0
                labels[i * k + nres] = csi.ids_per_dis[b * k + l];
544
0
                distances[i * k + nres] = b;
545
0
                nres++;
546
0
            }
547
0
        }
548
0
        while (nres < k) {
549
0
            labels[i * k + nres] = -1;
550
0
            distances[i * k + nres] = std::numeric_limits<int32_t>::max();
551
0
            ++nres;
552
0
        }
553
0
    }
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_124search_knn_hamming_countINS_16HammingComputer4ELb1EEEvPKNS_14IndexBinaryIVFEmPKhPKliPiPlPKNS_19SearchParametersIVFE.omp_outlined_debug__
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_124search_knn_hamming_countINS_16HammingComputer8ELb1EEEvPKNS_14IndexBinaryIVFEmPKhPKliPiPlPKNS_19SearchParametersIVFE.omp_outlined_debug__
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_124search_knn_hamming_countINS_17HammingComputer16ELb1EEEvPKNS_14IndexBinaryIVFEmPKhPKliPiPlPKNS_19SearchParametersIVFE.omp_outlined_debug__
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_124search_knn_hamming_countINS_17HammingComputer20ELb1EEEvPKNS_14IndexBinaryIVFEmPKhPKliPiPlPKNS_19SearchParametersIVFE.omp_outlined_debug__
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_124search_knn_hamming_countINS_17HammingComputer32ELb1EEEvPKNS_14IndexBinaryIVFEmPKhPKliPiPlPKNS_19SearchParametersIVFE.omp_outlined_debug__
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_124search_knn_hamming_countINS_17HammingComputer64ELb1EEEvPKNS_14IndexBinaryIVFEmPKhPKliPiPlPKNS_19SearchParametersIVFE.omp_outlined_debug__
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_124search_knn_hamming_countINS_22HammingComputerDefaultELb1EEEvPKNS_14IndexBinaryIVFEmPKhPKliPiPlPKNS_19SearchParametersIVFE.omp_outlined_debug__
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_124search_knn_hamming_countINS_16HammingComputer4ELb0EEEvPKNS_14IndexBinaryIVFEmPKhPKliPiPlPKNS_19SearchParametersIVFE.omp_outlined_debug__
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_124search_knn_hamming_countINS_16HammingComputer8ELb0EEEvPKNS_14IndexBinaryIVFEmPKhPKliPiPlPKNS_19SearchParametersIVFE.omp_outlined_debug__
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_124search_knn_hamming_countINS_17HammingComputer16ELb0EEEvPKNS_14IndexBinaryIVFEmPKhPKliPiPlPKNS_19SearchParametersIVFE.omp_outlined_debug__
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_124search_knn_hamming_countINS_17HammingComputer20ELb0EEEvPKNS_14IndexBinaryIVFEmPKhPKliPiPlPKNS_19SearchParametersIVFE.omp_outlined_debug__
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_124search_knn_hamming_countINS_17HammingComputer32ELb0EEEvPKNS_14IndexBinaryIVFEmPKhPKliPiPlPKNS_19SearchParametersIVFE.omp_outlined_debug__
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_124search_knn_hamming_countINS_17HammingComputer64ELb0EEEvPKNS_14IndexBinaryIVFEmPKhPKliPiPlPKNS_19SearchParametersIVFE.omp_outlined_debug__
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_124search_knn_hamming_countINS_22HammingComputerDefaultELb0EEEvPKNS_14IndexBinaryIVFEmPKhPKliPiPlPKNS_19SearchParametersIVFE.omp_outlined_debug__
554
555
0
    indexIVF_stats.nq += nx;
556
0
    indexIVF_stats.nlist += nlistv;
557
0
    indexIVF_stats.ndis += ndis;
558
0
}
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_124search_knn_hamming_countINS_16HammingComputer4ELb1EEEvPKNS_14IndexBinaryIVFEmPKhPKliPiPlPKNS_19SearchParametersIVFE
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_124search_knn_hamming_countINS_16HammingComputer8ELb1EEEvPKNS_14IndexBinaryIVFEmPKhPKliPiPlPKNS_19SearchParametersIVFE
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_124search_knn_hamming_countINS_17HammingComputer16ELb1EEEvPKNS_14IndexBinaryIVFEmPKhPKliPiPlPKNS_19SearchParametersIVFE
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_124search_knn_hamming_countINS_17HammingComputer20ELb1EEEvPKNS_14IndexBinaryIVFEmPKhPKliPiPlPKNS_19SearchParametersIVFE
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_124search_knn_hamming_countINS_17HammingComputer32ELb1EEEvPKNS_14IndexBinaryIVFEmPKhPKliPiPlPKNS_19SearchParametersIVFE
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_124search_knn_hamming_countINS_17HammingComputer64ELb1EEEvPKNS_14IndexBinaryIVFEmPKhPKliPiPlPKNS_19SearchParametersIVFE
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_124search_knn_hamming_countINS_22HammingComputerDefaultELb1EEEvPKNS_14IndexBinaryIVFEmPKhPKliPiPlPKNS_19SearchParametersIVFE
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_124search_knn_hamming_countINS_16HammingComputer4ELb0EEEvPKNS_14IndexBinaryIVFEmPKhPKliPiPlPKNS_19SearchParametersIVFE
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_124search_knn_hamming_countINS_16HammingComputer8ELb0EEEvPKNS_14IndexBinaryIVFEmPKhPKliPiPlPKNS_19SearchParametersIVFE
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_124search_knn_hamming_countINS_17HammingComputer16ELb0EEEvPKNS_14IndexBinaryIVFEmPKhPKliPiPlPKNS_19SearchParametersIVFE
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_124search_knn_hamming_countINS_17HammingComputer20ELb0EEEvPKNS_14IndexBinaryIVFEmPKhPKliPiPlPKNS_19SearchParametersIVFE
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_124search_knn_hamming_countINS_17HammingComputer32ELb0EEEvPKNS_14IndexBinaryIVFEmPKhPKliPiPlPKNS_19SearchParametersIVFE
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_124search_knn_hamming_countINS_17HammingComputer64ELb0EEEvPKNS_14IndexBinaryIVFEmPKhPKliPiPlPKNS_19SearchParametersIVFE
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_124search_knn_hamming_countINS_22HammingComputerDefaultELb0EEEvPKNS_14IndexBinaryIVFEmPKhPKliPiPlPKNS_19SearchParametersIVFE
559
560
/* Manages NQ queries at a time, stores results */
561
template <class HammingComputer, int NQ, int K>
562
struct BlockSearch {
563
    HammingComputer hcs[NQ];
564
    // heaps to update for each query
565
    int32_t* distances[NQ];
566
    idx_t* labels[NQ];
567
    // curent top of heap
568
    int32_t heap_tops[NQ];
569
570
    BlockSearch(
571
            size_t code_size,
572
            const uint8_t* __restrict x,
573
            const int32_t* __restrict keys,
574
            int32_t* __restrict all_distances,
575
0
            idx_t* __restrict all_labels) {
576
0
        for (idx_t q = 0; q < NQ; q++) {
577
0
            idx_t qno = keys[q];
578
0
            hcs[q] = HammingComputer(x + qno * code_size, code_size);
579
0
            distances[q] = all_distances + qno * K;
580
0
            labels[q] = all_labels + qno * K;
581
0
            heap_tops[q] = distances[q][0];
582
0
        }
583
0
    }
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_16HammingComputer4ELi4ELi1EEC2EmPKhPKiPiPl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_16HammingComputer4ELi4ELi2EEC2EmPKhPKiPiPl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_16HammingComputer4ELi4ELi4EEC2EmPKhPKiPiPl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_16HammingComputer8ELi4ELi1EEC2EmPKhPKiPiPl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_16HammingComputer8ELi4ELi2EEC2EmPKhPKiPiPl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_16HammingComputer8ELi4ELi4EEC2EmPKhPKiPiPl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_17HammingComputer16ELi4ELi1EEC2EmPKhPKiPiPl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_17HammingComputer16ELi4ELi2EEC2EmPKhPKiPiPl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_17HammingComputer16ELi4ELi4EEC2EmPKhPKiPiPl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_17HammingComputer20ELi4ELi1EEC2EmPKhPKiPiPl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_17HammingComputer20ELi4ELi2EEC2EmPKhPKiPiPl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_17HammingComputer20ELi4ELi4EEC2EmPKhPKiPiPl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_17HammingComputer32ELi4ELi1EEC2EmPKhPKiPiPl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_17HammingComputer32ELi4ELi2EEC2EmPKhPKiPiPl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_17HammingComputer32ELi4ELi4EEC2EmPKhPKiPiPl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_17HammingComputer64ELi4ELi1EEC2EmPKhPKiPiPl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_17HammingComputer64ELi4ELi2EEC2EmPKhPKiPiPl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_17HammingComputer64ELi4ELi4EEC2EmPKhPKiPiPl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_22HammingComputerDefaultELi4ELi1EEC2EmPKhPKiPiPl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_22HammingComputerDefaultELi4ELi2EEC2EmPKhPKiPiPl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_22HammingComputerDefaultELi4ELi4EEC2EmPKhPKiPiPl
584
585
0
    void add_bcode(const uint8_t* bcode, idx_t id) {
586
0
        using C = CMax<int32_t, idx_t>;
587
0
        for (int q = 0; q < NQ; q++) {
588
0
            int dis = hcs[q].hamming(bcode);
589
0
            if (dis < heap_tops[q]) {
590
0
                heap_replace_top<C>(K, distances[q], labels[q], dis, id);
591
0
                heap_tops[q] = distances[q][0];
592
0
            }
593
0
        }
594
0
    }
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_16HammingComputer4ELi4ELi1EE9add_bcodeEPKhl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_16HammingComputer4ELi4ELi2EE9add_bcodeEPKhl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_16HammingComputer4ELi4ELi4EE9add_bcodeEPKhl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_16HammingComputer8ELi4ELi1EE9add_bcodeEPKhl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_16HammingComputer8ELi4ELi2EE9add_bcodeEPKhl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_16HammingComputer8ELi4ELi4EE9add_bcodeEPKhl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_17HammingComputer16ELi4ELi1EE9add_bcodeEPKhl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_17HammingComputer16ELi4ELi2EE9add_bcodeEPKhl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_17HammingComputer16ELi4ELi4EE9add_bcodeEPKhl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_17HammingComputer20ELi4ELi1EE9add_bcodeEPKhl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_17HammingComputer20ELi4ELi2EE9add_bcodeEPKhl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_17HammingComputer20ELi4ELi4EE9add_bcodeEPKhl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_17HammingComputer32ELi4ELi1EE9add_bcodeEPKhl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_17HammingComputer32ELi4ELi2EE9add_bcodeEPKhl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_17HammingComputer32ELi4ELi4EE9add_bcodeEPKhl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_17HammingComputer64ELi4ELi1EE9add_bcodeEPKhl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_17HammingComputer64ELi4ELi2EE9add_bcodeEPKhl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_17HammingComputer64ELi4ELi4EE9add_bcodeEPKhl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_22HammingComputerDefaultELi4ELi1EE9add_bcodeEPKhl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_22HammingComputerDefaultELi4ELi2EE9add_bcodeEPKhl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_111BlockSearchINS_22HammingComputerDefaultELi4ELi4EE9add_bcodeEPKhl
595
};
596
597
template <class HammingComputer, int NQ>
598
struct BlockSearchVariableK {
599
    int k;
600
    HammingComputer hcs[NQ];
601
    // heaps to update for each query
602
    int32_t* distances[NQ];
603
    idx_t* labels[NQ];
604
    // curent top of heap
605
    int32_t heap_tops[NQ];
606
607
    BlockSearchVariableK(
608
            size_t code_size,
609
            int k,
610
            const uint8_t* __restrict x,
611
            const int32_t* __restrict keys,
612
            int32_t* __restrict all_distances,
613
            idx_t* __restrict all_labels)
614
0
            : k(k) {
615
0
        for (idx_t q = 0; q < NQ; q++) {
616
0
            idx_t qno = keys[q];
617
0
            hcs[q] = HammingComputer(x + qno * code_size, code_size);
618
0
            distances[q] = all_distances + qno * k;
619
0
            labels[q] = all_labels + qno * k;
620
0
            heap_tops[q] = distances[q][0];
621
0
        }
622
0
    }
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_120BlockSearchVariableKINS_16HammingComputer4ELi4EEC2EmiPKhPKiPiPl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_120BlockSearchVariableKINS_16HammingComputer8ELi4EEC2EmiPKhPKiPiPl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_120BlockSearchVariableKINS_17HammingComputer16ELi4EEC2EmiPKhPKiPiPl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_120BlockSearchVariableKINS_17HammingComputer20ELi4EEC2EmiPKhPKiPiPl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_120BlockSearchVariableKINS_17HammingComputer32ELi4EEC2EmiPKhPKiPiPl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_120BlockSearchVariableKINS_17HammingComputer64ELi4EEC2EmiPKhPKiPiPl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_120BlockSearchVariableKINS_22HammingComputerDefaultELi4EEC2EmiPKhPKiPiPl
623
624
0
    void add_bcode(const uint8_t* bcode, idx_t id) {
625
0
        using C = CMax<int32_t, idx_t>;
626
0
        for (int q = 0; q < NQ; q++) {
627
0
            int dis = hcs[q].hamming(bcode);
628
0
            if (dis < heap_tops[q]) {
629
0
                heap_replace_top<C>(k, distances[q], labels[q], dis, id);
630
0
                heap_tops[q] = distances[q][0];
631
0
            }
632
0
        }
633
0
    }
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_120BlockSearchVariableKINS_16HammingComputer4ELi4EE9add_bcodeEPKhl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_120BlockSearchVariableKINS_16HammingComputer8ELi4EE9add_bcodeEPKhl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_120BlockSearchVariableKINS_17HammingComputer16ELi4EE9add_bcodeEPKhl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_120BlockSearchVariableKINS_17HammingComputer20ELi4EE9add_bcodeEPKhl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_120BlockSearchVariableKINS_17HammingComputer32ELi4EE9add_bcodeEPKhl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_120BlockSearchVariableKINS_17HammingComputer64ELi4EE9add_bcodeEPKhl
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_120BlockSearchVariableKINS_22HammingComputerDefaultELi4EE9add_bcodeEPKhl
634
};
635
636
template <class HammingComputer>
637
void search_knn_hamming_per_invlist(
638
        const IndexBinaryIVF* ivf,
639
        size_t n,
640
        const uint8_t* __restrict x,
641
        idx_t k,
642
        const idx_t* __restrict keys_in,
643
        const int32_t* __restrict coarse_dis,
644
        int32_t* __restrict distances,
645
        idx_t* __restrict labels,
646
        bool store_pairs,
647
0
        const IVFSearchParameters* params) {
648
0
    idx_t nprobe = params ? params->nprobe : ivf->nprobe;
649
0
    nprobe = std::min((idx_t)ivf->nlist, nprobe);
650
0
    idx_t max_codes = params ? params->max_codes : ivf->max_codes;
651
0
    FAISS_THROW_IF_NOT(max_codes == 0);
652
0
    FAISS_THROW_IF_NOT(!store_pairs);
653
654
    // reorder buckets
655
0
    std::vector<int64_t> lims(n + 1);
656
0
    int32_t* keys = new int32_t[n * nprobe];
657
0
    std::unique_ptr<int32_t[]> delete_keys(keys);
658
0
    for (idx_t i = 0; i < n * nprobe; i++) {
659
0
        keys[i] = keys_in[i];
660
0
    }
661
0
    matrix_bucket_sort_inplace(n, nprobe, keys, ivf->nlist, lims.data(), 0);
662
663
0
    using C = CMax<int32_t, idx_t>;
664
0
    heap_heapify<C>(n * k, distances, labels);
665
0
    const size_t code_size = ivf->code_size;
666
667
0
    for (idx_t l = 0; l < ivf->nlist; l++) {
668
0
        idx_t l0 = lims[l], nq = lims[l + 1] - l0;
669
670
0
        InvertedLists::ScopedCodes scodes(ivf->invlists, l);
671
0
        InvertedLists::ScopedIds sidx(ivf->invlists, l);
672
0
        idx_t nb = ivf->invlists->list_size(l);
673
0
        const uint8_t* bcodes = scodes.get();
674
0
        const idx_t* ids = sidx.get();
675
676
0
        idx_t i = 0;
677
678
        // process as much as possible by blocks
679
0
        constexpr int BS = 4;
680
681
0
        if (k == 1) {
682
0
            for (; i + BS <= nq; i += BS) {
683
0
                BlockSearch<HammingComputer, BS, 1> bc(
684
0
                        code_size, x, keys + l0 + i, distances, labels);
685
0
                for (idx_t j = 0; j < nb; j++) {
686
0
                    bc.add_bcode(bcodes + j * code_size, ids[j]);
687
0
                }
688
0
            }
689
0
        } else if (k == 2) {
690
0
            for (; i + BS <= nq; i += BS) {
691
0
                BlockSearch<HammingComputer, BS, 2> bc(
692
0
                        code_size, x, keys + l0 + i, distances, labels);
693
0
                for (idx_t j = 0; j < nb; j++) {
694
0
                    bc.add_bcode(bcodes + j * code_size, ids[j]);
695
0
                }
696
0
            }
697
0
        } else if (k == 4) {
698
0
            for (; i + BS <= nq; i += BS) {
699
0
                BlockSearch<HammingComputer, BS, 4> bc(
700
0
                        code_size, x, keys + l0 + i, distances, labels);
701
0
                for (idx_t j = 0; j < nb; j++) {
702
0
                    bc.add_bcode(bcodes + j * code_size, ids[j]);
703
0
                }
704
0
            }
705
0
        } else {
706
0
            for (; i + BS <= nq; i += BS) {
707
0
                BlockSearchVariableK<HammingComputer, BS> bc(
708
0
                        code_size, k, x, keys + l0 + i, distances, labels);
709
0
                for (idx_t j = 0; j < nb; j++) {
710
0
                    bc.add_bcode(bcodes + j * code_size, ids[j]);
711
0
                }
712
0
            }
713
0
        }
714
715
        // leftovers
716
0
        for (; i < nq; i++) {
717
0
            idx_t qno = keys[l0 + i];
718
0
            HammingComputer hc(x + qno * code_size, code_size);
719
0
            idx_t* __restrict idxi = labels + qno * k;
720
0
            int32_t* __restrict simi = distances + qno * k;
721
0
            int32_t simi0 = simi[0];
722
0
            for (idx_t j = 0; j < nb; j++) {
723
0
                int dis = hc.hamming(bcodes + j * code_size);
724
725
0
                if (dis < simi0) {
726
0
                    idx_t id = store_pairs ? lo_build(l, j) : ids[j];
727
0
                    heap_replace_top<C>(k, simi, idxi, dis, id);
728
0
                    simi0 = simi[0];
729
0
                }
730
0
            }
731
0
        }
732
0
    }
733
0
    for (idx_t i = 0; i < n; i++) {
734
0
        heap_reorder<C>(k, distances + i * k, labels + i * k);
735
0
    }
736
0
}
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_130search_knn_hamming_per_invlistINS_16HammingComputer4EEEvPKNS_14IndexBinaryIVFEmPKhlPKlPKiPiPlbPKNS_19SearchParametersIVFE
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_130search_knn_hamming_per_invlistINS_16HammingComputer8EEEvPKNS_14IndexBinaryIVFEmPKhlPKlPKiPiPlbPKNS_19SearchParametersIVFE
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_130search_knn_hamming_per_invlistINS_17HammingComputer16EEEvPKNS_14IndexBinaryIVFEmPKhlPKlPKiPiPlbPKNS_19SearchParametersIVFE
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_130search_knn_hamming_per_invlistINS_17HammingComputer20EEEvPKNS_14IndexBinaryIVFEmPKhlPKlPKiPiPlbPKNS_19SearchParametersIVFE
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_130search_knn_hamming_per_invlistINS_17HammingComputer32EEEvPKNS_14IndexBinaryIVFEmPKhlPKlPKiPiPlbPKNS_19SearchParametersIVFE
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_130search_knn_hamming_per_invlistINS_17HammingComputer64EEEvPKNS_14IndexBinaryIVFEmPKhlPKlPKiPiPlbPKNS_19SearchParametersIVFE
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_130search_knn_hamming_per_invlistINS_22HammingComputerDefaultEEEvPKNS_14IndexBinaryIVFEmPKhlPKlPKiPiPlbPKNS_19SearchParametersIVFE
737
738
struct Run_search_knn_hamming_per_invlist {
739
    using T = void;
740
741
    template <class HammingComputer, class... Types>
742
0
    void f(Types... args) {
743
0
        search_knn_hamming_per_invlist<HammingComputer>(args...);
744
0
    }
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_134Run_search_knn_hamming_per_invlist1fINS_16HammingComputer4EJPKNS_14IndexBinaryIVFElPKhlPKlPKiPiPlbPKNS_19SearchParametersIVFEEEEvDpT0_
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_134Run_search_knn_hamming_per_invlist1fINS_16HammingComputer8EJPKNS_14IndexBinaryIVFElPKhlPKlPKiPiPlbPKNS_19SearchParametersIVFEEEEvDpT0_
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_134Run_search_knn_hamming_per_invlist1fINS_17HammingComputer16EJPKNS_14IndexBinaryIVFElPKhlPKlPKiPiPlbPKNS_19SearchParametersIVFEEEEvDpT0_
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_134Run_search_knn_hamming_per_invlist1fINS_17HammingComputer20EJPKNS_14IndexBinaryIVFElPKhlPKlPKiPiPlbPKNS_19SearchParametersIVFEEEEvDpT0_
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_134Run_search_knn_hamming_per_invlist1fINS_17HammingComputer32EJPKNS_14IndexBinaryIVFElPKhlPKlPKiPiPlbPKNS_19SearchParametersIVFEEEEvDpT0_
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_134Run_search_knn_hamming_per_invlist1fINS_17HammingComputer64EJPKNS_14IndexBinaryIVFElPKhlPKlPKiPiPlbPKNS_19SearchParametersIVFEEEEvDpT0_
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_134Run_search_knn_hamming_per_invlist1fINS_22HammingComputerDefaultEJPKNS_14IndexBinaryIVFElPKhlPKlPKiPiPlbPKNS_19SearchParametersIVFEEEEvDpT0_
745
};
746
747
template <bool store_pairs>
748
struct Run_search_knn_hamming_count {
749
    using T = void;
750
751
    template <class HammingComputer, class... Types>
752
0
    void f(Types... args) {
753
0
        search_knn_hamming_count<HammingComputer, store_pairs>(args...);
754
0
    }
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_128Run_search_knn_hamming_countILb1EE1fINS_16HammingComputer4EJPKNS_14IndexBinaryIVFElPKhPKllPiPlPKNS_19SearchParametersIVFEEEEvDpT0_
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_128Run_search_knn_hamming_countILb1EE1fINS_16HammingComputer8EJPKNS_14IndexBinaryIVFElPKhPKllPiPlPKNS_19SearchParametersIVFEEEEvDpT0_
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_128Run_search_knn_hamming_countILb1EE1fINS_17HammingComputer16EJPKNS_14IndexBinaryIVFElPKhPKllPiPlPKNS_19SearchParametersIVFEEEEvDpT0_
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_128Run_search_knn_hamming_countILb1EE1fINS_17HammingComputer20EJPKNS_14IndexBinaryIVFElPKhPKllPiPlPKNS_19SearchParametersIVFEEEEvDpT0_
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_128Run_search_knn_hamming_countILb1EE1fINS_17HammingComputer32EJPKNS_14IndexBinaryIVFElPKhPKllPiPlPKNS_19SearchParametersIVFEEEEvDpT0_
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_128Run_search_knn_hamming_countILb1EE1fINS_17HammingComputer64EJPKNS_14IndexBinaryIVFElPKhPKllPiPlPKNS_19SearchParametersIVFEEEEvDpT0_
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_128Run_search_knn_hamming_countILb1EE1fINS_22HammingComputerDefaultEJPKNS_14IndexBinaryIVFElPKhPKllPiPlPKNS_19SearchParametersIVFEEEEvDpT0_
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_128Run_search_knn_hamming_countILb0EE1fINS_16HammingComputer4EJPKNS_14IndexBinaryIVFElPKhPKllPiPlPKNS_19SearchParametersIVFEEEEvDpT0_
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_128Run_search_knn_hamming_countILb0EE1fINS_16HammingComputer8EJPKNS_14IndexBinaryIVFElPKhPKllPiPlPKNS_19SearchParametersIVFEEEEvDpT0_
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_128Run_search_knn_hamming_countILb0EE1fINS_17HammingComputer16EJPKNS_14IndexBinaryIVFElPKhPKllPiPlPKNS_19SearchParametersIVFEEEEvDpT0_
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_128Run_search_knn_hamming_countILb0EE1fINS_17HammingComputer20EJPKNS_14IndexBinaryIVFElPKhPKllPiPlPKNS_19SearchParametersIVFEEEEvDpT0_
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_128Run_search_knn_hamming_countILb0EE1fINS_17HammingComputer32EJPKNS_14IndexBinaryIVFElPKhPKllPiPlPKNS_19SearchParametersIVFEEEEvDpT0_
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_128Run_search_knn_hamming_countILb0EE1fINS_17HammingComputer64EJPKNS_14IndexBinaryIVFElPKhPKllPiPlPKNS_19SearchParametersIVFEEEEvDpT0_
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_128Run_search_knn_hamming_countILb0EE1fINS_22HammingComputerDefaultEJPKNS_14IndexBinaryIVFElPKhPKllPiPlPKNS_19SearchParametersIVFEEEEvDpT0_
755
};
756
757
struct BuildScanner {
758
    using T = BinaryInvertedListScanner*;
759
760
    template <class HammingComputer>
761
0
    T f(size_t code_size, bool store_pairs) {
762
0
        return new IVFBinaryScannerL2<HammingComputer>(code_size, store_pairs);
763
0
    }
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_112BuildScanner1fINS_16HammingComputer4EEEPNS_25BinaryInvertedListScannerEmb
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_112BuildScanner1fINS_16HammingComputer8EEEPNS_25BinaryInvertedListScannerEmb
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_112BuildScanner1fINS_17HammingComputer16EEEPNS_25BinaryInvertedListScannerEmb
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_112BuildScanner1fINS_17HammingComputer20EEEPNS_25BinaryInvertedListScannerEmb
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_112BuildScanner1fINS_17HammingComputer32EEEPNS_25BinaryInvertedListScannerEmb
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_112BuildScanner1fINS_17HammingComputer64EEEPNS_25BinaryInvertedListScannerEmb
Unexecuted instantiation: IndexBinaryIVF.cpp:_ZN5faiss12_GLOBAL__N_112BuildScanner1fINS_22HammingComputerDefaultEEEPNS_25BinaryInvertedListScannerEmb
764
};
765
766
} // anonymous namespace
767
768
BinaryInvertedListScanner* IndexBinaryIVF::get_InvertedListScanner(
769
0
        bool store_pairs) const {
770
0
    BuildScanner bs;
771
0
    return dispatch_HammingComputer(code_size, bs, code_size, store_pairs);
772
0
}
773
774
void IndexBinaryIVF::search_preassigned(
775
        idx_t n,
776
        const uint8_t* x,
777
        idx_t k,
778
        const idx_t* cidx,
779
        const int32_t* cdis,
780
        int32_t* dis,
781
        idx_t* idx,
782
        bool store_pairs,
783
0
        const IVFSearchParameters* params) const {
784
0
    if (per_invlist_search) {
785
0
        Run_search_knn_hamming_per_invlist r;
786
        // clang-format off
787
0
        dispatch_HammingComputer(
788
0
                code_size, r, this, n, x, k,
789
0
                cidx, cdis, dis, idx, store_pairs, params);
790
        // clang-format on
791
0
    } else if (use_heap) {
792
0
        search_knn_hamming_heap(
793
0
                this, n, x, k, cidx, cdis, dis, idx, store_pairs, params);
794
0
    } else if (store_pairs) { // !use_heap && store_pairs
795
0
        Run_search_knn_hamming_count<true> r;
796
0
        dispatch_HammingComputer(
797
0
                code_size, r, this, n, x, cidx, k, dis, idx, params);
798
0
    } else { // !use_heap && !store_pairs
799
0
        Run_search_knn_hamming_count<false> r;
800
0
        dispatch_HammingComputer(
801
0
                code_size, r, this, n, x, cidx, k, dis, idx, params);
802
0
    }
803
0
}
804
805
void IndexBinaryIVF::range_search(
806
        idx_t n,
807
        const uint8_t* __restrict x,
808
        int radius,
809
        RangeSearchResult* __restrict res,
810
0
        const SearchParameters* params) const {
811
0
    FAISS_THROW_IF_NOT_MSG(
812
0
            !params, "search params not supported for this index");
813
0
    const size_t nprobe_2 = std::min(nlist, this->nprobe);
814
0
    std::unique_ptr<idx_t[]> idx(new idx_t[n * nprobe_2]);
815
0
    std::unique_ptr<int32_t[]> coarse_dis(new int32_t[n * nprobe_2]);
816
817
0
    double t0 = getmillisecs();
818
0
    quantizer->search(n, x, nprobe_2, coarse_dis.get(), idx.get());
819
0
    indexIVF_stats.quantization_time += getmillisecs() - t0;
820
821
0
    t0 = getmillisecs();
822
0
    invlists->prefetch_lists(idx.get(), n * nprobe_2);
823
824
0
    range_search_preassigned(n, x, radius, idx.get(), coarse_dis.get(), res);
825
826
0
    indexIVF_stats.search_time += getmillisecs() - t0;
827
0
}
828
829
void IndexBinaryIVF::range_search_preassigned(
830
        idx_t n,
831
        const uint8_t* __restrict x,
832
        int radius,
833
        const idx_t* __restrict assign,
834
        const int32_t* __restrict centroid_dis,
835
0
        RangeSearchResult* __restrict res) const {
836
0
    const size_t nprobe_2 = std::min(nlist, this->nprobe);
837
0
    bool store_pairs = false;
838
0
    size_t nlistv = 0, ndis = 0;
839
840
0
    std::vector<RangeSearchPartialResult*> all_pres(omp_get_max_threads());
841
842
0
#pragma omp parallel reduction(+ : nlistv, ndis)
843
0
    {
844
0
        RangeSearchPartialResult pres(res);
845
0
        std::unique_ptr<BinaryInvertedListScanner> scanner(
846
0
                get_InvertedListScanner(store_pairs));
847
0
        FAISS_THROW_IF_NOT(scanner.get());
848
849
0
        all_pres[omp_get_thread_num()] = &pres;
850
851
0
        auto scan_list_func = [&](size_t i, size_t ik, RangeQueryResult& qres) {
852
0
            idx_t key = assign[i * nprobe_2 + ik]; /* select the list  */
853
0
            if (key < 0)
854
0
                return;
855
0
            FAISS_THROW_IF_NOT_FMT(
856
0
                    key < (idx_t)nlist,
857
0
                    "Invalid key=%" PRId64 " at ik=%zd nlist=%zd\n",
858
0
                    key,
859
0
                    ik,
860
0
                    nlist);
861
0
            const size_t list_size = invlists->list_size(key);
862
863
0
            if (list_size == 0)
864
0
                return;
865
866
0
            InvertedLists::ScopedCodes scodes(invlists, key);
867
0
            InvertedLists::ScopedIds ids(invlists, key);
868
869
0
            scanner->set_list(key, assign[i * nprobe_2 + ik]);
870
0
            nlistv++;
871
0
            ndis += list_size;
872
0
            scanner->scan_codes_range(
873
0
                    list_size, scodes.get(), ids.get(), radius, qres);
874
0
        };
875
876
0
#pragma omp for
877
0
        for (idx_t i = 0; i < n; i++) {
878
0
            scanner->set_query(x + i * code_size);
879
880
0
            RangeQueryResult& qres = pres.new_result(i);
881
882
0
            for (size_t ik = 0; ik < nprobe_2; ik++) {
883
0
                scan_list_func(i, ik, qres);
884
0
            }
885
0
        }
886
887
0
        pres.finalize();
888
0
    }
889
0
    indexIVF_stats.nq += n;
890
0
    indexIVF_stats.nlist += nlistv;
891
0
    indexIVF_stats.ndis += ndis;
892
0
}
893
894
0
IndexBinaryIVF::~IndexBinaryIVF() {
895
0
    if (own_invlists) {
896
0
        delete invlists;
897
0
    }
898
899
0
    if (own_fields) {
900
0
        delete quantizer;
901
0
    }
902
0
}
903
904
} // namespace faiss