Faiss
 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 
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
size_t k
allocated size per heap
Definition: Heap.h:355
void reorder()
reorder all the heaps
Definition: Heap.cpp:28
TI * ids
identifiers (size nh * k)
Definition: Heap.h:356
void heapify()
prepare all the heaps before adding
Definition: Heap.cpp:20
void hammings(const uint8_t *a, const uint8_t *b, size_t na, size_t nb, size_t nbytespercode, hamdis_t *dis)
T * val
values (distances or similarities), size nh * k
Definition: Heap.h:357
size_t nh
number of heaps
Definition: Heap.h:354
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