faiss 0.1.0 → 0.1.1

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 (226) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/README.md +103 -3
  4. data/ext/faiss/ext.cpp +99 -32
  5. data/ext/faiss/extconf.rb +12 -2
  6. data/lib/faiss/ext.bundle +0 -0
  7. data/lib/faiss/index.rb +3 -3
  8. data/lib/faiss/index_binary.rb +3 -3
  9. data/lib/faiss/kmeans.rb +1 -1
  10. data/lib/faiss/pca_matrix.rb +2 -2
  11. data/lib/faiss/product_quantizer.rb +3 -3
  12. data/lib/faiss/version.rb +1 -1
  13. data/vendor/faiss/AutoTune.cpp +719 -0
  14. data/vendor/faiss/AutoTune.h +212 -0
  15. data/vendor/faiss/Clustering.cpp +261 -0
  16. data/vendor/faiss/Clustering.h +101 -0
  17. data/vendor/faiss/IVFlib.cpp +339 -0
  18. data/vendor/faiss/IVFlib.h +132 -0
  19. data/vendor/faiss/Index.cpp +171 -0
  20. data/vendor/faiss/Index.h +261 -0
  21. data/vendor/faiss/Index2Layer.cpp +437 -0
  22. data/vendor/faiss/Index2Layer.h +85 -0
  23. data/vendor/faiss/IndexBinary.cpp +77 -0
  24. data/vendor/faiss/IndexBinary.h +163 -0
  25. data/vendor/faiss/IndexBinaryFlat.cpp +83 -0
  26. data/vendor/faiss/IndexBinaryFlat.h +54 -0
  27. data/vendor/faiss/IndexBinaryFromFloat.cpp +78 -0
  28. data/vendor/faiss/IndexBinaryFromFloat.h +52 -0
  29. data/vendor/faiss/IndexBinaryHNSW.cpp +325 -0
  30. data/vendor/faiss/IndexBinaryHNSW.h +56 -0
  31. data/vendor/faiss/IndexBinaryIVF.cpp +671 -0
  32. data/vendor/faiss/IndexBinaryIVF.h +211 -0
  33. data/vendor/faiss/IndexFlat.cpp +508 -0
  34. data/vendor/faiss/IndexFlat.h +175 -0
  35. data/vendor/faiss/IndexHNSW.cpp +1090 -0
  36. data/vendor/faiss/IndexHNSW.h +170 -0
  37. data/vendor/faiss/IndexIVF.cpp +909 -0
  38. data/vendor/faiss/IndexIVF.h +353 -0
  39. data/vendor/faiss/IndexIVFFlat.cpp +502 -0
  40. data/vendor/faiss/IndexIVFFlat.h +118 -0
  41. data/vendor/faiss/IndexIVFPQ.cpp +1207 -0
  42. data/vendor/faiss/IndexIVFPQ.h +161 -0
  43. data/vendor/faiss/IndexIVFPQR.cpp +219 -0
  44. data/vendor/faiss/IndexIVFPQR.h +65 -0
  45. data/vendor/faiss/IndexIVFSpectralHash.cpp +331 -0
  46. data/vendor/faiss/IndexIVFSpectralHash.h +75 -0
  47. data/vendor/faiss/IndexLSH.cpp +225 -0
  48. data/vendor/faiss/IndexLSH.h +87 -0
  49. data/vendor/faiss/IndexLattice.cpp +143 -0
  50. data/vendor/faiss/IndexLattice.h +68 -0
  51. data/vendor/faiss/IndexPQ.cpp +1188 -0
  52. data/vendor/faiss/IndexPQ.h +199 -0
  53. data/vendor/faiss/IndexPreTransform.cpp +288 -0
  54. data/vendor/faiss/IndexPreTransform.h +91 -0
  55. data/vendor/faiss/IndexReplicas.cpp +123 -0
  56. data/vendor/faiss/IndexReplicas.h +76 -0
  57. data/vendor/faiss/IndexScalarQuantizer.cpp +317 -0
  58. data/vendor/faiss/IndexScalarQuantizer.h +127 -0
  59. data/vendor/faiss/IndexShards.cpp +317 -0
  60. data/vendor/faiss/IndexShards.h +100 -0
  61. data/vendor/faiss/InvertedLists.cpp +623 -0
  62. data/vendor/faiss/InvertedLists.h +334 -0
  63. data/vendor/faiss/LICENSE +21 -0
  64. data/vendor/faiss/MatrixStats.cpp +252 -0
  65. data/vendor/faiss/MatrixStats.h +62 -0
  66. data/vendor/faiss/MetaIndexes.cpp +351 -0
  67. data/vendor/faiss/MetaIndexes.h +126 -0
  68. data/vendor/faiss/OnDiskInvertedLists.cpp +674 -0
  69. data/vendor/faiss/OnDiskInvertedLists.h +127 -0
  70. data/vendor/faiss/VectorTransform.cpp +1157 -0
  71. data/vendor/faiss/VectorTransform.h +322 -0
  72. data/vendor/faiss/c_api/AutoTune_c.cpp +83 -0
  73. data/vendor/faiss/c_api/AutoTune_c.h +64 -0
  74. data/vendor/faiss/c_api/Clustering_c.cpp +139 -0
  75. data/vendor/faiss/c_api/Clustering_c.h +117 -0
  76. data/vendor/faiss/c_api/IndexFlat_c.cpp +140 -0
  77. data/vendor/faiss/c_api/IndexFlat_c.h +115 -0
  78. data/vendor/faiss/c_api/IndexIVFFlat_c.cpp +64 -0
  79. data/vendor/faiss/c_api/IndexIVFFlat_c.h +58 -0
  80. data/vendor/faiss/c_api/IndexIVF_c.cpp +92 -0
  81. data/vendor/faiss/c_api/IndexIVF_c.h +135 -0
  82. data/vendor/faiss/c_api/IndexLSH_c.cpp +37 -0
  83. data/vendor/faiss/c_api/IndexLSH_c.h +40 -0
  84. data/vendor/faiss/c_api/IndexShards_c.cpp +44 -0
  85. data/vendor/faiss/c_api/IndexShards_c.h +42 -0
  86. data/vendor/faiss/c_api/Index_c.cpp +105 -0
  87. data/vendor/faiss/c_api/Index_c.h +183 -0
  88. data/vendor/faiss/c_api/MetaIndexes_c.cpp +49 -0
  89. data/vendor/faiss/c_api/MetaIndexes_c.h +49 -0
  90. data/vendor/faiss/c_api/clone_index_c.cpp +23 -0
  91. data/vendor/faiss/c_api/clone_index_c.h +32 -0
  92. data/vendor/faiss/c_api/error_c.h +42 -0
  93. data/vendor/faiss/c_api/error_impl.cpp +27 -0
  94. data/vendor/faiss/c_api/error_impl.h +16 -0
  95. data/vendor/faiss/c_api/faiss_c.h +58 -0
  96. data/vendor/faiss/c_api/gpu/GpuAutoTune_c.cpp +96 -0
  97. data/vendor/faiss/c_api/gpu/GpuAutoTune_c.h +56 -0
  98. data/vendor/faiss/c_api/gpu/GpuClonerOptions_c.cpp +52 -0
  99. data/vendor/faiss/c_api/gpu/GpuClonerOptions_c.h +68 -0
  100. data/vendor/faiss/c_api/gpu/GpuIndex_c.cpp +17 -0
  101. data/vendor/faiss/c_api/gpu/GpuIndex_c.h +30 -0
  102. data/vendor/faiss/c_api/gpu/GpuIndicesOptions_c.h +38 -0
  103. data/vendor/faiss/c_api/gpu/GpuResources_c.cpp +86 -0
  104. data/vendor/faiss/c_api/gpu/GpuResources_c.h +66 -0
  105. data/vendor/faiss/c_api/gpu/StandardGpuResources_c.cpp +54 -0
  106. data/vendor/faiss/c_api/gpu/StandardGpuResources_c.h +53 -0
  107. data/vendor/faiss/c_api/gpu/macros_impl.h +42 -0
  108. data/vendor/faiss/c_api/impl/AuxIndexStructures_c.cpp +220 -0
  109. data/vendor/faiss/c_api/impl/AuxIndexStructures_c.h +149 -0
  110. data/vendor/faiss/c_api/index_factory_c.cpp +26 -0
  111. data/vendor/faiss/c_api/index_factory_c.h +30 -0
  112. data/vendor/faiss/c_api/index_io_c.cpp +42 -0
  113. data/vendor/faiss/c_api/index_io_c.h +50 -0
  114. data/vendor/faiss/c_api/macros_impl.h +110 -0
  115. data/vendor/faiss/clone_index.cpp +147 -0
  116. data/vendor/faiss/clone_index.h +38 -0
  117. data/vendor/faiss/demos/demo_imi_flat.cpp +151 -0
  118. data/vendor/faiss/demos/demo_imi_pq.cpp +199 -0
  119. data/vendor/faiss/demos/demo_ivfpq_indexing.cpp +146 -0
  120. data/vendor/faiss/demos/demo_sift1M.cpp +252 -0
  121. data/vendor/faiss/gpu/GpuAutoTune.cpp +95 -0
  122. data/vendor/faiss/gpu/GpuAutoTune.h +27 -0
  123. data/vendor/faiss/gpu/GpuCloner.cpp +403 -0
  124. data/vendor/faiss/gpu/GpuCloner.h +82 -0
  125. data/vendor/faiss/gpu/GpuClonerOptions.cpp +28 -0
  126. data/vendor/faiss/gpu/GpuClonerOptions.h +53 -0
  127. data/vendor/faiss/gpu/GpuDistance.h +52 -0
  128. data/vendor/faiss/gpu/GpuFaissAssert.h +29 -0
  129. data/vendor/faiss/gpu/GpuIndex.h +148 -0
  130. data/vendor/faiss/gpu/GpuIndexBinaryFlat.h +89 -0
  131. data/vendor/faiss/gpu/GpuIndexFlat.h +190 -0
  132. data/vendor/faiss/gpu/GpuIndexIVF.h +89 -0
  133. data/vendor/faiss/gpu/GpuIndexIVFFlat.h +85 -0
  134. data/vendor/faiss/gpu/GpuIndexIVFPQ.h +143 -0
  135. data/vendor/faiss/gpu/GpuIndexIVFScalarQuantizer.h +100 -0
  136. data/vendor/faiss/gpu/GpuIndicesOptions.h +30 -0
  137. data/vendor/faiss/gpu/GpuResources.cpp +52 -0
  138. data/vendor/faiss/gpu/GpuResources.h +73 -0
  139. data/vendor/faiss/gpu/StandardGpuResources.cpp +295 -0
  140. data/vendor/faiss/gpu/StandardGpuResources.h +114 -0
  141. data/vendor/faiss/gpu/impl/RemapIndices.cpp +43 -0
  142. data/vendor/faiss/gpu/impl/RemapIndices.h +24 -0
  143. data/vendor/faiss/gpu/perf/IndexWrapper-inl.h +71 -0
  144. data/vendor/faiss/gpu/perf/IndexWrapper.h +39 -0
  145. data/vendor/faiss/gpu/perf/PerfClustering.cpp +115 -0
  146. data/vendor/faiss/gpu/perf/PerfIVFPQAdd.cpp +139 -0
  147. data/vendor/faiss/gpu/perf/WriteIndex.cpp +102 -0
  148. data/vendor/faiss/gpu/test/TestGpuIndexBinaryFlat.cpp +130 -0
  149. data/vendor/faiss/gpu/test/TestGpuIndexFlat.cpp +371 -0
  150. data/vendor/faiss/gpu/test/TestGpuIndexIVFFlat.cpp +550 -0
  151. data/vendor/faiss/gpu/test/TestGpuIndexIVFPQ.cpp +450 -0
  152. data/vendor/faiss/gpu/test/TestGpuMemoryException.cpp +84 -0
  153. data/vendor/faiss/gpu/test/TestUtils.cpp +315 -0
  154. data/vendor/faiss/gpu/test/TestUtils.h +93 -0
  155. data/vendor/faiss/gpu/test/demo_ivfpq_indexing_gpu.cpp +159 -0
  156. data/vendor/faiss/gpu/utils/DeviceMemory.cpp +77 -0
  157. data/vendor/faiss/gpu/utils/DeviceMemory.h +71 -0
  158. data/vendor/faiss/gpu/utils/DeviceUtils.h +185 -0
  159. data/vendor/faiss/gpu/utils/MemorySpace.cpp +89 -0
  160. data/vendor/faiss/gpu/utils/MemorySpace.h +44 -0
  161. data/vendor/faiss/gpu/utils/StackDeviceMemory.cpp +239 -0
  162. data/vendor/faiss/gpu/utils/StackDeviceMemory.h +129 -0
  163. data/vendor/faiss/gpu/utils/StaticUtils.h +83 -0
  164. data/vendor/faiss/gpu/utils/Timer.cpp +60 -0
  165. data/vendor/faiss/gpu/utils/Timer.h +52 -0
  166. data/vendor/faiss/impl/AuxIndexStructures.cpp +305 -0
  167. data/vendor/faiss/impl/AuxIndexStructures.h +246 -0
  168. data/vendor/faiss/impl/FaissAssert.h +95 -0
  169. data/vendor/faiss/impl/FaissException.cpp +66 -0
  170. data/vendor/faiss/impl/FaissException.h +71 -0
  171. data/vendor/faiss/impl/HNSW.cpp +818 -0
  172. data/vendor/faiss/impl/HNSW.h +275 -0
  173. data/vendor/faiss/impl/PolysemousTraining.cpp +953 -0
  174. data/vendor/faiss/impl/PolysemousTraining.h +158 -0
  175. data/vendor/faiss/impl/ProductQuantizer.cpp +876 -0
  176. data/vendor/faiss/impl/ProductQuantizer.h +242 -0
  177. data/vendor/faiss/impl/ScalarQuantizer.cpp +1628 -0
  178. data/vendor/faiss/impl/ScalarQuantizer.h +120 -0
  179. data/vendor/faiss/impl/ThreadedIndex-inl.h +192 -0
  180. data/vendor/faiss/impl/ThreadedIndex.h +80 -0
  181. data/vendor/faiss/impl/index_read.cpp +793 -0
  182. data/vendor/faiss/impl/index_write.cpp +558 -0
  183. data/vendor/faiss/impl/io.cpp +142 -0
  184. data/vendor/faiss/impl/io.h +98 -0
  185. data/vendor/faiss/impl/lattice_Zn.cpp +712 -0
  186. data/vendor/faiss/impl/lattice_Zn.h +199 -0
  187. data/vendor/faiss/index_factory.cpp +392 -0
  188. data/vendor/faiss/index_factory.h +25 -0
  189. data/vendor/faiss/index_io.h +75 -0
  190. data/vendor/faiss/misc/test_blas.cpp +84 -0
  191. data/vendor/faiss/tests/test_binary_flat.cpp +64 -0
  192. data/vendor/faiss/tests/test_dealloc_invlists.cpp +183 -0
  193. data/vendor/faiss/tests/test_ivfpq_codec.cpp +67 -0
  194. data/vendor/faiss/tests/test_ivfpq_indexing.cpp +98 -0
  195. data/vendor/faiss/tests/test_lowlevel_ivf.cpp +566 -0
  196. data/vendor/faiss/tests/test_merge.cpp +258 -0
  197. data/vendor/faiss/tests/test_omp_threads.cpp +14 -0
  198. data/vendor/faiss/tests/test_ondisk_ivf.cpp +220 -0
  199. data/vendor/faiss/tests/test_pairs_decoding.cpp +189 -0
  200. data/vendor/faiss/tests/test_params_override.cpp +231 -0
  201. data/vendor/faiss/tests/test_pq_encoding.cpp +98 -0
  202. data/vendor/faiss/tests/test_sliding_ivf.cpp +240 -0
  203. data/vendor/faiss/tests/test_threaded_index.cpp +253 -0
  204. data/vendor/faiss/tests/test_transfer_invlists.cpp +159 -0
  205. data/vendor/faiss/tutorial/cpp/1-Flat.cpp +98 -0
  206. data/vendor/faiss/tutorial/cpp/2-IVFFlat.cpp +81 -0
  207. data/vendor/faiss/tutorial/cpp/3-IVFPQ.cpp +93 -0
  208. data/vendor/faiss/tutorial/cpp/4-GPU.cpp +119 -0
  209. data/vendor/faiss/tutorial/cpp/5-Multiple-GPUs.cpp +99 -0
  210. data/vendor/faiss/utils/Heap.cpp +122 -0
  211. data/vendor/faiss/utils/Heap.h +495 -0
  212. data/vendor/faiss/utils/WorkerThread.cpp +126 -0
  213. data/vendor/faiss/utils/WorkerThread.h +61 -0
  214. data/vendor/faiss/utils/distances.cpp +765 -0
  215. data/vendor/faiss/utils/distances.h +243 -0
  216. data/vendor/faiss/utils/distances_simd.cpp +809 -0
  217. data/vendor/faiss/utils/extra_distances.cpp +336 -0
  218. data/vendor/faiss/utils/extra_distances.h +54 -0
  219. data/vendor/faiss/utils/hamming-inl.h +472 -0
  220. data/vendor/faiss/utils/hamming.cpp +792 -0
  221. data/vendor/faiss/utils/hamming.h +220 -0
  222. data/vendor/faiss/utils/random.cpp +192 -0
  223. data/vendor/faiss/utils/random.h +60 -0
  224. data/vendor/faiss/utils/utils.cpp +783 -0
  225. data/vendor/faiss/utils/utils.h +181 -0
  226. metadata +216 -2
@@ -0,0 +1,336 @@
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
+ #include <faiss/utils/distances.h>
11
+
12
+ #include <cmath>
13
+ #include <omp.h>
14
+
15
+
16
+ #include <faiss/utils/utils.h>
17
+ #include <faiss/impl/FaissAssert.h>
18
+ #include <faiss/impl/AuxIndexStructures.h>
19
+
20
+ namespace faiss {
21
+
22
+ /***************************************************************************
23
+ * Distance functions (other than L2 and IP)
24
+ ***************************************************************************/
25
+
26
+ struct VectorDistanceL2 {
27
+ size_t d;
28
+
29
+ float operator () (const float *x, const float *y) const {
30
+ return fvec_L2sqr (x, y, d);
31
+ }
32
+ };
33
+
34
+ struct VectorDistanceL1 {
35
+ size_t d;
36
+
37
+ float operator () (const float *x, const float *y) const {
38
+ return fvec_L1 (x, y, d);
39
+ }
40
+ };
41
+
42
+ struct VectorDistanceLinf {
43
+ size_t d;
44
+
45
+ float operator () (const float *x, const float *y) const {
46
+ return fvec_Linf (x, y, d);
47
+ /*
48
+ float vmax = 0;
49
+ for (size_t i = 0; i < d; i++) {
50
+ float diff = fabs (x[i] - y[i]);
51
+ if (diff > vmax) vmax = diff;
52
+ }
53
+ return vmax;*/
54
+ }
55
+ };
56
+
57
+ struct VectorDistanceLp {
58
+ size_t d;
59
+ const float p;
60
+
61
+ float operator () (const float *x, const float *y) const {
62
+ float accu = 0;
63
+ for (size_t i = 0; i < d; i++) {
64
+ float diff = fabs (x[i] - y[i]);
65
+ accu += powf (diff, p);
66
+ }
67
+ return accu;
68
+ }
69
+ };
70
+
71
+ struct VectorDistanceCanberra {
72
+ size_t d;
73
+
74
+ float operator () (const float *x, const float *y) const {
75
+ float accu = 0;
76
+ for (size_t i = 0; i < d; i++) {
77
+ float xi = x[i], yi = y[i];
78
+ accu += fabs (xi - yi) / (fabs(xi) + fabs(yi));
79
+ }
80
+ return accu;
81
+ }
82
+ };
83
+
84
+ struct VectorDistanceBrayCurtis {
85
+ size_t d;
86
+
87
+ float operator () (const float *x, const float *y) const {
88
+ float accu_num = 0, accu_den = 0;
89
+ for (size_t i = 0; i < d; i++) {
90
+ float xi = x[i], yi = y[i];
91
+ accu_num += fabs (xi - yi);
92
+ accu_den += fabs (xi + yi);
93
+ }
94
+ return accu_num / accu_den;
95
+ }
96
+ };
97
+
98
+ struct VectorDistanceJensenShannon {
99
+ size_t d;
100
+
101
+ float operator () (const float *x, const float *y) const {
102
+ float accu = 0;
103
+
104
+ for (size_t i = 0; i < d; i++) {
105
+ float xi = x[i], yi = y[i];
106
+ float mi = 0.5 * (xi + yi);
107
+ float kl1 = - xi * log(mi / xi);
108
+ float kl2 = - yi * log(mi / yi);
109
+ accu += kl1 + kl2;
110
+ }
111
+ return 0.5 * accu;
112
+ }
113
+ };
114
+
115
+
116
+
117
+
118
+
119
+
120
+
121
+
122
+
123
+
124
+ namespace {
125
+
126
+ template<class VD>
127
+ void pairwise_extra_distances_template (
128
+ VD vd,
129
+ int64_t nq, const float *xq,
130
+ int64_t nb, const float *xb,
131
+ float *dis,
132
+ int64_t ldq, int64_t ldb, int64_t ldd)
133
+ {
134
+
135
+ #pragma omp parallel for if(nq > 10)
136
+ for (int64_t i = 0; i < nq; i++) {
137
+ const float *xqi = xq + i * ldq;
138
+ const float *xbj = xb;
139
+ float *disi = dis + ldd * i;
140
+
141
+ for (int64_t j = 0; j < nb; j++) {
142
+ disi[j] = vd (xqi, xbj);
143
+ xbj += ldb;
144
+ }
145
+ }
146
+ }
147
+
148
+
149
+ template<class VD>
150
+ void knn_extra_metrics_template (
151
+ VD vd,
152
+ const float * x,
153
+ const float * y,
154
+ size_t nx, size_t ny,
155
+ float_maxheap_array_t * res)
156
+ {
157
+ size_t k = res->k;
158
+ size_t d = vd.d;
159
+ size_t check_period = InterruptCallback::get_period_hint (ny * d);
160
+ check_period *= omp_get_max_threads();
161
+
162
+ for (size_t i0 = 0; i0 < nx; i0 += check_period) {
163
+ size_t i1 = std::min(i0 + check_period, nx);
164
+
165
+ #pragma omp parallel for
166
+ for (size_t i = i0; i < i1; i++) {
167
+ const float * x_i = x + i * d;
168
+ const float * y_j = y;
169
+ size_t j;
170
+ float * simi = res->get_val(i);
171
+ int64_t * idxi = res->get_ids (i);
172
+
173
+ maxheap_heapify (k, simi, idxi);
174
+ for (j = 0; j < ny; j++) {
175
+ float disij = vd (x_i, y_j);
176
+
177
+ if (disij < simi[0]) {
178
+ maxheap_pop (k, simi, idxi);
179
+ maxheap_push (k, simi, idxi, disij, j);
180
+ }
181
+ y_j += d;
182
+ }
183
+ maxheap_reorder (k, simi, idxi);
184
+ }
185
+ InterruptCallback::check ();
186
+ }
187
+
188
+ }
189
+
190
+
191
+ template<class VD>
192
+ struct ExtraDistanceComputer : DistanceComputer {
193
+ VD vd;
194
+ Index::idx_t nb;
195
+ const float *q;
196
+ const float *b;
197
+
198
+ float operator () (idx_t i) override {
199
+ return vd (q, b + i * vd.d);
200
+ }
201
+
202
+ float symmetric_dis(idx_t i, idx_t j) override {
203
+ return vd (b + j * vd.d, b + i * vd.d);
204
+ }
205
+
206
+ ExtraDistanceComputer(const VD & vd, const float *xb,
207
+ size_t nb, const float *q = nullptr)
208
+ : vd(vd), nb(nb), q(q), b(xb) {}
209
+
210
+ void set_query(const float *x) override {
211
+ q = x;
212
+ }
213
+ };
214
+
215
+
216
+
217
+
218
+
219
+
220
+
221
+
222
+
223
+
224
+
225
+
226
+
227
+
228
+
229
+
230
+ } // anonymous namespace
231
+
232
+ void pairwise_extra_distances (
233
+ int64_t d,
234
+ int64_t nq, const float *xq,
235
+ int64_t nb, const float *xb,
236
+ MetricType mt, float metric_arg,
237
+ float *dis,
238
+ int64_t ldq, int64_t ldb, int64_t ldd)
239
+ {
240
+ if (nq == 0 || nb == 0) return;
241
+ if (ldq == -1) ldq = d;
242
+ if (ldb == -1) ldb = d;
243
+ if (ldd == -1) ldd = nb;
244
+
245
+ switch(mt) {
246
+ #define HANDLE_VAR(kw) \
247
+ case METRIC_ ## kw: { \
248
+ VectorDistance ## kw vd({(size_t)d}); \
249
+ pairwise_extra_distances_template (vd, nq, xq, nb, xb, \
250
+ dis, ldq, ldb, ldd); \
251
+ break; \
252
+ }
253
+ HANDLE_VAR(L2);
254
+ HANDLE_VAR(L1);
255
+ HANDLE_VAR(Linf);
256
+ HANDLE_VAR(Canberra);
257
+ HANDLE_VAR(BrayCurtis);
258
+ HANDLE_VAR(JensenShannon);
259
+ #undef HANDLE_VAR
260
+ case METRIC_Lp: {
261
+ VectorDistanceLp vd({(size_t)d, metric_arg});
262
+ pairwise_extra_distances_template (vd, nq, xq, nb, xb,
263
+ dis, ldq, ldb, ldd);
264
+ break;
265
+ }
266
+ default:
267
+ FAISS_THROW_MSG ("metric type not implemented");
268
+ }
269
+
270
+ }
271
+
272
+ void knn_extra_metrics (
273
+ const float * x,
274
+ const float * y,
275
+ size_t d, size_t nx, size_t ny,
276
+ MetricType mt, float metric_arg,
277
+ float_maxheap_array_t * res)
278
+ {
279
+
280
+ switch(mt) {
281
+ #define HANDLE_VAR(kw) \
282
+ case METRIC_ ## kw: { \
283
+ VectorDistance ## kw vd({(size_t)d}); \
284
+ knn_extra_metrics_template (vd, x, y, nx, ny, res); \
285
+ break; \
286
+ }
287
+ HANDLE_VAR(L2);
288
+ HANDLE_VAR(L1);
289
+ HANDLE_VAR(Linf);
290
+ HANDLE_VAR(Canberra);
291
+ HANDLE_VAR(BrayCurtis);
292
+ HANDLE_VAR(JensenShannon);
293
+ #undef HANDLE_VAR
294
+ case METRIC_Lp: {
295
+ VectorDistanceLp vd({(size_t)d, metric_arg});
296
+ knn_extra_metrics_template (vd, x, y, nx, ny, res);
297
+ break;
298
+ }
299
+ default:
300
+ FAISS_THROW_MSG ("metric type not implemented");
301
+ }
302
+
303
+ }
304
+
305
+ DistanceComputer *get_extra_distance_computer (
306
+ size_t d,
307
+ MetricType mt, float metric_arg,
308
+ size_t nb, const float *xb)
309
+ {
310
+
311
+ switch(mt) {
312
+ #define HANDLE_VAR(kw) \
313
+ case METRIC_ ## kw: { \
314
+ VectorDistance ## kw vd({(size_t)d}); \
315
+ return new ExtraDistanceComputer<VectorDistance ## kw>(vd, xb, nb); \
316
+ }
317
+ HANDLE_VAR(L2);
318
+ HANDLE_VAR(L1);
319
+ HANDLE_VAR(Linf);
320
+ HANDLE_VAR(Canberra);
321
+ HANDLE_VAR(BrayCurtis);
322
+ HANDLE_VAR(JensenShannon);
323
+ #undef HANDLE_VAR
324
+ case METRIC_Lp: {
325
+ VectorDistanceLp vd({(size_t)d, metric_arg});
326
+ return new ExtraDistanceComputer<VectorDistanceLp> (vd, xb, nb);
327
+ break;
328
+ }
329
+ default:
330
+ FAISS_THROW_MSG ("metric type not implemented");
331
+ }
332
+
333
+ }
334
+
335
+
336
+ } // namespace faiss
@@ -0,0 +1,54 @@
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
+ #ifndef FAISS_distances_h
11
+ #define FAISS_distances_h
12
+
13
+ /** In this file are the implementations of extra metrics beyond L2
14
+ * and inner product */
15
+
16
+ #include <stdint.h>
17
+
18
+ #include <faiss/Index.h>
19
+
20
+ #include <faiss/utils/Heap.h>
21
+
22
+
23
+
24
+ namespace faiss {
25
+
26
+
27
+ void pairwise_extra_distances (
28
+ int64_t d,
29
+ int64_t nq, const float *xq,
30
+ int64_t nb, const float *xb,
31
+ MetricType mt, float metric_arg,
32
+ float *dis,
33
+ int64_t ldq = -1, int64_t ldb = -1, int64_t ldd = -1);
34
+
35
+
36
+ void knn_extra_metrics (
37
+ const float * x,
38
+ const float * y,
39
+ size_t d, size_t nx, size_t ny,
40
+ MetricType mt, float metric_arg,
41
+ float_maxheap_array_t * res);
42
+
43
+
44
+ /** get a DistanceComputer that refers to this type of distance and
45
+ * indexes a flat array of size nb */
46
+ DistanceComputer *get_extra_distance_computer (
47
+ size_t d,
48
+ MetricType mt, float metric_arg,
49
+ size_t nb, const float *xb);
50
+
51
+ }
52
+
53
+
54
+ #endif
@@ -0,0 +1,472 @@
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
+
9
+
10
+ namespace faiss {
11
+
12
+
13
+ inline BitstringWriter::BitstringWriter(uint8_t *code, int code_size):
14
+ code (code), code_size (code_size), i(0)
15
+ {
16
+ bzero (code, code_size);
17
+ }
18
+
19
+ inline void BitstringWriter::write(uint64_t x, int nbit) {
20
+ assert (code_size * 8 >= nbit + i);
21
+ // nb of available bits in i / 8
22
+ int na = 8 - (i & 7);
23
+
24
+ if (nbit <= na) {
25
+ code[i >> 3] |= x << (i & 7);
26
+ i += nbit;
27
+ return;
28
+ } else {
29
+ int j = i >> 3;
30
+ code[j++] |= x << (i & 7);
31
+ i += nbit;
32
+ x >>= na;
33
+ while (x != 0) {
34
+ code[j++] |= x;
35
+ x >>= 8;
36
+ }
37
+ }
38
+ }
39
+
40
+
41
+ inline BitstringReader::BitstringReader(const uint8_t *code, int code_size):
42
+ code (code), code_size (code_size), i(0)
43
+ {}
44
+
45
+ inline uint64_t BitstringReader::read(int nbit) {
46
+ assert (code_size * 8 >= nbit + i);
47
+ // nb of available bits in i / 8
48
+ int na = 8 - (i & 7);
49
+ // get available bits in current byte
50
+ uint64_t res = code[i >> 3] >> (i & 7);
51
+ if (nbit <= na) {
52
+ res &= (1 << nbit) - 1;
53
+ i += nbit;
54
+ return res;
55
+ } else {
56
+ int ofs = na;
57
+ int j = (i >> 3) + 1;
58
+ i += nbit;
59
+ nbit -= na;
60
+ while (nbit > 8) {
61
+ res |= ((uint64_t)code[j++]) << ofs;
62
+ ofs += 8;
63
+ nbit -= 8; // TODO remove nbit
64
+ }
65
+ uint64_t last_byte = code[j];
66
+ last_byte &= (1 << nbit) - 1;
67
+ res |= last_byte << ofs;
68
+ return res;
69
+ }
70
+ }
71
+
72
+
73
+ /******************************************************************
74
+ * The HammingComputer series of classes compares a single code of
75
+ * size 4 to 32 to incoming codes. They are intended for use as a
76
+ * template class where it would be inefficient to switch on the code
77
+ * size in the inner loop. Hopefully the compiler will inline the
78
+ * hamming() functions and put the a0, a1, ... in registers.
79
+ ******************************************************************/
80
+
81
+
82
+ struct HammingComputer4 {
83
+ uint32_t a0;
84
+
85
+ HammingComputer4 () {}
86
+
87
+ HammingComputer4 (const uint8_t *a, int code_size) {
88
+ set (a, code_size);
89
+ }
90
+
91
+ void set (const uint8_t *a, int code_size) {
92
+ assert (code_size == 4);
93
+ a0 = *(uint32_t *)a;
94
+ }
95
+
96
+ inline int hamming (const uint8_t *b) const {
97
+ return popcount64 (*(uint32_t *)b ^ a0);
98
+ }
99
+
100
+ };
101
+
102
+ struct HammingComputer8 {
103
+ uint64_t a0;
104
+
105
+ HammingComputer8 () {}
106
+
107
+ HammingComputer8 (const uint8_t *a, int code_size) {
108
+ set (a, code_size);
109
+ }
110
+
111
+ void set (const uint8_t *a, int code_size) {
112
+ assert (code_size == 8);
113
+ a0 = *(uint64_t *)a;
114
+ }
115
+
116
+ inline int hamming (const uint8_t *b) const {
117
+ return popcount64 (*(uint64_t *)b ^ a0);
118
+ }
119
+
120
+ };
121
+
122
+
123
+ struct HammingComputer16 {
124
+ uint64_t a0, a1;
125
+
126
+ HammingComputer16 () {}
127
+
128
+ HammingComputer16 (const uint8_t *a8, int code_size) {
129
+ set (a8, code_size);
130
+ }
131
+
132
+ void set (const uint8_t *a8, int code_size) {
133
+ assert (code_size == 16);
134
+ const uint64_t *a = (uint64_t *)a8;
135
+ a0 = a[0]; a1 = a[1];
136
+ }
137
+
138
+ inline int hamming (const uint8_t *b8) const {
139
+ const uint64_t *b = (uint64_t *)b8;
140
+ return popcount64 (b[0] ^ a0) + popcount64 (b[1] ^ a1);
141
+ }
142
+
143
+ };
144
+
145
+ // when applied to an array, 1/2 of the 64-bit accesses are unaligned.
146
+ // This incurs a penalty of ~10% wrt. fully aligned accesses.
147
+ struct HammingComputer20 {
148
+ uint64_t a0, a1;
149
+ uint32_t a2;
150
+
151
+ HammingComputer20 () {}
152
+
153
+ HammingComputer20 (const uint8_t *a8, int code_size) {
154
+ set (a8, code_size);
155
+ }
156
+
157
+ void set (const uint8_t *a8, int code_size) {
158
+ assert (code_size == 20);
159
+ const uint64_t *a = (uint64_t *)a8;
160
+ a0 = a[0]; a1 = a[1]; a2 = a[2];
161
+ }
162
+
163
+ inline int hamming (const uint8_t *b8) const {
164
+ const uint64_t *b = (uint64_t *)b8;
165
+ return popcount64 (b[0] ^ a0) + popcount64 (b[1] ^ a1) +
166
+ popcount64 (*(uint32_t*)(b + 2) ^ a2);
167
+ }
168
+ };
169
+
170
+ struct HammingComputer32 {
171
+ uint64_t a0, a1, a2, a3;
172
+
173
+ HammingComputer32 () {}
174
+
175
+ HammingComputer32 (const uint8_t *a8, int code_size) {
176
+ set (a8, code_size);
177
+ }
178
+
179
+ void set (const uint8_t *a8, int code_size) {
180
+ assert (code_size == 32);
181
+ const uint64_t *a = (uint64_t *)a8;
182
+ a0 = a[0]; a1 = a[1]; a2 = a[2]; a3 = a[3];
183
+ }
184
+
185
+ inline int hamming (const uint8_t *b8) const {
186
+ const uint64_t *b = (uint64_t *)b8;
187
+ return popcount64 (b[0] ^ a0) + popcount64 (b[1] ^ a1) +
188
+ popcount64 (b[2] ^ a2) + popcount64 (b[3] ^ a3);
189
+ }
190
+
191
+ };
192
+
193
+ struct HammingComputer64 {
194
+ uint64_t a0, a1, a2, a3, a4, a5, a6, a7;
195
+
196
+ HammingComputer64 () {}
197
+
198
+ HammingComputer64 (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 == 64);
204
+ const uint64_t *a = (uint64_t *)a8;
205
+ a0 = a[0]; a1 = a[1]; a2 = a[2]; a3 = a[3];
206
+ a4 = a[4]; a5 = a[5]; a6 = a[6]; a7 = a[7];
207
+ }
208
+
209
+ inline int hamming (const uint8_t *b8) const {
210
+ const uint64_t *b = (uint64_t *)b8;
211
+ return popcount64 (b[0] ^ a0) + popcount64 (b[1] ^ a1) +
212
+ popcount64 (b[2] ^ a2) + popcount64 (b[3] ^ a3) +
213
+ popcount64 (b[4] ^ a4) + popcount64 (b[5] ^ a5) +
214
+ popcount64 (b[6] ^ a6) + popcount64 (b[7] ^ a7);
215
+ }
216
+
217
+ };
218
+
219
+ // very inefficient...
220
+ struct HammingComputerDefault {
221
+ const uint8_t *a;
222
+ int n;
223
+
224
+ HammingComputerDefault () {}
225
+
226
+ HammingComputerDefault (const uint8_t *a8, int code_size) {
227
+ set (a8, code_size);
228
+ }
229
+
230
+ void set (const uint8_t *a8, int code_size) {
231
+ a = a8;
232
+ n = code_size;
233
+ }
234
+
235
+ int hamming (const uint8_t *b8) const {
236
+ int accu = 0;
237
+ for (int i = 0; i < n; i++)
238
+ accu += popcount64 (a[i] ^ b8[i]);
239
+ return accu;
240
+ }
241
+
242
+ };
243
+
244
+ struct HammingComputerM8 {
245
+ const uint64_t *a;
246
+ int n;
247
+
248
+ HammingComputerM8 () {}
249
+
250
+ HammingComputerM8 (const uint8_t *a8, int code_size) {
251
+ set (a8, code_size);
252
+ }
253
+
254
+ void set (const uint8_t *a8, int code_size) {
255
+ assert (code_size % 8 == 0);
256
+ a = (uint64_t *)a8;
257
+ n = code_size / 8;
258
+ }
259
+
260
+ int hamming (const uint8_t *b8) const {
261
+ const uint64_t *b = (uint64_t *)b8;
262
+ int accu = 0;
263
+ for (int i = 0; i < n; i++)
264
+ accu += popcount64 (a[i] ^ b[i]);
265
+ return accu;
266
+ }
267
+
268
+ };
269
+
270
+ // even more inefficient!
271
+ struct HammingComputerM4 {
272
+ const uint32_t *a;
273
+ int n;
274
+
275
+ HammingComputerM4 () {}
276
+
277
+ HammingComputerM4 (const uint8_t *a4, int code_size) {
278
+ set (a4, code_size);
279
+ }
280
+
281
+ void set (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
+
287
+ int hamming (const uint8_t *b8) const {
288
+ const uint32_t *b = (uint32_t *)b8;
289
+ int accu = 0;
290
+ for (int i = 0; i < n; i++)
291
+ accu += popcount64 (a[i] ^ b[i]);
292
+ return accu;
293
+ }
294
+
295
+ };
296
+
297
+ /***************************************************************************
298
+ * Equivalence with a template class when code size is known at compile time
299
+ **************************************************************************/
300
+
301
+ // default template
302
+ template<int CODE_SIZE>
303
+ struct HammingComputer: HammingComputerM8 {
304
+ HammingComputer (const uint8_t *a, int code_size):
305
+ HammingComputerM8(a, code_size) {}
306
+ };
307
+
308
+ #define SPECIALIZED_HC(CODE_SIZE) \
309
+ template<> struct HammingComputer<CODE_SIZE>: \
310
+ HammingComputer ## CODE_SIZE { \
311
+ HammingComputer (const uint8_t *a): \
312
+ HammingComputer ## CODE_SIZE(a, CODE_SIZE) {} \
313
+ }
314
+
315
+ SPECIALIZED_HC(4);
316
+ SPECIALIZED_HC(8);
317
+ SPECIALIZED_HC(16);
318
+ SPECIALIZED_HC(20);
319
+ SPECIALIZED_HC(32);
320
+ SPECIALIZED_HC(64);
321
+
322
+ #undef SPECIALIZED_HC
323
+
324
+
325
+ /***************************************************************************
326
+ * generalized Hamming = number of bytes that are different between
327
+ * two codes.
328
+ ***************************************************************************/
329
+
330
+
331
+ inline int generalized_hamming_64 (uint64_t a) {
332
+ a |= a >> 1;
333
+ a |= a >> 2;
334
+ a |= a >> 4;
335
+ a &= 0x0101010101010101UL;
336
+ return popcount64 (a);
337
+ }
338
+
339
+
340
+ struct GenHammingComputer8 {
341
+ uint64_t a0;
342
+
343
+ GenHammingComputer8 (const uint8_t *a, int code_size) {
344
+ assert (code_size == 8);
345
+ a0 = *(uint64_t *)a;
346
+ }
347
+
348
+ inline int hamming (const uint8_t *b) const {
349
+ return generalized_hamming_64 (*(uint64_t *)b ^ a0);
350
+ }
351
+
352
+ };
353
+
354
+
355
+ struct GenHammingComputer16 {
356
+ uint64_t a0, a1;
357
+ GenHammingComputer16 (const uint8_t *a8, int code_size) {
358
+ assert (code_size == 16);
359
+ const uint64_t *a = (uint64_t *)a8;
360
+ a0 = a[0]; a1 = a[1];
361
+ }
362
+
363
+ inline int hamming (const uint8_t *b8) const {
364
+ const uint64_t *b = (uint64_t *)b8;
365
+ return generalized_hamming_64 (b[0] ^ a0) +
366
+ generalized_hamming_64 (b[1] ^ a1);
367
+ }
368
+
369
+ };
370
+
371
+ struct GenHammingComputer32 {
372
+ uint64_t a0, a1, a2, a3;
373
+
374
+ GenHammingComputer32 (const uint8_t *a8, int code_size) {
375
+ assert (code_size == 32);
376
+ const uint64_t *a = (uint64_t *)a8;
377
+ a0 = a[0]; a1 = a[1]; a2 = a[2]; a3 = a[3];
378
+ }
379
+
380
+ inline int hamming (const uint8_t *b8) const {
381
+ const uint64_t *b = (uint64_t *)b8;
382
+ return generalized_hamming_64 (b[0] ^ a0) +
383
+ generalized_hamming_64 (b[1] ^ a1) +
384
+ generalized_hamming_64 (b[2] ^ a2) +
385
+ generalized_hamming_64 (b[3] ^ a3);
386
+ }
387
+
388
+ };
389
+
390
+ struct GenHammingComputerM8 {
391
+ const uint64_t *a;
392
+ int n;
393
+
394
+ GenHammingComputerM8 (const uint8_t *a8, int code_size) {
395
+ assert (code_size % 8 == 0);
396
+ a = (uint64_t *)a8;
397
+ n = code_size / 8;
398
+ }
399
+
400
+ int hamming (const uint8_t *b8) const {
401
+ const uint64_t *b = (uint64_t *)b8;
402
+ int accu = 0;
403
+ for (int i = 0; i < n; i++)
404
+ accu += generalized_hamming_64 (a[i] ^ b[i]);
405
+ return accu;
406
+ }
407
+
408
+ };
409
+
410
+
411
+ /** generalized Hamming distances (= count number of code bytes that
412
+ are the same) */
413
+ void generalized_hammings_knn_hc (
414
+ int_maxheap_array_t * ha,
415
+ const uint8_t * a,
416
+ const uint8_t * b,
417
+ size_t nb,
418
+ size_t code_size,
419
+ int ordered = true);
420
+
421
+
422
+
423
+ /** This class maintains a list of best distances seen so far.
424
+ *
425
+ * Since the distances are in a limited range (0 to nbit), the
426
+ * object maintains one list per possible distance, and fills
427
+ * in only the n-first lists, such that the sum of sizes of the
428
+ * n lists is below k.
429
+ */
430
+ template<class HammingComputer>
431
+ struct HCounterState {
432
+ int *counters;
433
+ int64_t *ids_per_dis;
434
+
435
+ HammingComputer hc;
436
+ int thres;
437
+ int count_lt;
438
+ int count_eq;
439
+ int k;
440
+
441
+ HCounterState(int *counters, int64_t *ids_per_dis,
442
+ const uint8_t *x, int d, int k)
443
+ : counters(counters),
444
+ ids_per_dis(ids_per_dis),
445
+ hc(x, d / 8),
446
+ thres(d + 1),
447
+ count_lt(0),
448
+ count_eq(0),
449
+ k(k) {}
450
+
451
+ void update_counter(const uint8_t *y, size_t j) {
452
+ int32_t dis = hc.hamming(y);
453
+
454
+ if (dis <= thres) {
455
+ if (dis < thres) {
456
+ ids_per_dis[dis * k + counters[dis]++] = j;
457
+ ++count_lt;
458
+ while (count_lt == k && thres > 0) {
459
+ --thres;
460
+ count_eq = counters[thres];
461
+ count_lt -= count_eq;
462
+ }
463
+ } else if (count_eq < k) {
464
+ ids_per_dis[dis * k + count_eq++] = j;
465
+ counters[dis] = count_eq;
466
+ }
467
+ }
468
+ }
469
+ };
470
+
471
+
472
+ } // namespace faiss