Faiss

- Main Page
- Namespaces
- Classes
- Files

- File List

All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends
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
156 struct HammingComputer4 {
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
170 struct HammingComputer8 {
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
185 struct HammingComputer16 {
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.
202 struct HammingComputer20 {
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
219 struct HammingComputer32 {
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
236 struct HammingComputer64 {
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
256 struct HammingComputerM8 {
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...
277 struct HammingComputerM4 {
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>
302 struct HammingComputer: HammingComputerM8 {
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
339 struct GenHammingComputer8 {
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
354 struct GenHammingComputer16 {
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
370 struct GenHammingComputer32 {
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
389 struct GenHammingComputerM8 {
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) */
412 void generalized_hammings_knn (
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 */
faiss::HammingComputerM4
Definition: hamming.h:277
faiss::HammingComputer
Definition: hamming.h:302
faiss::HammingComputer20
Definition: hamming.h:202
faiss::GenHammingComputer16
Definition: hamming.h:354
faiss::GenHammingComputer8
Definition: hamming.h:339
faiss::HammingComputer8
Definition: hamming.h:170
faiss::HammingComputer64
Definition: hamming.h:236
faiss::generalized_hammings_knn
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:635
faiss::HammingComputer16
Definition: hamming.h:185
faiss::HammingComputer4
Definition: hamming.h:156
faiss::GenHammingComputerM8
Definition: hamming.h:389
faiss::HeapArray
Definition: Heap.h:351
faiss::hammings_knn
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:475
faiss::HammingComputer32
Definition: hamming.h:219
faiss::GenHammingComputer32
Definition: hamming.h:370
faiss::HammingComputerM8
Definition: hamming.h:256