Faiss

- Main Page
- Namespaces
- Classes
- Files

- File List

All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends
/data/users/hoss/faiss/hamming.cpp
1 /**
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 // -*- c++ -*-
9
10 /*
11 * Implementation of Hamming related functions (distances, smallest distance
12 * selection with regular heap|radix and probabilistic heap|radix.
13 *
14 * IMPLEMENTATION NOTES
15 * Bitvectors are generally assumed to be multiples of 64 bits.
16 *
17 * hamdis_t is used for distances because at this time
18 * it is not clear how we will need to balance
19 * - flexibility in vector size (unclear more than 2^16 or even 2^8 bitvectors)
20 * - memory usage
21 * - cache-misses when dealing with large volumes of data (lower bits is better)
22 *
23 * The hamdis_t should optimally be compatibe with one of the Torch Storage
24 * (Byte,Short,Long) and therefore should be signed for 2-bytes and 4-bytes
25 */
26
27 #include "hamming.h"
28
29 #include <vector>
30 #include <memory>
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <math.h>
34 #include <assert.h>
35 #include <limits.h>
36
37 #include "Heap.h"
38 #include "FaissAssert.h"
39
40 static const size_t BLOCKSIZE_QUERY = 8192;
41
42
43 namespace faiss {
44
45 size_t hamming_batch_size = 65536;
46
47 static const uint8_t hamdis_tab_ham_bytes[256] = {
48 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
49 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
50 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
51 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
52 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
53 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
54 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
55 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
56 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
57 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
58 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
59 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
60 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
61 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
62 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
63 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
64 };
65
66
67 /* Elementary Hamming distance computation: unoptimized */
68 template <size_t nbits, typename T>
69 T hamming (const uint8_t *bs1,
70 const uint8_t *bs2)
71 {
72 const size_t nbytes = nbits / 8;
73 size_t i;
74 T h = 0;
75 for (i = 0; i < nbytes; i++)
76 h += (T) hamdis_tab_ham_bytes[bs1[i]^bs2[i]];
77 return h;
78 }
79
80
81 /* Hamming distances for multiples of 64 bits */
82 template <size_t nbits>
83 hamdis_t hamming (const uint64_t * bs1, const uint64_t * bs2)
84 {
85 const size_t nwords = nbits / 64;
86 size_t i;
87 hamdis_t h = 0;
88 for (i = 0; i < nwords; i++)
89 h += popcount64 (bs1[i] ^ bs2[i]);
90 return h;
91 }
92
93
94
95 /* specialized (optimized) functions */
96 template <>
97 hamdis_t hamming<64> (const uint64_t * pa, const uint64_t * pb)
98 {
99 return popcount64 (pa[0] ^ pb[0]);
100 }
101
102
103 template <>
104 hamdis_t hamming<128> (const uint64_t *pa, const uint64_t *pb)
105 {
106 return popcount64 (pa[0] ^ pb[0]) + popcount64(pa[1] ^ pb[1]);
107 }
108
109
110 template <>
111 hamdis_t hamming<256> (const uint64_t * pa, const uint64_t * pb)
112 {
113 return popcount64 (pa[0] ^ pb[0])
114 + popcount64 (pa[1] ^ pb[1])
115 + popcount64 (pa[2] ^ pb[2])
116 + popcount64 (pa[3] ^ pb[3]);
117 }
118
119
120 /* Hamming distances for multiple of 64 bits */
121 hamdis_t hamming (
122 const uint64_t * bs1,
123 const uint64_t * bs2,
124 size_t nwords)
125 {
126 size_t i;
127 hamdis_t h = 0;
128 for (i = 0; i < nwords; i++)
129 h += popcount64 (bs1[i] ^ bs2[i]);
130 return h;
131 }
132
133
134
135 template <size_t nbits>
136 void hammings (
137 const uint64_t * bs1,
138 const uint64_t * bs2,
139 size_t n1, size_t n2,
140 hamdis_t * dis)
141
142 {
143 size_t i, j;
144 const size_t nwords = nbits / 64;
145 for (i = 0; i < n1; i++) {
146 const uint64_t * __restrict bs1_ = bs1 + i * nwords;
147 hamdis_t * __restrict dis_ = dis + i * n2;
148 for (j = 0; j < n2; j++)
149 dis_[j] = hamming<nbits>(bs1_, bs2 + j * nwords);
150 }
151 }
152
153
154
155 void hammings (
156 const uint64_t * bs1,
157 const uint64_t * bs2,
158 size_t n1,
159 size_t n2,
160 size_t nwords,
161 hamdis_t * __restrict dis)
162 {
163 size_t i, j;
164 n1 *= nwords;
165 n2 *= nwords;
166 for (i = 0; i < n1; i+=nwords) {
167 const uint64_t * bs1_ = bs1+i;
168 for (j = 0; j < n2; j+=nwords)
169 dis[j] = hamming (bs1_, bs2+j, nwords);
170 }
171 }
172
173
174
175
176 /* Count number of matches given a max threshold */
177 template <size_t nbits>
178 void hamming_count_thres (
179 const uint64_t * bs1,
180 const uint64_t * bs2,
181 size_t n1,
182 size_t n2,
183 hamdis_t ht,
184 size_t * nptr)
185 {
186 const size_t nwords = nbits / 64;
187 size_t i, j, posm = 0;
188 const uint64_t * bs2_ = bs2;
189
190 for (i = 0; i < n1; i++) {
191 bs2 = bs2_;
192 for (j = 0; j < n2; j++) {
193 /* collect the match only if this satisfies the threshold */
194 if (hamming <nbits> (bs1, bs2) <= ht)
195 posm++;
196 bs2 += nwords;
197 }
198 bs1 += nwords; /* next signature */
199 }
200 *nptr = posm;
201 }
202
203
204 template <size_t nbits>
205 void crosshamming_count_thres (
206 const uint64_t * dbs,
207 size_t n,
208 int ht,
209 size_t * nptr)
210 {
211 const size_t nwords = nbits / 64;
212 size_t i, j, posm = 0;
213 const uint64_t * bs1 = dbs;
214 for (i = 0; i < n; i++) {
215 const uint64_t * bs2 = bs1 + 2;
216 for (j = i + 1; j < n; j++) {
217 /* collect the match only if this satisfies the threshold */
218 if (hamming <nbits> (bs1, bs2) <= ht)
219 posm++;
220 bs2 += nwords;
221 }
222 bs1 += nwords;
223 }
224 *nptr = posm;
225 }
226
227
228 template <size_t nbits>
229 size_t match_hamming_thres (
230 const uint64_t * bs1,
231 const uint64_t * bs2,
232 size_t n1,
233 size_t n2,
234 int ht,
235 long * idx,
236 hamdis_t * hams)
237 {
238 const size_t nwords = nbits / 64;
239 size_t i, j, posm = 0;
240 hamdis_t h;
241 const uint64_t * bs2_ = bs2;
242 for (i = 0; i < n1; i++) {
243 bs2 = bs2_;
244 for (j = 0; j < n2; j++) {
245 /* Here perform the real work of computing the distance */
246 h = hamming <nbits> (bs1, bs2);
247
248 /* collect the match only if this satisfies the threshold */
249 if (h <= ht) {
250 /* Enough space to store another match ? */
251 *idx = i; idx++;
252 *idx = j; idx++;
253 *hams = h;
254 hams++;
255 posm++;
256 }
257 bs2+=nwords; /* next signature */
258 }
259 bs1+=nwords;
260 }
261 return posm;
262 }
263
264
265 /* Return closest neighbors w.r.t Hamming distance, using a heap. */
266 template <class HammingComputer>
267 static
268 void hammings_knn_hc (
269 int bytes_per_code,
270 int_maxheap_array_t * ha,
271 const uint8_t * bs1,
272 const uint8_t * bs2,
273 size_t n2,
274 bool order = true,
275 bool init_heap = true)
276 {
277 size_t k = ha->k;
278 if (init_heap) ha->heapify ();
279
280 const size_t block_size = hamming_batch_size;
281 for (size_t j0 = 0; j0 < n2; j0 += block_size) {
282 const size_t j1 = std::min(j0 + block_size, n2);
283 #pragma omp parallel for
284 for (size_t i = 0; i < ha->nh; i++) {
285 HammingComputer hc (bs1 + i * bytes_per_code, bytes_per_code);
286
287 const uint8_t * bs2_ = bs2 + j0 * bytes_per_code;
288 hamdis_t dis;
289 hamdis_t * __restrict bh_val_ = ha->val + i * k;
290 long * __restrict bh_ids_ = ha->ids + i * k;
291 size_t j;
292 for (j = j0; j < j1; j++, bs2_+= bytes_per_code) {
293 dis = hc.hamming (bs2_);
294 if (dis < bh_val_[0]) {
295 faiss::maxheap_pop<hamdis_t> (k, bh_val_, bh_ids_);
296 faiss::maxheap_push<hamdis_t> (k, bh_val_, bh_ids_, dis, j);
297 }
298 }
299 }
300 }
301 if (order) ha->reorder ();
302 }
303
304 /* Return closest neighbors w.r.t Hamming distance, using max count. */
305 template <class HammingComputer>
306 static
307 void hammings_knn_mc (
308 int bytes_per_code,
309 const uint8_t *a,
310 const uint8_t *b,
311 size_t na,
312 size_t nb,
313 size_t k,
314 int32_t *distances,
315 long *labels)
316 {
317 const int nBuckets = bytes_per_code * 8 + 1;
318 std::vector<int> all_counters(na * nBuckets, 0);
319 std::unique_ptr<long[]> all_ids_per_dis(new long[na * nBuckets * k]);
320
321 std::vector<HCounterState<HammingComputer>> cs;
322 for (size_t i = 0; i < na; ++i) {
323 cs.push_back(HCounterState<HammingComputer>(
324 all_counters.data() + i * nBuckets,
325 all_ids_per_dis.get() + i * nBuckets * k,
326 a + i * bytes_per_code,
327 8 * bytes_per_code,
328 k
329 ));
330 }
331
332 const size_t block_size = hamming_batch_size;
333 for (size_t j0 = 0; j0 < nb; j0 += block_size) {
334 const size_t j1 = std::min(j0 + block_size, nb);
335 #pragma omp parallel for
336 for (size_t i = 0; i < na; ++i) {
337 for (size_t j = j0; j < j1; ++j) {
338 cs[i].update_counter(b + j * bytes_per_code, j);
339 }
340 }
341 }
342
343 for (size_t i = 0; i < na; ++i) {
344 HCounterState<HammingComputer>& csi = cs[i];
345
346 int nres = 0;
347 for (int b = 0; b < nBuckets && nres < k; b++) {
348 for (int l = 0; l < csi.counters[b] && nres < k; l++) {
349 labels[i * k + nres] = csi.ids_per_dis[b * k + l];
350 distances[i * k + nres] = b;
351 nres++;
352 }
353 }
354 while (nres < k) {
355 labels[i * k + nres] = -1;
356 distances[i * k + nres] = std::numeric_limits<int32_t>::max();
357 ++nres;
358 }
359 }
360 }
361
362
363
364 // works faster than the template version
365 static
366 void hammings_knn_hc_1 (
367 int_maxheap_array_t * ha,
368 const uint64_t * bs1,
369 const uint64_t * bs2,
370 size_t n2,
371 bool order = true,
372 bool init_heap = true)
373 {
374 const size_t nwords = 1;
375 size_t k = ha->k;
376
377
378 if (init_heap) {
379 ha->heapify ();
380 }
381
382 #pragma omp parallel for
383 for (size_t i = 0; i < ha->nh; i++) {
384 const uint64_t bs1_ = bs1 [i];
385 const uint64_t * bs2_ = bs2;
386 hamdis_t dis;
387 hamdis_t * bh_val_ = ha->val + i * k;
388 hamdis_t bh_val_0 = bh_val_[0];
389 long * bh_ids_ = ha->ids + i * k;
390 size_t j;
391 for (j = 0; j < n2; j++, bs2_+= nwords) {
392 dis = popcount64 (bs1_ ^ *bs2_);
393 if (dis < bh_val_0) {
394 faiss::maxheap_pop<hamdis_t> (k, bh_val_, bh_ids_);
395 faiss::maxheap_push<hamdis_t> (k, bh_val_, bh_ids_, dis, j);
396 bh_val_0 = bh_val_[0];
397 }
398 }
399 }
400 if (order) {
401 ha->reorder ();
402 }
403 }
404
405
406
407
408 /* Functions to maps vectors to bits. Assume proper allocation done beforehand,
409 meaning that b should be be able to receive as many bits as x may produce. */
410
411 /*
412 * dimension 0 corresponds to the least significant bit of b[0], or
413 * equivalently to the lsb of the first byte that is stored.
414 */
415 void fvec2bitvec (const float * x, uint8_t * b, size_t d)
416 {
417 for (int i = 0; i < d; i += 8) {
418 uint8_t w = 0;
419 uint8_t mask = 1;
420 int nj = i + 8 <= d ? 8 : d - i;
421 for (int j = 0; j < nj; j++) {
422 if (x[i + j] >= 0)
423 w |= mask;
424 mask <<= 1;
425 }
426 *b = w;
427 b++;
428 }
429 }
430
431
432
433 /* Same but for n vectors.
434 Ensure that the ouptut b is byte-aligned (pad with 0s). */
435 void fvecs2bitvecs (const float * x, uint8_t * b, size_t d, size_t n)
436 {
437 const long ncodes = ((d + 7) / 8);
438 #pragma omp parallel for
439 for (size_t i = 0; i < n; i++)
440 fvec2bitvec (x + i * d, b + i * ncodes, d);
441 }
442
443
444 /* Reverse bit (NOT a optimized function, only used for print purpose) */
445 static uint64_t uint64_reverse_bits (uint64_t b)
446 {
447 int i;
448 uint64_t revb = 0;
449 for (i = 0; i < 64; i++) {
450 revb <<= 1;
451 revb |= b & 1;
452 b >>= 1;
453 }
454 return revb;
455 }
456
457
458 /* print the bit vector */
459 void bitvec_print (const uint8_t * b, size_t d)
460 {
461 size_t i, j;
462 for (i = 0; i < d; ) {
463 uint64_t brev = uint64_reverse_bits (* (uint64_t *) b);
464 for (j = 0; j < 64 && i < d; j++, i++) {
465 printf ("%d", (int) (brev & 1));
466 brev >>= 1;
467 }
468 b += 8;
469 printf (" ");
470 }
471 }
472
473
474
475
476
477 /*----------------------------------------*/
478 /* Hamming distance computation and k-nn */
479
480
481 #define C64(x) ((uint64_t *)x)
482
483
484 /* Compute a set of Hamming distances */
485 void hammings (
486 const uint8_t * a,
487 const uint8_t * b,
488 size_t na, size_t nb,
489 size_t ncodes,
490 hamdis_t * __restrict dis)
491 {
492 FAISS_THROW_IF_NOT (ncodes % 8 == 0);
493 switch (ncodes) {
494 case 8:
495 faiss::hammings <64> (C64(a), C64(b), na, nb, dis); return;
496 case 16:
497 faiss::hammings <128> (C64(a), C64(b), na, nb, dis); return;
498 case 32:
499 faiss::hammings <256> (C64(a), C64(b), na, nb, dis); return;
500 case 64:
501 faiss::hammings <512> (C64(a), C64(b), na, nb, dis); return;
502 default:
503 faiss::hammings (C64(a), C64(b), na, nb, ncodes * 8, dis); return;
504 }
505 }
506
507 void hammings_knn(
508 int_maxheap_array_t *ha,
509 const uint8_t *a,
510 const uint8_t *b,
511 size_t nb,
512 size_t ncodes,
513 int order)
514 {
515 hammings_knn_hc(ha, a, b, nb, ncodes, order);
516 }
517 void hammings_knn_hc (
518 int_maxheap_array_t * ha,
519 const uint8_t * a,
520 const uint8_t * b,
521 size_t nb,
522 size_t ncodes,
523 int order)
524 {
525 switch (ncodes) {
526 case 4:
527 hammings_knn_hc<faiss::HammingComputer4>
528 (4, ha, a, b, nb, order, true);
529 break;
530 case 8:
531 hammings_knn_hc_1 (ha, C64(a), C64(b), nb, order, true);
532 // hammings_knn_hc<faiss::HammingComputer8>
533 // (8, ha, a, b, nb, order, true);
534 break;
535 case 16:
536 hammings_knn_hc<faiss::HammingComputer16>
537 (16, ha, a, b, nb, order, true);
538 break;
539 case 32:
540 hammings_knn_hc<faiss::HammingComputer32>
541 (32, ha, a, b, nb, order, true);
542 break;
543 default:
544 if(ncodes % 8 == 0) {
545 hammings_knn_hc<faiss::HammingComputerM8>
546 (ncodes, ha, a, b, nb, order, true);
547 } else {
548 hammings_knn_hc<faiss::HammingComputerDefault>
549 (ncodes, ha, a, b, nb, order, true);
550
551 }
552 }
553 }
554
555 void hammings_knn_mc(
556 const uint8_t * a,
557 const uint8_t * b,
558 size_t na,
559 size_t nb,
560 size_t k,
561 size_t ncodes,
562 int32_t *distances,
563 long *labels)
564 {
565 switch (ncodes) {
566 case 4:
567 hammings_knn_mc<faiss::HammingComputer4>(
568 4, a, b, na, nb, k, distances, labels
569 );
570 break;
571 case 8:
572 // TODO(hoss): Write analog to hammings_knn_hc_1
573 // hammings_knn_hc_1 (ha, C64(a), C64(b), nb, order, true);
574 hammings_knn_mc<faiss::HammingComputer8>(
575 8, a, b, na, nb, k, distances, labels
576 );
577 break;
578 case 16:
579 hammings_knn_mc<faiss::HammingComputer16>(
580 16, a, b, na, nb, k, distances, labels
581 );
582 break;
583 case 32:
584 hammings_knn_mc<faiss::HammingComputer32>(
585 32, a, b, na, nb, k, distances, labels
586 );
587 break;
588 default:
589 if(ncodes % 8 == 0) {
590 hammings_knn_mc<faiss::HammingComputerM8>(
591 ncodes, a, b, na, nb, k, distances, labels
592 );
593 } else {
594 hammings_knn_mc<faiss::HammingComputerDefault>(
595 ncodes, a, b, na, nb, k, distances, labels
596 );
597 }
598 }
599 }
600
601
602
603
604 /* Count number of matches given a max threshold */
605 void hamming_count_thres (
606 const uint8_t * bs1,
607 const uint8_t * bs2,
608 size_t n1,
609 size_t n2,
610 hamdis_t ht,
611 size_t ncodes,
612 size_t * nptr)
613 {
614 switch (ncodes) {
615 case 8:
616 faiss::hamming_count_thres <64> (C64(bs1), C64(bs2),
617 n1, n2, ht, nptr);
618 return;
619 case 16:
620 faiss::hamming_count_thres <128> (C64(bs1), C64(bs2),
621 n1, n2, ht, nptr);
622 return;
623 case 32:
624 faiss::hamming_count_thres <256> (C64(bs1), C64(bs2),
625 n1, n2, ht, nptr);
626 return;
627 case 64:
628 faiss::hamming_count_thres <512> (C64(bs1), C64(bs2),
629 n1, n2, ht, nptr);
630 return;
631 default:
632 FAISS_THROW_FMT ("not implemented for %zu bits", ncodes);
633 }
634 }
635
636
637 /* Count number of cross-matches given a threshold */
638 void crosshamming_count_thres (
639 const uint8_t * dbs,
640 size_t n,
641 hamdis_t ht,
642 size_t ncodes,
643 size_t * nptr)
644 {
645 switch (ncodes) {
646 case 8:
647 faiss::crosshamming_count_thres <64> (C64(dbs), n, ht, nptr);
648 return;
649 case 16:
650 faiss::crosshamming_count_thres <128> (C64(dbs), n, ht, nptr);
651 return;
652 case 32:
653 faiss::crosshamming_count_thres <256> (C64(dbs), n, ht, nptr);
654 return;
655 case 64:
656 faiss::crosshamming_count_thres <512> (C64(dbs), n, ht, nptr);
657 return;
658 default:
659 FAISS_THROW_FMT ("not implemented for %zu bits", ncodes);
660 }
661 }
662
663
664 /* Returns all matches given a threshold */
665 size_t match_hamming_thres (
666 const uint8_t * bs1,
667 const uint8_t * bs2,
668 size_t n1,
669 size_t n2,
670 hamdis_t ht,
671 size_t ncodes,
672 long * idx,
673 hamdis_t * dis)
674 {
675 switch (ncodes) {
676 case 8:
677 return faiss::match_hamming_thres <64> (C64(bs1), C64(bs2),
678 n1, n2, ht, idx, dis);
679 case 16:
680 return faiss::match_hamming_thres <128> (C64(bs1), C64(bs2),
681 n1, n2, ht, idx, dis);
682 case 32:
683 return faiss::match_hamming_thres <256> (C64(bs1), C64(bs2),
684 n1, n2, ht, idx, dis);
685 case 64:
686 return faiss::match_hamming_thres <512> (C64(bs1), C64(bs2),
687 n1, n2, ht, idx, dis);
688 default:
689 FAISS_THROW_FMT ("not implemented for %zu bits", ncodes);
690 return 0;
691 }
692 }
693
694
695 #undef C64
696
697
698
699 /*************************************
700 * generalized Hamming distances
701 ************************************/
702
703
704
705 template <class HammingComputer>
706 static void hamming_dis_inner_loop (
707 const uint8_t *ca,
708 const uint8_t *cb,
709 size_t nb,
710 size_t code_size,
711 int k,
712 hamdis_t * bh_val_,
713 long * bh_ids_)
714 {
715
716 HammingComputer hc (ca, code_size);
717
718 for (size_t j = 0; j < nb; j++) {
719 int ndiff = hc.hamming (cb);
720 cb += code_size;
721 if (ndiff < bh_val_[0]) {
722 maxheap_pop<hamdis_t> (k, bh_val_, bh_ids_);
723 maxheap_push<hamdis_t> (k, bh_val_, bh_ids_, ndiff, j);
724 }
725 }
726 }
727
728 void generalized_hammings_knn_hc (
729 int_maxheap_array_t * ha,
730 const uint8_t * a,
731 const uint8_t * b,
732 size_t nb,
733 size_t code_size,
734 int ordered)
735 {
736 int na = ha->nh;
737 int k = ha->k;
738
739 if (ordered)
740 ha->heapify ();
741
742 #pragma omp parallel for
743 for (int i = 0; i < na; i++) {
744 const uint8_t *ca = a + i * code_size;
745 const uint8_t *cb = b;
746
747 hamdis_t * bh_val_ = ha->val + i * k;
748 long * bh_ids_ = ha->ids + i * k;
749
750 switch (code_size) {
751 case 8:
752 hamming_dis_inner_loop<GenHammingComputer8>
753 (ca, cb, nb, 8, k, bh_val_, bh_ids_);
754 break;
755 case 16:
756 hamming_dis_inner_loop<GenHammingComputer16>
757 (ca, cb, nb, 16, k, bh_val_, bh_ids_);
758 break;
759 case 32:
760 hamming_dis_inner_loop<GenHammingComputer32>
761 (ca, cb, nb, 32, k, bh_val_, bh_ids_);
762 break;
763 default:
764 hamming_dis_inner_loop<GenHammingComputerM8>
765 (ca, cb, nb, code_size, k, bh_val_, bh_ids_);
766 break;
767 }
768 }
769
770 if (ordered)
771 ha->reorder ();
772
773 }
774
775
776 } // namespace faiss
faiss::HeapArray::k
size_t k
allocated size per heap
Definition: Heap.h:354
faiss::HeapArray::reorder
void reorder()
reorder all the heaps
Definition: Heap.cpp:27
faiss::HeapArray
Definition: Heap.h:349
faiss::HeapArray::ids
TI * ids
identifiers (size nh * k)
Definition: Heap.h:355
faiss::HeapArray::heapify
void heapify()
prepare all the heaps before adding
Definition: Heap.cpp:19
faiss::hammings
void hammings(const uint8_t *a, const uint8_t *b, size_t na, size_t nb, size_t nbytespercode, hamdis_t *dis)
faiss::HeapArray::val
T * val
values (distances or similarities), size nh * k
Definition: Heap.h:356
faiss::HeapArray::nh
size_t nh
number of heaps
Definition: Heap.h:353
faiss::generalized_hammings_knn_hc
void generalized_hammings_knn_hc(int_maxheap_array_t *ha, const uint8_t *a, const uint8_t *b, size_t nb, size_t code_size, int ordered)
Definition: hamming.cpp:728