Faiss

- Main Page
- Namespaces
- Classes
- Files

- File List

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