Faiss
 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 
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
size_t k
allocated size per heap
Definition: Heap.h:354
void reorder()
reorder all the heaps
Definition: Heap.cpp:27
TI * ids
identifiers (size nh * k)
Definition: Heap.h:355
void heapify()
prepare all the heaps before adding
Definition: Heap.cpp:19
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:356
size_t nh
number of heaps
Definition: Heap.h:353
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