faiss 0.2.6 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -0
  3. data/ext/faiss/extconf.rb +1 -1
  4. data/lib/faiss/version.rb +1 -1
  5. data/lib/faiss.rb +1 -1
  6. data/vendor/faiss/faiss/AutoTune.cpp +15 -4
  7. data/vendor/faiss/faiss/AutoTune.h +0 -1
  8. data/vendor/faiss/faiss/Clustering.cpp +1 -5
  9. data/vendor/faiss/faiss/Clustering.h +0 -2
  10. data/vendor/faiss/faiss/IVFlib.h +0 -2
  11. data/vendor/faiss/faiss/Index.h +1 -2
  12. data/vendor/faiss/faiss/IndexAdditiveQuantizer.cpp +17 -3
  13. data/vendor/faiss/faiss/IndexAdditiveQuantizer.h +10 -1
  14. data/vendor/faiss/faiss/IndexBinary.h +0 -1
  15. data/vendor/faiss/faiss/IndexBinaryFlat.cpp +2 -1
  16. data/vendor/faiss/faiss/IndexBinaryFlat.h +4 -0
  17. data/vendor/faiss/faiss/IndexBinaryHash.cpp +1 -3
  18. data/vendor/faiss/faiss/IndexBinaryIVF.cpp +273 -48
  19. data/vendor/faiss/faiss/IndexBinaryIVF.h +18 -11
  20. data/vendor/faiss/faiss/IndexFastScan.cpp +13 -10
  21. data/vendor/faiss/faiss/IndexFastScan.h +5 -1
  22. data/vendor/faiss/faiss/IndexFlat.cpp +16 -3
  23. data/vendor/faiss/faiss/IndexFlat.h +1 -1
  24. data/vendor/faiss/faiss/IndexFlatCodes.cpp +5 -0
  25. data/vendor/faiss/faiss/IndexFlatCodes.h +7 -2
  26. data/vendor/faiss/faiss/IndexHNSW.cpp +3 -6
  27. data/vendor/faiss/faiss/IndexHNSW.h +0 -1
  28. data/vendor/faiss/faiss/IndexIDMap.cpp +4 -4
  29. data/vendor/faiss/faiss/IndexIDMap.h +0 -2
  30. data/vendor/faiss/faiss/IndexIVF.cpp +155 -129
  31. data/vendor/faiss/faiss/IndexIVF.h +121 -61
  32. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +2 -2
  33. data/vendor/faiss/faiss/IndexIVFFastScan.cpp +12 -11
  34. data/vendor/faiss/faiss/IndexIVFFastScan.h +6 -1
  35. data/vendor/faiss/faiss/IndexIVFPQ.cpp +221 -165
  36. data/vendor/faiss/faiss/IndexIVFPQ.h +1 -0
  37. data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +6 -1
  38. data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +0 -2
  39. data/vendor/faiss/faiss/IndexNNDescent.cpp +1 -2
  40. data/vendor/faiss/faiss/IndexNNDescent.h +0 -1
  41. data/vendor/faiss/faiss/IndexNSG.cpp +1 -2
  42. data/vendor/faiss/faiss/IndexPQ.cpp +7 -9
  43. data/vendor/faiss/faiss/IndexRefine.cpp +1 -1
  44. data/vendor/faiss/faiss/IndexReplicas.cpp +3 -4
  45. data/vendor/faiss/faiss/IndexReplicas.h +0 -1
  46. data/vendor/faiss/faiss/IndexRowwiseMinMax.cpp +8 -1
  47. data/vendor/faiss/faiss/IndexRowwiseMinMax.h +7 -0
  48. data/vendor/faiss/faiss/IndexShards.cpp +26 -109
  49. data/vendor/faiss/faiss/IndexShards.h +2 -3
  50. data/vendor/faiss/faiss/IndexShardsIVF.cpp +246 -0
  51. data/vendor/faiss/faiss/IndexShardsIVF.h +42 -0
  52. data/vendor/faiss/faiss/MetaIndexes.cpp +86 -0
  53. data/vendor/faiss/faiss/MetaIndexes.h +29 -0
  54. data/vendor/faiss/faiss/MetricType.h +14 -0
  55. data/vendor/faiss/faiss/VectorTransform.cpp +8 -10
  56. data/vendor/faiss/faiss/VectorTransform.h +1 -3
  57. data/vendor/faiss/faiss/clone_index.cpp +232 -18
  58. data/vendor/faiss/faiss/cppcontrib/SaDecodeKernels.h +25 -3
  59. data/vendor/faiss/faiss/cppcontrib/detail/CoarseBitType.h +7 -0
  60. data/vendor/faiss/faiss/cppcontrib/detail/UintReader.h +78 -0
  61. data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-avx2-inl.h +20 -6
  62. data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-inl.h +7 -1
  63. data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-neon-inl.h +21 -7
  64. data/vendor/faiss/faiss/cppcontrib/sa_decode/MinMax-inl.h +7 -0
  65. data/vendor/faiss/faiss/cppcontrib/sa_decode/MinMaxFP16-inl.h +7 -0
  66. data/vendor/faiss/faiss/cppcontrib/sa_decode/PQ-avx2-inl.h +10 -3
  67. data/vendor/faiss/faiss/cppcontrib/sa_decode/PQ-inl.h +7 -1
  68. data/vendor/faiss/faiss/cppcontrib/sa_decode/PQ-neon-inl.h +11 -3
  69. data/vendor/faiss/faiss/gpu/GpuAutoTune.cpp +25 -2
  70. data/vendor/faiss/faiss/gpu/GpuCloner.cpp +76 -29
  71. data/vendor/faiss/faiss/gpu/GpuCloner.h +2 -2
  72. data/vendor/faiss/faiss/gpu/GpuClonerOptions.h +14 -13
  73. data/vendor/faiss/faiss/gpu/GpuDistance.h +18 -6
  74. data/vendor/faiss/faiss/gpu/GpuIndex.h +23 -21
  75. data/vendor/faiss/faiss/gpu/GpuIndexBinaryFlat.h +10 -10
  76. data/vendor/faiss/faiss/gpu/GpuIndexFlat.h +11 -12
  77. data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +29 -50
  78. data/vendor/faiss/faiss/gpu/GpuIndexIVFFlat.h +3 -3
  79. data/vendor/faiss/faiss/gpu/GpuIndexIVFPQ.h +8 -8
  80. data/vendor/faiss/faiss/gpu/GpuIndexIVFScalarQuantizer.h +4 -4
  81. data/vendor/faiss/faiss/gpu/impl/IndexUtils.h +2 -5
  82. data/vendor/faiss/faiss/gpu/impl/RemapIndices.cpp +9 -7
  83. data/vendor/faiss/faiss/gpu/impl/RemapIndices.h +4 -4
  84. data/vendor/faiss/faiss/gpu/perf/IndexWrapper-inl.h +2 -2
  85. data/vendor/faiss/faiss/gpu/perf/IndexWrapper.h +1 -1
  86. data/vendor/faiss/faiss/gpu/test/TestGpuIndexBinaryFlat.cpp +55 -6
  87. data/vendor/faiss/faiss/gpu/test/TestGpuIndexFlat.cpp +20 -6
  88. data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFFlat.cpp +95 -25
  89. data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFPQ.cpp +67 -16
  90. data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFScalarQuantizer.cpp +4 -4
  91. data/vendor/faiss/faiss/gpu/test/TestUtils.cpp +7 -7
  92. data/vendor/faiss/faiss/gpu/test/TestUtils.h +4 -4
  93. data/vendor/faiss/faiss/gpu/test/demo_ivfpq_indexing_gpu.cpp +1 -1
  94. data/vendor/faiss/faiss/gpu/utils/DeviceUtils.h +6 -0
  95. data/vendor/faiss/faiss/impl/AdditiveQuantizer.cpp +0 -7
  96. data/vendor/faiss/faiss/impl/AdditiveQuantizer.h +9 -9
  97. data/vendor/faiss/faiss/impl/AuxIndexStructures.cpp +1 -1
  98. data/vendor/faiss/faiss/impl/AuxIndexStructures.h +2 -7
  99. data/vendor/faiss/faiss/impl/CodePacker.cpp +67 -0
  100. data/vendor/faiss/faiss/impl/CodePacker.h +71 -0
  101. data/vendor/faiss/faiss/impl/DistanceComputer.h +0 -2
  102. data/vendor/faiss/faiss/impl/HNSW.cpp +3 -7
  103. data/vendor/faiss/faiss/impl/HNSW.h +6 -9
  104. data/vendor/faiss/faiss/impl/IDSelector.cpp +1 -1
  105. data/vendor/faiss/faiss/impl/IDSelector.h +39 -1
  106. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +62 -51
  107. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.h +11 -12
  108. data/vendor/faiss/faiss/impl/NNDescent.cpp +3 -9
  109. data/vendor/faiss/faiss/impl/NNDescent.h +10 -10
  110. data/vendor/faiss/faiss/impl/NSG.cpp +1 -6
  111. data/vendor/faiss/faiss/impl/NSG.h +4 -7
  112. data/vendor/faiss/faiss/impl/PolysemousTraining.cpp +1 -15
  113. data/vendor/faiss/faiss/impl/PolysemousTraining.h +11 -10
  114. data/vendor/faiss/faiss/impl/ProductAdditiveQuantizer.cpp +0 -7
  115. data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +25 -12
  116. data/vendor/faiss/faiss/impl/ProductQuantizer.h +2 -4
  117. data/vendor/faiss/faiss/impl/Quantizer.h +6 -3
  118. data/vendor/faiss/faiss/impl/ResidualQuantizer.cpp +796 -174
  119. data/vendor/faiss/faiss/impl/ResidualQuantizer.h +16 -8
  120. data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +3 -5
  121. data/vendor/faiss/faiss/impl/ScalarQuantizer.h +4 -4
  122. data/vendor/faiss/faiss/impl/ThreadedIndex-inl.h +3 -3
  123. data/vendor/faiss/faiss/impl/ThreadedIndex.h +4 -4
  124. data/vendor/faiss/faiss/impl/code_distance/code_distance-avx2.h +291 -0
  125. data/vendor/faiss/faiss/impl/code_distance/code_distance-generic.h +74 -0
  126. data/vendor/faiss/faiss/impl/code_distance/code_distance.h +123 -0
  127. data/vendor/faiss/faiss/impl/code_distance/code_distance_avx512.h +102 -0
  128. data/vendor/faiss/faiss/impl/index_read.cpp +13 -10
  129. data/vendor/faiss/faiss/impl/index_write.cpp +3 -4
  130. data/vendor/faiss/faiss/impl/kmeans1d.cpp +0 -1
  131. data/vendor/faiss/faiss/impl/kmeans1d.h +3 -3
  132. data/vendor/faiss/faiss/impl/lattice_Zn.cpp +1 -1
  133. data/vendor/faiss/faiss/impl/platform_macros.h +61 -0
  134. data/vendor/faiss/faiss/impl/pq4_fast_scan.cpp +48 -4
  135. data/vendor/faiss/faiss/impl/pq4_fast_scan.h +18 -4
  136. data/vendor/faiss/faiss/impl/pq4_fast_scan_search_qbs.cpp +2 -2
  137. data/vendor/faiss/faiss/index_factory.cpp +8 -10
  138. data/vendor/faiss/faiss/invlists/BlockInvertedLists.cpp +29 -12
  139. data/vendor/faiss/faiss/invlists/BlockInvertedLists.h +8 -2
  140. data/vendor/faiss/faiss/invlists/DirectMap.cpp +1 -1
  141. data/vendor/faiss/faiss/invlists/DirectMap.h +2 -4
  142. data/vendor/faiss/faiss/invlists/InvertedLists.cpp +118 -18
  143. data/vendor/faiss/faiss/invlists/InvertedLists.h +44 -4
  144. data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +3 -3
  145. data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.h +1 -1
  146. data/vendor/faiss/faiss/python/python_callbacks.cpp +1 -1
  147. data/vendor/faiss/faiss/python/python_callbacks.h +1 -1
  148. data/vendor/faiss/faiss/utils/AlignedTable.h +3 -1
  149. data/vendor/faiss/faiss/utils/Heap.cpp +139 -3
  150. data/vendor/faiss/faiss/utils/Heap.h +35 -1
  151. data/vendor/faiss/faiss/utils/approx_topk/approx_topk.h +84 -0
  152. data/vendor/faiss/faiss/utils/approx_topk/avx2-inl.h +196 -0
  153. data/vendor/faiss/faiss/utils/approx_topk/generic.h +138 -0
  154. data/vendor/faiss/faiss/utils/approx_topk/mode.h +34 -0
  155. data/vendor/faiss/faiss/utils/approx_topk_hamming/approx_topk_hamming.h +367 -0
  156. data/vendor/faiss/faiss/utils/distances.cpp +61 -7
  157. data/vendor/faiss/faiss/utils/distances.h +11 -0
  158. data/vendor/faiss/faiss/utils/distances_fused/avx512.cpp +346 -0
  159. data/vendor/faiss/faiss/utils/distances_fused/avx512.h +36 -0
  160. data/vendor/faiss/faiss/utils/distances_fused/distances_fused.cpp +42 -0
  161. data/vendor/faiss/faiss/utils/distances_fused/distances_fused.h +40 -0
  162. data/vendor/faiss/faiss/utils/distances_fused/simdlib_based.cpp +352 -0
  163. data/vendor/faiss/faiss/utils/distances_fused/simdlib_based.h +32 -0
  164. data/vendor/faiss/faiss/utils/distances_simd.cpp +515 -327
  165. data/vendor/faiss/faiss/utils/extra_distances-inl.h +17 -1
  166. data/vendor/faiss/faiss/utils/extra_distances.cpp +37 -8
  167. data/vendor/faiss/faiss/utils/extra_distances.h +2 -1
  168. data/vendor/faiss/faiss/utils/fp16-fp16c.h +7 -0
  169. data/vendor/faiss/faiss/utils/fp16-inl.h +7 -0
  170. data/vendor/faiss/faiss/utils/fp16.h +7 -0
  171. data/vendor/faiss/faiss/utils/hamming-inl.h +0 -456
  172. data/vendor/faiss/faiss/utils/hamming.cpp +104 -120
  173. data/vendor/faiss/faiss/utils/hamming.h +21 -10
  174. data/vendor/faiss/faiss/utils/hamming_distance/avx2-inl.h +535 -0
  175. data/vendor/faiss/faiss/utils/hamming_distance/common.h +48 -0
  176. data/vendor/faiss/faiss/utils/hamming_distance/generic-inl.h +519 -0
  177. data/vendor/faiss/faiss/utils/hamming_distance/hamdis-inl.h +26 -0
  178. data/vendor/faiss/faiss/utils/hamming_distance/neon-inl.h +614 -0
  179. data/vendor/faiss/faiss/utils/partitioning.cpp +21 -25
  180. data/vendor/faiss/faiss/utils/simdlib_avx2.h +344 -3
  181. data/vendor/faiss/faiss/utils/simdlib_emulated.h +390 -0
  182. data/vendor/faiss/faiss/utils/simdlib_neon.h +655 -130
  183. data/vendor/faiss/faiss/utils/sorting.cpp +692 -0
  184. data/vendor/faiss/faiss/utils/sorting.h +71 -0
  185. data/vendor/faiss/faiss/utils/transpose/transpose-avx2-inl.h +165 -0
  186. data/vendor/faiss/faiss/utils/utils.cpp +4 -176
  187. data/vendor/faiss/faiss/utils/utils.h +2 -9
  188. metadata +30 -4
  189. data/vendor/faiss/faiss/gpu/GpuClonerOptions.cpp +0 -26
@@ -8,6 +8,7 @@
8
8
  /** In this file are the implementations of extra metrics beyond L2
9
9
  * and inner product */
10
10
 
11
+ #include <faiss/MetricType.h>
11
12
  #include <faiss/utils/distances.h>
12
13
  #include <type_traits>
13
14
 
@@ -17,12 +18,13 @@ template <MetricType mt>
17
18
  struct VectorDistance {
18
19
  size_t d;
19
20
  float metric_arg;
21
+ static constexpr bool is_similarity = is_similarity_metric(mt);
20
22
 
21
23
  inline float operator()(const float* x, const float* y) const;
22
24
 
23
25
  // heap template to use for this type of metric
24
26
  using C = typename std::conditional<
25
- mt == METRIC_INNER_PRODUCT,
27
+ is_similarity_metric(mt),
26
28
  CMin<float, int64_t>,
27
29
  CMax<float, int64_t>>::type;
28
30
  };
@@ -114,4 +116,18 @@ inline float VectorDistance<METRIC_JensenShannon>::operator()(
114
116
  return 0.5 * accu;
115
117
  }
116
118
 
119
+ template <>
120
+ inline float VectorDistance<METRIC_Jaccard>::operator()(
121
+ const float* x,
122
+ const float* y) const {
123
+ // WARNING: this distance is defined only for positive input vectors.
124
+ // Providing vectors with negative values would lead to incorrect results.
125
+ float accu_num = 0, accu_den = 0;
126
+ for (size_t i = 0; i < d; i++) {
127
+ accu_num += fmin(x[i], y[i]);
128
+ accu_den += fmax(x[i], y[i]);
129
+ }
130
+ return accu_num / accu_den;
131
+ }
132
+
117
133
  } // namespace faiss
@@ -50,14 +50,14 @@ void pairwise_extra_distances_template(
50
50
  }
51
51
  }
52
52
 
53
- template <class VD>
53
+ template <class VD, class C>
54
54
  void knn_extra_metrics_template(
55
55
  VD vd,
56
56
  const float* x,
57
57
  const float* y,
58
58
  size_t nx,
59
59
  size_t ny,
60
- float_maxheap_array_t* res) {
60
+ HeapArray<C>* res) {
61
61
  size_t k = res->k;
62
62
  size_t d = vd.d;
63
63
  size_t check_period = InterruptCallback::get_period_hint(ny * d);
@@ -74,16 +74,21 @@ void knn_extra_metrics_template(
74
74
  float* simi = res->get_val(i);
75
75
  int64_t* idxi = res->get_ids(i);
76
76
 
77
- maxheap_heapify(k, simi, idxi);
77
+ // maxheap_heapify(k, simi, idxi);
78
+ heap_heapify<C>(k, simi, idxi);
78
79
  for (j = 0; j < ny; j++) {
79
80
  float disij = vd(x_i, y_j);
80
81
 
81
- if (disij < simi[0]) {
82
- maxheap_replace_top(k, simi, idxi, disij, j);
82
+ // if (disij < simi[0]) {
83
+ if ((!vd.is_similarity && (disij < simi[0])) ||
84
+ (vd.is_similarity && (disij > simi[0]))) {
85
+ // maxheap_replace_top(k, simi, idxi, disij, j);
86
+ heap_replace_top<C>(k, simi, idxi, disij, j);
83
87
  }
84
88
  y_j += d;
85
89
  }
86
- maxheap_reorder(k, simi, idxi);
90
+ // maxheap_reorder(k, simi, idxi);
91
+ heap_reorder<C>(k, simi, idxi);
87
92
  }
88
93
  InterruptCallback::check();
89
94
  }
@@ -92,7 +97,7 @@ void knn_extra_metrics_template(
92
97
  template <class VD>
93
98
  struct ExtraDistanceComputer : FlatCodesDistanceComputer {
94
99
  VD vd;
95
- Index::idx_t nb;
100
+ idx_t nb;
96
101
  const float* q;
97
102
  const float* b;
98
103
 
@@ -158,12 +163,14 @@ void pairwise_extra_distances(
158
163
  HANDLE_VAR(BrayCurtis);
159
164
  HANDLE_VAR(JensenShannon);
160
165
  HANDLE_VAR(Lp);
166
+ HANDLE_VAR(Jaccard);
161
167
  #undef HANDLE_VAR
162
168
  default:
163
169
  FAISS_THROW_MSG("metric type not implemented");
164
170
  }
165
171
  }
166
172
 
173
+ template <class C>
167
174
  void knn_extra_metrics(
168
175
  const float* x,
169
176
  const float* y,
@@ -172,7 +179,7 @@ void knn_extra_metrics(
172
179
  size_t ny,
173
180
  MetricType mt,
174
181
  float metric_arg,
175
- float_maxheap_array_t* res) {
182
+ HeapArray<C>* res) {
176
183
  switch (mt) {
177
184
  #define HANDLE_VAR(kw) \
178
185
  case METRIC_##kw: { \
@@ -187,12 +194,33 @@ void knn_extra_metrics(
187
194
  HANDLE_VAR(BrayCurtis);
188
195
  HANDLE_VAR(JensenShannon);
189
196
  HANDLE_VAR(Lp);
197
+ HANDLE_VAR(Jaccard);
190
198
  #undef HANDLE_VAR
191
199
  default:
192
200
  FAISS_THROW_MSG("metric type not implemented");
193
201
  }
194
202
  }
195
203
 
204
+ template void knn_extra_metrics<CMax<float, int64_t>>(
205
+ const float* x,
206
+ const float* y,
207
+ size_t d,
208
+ size_t nx,
209
+ size_t ny,
210
+ MetricType mt,
211
+ float metric_arg,
212
+ HeapArray<CMax<float, int64_t>>* res);
213
+
214
+ template void knn_extra_metrics<CMin<float, int64_t>>(
215
+ const float* x,
216
+ const float* y,
217
+ size_t d,
218
+ size_t nx,
219
+ size_t ny,
220
+ MetricType mt,
221
+ float metric_arg,
222
+ HeapArray<CMin<float, int64_t>>* res);
223
+
196
224
  FlatCodesDistanceComputer* get_extra_distance_computer(
197
225
  size_t d,
198
226
  MetricType mt,
@@ -213,6 +241,7 @@ FlatCodesDistanceComputer* get_extra_distance_computer(
213
241
  HANDLE_VAR(BrayCurtis);
214
242
  HANDLE_VAR(JensenShannon);
215
243
  HANDLE_VAR(Lp);
244
+ HANDLE_VAR(Jaccard);
216
245
  #undef HANDLE_VAR
217
246
  default:
218
247
  FAISS_THROW_MSG("metric type not implemented");
@@ -33,6 +33,7 @@ void pairwise_extra_distances(
33
33
  int64_t ldb = -1,
34
34
  int64_t ldd = -1);
35
35
 
36
+ template <class C>
36
37
  void knn_extra_metrics(
37
38
  const float* x,
38
39
  const float* y,
@@ -41,7 +42,7 @@ void knn_extra_metrics(
41
42
  size_t ny,
42
43
  MetricType mt,
43
44
  float metric_arg,
44
- float_maxheap_array_t* res);
45
+ HeapArray<C>* res);
45
46
 
46
47
  /** get a DistanceComputer that refers to this type of distance and
47
48
  * indexes a flat array of size nb */
@@ -1,3 +1,10 @@
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
+
1
8
  #pragma once
2
9
 
3
10
  #include <immintrin.h>
@@ -1,3 +1,10 @@
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
+
1
8
  #pragma once
2
9
 
3
10
  #include <algorithm>
@@ -1,3 +1,10 @@
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
+
1
8
  #pragma once
2
9
 
3
10
  #include <cstdint>
@@ -7,61 +7,6 @@
7
7
 
8
8
  namespace faiss {
9
9
 
10
- extern const uint8_t hamdis_tab_ham_bytes[256];
11
-
12
- /* Elementary Hamming distance computation: unoptimized */
13
- template <size_t nbits, typename T>
14
- inline T hamming(const uint8_t* bs1, const uint8_t* bs2) {
15
- const size_t nbytes = nbits / 8;
16
- size_t i;
17
- T h = 0;
18
- for (i = 0; i < nbytes; i++) {
19
- h += (T)hamdis_tab_ham_bytes[bs1[i] ^ bs2[i]];
20
- }
21
- return h;
22
- }
23
-
24
- /* Hamming distances for multiples of 64 bits */
25
- template <size_t nbits>
26
- inline hamdis_t hamming(const uint64_t* bs1, const uint64_t* bs2) {
27
- const size_t nwords = nbits / 64;
28
- size_t i;
29
- hamdis_t h = 0;
30
- for (i = 0; i < nwords; i++) {
31
- h += popcount64(bs1[i] ^ bs2[i]);
32
- }
33
- return h;
34
- }
35
-
36
- /* specialized (optimized) functions */
37
- template <>
38
- inline hamdis_t hamming<64>(const uint64_t* pa, const uint64_t* pb) {
39
- return popcount64(pa[0] ^ pb[0]);
40
- }
41
-
42
- template <>
43
- inline hamdis_t hamming<128>(const uint64_t* pa, const uint64_t* pb) {
44
- return popcount64(pa[0] ^ pb[0]) + popcount64(pa[1] ^ pb[1]);
45
- }
46
-
47
- template <>
48
- inline hamdis_t hamming<256>(const uint64_t* pa, const uint64_t* pb) {
49
- return popcount64(pa[0] ^ pb[0]) + popcount64(pa[1] ^ pb[1]) +
50
- popcount64(pa[2] ^ pb[2]) + popcount64(pa[3] ^ pb[3]);
51
- }
52
-
53
- /* Hamming distances for multiple of 64 bits */
54
- inline hamdis_t hamming(
55
- const uint64_t* bs1,
56
- const uint64_t* bs2,
57
- size_t nwords) {
58
- hamdis_t h = 0;
59
- for (size_t i = 0; i < nwords; i++) {
60
- h += popcount64(bs1[i] ^ bs2[i]);
61
- }
62
- return h;
63
- }
64
-
65
10
  // BitstringWriter and BitstringReader functions
66
11
  inline BitstringWriter::BitstringWriter(uint8_t* code, size_t code_size)
67
12
  : code(code), code_size(code_size), i(0) {
@@ -119,407 +64,6 @@ inline uint64_t BitstringReader::read(int nbit) {
119
64
  }
120
65
  }
121
66
 
122
- /******************************************************************
123
- * The HammingComputer series of classes compares a single code of
124
- * size 4 to 32 to incoming codes. They are intended for use as a
125
- * template class where it would be inefficient to switch on the code
126
- * size in the inner loop. Hopefully the compiler will inline the
127
- * hamming() functions and put the a0, a1, ... in registers.
128
- ******************************************************************/
129
-
130
- struct HammingComputer4 {
131
- uint32_t a0;
132
-
133
- HammingComputer4() {}
134
-
135
- HammingComputer4(const uint8_t* a, int code_size) {
136
- set(a, code_size);
137
- }
138
-
139
- void set(const uint8_t* a, int code_size) {
140
- assert(code_size == 4);
141
- a0 = *(uint32_t*)a;
142
- }
143
-
144
- inline int hamming(const uint8_t* b) const {
145
- return popcount64(*(uint32_t*)b ^ a0);
146
- }
147
- };
148
-
149
- struct HammingComputer8 {
150
- uint64_t a0;
151
-
152
- HammingComputer8() {}
153
-
154
- HammingComputer8(const uint8_t* a, int code_size) {
155
- set(a, code_size);
156
- }
157
-
158
- void set(const uint8_t* a, int code_size) {
159
- assert(code_size == 8);
160
- a0 = *(uint64_t*)a;
161
- }
162
-
163
- inline int hamming(const uint8_t* b) const {
164
- return popcount64(*(uint64_t*)b ^ a0);
165
- }
166
- };
167
-
168
- struct HammingComputer16 {
169
- uint64_t a0, a1;
170
-
171
- HammingComputer16() {}
172
-
173
- HammingComputer16(const uint8_t* a8, int code_size) {
174
- set(a8, code_size);
175
- }
176
-
177
- void set(const uint8_t* a8, int code_size) {
178
- assert(code_size == 16);
179
- const uint64_t* a = (uint64_t*)a8;
180
- a0 = a[0];
181
- a1 = a[1];
182
- }
183
-
184
- inline int hamming(const uint8_t* b8) const {
185
- const uint64_t* b = (uint64_t*)b8;
186
- return popcount64(b[0] ^ a0) + popcount64(b[1] ^ a1);
187
- }
188
- };
189
-
190
- // when applied to an array, 1/2 of the 64-bit accesses are unaligned.
191
- // This incurs a penalty of ~10% wrt. fully aligned accesses.
192
- struct HammingComputer20 {
193
- uint64_t a0, a1;
194
- uint32_t a2;
195
-
196
- HammingComputer20() {}
197
-
198
- HammingComputer20(const uint8_t* a8, int code_size) {
199
- set(a8, code_size);
200
- }
201
-
202
- void set(const uint8_t* a8, int code_size) {
203
- assert(code_size == 20);
204
- const uint64_t* a = (uint64_t*)a8;
205
- a0 = a[0];
206
- a1 = a[1];
207
- a2 = a[2];
208
- }
209
-
210
- inline int hamming(const uint8_t* b8) const {
211
- const uint64_t* b = (uint64_t*)b8;
212
- return popcount64(b[0] ^ a0) + popcount64(b[1] ^ a1) +
213
- popcount64(*(uint32_t*)(b + 2) ^ a2);
214
- }
215
- };
216
-
217
- struct HammingComputer32 {
218
- uint64_t a0, a1, a2, a3;
219
-
220
- HammingComputer32() {}
221
-
222
- HammingComputer32(const uint8_t* a8, int code_size) {
223
- set(a8, code_size);
224
- }
225
-
226
- void set(const uint8_t* a8, int code_size) {
227
- assert(code_size == 32);
228
- const uint64_t* a = (uint64_t*)a8;
229
- a0 = a[0];
230
- a1 = a[1];
231
- a2 = a[2];
232
- a3 = a[3];
233
- }
234
-
235
- inline int hamming(const uint8_t* b8) const {
236
- const uint64_t* b = (uint64_t*)b8;
237
- return popcount64(b[0] ^ a0) + popcount64(b[1] ^ a1) +
238
- popcount64(b[2] ^ a2) + popcount64(b[3] ^ a3);
239
- }
240
- };
241
-
242
- struct HammingComputer64 {
243
- uint64_t a0, a1, a2, a3, a4, a5, a6, a7;
244
-
245
- HammingComputer64() {}
246
-
247
- HammingComputer64(const uint8_t* a8, int code_size) {
248
- set(a8, code_size);
249
- }
250
-
251
- void set(const uint8_t* a8, int code_size) {
252
- assert(code_size == 64);
253
- const uint64_t* a = (uint64_t*)a8;
254
- a0 = a[0];
255
- a1 = a[1];
256
- a2 = a[2];
257
- a3 = a[3];
258
- a4 = a[4];
259
- a5 = a[5];
260
- a6 = a[6];
261
- a7 = a[7];
262
- }
263
-
264
- inline int hamming(const uint8_t* b8) const {
265
- const uint64_t* b = (uint64_t*)b8;
266
- return popcount64(b[0] ^ a0) + popcount64(b[1] ^ a1) +
267
- popcount64(b[2] ^ a2) + popcount64(b[3] ^ a3) +
268
- popcount64(b[4] ^ a4) + popcount64(b[5] ^ a5) +
269
- popcount64(b[6] ^ a6) + popcount64(b[7] ^ a7);
270
- }
271
- };
272
-
273
- struct HammingComputerDefault {
274
- const uint8_t* a8;
275
- int quotient8;
276
- int remainder8;
277
-
278
- HammingComputerDefault() {}
279
-
280
- HammingComputerDefault(const uint8_t* a8, int code_size) {
281
- set(a8, code_size);
282
- }
283
-
284
- void set(const uint8_t* a8, int code_size) {
285
- this->a8 = a8;
286
- quotient8 = code_size / 8;
287
- remainder8 = code_size % 8;
288
- }
289
-
290
- int hamming(const uint8_t* b8) const {
291
- int accu = 0;
292
-
293
- const uint64_t* a64 = reinterpret_cast<const uint64_t*>(a8);
294
- const uint64_t* b64 = reinterpret_cast<const uint64_t*>(b8);
295
- int i = 0, len = quotient8;
296
- switch (len & 7) {
297
- default:
298
- while (len > 7) {
299
- len -= 8;
300
- accu += popcount64(a64[i] ^ b64[i]);
301
- i++;
302
- case 7:
303
- accu += popcount64(a64[i] ^ b64[i]);
304
- i++;
305
- case 6:
306
- accu += popcount64(a64[i] ^ b64[i]);
307
- i++;
308
- case 5:
309
- accu += popcount64(a64[i] ^ b64[i]);
310
- i++;
311
- case 4:
312
- accu += popcount64(a64[i] ^ b64[i]);
313
- i++;
314
- case 3:
315
- accu += popcount64(a64[i] ^ b64[i]);
316
- i++;
317
- case 2:
318
- accu += popcount64(a64[i] ^ b64[i]);
319
- i++;
320
- case 1:
321
- accu += popcount64(a64[i] ^ b64[i]);
322
- i++;
323
- }
324
- }
325
- if (remainder8) {
326
- const uint8_t* a = a8 + 8 * quotient8;
327
- const uint8_t* b = b8 + 8 * quotient8;
328
- switch (remainder8) {
329
- case 7:
330
- accu += hamdis_tab_ham_bytes[a[6] ^ b[6]];
331
- case 6:
332
- accu += hamdis_tab_ham_bytes[a[5] ^ b[5]];
333
- case 5:
334
- accu += hamdis_tab_ham_bytes[a[4] ^ b[4]];
335
- case 4:
336
- accu += hamdis_tab_ham_bytes[a[3] ^ b[3]];
337
- case 3:
338
- accu += hamdis_tab_ham_bytes[a[2] ^ b[2]];
339
- case 2:
340
- accu += hamdis_tab_ham_bytes[a[1] ^ b[1]];
341
- case 1:
342
- accu += hamdis_tab_ham_bytes[a[0] ^ b[0]];
343
- default:
344
- break;
345
- }
346
- }
347
-
348
- return accu;
349
- }
350
- };
351
-
352
- // more inefficient than HammingComputerDefault (obsolete)
353
- struct HammingComputerM8 {
354
- const uint64_t* a;
355
- int n;
356
-
357
- HammingComputerM8() {}
358
-
359
- HammingComputerM8(const uint8_t* a8, int code_size) {
360
- set(a8, code_size);
361
- }
362
-
363
- void set(const uint8_t* a8, int code_size) {
364
- assert(code_size % 8 == 0);
365
- a = (uint64_t*)a8;
366
- n = code_size / 8;
367
- }
368
-
369
- int hamming(const uint8_t* b8) const {
370
- const uint64_t* b = (uint64_t*)b8;
371
- int accu = 0;
372
- for (int i = 0; i < n; i++)
373
- accu += popcount64(a[i] ^ b[i]);
374
- return accu;
375
- }
376
- };
377
-
378
- // more inefficient than HammingComputerDefault (obsolete)
379
- struct HammingComputerM4 {
380
- const uint32_t* a;
381
- int n;
382
-
383
- HammingComputerM4() {}
384
-
385
- HammingComputerM4(const uint8_t* a4, int code_size) {
386
- set(a4, code_size);
387
- }
388
-
389
- void set(const uint8_t* a4, int code_size) {
390
- assert(code_size % 4 == 0);
391
- a = (uint32_t*)a4;
392
- n = code_size / 4;
393
- }
394
-
395
- int hamming(const uint8_t* b8) const {
396
- const uint32_t* b = (uint32_t*)b8;
397
- int accu = 0;
398
- for (int i = 0; i < n; i++)
399
- accu += popcount64(a[i] ^ b[i]);
400
- return accu;
401
- }
402
- };
403
-
404
- /***************************************************************************
405
- * Equivalence with a template class when code size is known at compile time
406
- **************************************************************************/
407
-
408
- // default template
409
- template <int CODE_SIZE>
410
- struct HammingComputer : HammingComputerDefault {
411
- HammingComputer(const uint8_t* a, int code_size)
412
- : HammingComputerDefault(a, code_size) {}
413
- };
414
-
415
- #define SPECIALIZED_HC(CODE_SIZE) \
416
- template <> \
417
- struct HammingComputer<CODE_SIZE> : HammingComputer##CODE_SIZE { \
418
- HammingComputer(const uint8_t* a) \
419
- : HammingComputer##CODE_SIZE(a, CODE_SIZE) {} \
420
- }
421
-
422
- SPECIALIZED_HC(4);
423
- SPECIALIZED_HC(8);
424
- SPECIALIZED_HC(16);
425
- SPECIALIZED_HC(20);
426
- SPECIALIZED_HC(32);
427
- SPECIALIZED_HC(64);
428
-
429
- #undef SPECIALIZED_HC
430
-
431
- /***************************************************************************
432
- * generalized Hamming = number of bytes that are different between
433
- * two codes.
434
- ***************************************************************************/
435
-
436
- inline int generalized_hamming_64(uint64_t a) {
437
- a |= a >> 1;
438
- a |= a >> 2;
439
- a |= a >> 4;
440
- a &= 0x0101010101010101UL;
441
- return popcount64(a);
442
- }
443
-
444
- struct GenHammingComputer8 {
445
- uint64_t a0;
446
-
447
- GenHammingComputer8(const uint8_t* a, int code_size) {
448
- assert(code_size == 8);
449
- a0 = *(uint64_t*)a;
450
- }
451
-
452
- inline int hamming(const uint8_t* b) const {
453
- return generalized_hamming_64(*(uint64_t*)b ^ a0);
454
- }
455
- };
456
-
457
- struct GenHammingComputer16 {
458
- uint64_t a0, a1;
459
- GenHammingComputer16(const uint8_t* a8, int code_size) {
460
- assert(code_size == 16);
461
- const uint64_t* a = (uint64_t*)a8;
462
- a0 = a[0];
463
- a1 = a[1];
464
- }
465
-
466
- inline int hamming(const uint8_t* b8) const {
467
- const uint64_t* b = (uint64_t*)b8;
468
- return generalized_hamming_64(b[0] ^ a0) +
469
- generalized_hamming_64(b[1] ^ a1);
470
- }
471
- };
472
-
473
- struct GenHammingComputer32 {
474
- uint64_t a0, a1, a2, a3;
475
-
476
- GenHammingComputer32(const uint8_t* a8, int code_size) {
477
- assert(code_size == 32);
478
- const uint64_t* a = (uint64_t*)a8;
479
- a0 = a[0];
480
- a1 = a[1];
481
- a2 = a[2];
482
- a3 = a[3];
483
- }
484
-
485
- inline int hamming(const uint8_t* b8) const {
486
- const uint64_t* b = (uint64_t*)b8;
487
- return generalized_hamming_64(b[0] ^ a0) +
488
- generalized_hamming_64(b[1] ^ a1) +
489
- generalized_hamming_64(b[2] ^ a2) +
490
- generalized_hamming_64(b[3] ^ a3);
491
- }
492
- };
493
-
494
- struct GenHammingComputerM8 {
495
- const uint64_t* a;
496
- int n;
497
-
498
- GenHammingComputerM8(const uint8_t* a8, int code_size) {
499
- assert(code_size % 8 == 0);
500
- a = (uint64_t*)a8;
501
- n = code_size / 8;
502
- }
503
-
504
- int hamming(const uint8_t* b8) const {
505
- const uint64_t* b = (uint64_t*)b8;
506
- int accu = 0;
507
- for (int i = 0; i < n; i++)
508
- accu += generalized_hamming_64(a[i] ^ b[i]);
509
- return accu;
510
- }
511
- };
512
-
513
- /** generalized Hamming distances (= count number of code bytes that
514
- are the same) */
515
- void generalized_hammings_knn_hc(
516
- int_maxheap_array_t* ha,
517
- const uint8_t* a,
518
- const uint8_t* b,
519
- size_t nb,
520
- size_t code_size,
521
- int ordered = true);
522
-
523
67
  /** This class maintains a list of best distances seen so far.
524
68
  *
525
69
  * Since the distances are in a limited range (0 to nbit), the