Faiss
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends
/data/users/matthijs/github_faiss/faiss/hamming.h
1 
2 /**
3  * Copyright (c) 2015-present, Facebook, Inc.
4  * All rights reserved.
5  *
6  * This source code is licensed under the CC-by-NC license found in the
7  * LICENSE file in the root directory of this source tree.
8  */
9 
10 
11 /* Copyright 2004-present Facebook. All Rights Reserved.
12  *
13  * Hamming distances. The binary vector dimensionality should be a multiple
14  * of 64, as the elementary operations operate on words. If you really need
15  * other sizes, just pad with 0s (this is done by function fvecs2bitvecs).
16  *
17  * User-defined type hamdis_t is used for distances because at this time
18  * it is still uncler clear how we will need to balance
19  * - flexibility in vector size (may need 16- or even 8-bit vectors)
20  * - memory usage
21  * - cache-misses when dealing with large volumes of data (fewer bits is better)
22  *
23  * 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 #ifndef FAISS_hamming_h
28 #define FAISS_hamming_h
29 
30 
31 #include <stdint.h>
32 
33 #include "Heap.h"
34 
35 
36 /* The Hamming distance type should be exportable to Lua Tensor, which
37  excludes most unsigned type */
38 typedef int32_t hamdis_t;
39 
40 namespace faiss {
41 
42 inline int popcount64(uint64_t x) {
43  return __builtin_popcountl(x);
44 }
45 
46 
47 /** Compute a set of Hamming distances between na and nb binary vectors
48  *
49  * @param a size na * nbytespercode
50  * @param b size nb * nbytespercode
51  * @param nbytespercode should be multiple of 8
52  * @param dis output distances, size na * nb
53  */
54 void hammings (
55  const uint8_t * a,
56  const uint8_t * b,
57  size_t na, size_t nb,
58  size_t nbytespercode,
59  hamdis_t * dis);
60 
61 void bitvec_print (const uint8_t * b, size_t d);
62 
63 
64 /* Functions for casting vectors of regular types to compact bits.
65  They assume proper allocation done beforehand, meaning that b
66  should be be able to receive as many bits as x may produce. */
67 
68 /* Makes an array of bits from the signs of a float array. The length
69  of the output array b is rounded up to byte size (allocate
70  accordingly) */
71 void fvecs2bitvecs (
72  const float * x,
73  uint8_t * b,
74  size_t d,
75  size_t n);
76 
77 
78 void fvec2bitvec (const float * x, uint8_t * b, size_t d);
79 
80 
81 
82 /** Return the k smallest Hamming distances for a set of binary query vectors
83  * @param a queries, size ha->nh * ncodes
84  * @param b database, size nb * ncodes
85  * @param nb number of database vectors
86  * @param ncodes size of the binary codes (bytes)
87  * @param ordered if != 0: order the results by decreasing distance
88  * (may be bottleneck for k/n > 0.01) */
89 void hammings_knn (
90  int_maxheap_array_t * ha,
91  const uint8_t * a,
92  const uint8_t * b,
93  size_t nb,
94  size_t ncodes,
95  int ordered);
96 
97 /* The core function, without initialization and no re-ordering */
98 void hammings_knn_core (
99  int_maxheap_array_t * ha,
100  const uint8_t * a,
101  const uint8_t * b,
102  size_t nb,
103  size_t ncodes);
104 
105 
106 /* Counting the number of matches or of cross-matches (without returning them)
107  For use with function that assume pre-allocated memory */
108 void hamming_count_thres (
109  const uint8_t * bs1,
110  const uint8_t * bs2,
111  size_t n1,
112  size_t n2,
113  hamdis_t ht,
114  size_t ncodes,
115  size_t * nptr);
116 
117 /* Return all Hamming distances/index passing a thres. Pre-allocation of output
118  is required. Use hamming_count_thres to determine the proper size. */
119 size_t match_hamming_thres (
120  const uint8_t * bs1,
121  const uint8_t * bs2,
122  size_t n1,
123  size_t n2,
124  hamdis_t ht,
125  size_t ncodes,
126  long * idx,
127  hamdis_t * dis);
128 
129 /* Cross-matching in a set of vectors */
130 void crosshamming_count_thres (
131  const uint8_t * dbs,
132  size_t n,
133  hamdis_t ht,
134  size_t ncodes,
135  size_t * nptr);
136 
137 
138 /* compute the Hamming distances between two codewords of nwords*64 bits */
139 hamdis_t hamming (
140  const uint64_t * bs1,
141  const uint64_t * bs2,
142  size_t nwords);
143 
144 
145 
146 
147 /******************************************************************
148  * The HammingComputer series of classes compares a single code of
149  * size 4 to 32 to incoming codes. They are intended for use as a
150  * template class where it would be inefficient to switch on the code
151  * size in the inner loop. Hopefully the compiler will inline the
152  * hamming() functions and put the a0, a1, ... in registers.
153  ******************************************************************/
154 
155 
157  uint32_t a0;
158 
159  HammingComputer4 (const uint8_t *a, int code_size) {
160  assert (code_size == 4);
161  a0 = *(uint32_t *)a;
162  }
163 
164  inline int hamming (const uint8_t *b) const {
165  return popcount64 (*(uint32_t *)b ^ a0);
166  }
167 
168 };
169 
171  uint64_t a0;
172 
173  HammingComputer8 (const uint8_t *a, int code_size) {
174  assert (code_size == 8);
175  a0 = *(uint64_t *)a;
176  }
177 
178  inline int hamming (const uint8_t *b) const {
179  return popcount64 (*(uint64_t *)b ^ a0);
180  }
181 
182 };
183 
184 
186  uint64_t a0, a1;
187  HammingComputer16 (const uint8_t *a8, int code_size) {
188  assert (code_size == 16);
189  const uint64_t *a = (uint64_t *)a8;
190  a0 = a[0]; a1 = a[1];
191  }
192 
193  inline int hamming (const uint8_t *b8) const {
194  const uint64_t *b = (uint64_t *)b8;
195  return popcount64 (b[0] ^ a0) + popcount64 (b[1] ^ a1);
196  }
197 
198 };
199 
200 // when applied to an array, 1/2 of the 64-bit accesses are unaligned.
201 // This incurs a penalty of ~10% wrt. fully aligned accesses.
203  uint64_t a0, a1;
204  uint32_t a2;
205 
206  HammingComputer20 (const uint8_t *a8, int code_size) {
207  assert (code_size == 20);
208  const uint64_t *a = (uint64_t *)a8;
209  a0 = a[0]; a1 = a[1]; a2 = a[2];
210  }
211 
212  inline int hamming (const uint8_t *b8) const {
213  const uint64_t *b = (uint64_t *)b8;
214  return popcount64 (b[0] ^ a0) + popcount64 (b[1] ^ a1) +
215  popcount64 (*(uint32_t*)(b + 2) ^ a2);
216  }
217 };
218 
220  uint64_t a0, a1, a2, a3;
221 
222  HammingComputer32 (const uint8_t *a8, int code_size) {
223  assert (code_size == 32);
224  const uint64_t *a = (uint64_t *)a8;
225  a0 = a[0]; a1 = a[1]; a2 = a[2]; a3 = a[3];
226  }
227 
228  inline int hamming (const uint8_t *b8) const {
229  const uint64_t *b = (uint64_t *)b8;
230  return popcount64 (b[0] ^ a0) + popcount64 (b[1] ^ a1) +
231  popcount64 (b[2] ^ a2) + popcount64 (b[3] ^ a3);
232  }
233 
234 };
235 
237  uint64_t a0, a1, a2, a3, a4, a5, a6, a7;
238 
239  HammingComputer64 (const uint8_t *a8, int code_size) {
240  assert (code_size == 64);
241  const uint64_t *a = (uint64_t *)a8;
242  a0 = a[0]; a1 = a[1]; a2 = a[2]; a3 = a[3];
243  a4 = a[4]; a5 = a[5]; a6 = a[6]; a7 = a[7];
244  }
245 
246  inline int hamming (const uint8_t *b8) const {
247  const uint64_t *b = (uint64_t *)b8;
248  return popcount64 (b[0] ^ a0) + popcount64 (b[1] ^ a1) +
249  popcount64 (b[2] ^ a2) + popcount64 (b[3] ^ a3) +
250  popcount64 (b[4] ^ a4) + popcount64 (b[5] ^ a5) +
251  popcount64 (b[6] ^ a6) + popcount64 (b[7] ^ a7);
252  }
253 
254 };
255 
257  const uint64_t *a;
258  int n;
259 
260  HammingComputerM8 (const uint8_t *a8, int code_size) {
261  assert (code_size % 8 == 0);
262  a = (uint64_t *)a8;
263  n = code_size / 8;
264  }
265 
266  int hamming (const uint8_t *b8) const {
267  const uint64_t *b = (uint64_t *)b8;
268  int accu = 0;
269  for (int i = 0; i < n; i++)
270  accu += popcount64 (a[i] ^ b[i]);
271  return accu;
272  }
273 
274 };
275 
276 // very inefficient...
278  const uint32_t *a;
279  int n;
280 
281  HammingComputerM4 (const uint8_t *a4, int code_size) {
282  assert (code_size % 4 == 0);
283  a = (uint32_t *)a4;
284  n = code_size / 4;
285  }
286  int hamming (const uint8_t *b8) const {
287  const uint32_t *b = (uint32_t *)b8;
288  int accu = 0;
289  for (int i = 0; i < n; i++)
290  accu += popcount64 (a[i] ^ b[i]);
291  return accu;
292  }
293 
294 };
295 
296 /***************************************************************************
297  * Equivalence with a template class when code size is known at compile time
298  **************************************************************************/
299 
300 // default template
301 template<int CODE_SIZE>
303  HammingComputer (const uint8_t *a, int code_size):
304  HammingComputerM8(a, code_size) {}
305 };
306 
307 #define SPECIALIZED_HC(CODE_SIZE) \
308  template<> struct HammingComputer<CODE_SIZE>: \
309  HammingComputer ## CODE_SIZE { \
310  HammingComputer (const uint8_t *a): \
311  HammingComputer ## CODE_SIZE(a, CODE_SIZE) {} \
312  }
313 
314 SPECIALIZED_HC(4);
315 SPECIALIZED_HC(8);
316 SPECIALIZED_HC(16);
317 SPECIALIZED_HC(20);
318 SPECIALIZED_HC(32);
319 SPECIALIZED_HC(64);
320 
321 #undef SPECIALIZED_HC
322 
323 
324 /***************************************************************************
325  * generalized Hamming = number of bytes that are different between
326  * two codes.
327  ***************************************************************************/
328 
329 
330 inline int generalized_hamming_64 (uint64_t a) {
331  a |= a >> 1;
332  a |= a >> 2;
333  a |= a >> 4;
334  a &= 0x0101010101010101UL;
335  return popcount64 (a);
336 }
337 
338 
340  uint64_t a0;
341 
342  GenHammingComputer8 (const uint8_t *a, int code_size) {
343  assert (code_size == 8);
344  a0 = *(uint64_t *)a;
345  }
346 
347  inline int hamming (const uint8_t *b) const {
348  return generalized_hamming_64 (*(uint64_t *)b ^ a0);
349  }
350 
351 };
352 
353 
355  uint64_t a0, a1;
356  GenHammingComputer16 (const uint8_t *a8, int code_size) {
357  assert (code_size == 16);
358  const uint64_t *a = (uint64_t *)a8;
359  a0 = a[0]; a1 = a[1];
360  }
361 
362  inline int hamming (const uint8_t *b8) const {
363  const uint64_t *b = (uint64_t *)b8;
364  return generalized_hamming_64 (b[0] ^ a0) +
365  generalized_hamming_64 (b[1] ^ a1);
366  }
367 
368 };
369 
371  uint64_t a0, a1, a2, a3;
372 
373  GenHammingComputer32 (const uint8_t *a8, int code_size) {
374  assert (code_size == 32);
375  const uint64_t *a = (uint64_t *)a8;
376  a0 = a[0]; a1 = a[1]; a2 = a[2]; a3 = a[3];
377  }
378 
379  inline int hamming (const uint8_t *b8) const {
380  const uint64_t *b = (uint64_t *)b8;
381  return generalized_hamming_64 (b[0] ^ a0) +
382  generalized_hamming_64 (b[1] ^ a1) +
383  generalized_hamming_64 (b[2] ^ a2) +
384  generalized_hamming_64 (b[3] ^ a3);
385  }
386 
387 };
388 
390  const uint64_t *a;
391  int n;
392 
393  GenHammingComputerM8 (const uint8_t *a8, int code_size) {
394  assert (code_size % 8 == 0);
395  a = (uint64_t *)a8;
396  n = code_size / 8;
397  }
398 
399  int hamming (const uint8_t *b8) const {
400  const uint64_t *b = (uint64_t *)b8;
401  int accu = 0;
402  for (int i = 0; i < n; i++)
403  accu += generalized_hamming_64 (a[i] ^ b[i]);
404  return accu;
405  }
406 
407 };
408 
409 
410 /** generalized Hamming distances (= count number of code bytes that
411  are the same) */
413  int_maxheap_array_t * ha,
414  const uint8_t * a,
415  const uint8_t * b,
416  size_t nb,
417  size_t code_size,
418  int ordered = true);
419 
420 
421 
422 
423 } // namespace faiss
424 
425 
426 
427 
428 #endif /* FAISS_hamming_h */
void generalized_hammings_knn(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:626
void hammings_knn(int_maxheap_array_t *ha, const uint8_t *a, const uint8_t *b, size_t nb, size_t ncodes, int order)
Definition: hamming.cpp:471