Faiss
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends
/tmp/faiss/hamming.h
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  * Hamming distances. The binary vector dimensionality should be a multiple
13  * of 64, as the elementary operations operate on words. If you really need
14  * other sizes, just pad with 0s (this is done by function fvecs2bitvecs).
15  *
16  * User-defined type hamdis_t is used for distances because at this time
17  * it is still uncler clear how we will need to balance
18  * - flexibility in vector size (may need 16- or even 8-bit vectors)
19  * - memory usage
20  * - cache-misses when dealing with large volumes of data (fewer bits is better)
21  *
22  * hamdis_t should optimally be compatibe with one of the Torch Storage
23  * (Byte,Short,Long) and therefore should be signed for 2-bytes and 4-bytes.
24  */
25 
26 #ifndef FAISS_hamming_h
27 #define FAISS_hamming_h
28 
29 
30 #include <stdint.h>
31 
32 #include "Heap.h"
33 
34 
35 /* The Hamming distance type should be exportable to Lua Tensor, which
36  excludes most unsigned type */
37 typedef int32_t hamdis_t;
38 
39 namespace faiss {
40 
41 
42 extern size_t hamming_batch_size;
43 
44 inline int popcount64(uint64_t x) {
45  return __builtin_popcountl(x);
46 }
47 
48 
49 /** Compute a set of Hamming distances between na and nb binary vectors
50  *
51  * @param a size na * nbytespercode
52  * @param b size nb * nbytespercode
53  * @param nbytespercode should be multiple of 8
54  * @param dis output distances, size na * nb
55  */
56 void hammings (
57  const uint8_t * a,
58  const uint8_t * b,
59  size_t na, size_t nb,
60  size_t nbytespercode,
61  hamdis_t * dis);
62 
63 void bitvec_print (const uint8_t * b, size_t d);
64 
65 
66 /* Functions for casting vectors of regular types to compact bits.
67  They assume proper allocation done beforehand, meaning that b
68  should be be able to receive as many bits as x may produce. */
69 
70 /* Makes an array of bits from the signs of a float array. The length
71  of the output array b is rounded up to byte size (allocate
72  accordingly) */
73 void fvecs2bitvecs (
74  const float * x,
75  uint8_t * b,
76  size_t d,
77  size_t n);
78 
79 
80 void fvec2bitvec (const float * x, uint8_t * b, size_t d);
81 
82 
83 
84 /** Return the k smallest Hamming distances for a set of binary query vectors,
85  * using a max heap.
86  * @param a queries, size ha->nh * ncodes
87  * @param b database, size nb * ncodes
88  * @param nb number of database vectors
89  * @param ncodes size of the binary codes (bytes)
90  * @param ordered if != 0: order the results by decreasing distance
91  * (may be bottleneck for k/n > 0.01) */
92 void hammings_knn_hc (
93  int_maxheap_array_t * ha,
94  const uint8_t * a,
95  const uint8_t * b,
96  size_t nb,
97  size_t ncodes,
98  int ordered);
99 
100 /* Legacy alias to hammings_knn_hc. */
101 void hammings_knn (
102  int_maxheap_array_t * ha,
103  const uint8_t * a,
104  const uint8_t * b,
105  size_t nb,
106  size_t ncodes,
107  int ordered);
108 
109 /** Return the k smallest Hamming distances for a set of binary query vectors,
110  * using counting max.
111  * @param a queries, size na * ncodes
112  * @param b database, size nb * ncodes
113  * @param na number of query vectors
114  * @param nb number of database vectors
115  * @param k number of vectors/distances to return
116  * @param ncodes size of the binary codes (bytes)
117  * @param distances output distances from each query vector to its k nearest
118  * neighbors
119  * @param labels output ids of the k nearest neighbors to each query vector
120  */
121 void hammings_knn_mc (
122  const uint8_t * a,
123  const uint8_t * b,
124  size_t na,
125  size_t nb,
126  size_t k,
127  size_t ncodes,
128  int32_t *distances,
129  long *labels);
130 
131 /* Counting the number of matches or of cross-matches (without returning them)
132  For use with function that assume pre-allocated memory */
133 void hamming_count_thres (
134  const uint8_t * bs1,
135  const uint8_t * bs2,
136  size_t n1,
137  size_t n2,
138  hamdis_t ht,
139  size_t ncodes,
140  size_t * nptr);
141 
142 /* Return all Hamming distances/index passing a thres. Pre-allocation of output
143  is required. Use hamming_count_thres to determine the proper size. */
144 size_t match_hamming_thres (
145  const uint8_t * bs1,
146  const uint8_t * bs2,
147  size_t n1,
148  size_t n2,
149  hamdis_t ht,
150  size_t ncodes,
151  long * idx,
152  hamdis_t * dis);
153 
154 /* Cross-matching in a set of vectors */
155 void crosshamming_count_thres (
156  const uint8_t * dbs,
157  size_t n,
158  hamdis_t ht,
159  size_t ncodes,
160  size_t * nptr);
161 
162 
163 /* compute the Hamming distances between two codewords of nwords*64 bits */
164 hamdis_t hamming (
165  const uint64_t * bs1,
166  const uint64_t * bs2,
167  size_t nwords);
168 
169 
170 
171 
172 /******************************************************************
173  * The HammingComputer series of classes compares a single code of
174  * size 4 to 32 to incoming codes. They are intended for use as a
175  * template class where it would be inefficient to switch on the code
176  * size in the inner loop. Hopefully the compiler will inline the
177  * hamming() functions and put the a0, a1, ... in registers.
178  ******************************************************************/
179 
180 
182  uint32_t a0;
183 
184  HammingComputer4 () {}
185 
186  HammingComputer4 (const uint8_t *a, int code_size) {
187  set (a, code_size);
188  }
189 
190  void set (const uint8_t *a, int code_size) {
191  assert (code_size == 4);
192  a0 = *(uint32_t *)a;
193  }
194 
195  inline int hamming (const uint8_t *b) const {
196  return popcount64 (*(uint32_t *)b ^ a0);
197  }
198 
199 };
200 
202  uint64_t a0;
203 
204  HammingComputer8 () {}
205 
206  HammingComputer8 (const uint8_t *a, int code_size) {
207  set (a, code_size);
208  }
209 
210  void set (const uint8_t *a, int code_size) {
211  assert (code_size == 8);
212  a0 = *(uint64_t *)a;
213  }
214 
215  inline int hamming (const uint8_t *b) const {
216  return popcount64 (*(uint64_t *)b ^ a0);
217  }
218 
219 };
220 
221 
223  uint64_t a0, a1;
224 
225  HammingComputer16 () {}
226 
227  HammingComputer16 (const uint8_t *a8, int code_size) {
228  set (a8, code_size);
229  }
230 
231  void set (const uint8_t *a8, int code_size) {
232  assert (code_size == 16);
233  const uint64_t *a = (uint64_t *)a8;
234  a0 = a[0]; a1 = a[1];
235  }
236 
237  inline int hamming (const uint8_t *b8) const {
238  const uint64_t *b = (uint64_t *)b8;
239  return popcount64 (b[0] ^ a0) + popcount64 (b[1] ^ a1);
240  }
241 
242 };
243 
244 // when applied to an array, 1/2 of the 64-bit accesses are unaligned.
245 // This incurs a penalty of ~10% wrt. fully aligned accesses.
247  uint64_t a0, a1;
248  uint32_t a2;
249 
250  HammingComputer20 () {}
251 
252  HammingComputer20 (const uint8_t *a8, int code_size) {
253  set (a8, code_size);
254  }
255 
256  void set (const uint8_t *a8, int code_size) {
257  assert (code_size == 20);
258  const uint64_t *a = (uint64_t *)a8;
259  a0 = a[0]; a1 = a[1]; a2 = a[2];
260  }
261 
262  inline int hamming (const uint8_t *b8) const {
263  const uint64_t *b = (uint64_t *)b8;
264  return popcount64 (b[0] ^ a0) + popcount64 (b[1] ^ a1) +
265  popcount64 (*(uint32_t*)(b + 2) ^ a2);
266  }
267 };
268 
270  uint64_t a0, a1, a2, a3;
271 
272  HammingComputer32 () {}
273 
274  HammingComputer32 (const uint8_t *a8, int code_size) {
275  set (a8, code_size);
276  }
277 
278  void set (const uint8_t *a8, int code_size) {
279  assert (code_size == 32);
280  const uint64_t *a = (uint64_t *)a8;
281  a0 = a[0]; a1 = a[1]; a2 = a[2]; a3 = a[3];
282  }
283 
284  inline int hamming (const uint8_t *b8) const {
285  const uint64_t *b = (uint64_t *)b8;
286  return popcount64 (b[0] ^ a0) + popcount64 (b[1] ^ a1) +
287  popcount64 (b[2] ^ a2) + popcount64 (b[3] ^ a3);
288  }
289 
290 };
291 
293  uint64_t a0, a1, a2, a3, a4, a5, a6, a7;
294 
295  HammingComputer64 () {}
296 
297  HammingComputer64 (const uint8_t *a8, int code_size) {
298  set (a8, code_size);
299  }
300 
301  void set (const uint8_t *a8, int code_size) {
302  assert (code_size == 64);
303  const uint64_t *a = (uint64_t *)a8;
304  a0 = a[0]; a1 = a[1]; a2 = a[2]; a3 = a[3];
305  a4 = a[4]; a5 = a[5]; a6 = a[6]; a7 = a[7];
306  }
307 
308  inline int hamming (const uint8_t *b8) const {
309  const uint64_t *b = (uint64_t *)b8;
310  return popcount64 (b[0] ^ a0) + popcount64 (b[1] ^ a1) +
311  popcount64 (b[2] ^ a2) + popcount64 (b[3] ^ a3) +
312  popcount64 (b[4] ^ a4) + popcount64 (b[5] ^ a5) +
313  popcount64 (b[6] ^ a6) + popcount64 (b[7] ^ a7);
314  }
315 
316 };
317 
318 // very inefficient...
320  const uint8_t *a;
321  int n;
322 
324 
325  HammingComputerDefault (const uint8_t *a8, int code_size) {
326  set (a8, code_size);
327  }
328 
329  void set (const uint8_t *a8, int code_size) {
330  a = a8;
331  n = code_size;
332  }
333 
334  int hamming (const uint8_t *b8) const {
335  int accu = 0;
336  for (int i = 0; i < n; i++)
337  accu += popcount64 (a[i] ^ b8[i]);
338  return accu;
339  }
340 
341 };
342 
343 
345  const uint64_t *a;
346  int n;
347 
348  HammingComputerM8 () {}
349 
350  HammingComputerM8 (const uint8_t *a8, int code_size) {
351  set (a8, code_size);
352  }
353 
354  void set (const uint8_t *a8, int code_size) {
355  assert (code_size % 8 == 0);
356  a = (uint64_t *)a8;
357  n = code_size / 8;
358  }
359 
360  int hamming (const uint8_t *b8) const {
361  const uint64_t *b = (uint64_t *)b8;
362  int accu = 0;
363  for (int i = 0; i < n; i++)
364  accu += popcount64 (a[i] ^ b[i]);
365  return accu;
366  }
367 
368 };
369 
370 // even more inefficient!
372  const uint32_t *a;
373  int n;
374 
375  HammingComputerM4 () {}
376 
377  HammingComputerM4 (const uint8_t *a4, int code_size) {
378  set (a4, code_size);
379  }
380 
381  void set (const uint8_t *a4, int code_size) {
382  assert (code_size % 4 == 0);
383  a = (uint32_t *)a4;
384  n = code_size / 4;
385  }
386 
387  int hamming (const uint8_t *b8) const {
388  const uint32_t *b = (uint32_t *)b8;
389  int accu = 0;
390  for (int i = 0; i < n; i++)
391  accu += popcount64 (a[i] ^ b[i]);
392  return accu;
393  }
394 
395 };
396 
397 /***************************************************************************
398  * Equivalence with a template class when code size is known at compile time
399  **************************************************************************/
400 
401 // default template
402 template<int CODE_SIZE>
404  HammingComputer (const uint8_t *a, int code_size):
405  HammingComputerM8(a, code_size) {}
406 };
407 
408 #define SPECIALIZED_HC(CODE_SIZE) \
409  template<> struct HammingComputer<CODE_SIZE>: \
410  HammingComputer ## CODE_SIZE { \
411  HammingComputer (const uint8_t *a): \
412  HammingComputer ## CODE_SIZE(a, CODE_SIZE) {} \
413  }
414 
415 SPECIALIZED_HC(4);
416 SPECIALIZED_HC(8);
417 SPECIALIZED_HC(16);
418 SPECIALIZED_HC(20);
419 SPECIALIZED_HC(32);
420 SPECIALIZED_HC(64);
421 
422 #undef SPECIALIZED_HC
423 
424 
425 /***************************************************************************
426  * generalized Hamming = number of bytes that are different between
427  * two codes.
428  ***************************************************************************/
429 
430 
431 inline int generalized_hamming_64 (uint64_t a) {
432  a |= a >> 1;
433  a |= a >> 2;
434  a |= a >> 4;
435  a &= 0x0101010101010101UL;
436  return popcount64 (a);
437 }
438 
439 
441  uint64_t a0;
442 
443  GenHammingComputer8 (const uint8_t *a, int code_size) {
444  assert (code_size == 8);
445  a0 = *(uint64_t *)a;
446  }
447 
448  inline int hamming (const uint8_t *b) const {
449  return generalized_hamming_64 (*(uint64_t *)b ^ a0);
450  }
451 
452 };
453 
454 
456  uint64_t a0, a1;
457  GenHammingComputer16 (const uint8_t *a8, int code_size) {
458  assert (code_size == 16);
459  const uint64_t *a = (uint64_t *)a8;
460  a0 = a[0]; a1 = a[1];
461  }
462 
463  inline int hamming (const uint8_t *b8) const {
464  const uint64_t *b = (uint64_t *)b8;
465  return generalized_hamming_64 (b[0] ^ a0) +
466  generalized_hamming_64 (b[1] ^ a1);
467  }
468 
469 };
470 
472  uint64_t a0, a1, a2, a3;
473 
474  GenHammingComputer32 (const uint8_t *a8, int code_size) {
475  assert (code_size == 32);
476  const uint64_t *a = (uint64_t *)a8;
477  a0 = a[0]; a1 = a[1]; a2 = a[2]; a3 = a[3];
478  }
479 
480  inline int hamming (const uint8_t *b8) const {
481  const uint64_t *b = (uint64_t *)b8;
482  return generalized_hamming_64 (b[0] ^ a0) +
483  generalized_hamming_64 (b[1] ^ a1) +
484  generalized_hamming_64 (b[2] ^ a2) +
485  generalized_hamming_64 (b[3] ^ a3);
486  }
487 
488 };
489 
491  const uint64_t *a;
492  int n;
493 
494  GenHammingComputerM8 (const uint8_t *a8, int code_size) {
495  assert (code_size % 8 == 0);
496  a = (uint64_t *)a8;
497  n = code_size / 8;
498  }
499 
500  int hamming (const uint8_t *b8) const {
501  const uint64_t *b = (uint64_t *)b8;
502  int accu = 0;
503  for (int i = 0; i < n; i++)
504  accu += generalized_hamming_64 (a[i] ^ b[i]);
505  return accu;
506  }
507 
508 };
509 
510 
511 /** generalized Hamming distances (= count number of code bytes that
512  are the same) */
514  int_maxheap_array_t * ha,
515  const uint8_t * a,
516  const uint8_t * b,
517  size_t nb,
518  size_t code_size,
519  int ordered = true);
520 
521 
522 
523 /** This class maintains a list of best distances seen so far.
524  *
525  * Since the distances are in a limited range (0 to nbit), the
526  * object maintains one list per possible distance, and fills
527  * in only the n-first lists, such that the sum of sizes of the
528  * n lists is below k.
529  */
530 template<class HammingComputer>
532  int *counters;
533  long *ids_per_dis;
534 
535  HammingComputer hc;
536  int thres;
537  int count_lt;
538  int count_eq;
539  int k;
540 
541  HCounterState(int *counters, long *ids_per_dis,
542  const uint8_t *x, int d, int k)
543  : counters(counters),
544  ids_per_dis(ids_per_dis),
545  hc(x, d / 8),
546  thres(d + 1),
547  count_lt(0),
548  count_eq(0),
549  k(k) {}
550 
551  void update_counter(const uint8_t *y, size_t j) {
552  int32_t dis = hc.hamming(y);
553 
554  if (dis <= thres) {
555  if (dis < thres) {
556  ids_per_dis[dis * k + counters[dis]++] = j;
557  ++count_lt;
558  while (count_lt == k && thres > 0) {
559  --thres;
560  count_eq = counters[thres];
561  count_lt -= count_eq;
562  }
563  } else if (count_eq < k) {
564  ids_per_dis[dis * k + count_eq++] = j;
565  counters[dis] = count_eq;
566  }
567  }
568  }
569 };
570 
571 
572 } // namespace faiss
573 
574 
575 #endif /* FAISS_hamming_h */
void hammings_knn_hc(int_maxheap_array_t *ha, const uint8_t *a, const uint8_t *b, size_t nb, size_t ncodes, int order)
Definition: hamming.cpp:518
void hammings_knn_mc(const uint8_t *a, const uint8_t *b, size_t na, size_t nb, size_t k, size_t ncodes, int32_t *distances, long *labels)
Definition: hamming.cpp:556
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