faiss 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +103 -3
- data/ext/faiss/ext.cpp +99 -32
- data/ext/faiss/extconf.rb +12 -2
- data/lib/faiss/ext.bundle +0 -0
- data/lib/faiss/index.rb +3 -3
- data/lib/faiss/index_binary.rb +3 -3
- data/lib/faiss/kmeans.rb +1 -1
- data/lib/faiss/pca_matrix.rb +2 -2
- data/lib/faiss/product_quantizer.rb +3 -3
- data/lib/faiss/version.rb +1 -1
- data/vendor/faiss/AutoTune.cpp +719 -0
- data/vendor/faiss/AutoTune.h +212 -0
- data/vendor/faiss/Clustering.cpp +261 -0
- data/vendor/faiss/Clustering.h +101 -0
- data/vendor/faiss/IVFlib.cpp +339 -0
- data/vendor/faiss/IVFlib.h +132 -0
- data/vendor/faiss/Index.cpp +171 -0
- data/vendor/faiss/Index.h +261 -0
- data/vendor/faiss/Index2Layer.cpp +437 -0
- data/vendor/faiss/Index2Layer.h +85 -0
- data/vendor/faiss/IndexBinary.cpp +77 -0
- data/vendor/faiss/IndexBinary.h +163 -0
- data/vendor/faiss/IndexBinaryFlat.cpp +83 -0
- data/vendor/faiss/IndexBinaryFlat.h +54 -0
- data/vendor/faiss/IndexBinaryFromFloat.cpp +78 -0
- data/vendor/faiss/IndexBinaryFromFloat.h +52 -0
- data/vendor/faiss/IndexBinaryHNSW.cpp +325 -0
- data/vendor/faiss/IndexBinaryHNSW.h +56 -0
- data/vendor/faiss/IndexBinaryIVF.cpp +671 -0
- data/vendor/faiss/IndexBinaryIVF.h +211 -0
- data/vendor/faiss/IndexFlat.cpp +508 -0
- data/vendor/faiss/IndexFlat.h +175 -0
- data/vendor/faiss/IndexHNSW.cpp +1090 -0
- data/vendor/faiss/IndexHNSW.h +170 -0
- data/vendor/faiss/IndexIVF.cpp +909 -0
- data/vendor/faiss/IndexIVF.h +353 -0
- data/vendor/faiss/IndexIVFFlat.cpp +502 -0
- data/vendor/faiss/IndexIVFFlat.h +118 -0
- data/vendor/faiss/IndexIVFPQ.cpp +1207 -0
- data/vendor/faiss/IndexIVFPQ.h +161 -0
- data/vendor/faiss/IndexIVFPQR.cpp +219 -0
- data/vendor/faiss/IndexIVFPQR.h +65 -0
- data/vendor/faiss/IndexIVFSpectralHash.cpp +331 -0
- data/vendor/faiss/IndexIVFSpectralHash.h +75 -0
- data/vendor/faiss/IndexLSH.cpp +225 -0
- data/vendor/faiss/IndexLSH.h +87 -0
- data/vendor/faiss/IndexLattice.cpp +143 -0
- data/vendor/faiss/IndexLattice.h +68 -0
- data/vendor/faiss/IndexPQ.cpp +1188 -0
- data/vendor/faiss/IndexPQ.h +199 -0
- data/vendor/faiss/IndexPreTransform.cpp +288 -0
- data/vendor/faiss/IndexPreTransform.h +91 -0
- data/vendor/faiss/IndexReplicas.cpp +123 -0
- data/vendor/faiss/IndexReplicas.h +76 -0
- data/vendor/faiss/IndexScalarQuantizer.cpp +317 -0
- data/vendor/faiss/IndexScalarQuantizer.h +127 -0
- data/vendor/faiss/IndexShards.cpp +317 -0
- data/vendor/faiss/IndexShards.h +100 -0
- data/vendor/faiss/InvertedLists.cpp +623 -0
- data/vendor/faiss/InvertedLists.h +334 -0
- data/vendor/faiss/LICENSE +21 -0
- data/vendor/faiss/MatrixStats.cpp +252 -0
- data/vendor/faiss/MatrixStats.h +62 -0
- data/vendor/faiss/MetaIndexes.cpp +351 -0
- data/vendor/faiss/MetaIndexes.h +126 -0
- data/vendor/faiss/OnDiskInvertedLists.cpp +674 -0
- data/vendor/faiss/OnDiskInvertedLists.h +127 -0
- data/vendor/faiss/VectorTransform.cpp +1157 -0
- data/vendor/faiss/VectorTransform.h +322 -0
- data/vendor/faiss/c_api/AutoTune_c.cpp +83 -0
- data/vendor/faiss/c_api/AutoTune_c.h +64 -0
- data/vendor/faiss/c_api/Clustering_c.cpp +139 -0
- data/vendor/faiss/c_api/Clustering_c.h +117 -0
- data/vendor/faiss/c_api/IndexFlat_c.cpp +140 -0
- data/vendor/faiss/c_api/IndexFlat_c.h +115 -0
- data/vendor/faiss/c_api/IndexIVFFlat_c.cpp +64 -0
- data/vendor/faiss/c_api/IndexIVFFlat_c.h +58 -0
- data/vendor/faiss/c_api/IndexIVF_c.cpp +92 -0
- data/vendor/faiss/c_api/IndexIVF_c.h +135 -0
- data/vendor/faiss/c_api/IndexLSH_c.cpp +37 -0
- data/vendor/faiss/c_api/IndexLSH_c.h +40 -0
- data/vendor/faiss/c_api/IndexShards_c.cpp +44 -0
- data/vendor/faiss/c_api/IndexShards_c.h +42 -0
- data/vendor/faiss/c_api/Index_c.cpp +105 -0
- data/vendor/faiss/c_api/Index_c.h +183 -0
- data/vendor/faiss/c_api/MetaIndexes_c.cpp +49 -0
- data/vendor/faiss/c_api/MetaIndexes_c.h +49 -0
- data/vendor/faiss/c_api/clone_index_c.cpp +23 -0
- data/vendor/faiss/c_api/clone_index_c.h +32 -0
- data/vendor/faiss/c_api/error_c.h +42 -0
- data/vendor/faiss/c_api/error_impl.cpp +27 -0
- data/vendor/faiss/c_api/error_impl.h +16 -0
- data/vendor/faiss/c_api/faiss_c.h +58 -0
- data/vendor/faiss/c_api/gpu/GpuAutoTune_c.cpp +96 -0
- data/vendor/faiss/c_api/gpu/GpuAutoTune_c.h +56 -0
- data/vendor/faiss/c_api/gpu/GpuClonerOptions_c.cpp +52 -0
- data/vendor/faiss/c_api/gpu/GpuClonerOptions_c.h +68 -0
- data/vendor/faiss/c_api/gpu/GpuIndex_c.cpp +17 -0
- data/vendor/faiss/c_api/gpu/GpuIndex_c.h +30 -0
- data/vendor/faiss/c_api/gpu/GpuIndicesOptions_c.h +38 -0
- data/vendor/faiss/c_api/gpu/GpuResources_c.cpp +86 -0
- data/vendor/faiss/c_api/gpu/GpuResources_c.h +66 -0
- data/vendor/faiss/c_api/gpu/StandardGpuResources_c.cpp +54 -0
- data/vendor/faiss/c_api/gpu/StandardGpuResources_c.h +53 -0
- data/vendor/faiss/c_api/gpu/macros_impl.h +42 -0
- data/vendor/faiss/c_api/impl/AuxIndexStructures_c.cpp +220 -0
- data/vendor/faiss/c_api/impl/AuxIndexStructures_c.h +149 -0
- data/vendor/faiss/c_api/index_factory_c.cpp +26 -0
- data/vendor/faiss/c_api/index_factory_c.h +30 -0
- data/vendor/faiss/c_api/index_io_c.cpp +42 -0
- data/vendor/faiss/c_api/index_io_c.h +50 -0
- data/vendor/faiss/c_api/macros_impl.h +110 -0
- data/vendor/faiss/clone_index.cpp +147 -0
- data/vendor/faiss/clone_index.h +38 -0
- data/vendor/faiss/demos/demo_imi_flat.cpp +151 -0
- data/vendor/faiss/demos/demo_imi_pq.cpp +199 -0
- data/vendor/faiss/demos/demo_ivfpq_indexing.cpp +146 -0
- data/vendor/faiss/demos/demo_sift1M.cpp +252 -0
- data/vendor/faiss/gpu/GpuAutoTune.cpp +95 -0
- data/vendor/faiss/gpu/GpuAutoTune.h +27 -0
- data/vendor/faiss/gpu/GpuCloner.cpp +403 -0
- data/vendor/faiss/gpu/GpuCloner.h +82 -0
- data/vendor/faiss/gpu/GpuClonerOptions.cpp +28 -0
- data/vendor/faiss/gpu/GpuClonerOptions.h +53 -0
- data/vendor/faiss/gpu/GpuDistance.h +52 -0
- data/vendor/faiss/gpu/GpuFaissAssert.h +29 -0
- data/vendor/faiss/gpu/GpuIndex.h +148 -0
- data/vendor/faiss/gpu/GpuIndexBinaryFlat.h +89 -0
- data/vendor/faiss/gpu/GpuIndexFlat.h +190 -0
- data/vendor/faiss/gpu/GpuIndexIVF.h +89 -0
- data/vendor/faiss/gpu/GpuIndexIVFFlat.h +85 -0
- data/vendor/faiss/gpu/GpuIndexIVFPQ.h +143 -0
- data/vendor/faiss/gpu/GpuIndexIVFScalarQuantizer.h +100 -0
- data/vendor/faiss/gpu/GpuIndicesOptions.h +30 -0
- data/vendor/faiss/gpu/GpuResources.cpp +52 -0
- data/vendor/faiss/gpu/GpuResources.h +73 -0
- data/vendor/faiss/gpu/StandardGpuResources.cpp +295 -0
- data/vendor/faiss/gpu/StandardGpuResources.h +114 -0
- data/vendor/faiss/gpu/impl/RemapIndices.cpp +43 -0
- data/vendor/faiss/gpu/impl/RemapIndices.h +24 -0
- data/vendor/faiss/gpu/perf/IndexWrapper-inl.h +71 -0
- data/vendor/faiss/gpu/perf/IndexWrapper.h +39 -0
- data/vendor/faiss/gpu/perf/PerfClustering.cpp +115 -0
- data/vendor/faiss/gpu/perf/PerfIVFPQAdd.cpp +139 -0
- data/vendor/faiss/gpu/perf/WriteIndex.cpp +102 -0
- data/vendor/faiss/gpu/test/TestGpuIndexBinaryFlat.cpp +130 -0
- data/vendor/faiss/gpu/test/TestGpuIndexFlat.cpp +371 -0
- data/vendor/faiss/gpu/test/TestGpuIndexIVFFlat.cpp +550 -0
- data/vendor/faiss/gpu/test/TestGpuIndexIVFPQ.cpp +450 -0
- data/vendor/faiss/gpu/test/TestGpuMemoryException.cpp +84 -0
- data/vendor/faiss/gpu/test/TestUtils.cpp +315 -0
- data/vendor/faiss/gpu/test/TestUtils.h +93 -0
- data/vendor/faiss/gpu/test/demo_ivfpq_indexing_gpu.cpp +159 -0
- data/vendor/faiss/gpu/utils/DeviceMemory.cpp +77 -0
- data/vendor/faiss/gpu/utils/DeviceMemory.h +71 -0
- data/vendor/faiss/gpu/utils/DeviceUtils.h +185 -0
- data/vendor/faiss/gpu/utils/MemorySpace.cpp +89 -0
- data/vendor/faiss/gpu/utils/MemorySpace.h +44 -0
- data/vendor/faiss/gpu/utils/StackDeviceMemory.cpp +239 -0
- data/vendor/faiss/gpu/utils/StackDeviceMemory.h +129 -0
- data/vendor/faiss/gpu/utils/StaticUtils.h +83 -0
- data/vendor/faiss/gpu/utils/Timer.cpp +60 -0
- data/vendor/faiss/gpu/utils/Timer.h +52 -0
- data/vendor/faiss/impl/AuxIndexStructures.cpp +305 -0
- data/vendor/faiss/impl/AuxIndexStructures.h +246 -0
- data/vendor/faiss/impl/FaissAssert.h +95 -0
- data/vendor/faiss/impl/FaissException.cpp +66 -0
- data/vendor/faiss/impl/FaissException.h +71 -0
- data/vendor/faiss/impl/HNSW.cpp +818 -0
- data/vendor/faiss/impl/HNSW.h +275 -0
- data/vendor/faiss/impl/PolysemousTraining.cpp +953 -0
- data/vendor/faiss/impl/PolysemousTraining.h +158 -0
- data/vendor/faiss/impl/ProductQuantizer.cpp +876 -0
- data/vendor/faiss/impl/ProductQuantizer.h +242 -0
- data/vendor/faiss/impl/ScalarQuantizer.cpp +1628 -0
- data/vendor/faiss/impl/ScalarQuantizer.h +120 -0
- data/vendor/faiss/impl/ThreadedIndex-inl.h +192 -0
- data/vendor/faiss/impl/ThreadedIndex.h +80 -0
- data/vendor/faiss/impl/index_read.cpp +793 -0
- data/vendor/faiss/impl/index_write.cpp +558 -0
- data/vendor/faiss/impl/io.cpp +142 -0
- data/vendor/faiss/impl/io.h +98 -0
- data/vendor/faiss/impl/lattice_Zn.cpp +712 -0
- data/vendor/faiss/impl/lattice_Zn.h +199 -0
- data/vendor/faiss/index_factory.cpp +392 -0
- data/vendor/faiss/index_factory.h +25 -0
- data/vendor/faiss/index_io.h +75 -0
- data/vendor/faiss/misc/test_blas.cpp +84 -0
- data/vendor/faiss/tests/test_binary_flat.cpp +64 -0
- data/vendor/faiss/tests/test_dealloc_invlists.cpp +183 -0
- data/vendor/faiss/tests/test_ivfpq_codec.cpp +67 -0
- data/vendor/faiss/tests/test_ivfpq_indexing.cpp +98 -0
- data/vendor/faiss/tests/test_lowlevel_ivf.cpp +566 -0
- data/vendor/faiss/tests/test_merge.cpp +258 -0
- data/vendor/faiss/tests/test_omp_threads.cpp +14 -0
- data/vendor/faiss/tests/test_ondisk_ivf.cpp +220 -0
- data/vendor/faiss/tests/test_pairs_decoding.cpp +189 -0
- data/vendor/faiss/tests/test_params_override.cpp +231 -0
- data/vendor/faiss/tests/test_pq_encoding.cpp +98 -0
- data/vendor/faiss/tests/test_sliding_ivf.cpp +240 -0
- data/vendor/faiss/tests/test_threaded_index.cpp +253 -0
- data/vendor/faiss/tests/test_transfer_invlists.cpp +159 -0
- data/vendor/faiss/tutorial/cpp/1-Flat.cpp +98 -0
- data/vendor/faiss/tutorial/cpp/2-IVFFlat.cpp +81 -0
- data/vendor/faiss/tutorial/cpp/3-IVFPQ.cpp +93 -0
- data/vendor/faiss/tutorial/cpp/4-GPU.cpp +119 -0
- data/vendor/faiss/tutorial/cpp/5-Multiple-GPUs.cpp +99 -0
- data/vendor/faiss/utils/Heap.cpp +122 -0
- data/vendor/faiss/utils/Heap.h +495 -0
- data/vendor/faiss/utils/WorkerThread.cpp +126 -0
- data/vendor/faiss/utils/WorkerThread.h +61 -0
- data/vendor/faiss/utils/distances.cpp +765 -0
- data/vendor/faiss/utils/distances.h +243 -0
- data/vendor/faiss/utils/distances_simd.cpp +809 -0
- data/vendor/faiss/utils/extra_distances.cpp +336 -0
- data/vendor/faiss/utils/extra_distances.h +54 -0
- data/vendor/faiss/utils/hamming-inl.h +472 -0
- data/vendor/faiss/utils/hamming.cpp +792 -0
- data/vendor/faiss/utils/hamming.h +220 -0
- data/vendor/faiss/utils/random.cpp +192 -0
- data/vendor/faiss/utils/random.h +60 -0
- data/vendor/faiss/utils/utils.cpp +783 -0
- data/vendor/faiss/utils/utils.h +181 -0
- 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
|