faiss 0.1.3 → 0.2.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 (199) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -0
  3. data/LICENSE.txt +1 -1
  4. data/README.md +16 -4
  5. data/ext/faiss/ext.cpp +12 -308
  6. data/ext/faiss/extconf.rb +6 -3
  7. data/ext/faiss/index.cpp +189 -0
  8. data/ext/faiss/index_binary.cpp +75 -0
  9. data/ext/faiss/kmeans.cpp +40 -0
  10. data/ext/faiss/numo.hpp +867 -0
  11. data/ext/faiss/pca_matrix.cpp +33 -0
  12. data/ext/faiss/product_quantizer.cpp +53 -0
  13. data/ext/faiss/utils.cpp +13 -0
  14. data/ext/faiss/utils.h +5 -0
  15. data/lib/faiss.rb +0 -5
  16. data/lib/faiss/version.rb +1 -1
  17. data/vendor/faiss/faiss/AutoTune.cpp +36 -33
  18. data/vendor/faiss/faiss/AutoTune.h +6 -3
  19. data/vendor/faiss/faiss/Clustering.cpp +16 -12
  20. data/vendor/faiss/faiss/Index.cpp +3 -4
  21. data/vendor/faiss/faiss/Index.h +3 -3
  22. data/vendor/faiss/faiss/IndexBinary.cpp +3 -4
  23. data/vendor/faiss/faiss/IndexBinary.h +1 -1
  24. data/vendor/faiss/faiss/IndexBinaryHash.cpp +2 -12
  25. data/vendor/faiss/faiss/IndexBinaryIVF.cpp +1 -2
  26. data/vendor/faiss/faiss/IndexFlat.cpp +0 -148
  27. data/vendor/faiss/faiss/IndexFlat.h +0 -51
  28. data/vendor/faiss/faiss/IndexHNSW.cpp +4 -5
  29. data/vendor/faiss/faiss/IndexIVF.cpp +118 -31
  30. data/vendor/faiss/faiss/IndexIVF.h +22 -15
  31. data/vendor/faiss/faiss/IndexIVFFlat.cpp +3 -3
  32. data/vendor/faiss/faiss/IndexIVFFlat.h +2 -1
  33. data/vendor/faiss/faiss/IndexIVFPQ.cpp +39 -15
  34. data/vendor/faiss/faiss/IndexIVFPQ.h +25 -9
  35. data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +1116 -0
  36. data/vendor/faiss/faiss/IndexIVFPQFastScan.h +166 -0
  37. data/vendor/faiss/faiss/IndexIVFPQR.cpp +8 -9
  38. data/vendor/faiss/faiss/IndexIVFPQR.h +2 -1
  39. data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +1 -2
  40. data/vendor/faiss/faiss/IndexPQ.cpp +34 -18
  41. data/vendor/faiss/faiss/IndexPQFastScan.cpp +536 -0
  42. data/vendor/faiss/faiss/IndexPQFastScan.h +111 -0
  43. data/vendor/faiss/faiss/IndexPreTransform.cpp +47 -0
  44. data/vendor/faiss/faiss/IndexPreTransform.h +2 -0
  45. data/vendor/faiss/faiss/IndexRefine.cpp +256 -0
  46. data/vendor/faiss/faiss/IndexRefine.h +73 -0
  47. data/vendor/faiss/faiss/IndexScalarQuantizer.cpp +2 -2
  48. data/vendor/faiss/faiss/IndexScalarQuantizer.h +1 -1
  49. data/vendor/faiss/faiss/gpu/GpuDistance.h +1 -1
  50. data/vendor/faiss/faiss/gpu/GpuIndex.h +16 -9
  51. data/vendor/faiss/faiss/gpu/GpuIndexBinaryFlat.h +8 -1
  52. data/vendor/faiss/faiss/gpu/GpuIndexFlat.h +11 -11
  53. data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +19 -2
  54. data/vendor/faiss/faiss/gpu/GpuIndexIVFFlat.h +28 -2
  55. data/vendor/faiss/faiss/gpu/GpuIndexIVFPQ.h +24 -14
  56. data/vendor/faiss/faiss/gpu/GpuIndexIVFScalarQuantizer.h +29 -2
  57. data/vendor/faiss/faiss/gpu/GpuResources.h +4 -0
  58. data/vendor/faiss/faiss/gpu/StandardGpuResources.cpp +60 -27
  59. data/vendor/faiss/faiss/gpu/StandardGpuResources.h +28 -6
  60. data/vendor/faiss/faiss/gpu/impl/InterleavedCodes.cpp +547 -0
  61. data/vendor/faiss/faiss/gpu/impl/InterleavedCodes.h +51 -0
  62. data/vendor/faiss/faiss/gpu/impl/RemapIndices.cpp +3 -3
  63. data/vendor/faiss/faiss/gpu/impl/RemapIndices.h +3 -2
  64. data/vendor/faiss/faiss/gpu/test/TestCodePacking.cpp +274 -0
  65. data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFFlat.cpp +7 -2
  66. data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFPQ.cpp +5 -1
  67. data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFScalarQuantizer.cpp +231 -0
  68. data/vendor/faiss/faiss/gpu/test/TestUtils.h +33 -0
  69. data/vendor/faiss/faiss/gpu/utils/StackDeviceMemory.cpp +1 -0
  70. data/vendor/faiss/faiss/gpu/utils/StaticUtils.h +6 -0
  71. data/vendor/faiss/faiss/gpu/utils/Timer.cpp +5 -6
  72. data/vendor/faiss/faiss/gpu/utils/Timer.h +2 -2
  73. data/vendor/faiss/faiss/impl/AuxIndexStructures.h +5 -4
  74. data/vendor/faiss/faiss/impl/HNSW.cpp +2 -4
  75. data/vendor/faiss/faiss/impl/PolysemousTraining.h +4 -4
  76. data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +22 -12
  77. data/vendor/faiss/faiss/impl/ProductQuantizer.h +2 -0
  78. data/vendor/faiss/faiss/impl/ResultHandler.h +452 -0
  79. data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +29 -19
  80. data/vendor/faiss/faiss/impl/ScalarQuantizer.h +6 -0
  81. data/vendor/faiss/faiss/impl/index_read.cpp +64 -96
  82. data/vendor/faiss/faiss/impl/index_write.cpp +34 -25
  83. data/vendor/faiss/faiss/impl/io.cpp +33 -2
  84. data/vendor/faiss/faiss/impl/io.h +7 -2
  85. data/vendor/faiss/faiss/impl/lattice_Zn.cpp +1 -15
  86. data/vendor/faiss/faiss/impl/platform_macros.h +44 -0
  87. data/vendor/faiss/faiss/impl/pq4_fast_scan.cpp +272 -0
  88. data/vendor/faiss/faiss/impl/pq4_fast_scan.h +169 -0
  89. data/vendor/faiss/faiss/impl/pq4_fast_scan_search_1.cpp +180 -0
  90. data/vendor/faiss/faiss/impl/pq4_fast_scan_search_qbs.cpp +354 -0
  91. data/vendor/faiss/faiss/impl/simd_result_handlers.h +559 -0
  92. data/vendor/faiss/faiss/index_factory.cpp +112 -7
  93. data/vendor/faiss/faiss/index_io.h +1 -48
  94. data/vendor/faiss/faiss/invlists/BlockInvertedLists.cpp +151 -0
  95. data/vendor/faiss/faiss/invlists/BlockInvertedLists.h +76 -0
  96. data/vendor/faiss/faiss/{DirectMap.cpp → invlists/DirectMap.cpp} +1 -1
  97. data/vendor/faiss/faiss/{DirectMap.h → invlists/DirectMap.h} +1 -1
  98. data/vendor/faiss/faiss/{InvertedLists.cpp → invlists/InvertedLists.cpp} +72 -1
  99. data/vendor/faiss/faiss/{InvertedLists.h → invlists/InvertedLists.h} +32 -1
  100. data/vendor/faiss/faiss/invlists/InvertedListsIOHook.cpp +107 -0
  101. data/vendor/faiss/faiss/invlists/InvertedListsIOHook.h +63 -0
  102. data/vendor/faiss/faiss/{OnDiskInvertedLists.cpp → invlists/OnDiskInvertedLists.cpp} +21 -6
  103. data/vendor/faiss/faiss/{OnDiskInvertedLists.h → invlists/OnDiskInvertedLists.h} +5 -2
  104. data/vendor/faiss/faiss/python/python_callbacks.h +8 -1
  105. data/vendor/faiss/faiss/utils/AlignedTable.h +141 -0
  106. data/vendor/faiss/faiss/utils/Heap.cpp +2 -4
  107. data/vendor/faiss/faiss/utils/Heap.h +61 -50
  108. data/vendor/faiss/faiss/utils/distances.cpp +164 -319
  109. data/vendor/faiss/faiss/utils/distances.h +28 -20
  110. data/vendor/faiss/faiss/utils/distances_simd.cpp +277 -49
  111. data/vendor/faiss/faiss/utils/extra_distances.cpp +1 -2
  112. data/vendor/faiss/faiss/utils/hamming-inl.h +4 -4
  113. data/vendor/faiss/faiss/utils/hamming.cpp +3 -6
  114. data/vendor/faiss/faiss/utils/hamming.h +2 -7
  115. data/vendor/faiss/faiss/utils/ordered_key_value.h +98 -0
  116. data/vendor/faiss/faiss/utils/partitioning.cpp +1256 -0
  117. data/vendor/faiss/faiss/utils/partitioning.h +69 -0
  118. data/vendor/faiss/faiss/utils/quantize_lut.cpp +277 -0
  119. data/vendor/faiss/faiss/utils/quantize_lut.h +80 -0
  120. data/vendor/faiss/faiss/utils/simdlib.h +31 -0
  121. data/vendor/faiss/faiss/utils/simdlib_avx2.h +461 -0
  122. data/vendor/faiss/faiss/utils/simdlib_emulated.h +589 -0
  123. metadata +54 -149
  124. data/lib/faiss/index.rb +0 -20
  125. data/lib/faiss/index_binary.rb +0 -20
  126. data/lib/faiss/kmeans.rb +0 -15
  127. data/lib/faiss/pca_matrix.rb +0 -15
  128. data/lib/faiss/product_quantizer.rb +0 -22
  129. data/vendor/faiss/benchs/bench_6bit_codec.cpp +0 -80
  130. data/vendor/faiss/c_api/AutoTune_c.cpp +0 -83
  131. data/vendor/faiss/c_api/AutoTune_c.h +0 -66
  132. data/vendor/faiss/c_api/Clustering_c.cpp +0 -145
  133. data/vendor/faiss/c_api/Clustering_c.h +0 -123
  134. data/vendor/faiss/c_api/IndexFlat_c.cpp +0 -140
  135. data/vendor/faiss/c_api/IndexFlat_c.h +0 -115
  136. data/vendor/faiss/c_api/IndexIVFFlat_c.cpp +0 -64
  137. data/vendor/faiss/c_api/IndexIVFFlat_c.h +0 -58
  138. data/vendor/faiss/c_api/IndexIVF_c.cpp +0 -99
  139. data/vendor/faiss/c_api/IndexIVF_c.h +0 -142
  140. data/vendor/faiss/c_api/IndexLSH_c.cpp +0 -37
  141. data/vendor/faiss/c_api/IndexLSH_c.h +0 -40
  142. data/vendor/faiss/c_api/IndexPreTransform_c.cpp +0 -21
  143. data/vendor/faiss/c_api/IndexPreTransform_c.h +0 -32
  144. data/vendor/faiss/c_api/IndexShards_c.cpp +0 -38
  145. data/vendor/faiss/c_api/IndexShards_c.h +0 -39
  146. data/vendor/faiss/c_api/Index_c.cpp +0 -105
  147. data/vendor/faiss/c_api/Index_c.h +0 -183
  148. data/vendor/faiss/c_api/MetaIndexes_c.cpp +0 -49
  149. data/vendor/faiss/c_api/MetaIndexes_c.h +0 -49
  150. data/vendor/faiss/c_api/clone_index_c.cpp +0 -23
  151. data/vendor/faiss/c_api/clone_index_c.h +0 -32
  152. data/vendor/faiss/c_api/error_c.h +0 -42
  153. data/vendor/faiss/c_api/error_impl.cpp +0 -27
  154. data/vendor/faiss/c_api/error_impl.h +0 -16
  155. data/vendor/faiss/c_api/faiss_c.h +0 -58
  156. data/vendor/faiss/c_api/gpu/GpuAutoTune_c.cpp +0 -98
  157. data/vendor/faiss/c_api/gpu/GpuAutoTune_c.h +0 -56
  158. data/vendor/faiss/c_api/gpu/GpuClonerOptions_c.cpp +0 -52
  159. data/vendor/faiss/c_api/gpu/GpuClonerOptions_c.h +0 -68
  160. data/vendor/faiss/c_api/gpu/GpuIndex_c.cpp +0 -17
  161. data/vendor/faiss/c_api/gpu/GpuIndex_c.h +0 -30
  162. data/vendor/faiss/c_api/gpu/GpuIndicesOptions_c.h +0 -38
  163. data/vendor/faiss/c_api/gpu/GpuResources_c.cpp +0 -86
  164. data/vendor/faiss/c_api/gpu/GpuResources_c.h +0 -66
  165. data/vendor/faiss/c_api/gpu/StandardGpuResources_c.cpp +0 -54
  166. data/vendor/faiss/c_api/gpu/StandardGpuResources_c.h +0 -53
  167. data/vendor/faiss/c_api/gpu/macros_impl.h +0 -42
  168. data/vendor/faiss/c_api/impl/AuxIndexStructures_c.cpp +0 -220
  169. data/vendor/faiss/c_api/impl/AuxIndexStructures_c.h +0 -149
  170. data/vendor/faiss/c_api/index_factory_c.cpp +0 -26
  171. data/vendor/faiss/c_api/index_factory_c.h +0 -30
  172. data/vendor/faiss/c_api/index_io_c.cpp +0 -42
  173. data/vendor/faiss/c_api/index_io_c.h +0 -50
  174. data/vendor/faiss/c_api/macros_impl.h +0 -110
  175. data/vendor/faiss/demos/demo_imi_flat.cpp +0 -154
  176. data/vendor/faiss/demos/demo_imi_pq.cpp +0 -203
  177. data/vendor/faiss/demos/demo_ivfpq_indexing.cpp +0 -151
  178. data/vendor/faiss/demos/demo_sift1M.cpp +0 -252
  179. data/vendor/faiss/demos/demo_weighted_kmeans.cpp +0 -185
  180. data/vendor/faiss/misc/test_blas.cpp +0 -87
  181. data/vendor/faiss/tests/test_binary_flat.cpp +0 -62
  182. data/vendor/faiss/tests/test_dealloc_invlists.cpp +0 -188
  183. data/vendor/faiss/tests/test_ivfpq_codec.cpp +0 -70
  184. data/vendor/faiss/tests/test_ivfpq_indexing.cpp +0 -100
  185. data/vendor/faiss/tests/test_lowlevel_ivf.cpp +0 -573
  186. data/vendor/faiss/tests/test_merge.cpp +0 -260
  187. data/vendor/faiss/tests/test_omp_threads.cpp +0 -14
  188. data/vendor/faiss/tests/test_ondisk_ivf.cpp +0 -225
  189. data/vendor/faiss/tests/test_pairs_decoding.cpp +0 -193
  190. data/vendor/faiss/tests/test_params_override.cpp +0 -236
  191. data/vendor/faiss/tests/test_pq_encoding.cpp +0 -98
  192. data/vendor/faiss/tests/test_sliding_ivf.cpp +0 -246
  193. data/vendor/faiss/tests/test_threaded_index.cpp +0 -253
  194. data/vendor/faiss/tests/test_transfer_invlists.cpp +0 -159
  195. data/vendor/faiss/tutorial/cpp/1-Flat.cpp +0 -104
  196. data/vendor/faiss/tutorial/cpp/2-IVFFlat.cpp +0 -85
  197. data/vendor/faiss/tutorial/cpp/3-IVFPQ.cpp +0 -98
  198. data/vendor/faiss/tutorial/cpp/4-GPU.cpp +0 -122
  199. data/vendor/faiss/tutorial/cpp/5-Multiple-GPUs.cpp +0 -104
@@ -0,0 +1,180 @@
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
+ #include <faiss/impl/pq4_fast_scan.h>
10
+
11
+ #include <faiss/impl/FaissAssert.h>
12
+ #include <faiss/impl/simd_result_handlers.h>
13
+
14
+
15
+ namespace faiss {
16
+
17
+
18
+ using namespace simd_result_handlers;
19
+
20
+ /***************************************************************
21
+ * accumulation functions
22
+ ***************************************************************/
23
+
24
+ namespace {
25
+
26
+ /*
27
+ * The computation kernel
28
+ * It accumulates results for NQ queries and BB * 32 database elements
29
+ * writes results in a ResultHandler
30
+ */
31
+
32
+ template<int NQ, int BB, class ResultHandler>
33
+ void kernel_accumulate_block(
34
+ int nsq,
35
+ const uint8_t *codes,
36
+ const uint8_t *LUT,
37
+ ResultHandler & res)
38
+ {
39
+ // distance accumulators
40
+ simd16uint16 accu[NQ][BB][4];
41
+
42
+ for(int q = 0; q < NQ; q++) {
43
+ for(int b = 0; b < BB; b++) {
44
+ accu[q][b][0].clear();
45
+ accu[q][b][1].clear();
46
+ accu[q][b][2].clear();
47
+ accu[q][b][3].clear();
48
+ }
49
+ }
50
+
51
+ for(int sq = 0; sq < nsq; sq += 2) {
52
+ simd32uint8 lut_cache[NQ];
53
+ for(int q = 0; q < NQ; q++) {
54
+ lut_cache[q] = simd32uint8(LUT);
55
+ LUT += 32;
56
+ }
57
+
58
+ for (int b = 0; b < BB; b++) {
59
+ simd32uint8 c = simd32uint8(codes);
60
+ codes += 32;
61
+ simd32uint8 mask(15);
62
+ simd32uint8 chi = simd32uint8(simd16uint16(c) >> 4) & mask;
63
+ simd32uint8 clo = c & mask;
64
+
65
+ for(int q = 0; q < NQ; q++) {
66
+ simd32uint8 lut = lut_cache[q];
67
+ simd32uint8 res0 = lut.lookup_2_lanes(clo);
68
+ simd32uint8 res1 = lut.lookup_2_lanes(chi);
69
+
70
+ accu[q][b][0] += simd16uint16(res0);
71
+ accu[q][b][1] += simd16uint16(res0) >> 8;
72
+
73
+ accu[q][b][2] += simd16uint16(res1);
74
+ accu[q][b][3] += simd16uint16(res1) >> 8;
75
+ }
76
+ }
77
+ }
78
+
79
+ for(int q = 0; q < NQ; q++) {
80
+ for (int b = 0; b < BB; b++) {
81
+
82
+ accu[q][b][0] -= accu[q][b][1] << 8;
83
+ simd16uint16 dis0 = combine2x2(accu[q][b][0], accu[q][b][1]);
84
+
85
+ accu[q][b][2] -= accu[q][b][3] << 8;
86
+ simd16uint16 dis1 = combine2x2(accu[q][b][2], accu[q][b][3]);
87
+
88
+ res.handle(q, b, dis0, dis1);
89
+ }
90
+ }
91
+
92
+
93
+ }
94
+
95
+
96
+ template<int NQ, int BB, class ResultHandler>
97
+ void accumulate_fixed_blocks(
98
+ size_t nb,
99
+ int nsq,
100
+ const uint8_t *codes,
101
+ const uint8_t *LUT,
102
+ ResultHandler & res)
103
+ {
104
+ constexpr int bbs = 32 * BB;
105
+ for (int64_t j0 = 0; j0 < nb; j0 += bbs) {
106
+ FixedStorageHandler<NQ, 2 * BB> res2;
107
+ kernel_accumulate_block<NQ, BB>(nsq, codes, LUT, res2);
108
+ res.set_block_origin(0, j0);
109
+ res2.to_other_handler(res);
110
+ codes += bbs * nsq / 2;
111
+ }
112
+ }
113
+
114
+
115
+ } // anonymous namespace
116
+
117
+ template<class ResultHandler>
118
+ void pq4_accumulate_loop(
119
+ int nq,
120
+ size_t nb, int bbs,
121
+ int nsq,
122
+ const uint8_t *codes,
123
+ const uint8_t *LUT,
124
+ ResultHandler & res)
125
+ {
126
+ FAISS_THROW_IF_NOT(is_aligned_pointer(codes));
127
+ FAISS_THROW_IF_NOT(is_aligned_pointer(LUT));
128
+ FAISS_THROW_IF_NOT(bbs % 32 == 0);
129
+ FAISS_THROW_IF_NOT(nb % bbs == 0);
130
+
131
+ #define DISPATCH(NQ, BB) \
132
+ case NQ * 1000 + BB: \
133
+ accumulate_fixed_blocks<NQ, BB>(nb, nsq, codes, LUT, res); \
134
+ break
135
+
136
+ switch(nq * 1000 + bbs / 32) {
137
+ DISPATCH(1, 1);
138
+ DISPATCH(1, 2);
139
+ DISPATCH(1, 3);
140
+ DISPATCH(1, 4);
141
+ DISPATCH(1, 5);
142
+ DISPATCH(2, 1);
143
+ DISPATCH(2, 2);
144
+ DISPATCH(3, 1);
145
+ DISPATCH(4, 1);
146
+ default:
147
+ FAISS_THROW_FMT("nq=%d bbs=%d not instantiated", nq, bbs);
148
+ }
149
+ #undef DISPATCH
150
+
151
+ }
152
+
153
+ // explicit template instantiations
154
+
155
+
156
+
157
+
158
+ #define INSTANTIATE_ACCUMULATE(TH, C, with_id_map) \
159
+ template void pq4_accumulate_loop<TH<C, with_id_map>> \
160
+ (int, size_t, int, int, const uint8_t *, const uint8_t *, TH<C, with_id_map> &);
161
+
162
+ #define INSTANTIATE_3(C, with_id_map) \
163
+ INSTANTIATE_ACCUMULATE(SingleResultHandler, C, with_id_map) \
164
+ INSTANTIATE_ACCUMULATE(HeapHandler, C, with_id_map) \
165
+ INSTANTIATE_ACCUMULATE(ReservoirHandler, C, with_id_map) \
166
+
167
+ using Csi = CMax<uint16_t, int>;
168
+ INSTANTIATE_3(Csi, false);
169
+ using CsiMin = CMin<uint16_t, int>;
170
+ INSTANTIATE_3(CsiMin, false);
171
+
172
+ using Csl = CMax<uint16_t, int64_t>;
173
+ INSTANTIATE_3(Csl, true);
174
+ using CslMin = CMin<uint16_t, int64_t>;
175
+ INSTANTIATE_3(CslMin, true);
176
+
177
+
178
+
179
+ } // namespace faiss
180
+
@@ -0,0 +1,354 @@
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
+ #include <faiss/impl/pq4_fast_scan.h>
9
+
10
+ #include <faiss/impl/FaissAssert.h>
11
+ #include <faiss/utils/simdlib.h>
12
+ #include <faiss/impl/simd_result_handlers.h>
13
+
14
+
15
+ namespace faiss {
16
+
17
+
18
+ using namespace simd_result_handlers;
19
+
20
+ /************************************************************
21
+ * Accumulation functions
22
+ ************************************************************/
23
+
24
+ namespace {
25
+
26
+ /*
27
+ * The computation kernel
28
+ * It accumulates results for NQ queries and 2 * 16 database elements
29
+ * writes results in a ResultHandler
30
+ */
31
+
32
+ template<int NQ, class ResultHandler>
33
+ void kernel_accumulate_block(
34
+ int nsq,
35
+ const uint8_t *codes,
36
+ const uint8_t *LUT,
37
+ ResultHandler & res)
38
+ {
39
+ // dummy alloc to keep the windows compiler happy
40
+ constexpr int NQA = NQ > 0 ? NQ : 1;
41
+ // distance accumulators
42
+ simd16uint16 accu[NQA][4];
43
+
44
+ for(int q = 0; q < NQ; q++) {
45
+ for(int b = 0; b < 4; b++) {
46
+ accu[q][b].clear();
47
+ }
48
+ }
49
+
50
+ // _mm_prefetch(codes + 768, 0);
51
+ for(int sq = 0; sq < nsq; sq += 2) {
52
+
53
+ // prefetch
54
+ simd32uint8 c(codes);
55
+ codes += 32;
56
+
57
+ simd32uint8 mask(0xf);
58
+ // shift op does not exist for int8...
59
+ simd32uint8 chi = simd32uint8(simd16uint16(c) >> 4) & mask;
60
+ simd32uint8 clo = c & mask;
61
+
62
+ for(int q = 0; q < NQ; q++) {
63
+ // load LUTs for 2 quantizers
64
+ simd32uint8 lut(LUT);
65
+ LUT += 32;
66
+
67
+ simd32uint8 res0 = lut.lookup_2_lanes(clo);
68
+ simd32uint8 res1 = lut.lookup_2_lanes(chi);
69
+
70
+ accu[q][0] += simd16uint16(res0);
71
+ accu[q][1] += simd16uint16(res0) >> 8;
72
+
73
+ accu[q][2] += simd16uint16(res1);
74
+ accu[q][3] += simd16uint16(res1) >> 8;
75
+ }
76
+ }
77
+
78
+ for(int q = 0; q < NQ; q++) {
79
+ accu[q][0] -= accu[q][1] << 8;
80
+ simd16uint16 dis0 = combine2x2(accu[q][0], accu[q][1]);
81
+ accu[q][2] -= accu[q][3] << 8;
82
+ simd16uint16 dis1 = combine2x2(accu[q][2], accu[q][3]);
83
+ res.handle(q, 0, dis0, dis1);
84
+ }
85
+
86
+ }
87
+
88
+ // handle at most 4 blocks of queries
89
+ template<int QBS, class ResultHandler>
90
+ void accumulate_q_4step(
91
+ size_t ntotal2,
92
+ int nsq,
93
+ const uint8_t *codes,
94
+ const uint8_t *LUT0,
95
+ ResultHandler & res)
96
+ {
97
+
98
+ constexpr int Q1 = QBS & 15;
99
+ constexpr int Q2 = (QBS >> 4) & 15;
100
+ constexpr int Q3 = (QBS >> 8) & 15;
101
+ constexpr int Q4 = (QBS >> 12) & 15;
102
+ constexpr int SQ = Q1 + Q2 + Q3 + Q4;
103
+
104
+ for (int64_t j0 = 0; j0 < ntotal2; j0 += 32) {
105
+ FixedStorageHandler<SQ, 2> res2;
106
+ const uint8_t *LUT = LUT0;
107
+ kernel_accumulate_block<Q1>(nsq, codes, LUT, res2);
108
+ LUT += Q1 * nsq * 16;
109
+ if (Q2 > 0) {
110
+ res2.set_block_origin(Q1, 0);
111
+ kernel_accumulate_block<Q2>(nsq, codes, LUT, res2);
112
+ LUT += Q2 * nsq * 16;
113
+ }
114
+ if (Q3 > 0) {
115
+ res2.set_block_origin(Q1 + Q2, 0);
116
+ kernel_accumulate_block<Q3>(nsq, codes, LUT, res2);
117
+ LUT += Q3 * nsq * 16;
118
+ }
119
+ if (Q4 > 0) {
120
+ res2.set_block_origin(Q1 + Q2 + Q3, 0);
121
+ kernel_accumulate_block<Q4>(nsq, codes, LUT, res2);
122
+ }
123
+ res.set_block_origin(0, j0);
124
+ res2.to_other_handler(res);
125
+ codes += 32 * nsq / 2;
126
+ }
127
+ }
128
+
129
+
130
+
131
+
132
+ template<int NQ, class ResultHandler>
133
+ void kernel_accumulate_block_loop(
134
+ size_t ntotal2,
135
+ int nsq,
136
+ const uint8_t *codes,
137
+ const uint8_t *LUT,
138
+ ResultHandler & res)
139
+ {
140
+
141
+ for (int64_t j0 = 0; j0 < ntotal2; j0 += 32) {
142
+ res.set_block_origin(0, j0);
143
+ kernel_accumulate_block<NQ, ResultHandler>
144
+ (nsq, codes + j0 * nsq / 2, LUT, res);
145
+ }
146
+
147
+ }
148
+
149
+ // non-template version of accumulate kernel -- dispatches dynamically
150
+ template<class ResultHandler>
151
+ void accumulate(
152
+ int nq,
153
+ size_t ntotal2,
154
+ int nsq,
155
+ const uint8_t *codes,
156
+ const uint8_t *LUT,
157
+ ResultHandler & res)
158
+ {
159
+
160
+ assert(nsq % 2 == 0);
161
+ assert(is_aligned_pointer(codes));
162
+ assert(is_aligned_pointer(LUT));
163
+
164
+ #define DISPATCH(NQ) \
165
+ case NQ: \
166
+ kernel_accumulate_block_loop<NQ, ResultHandler> \
167
+ (ntotal2, nsq, codes, LUT, res); \
168
+ return
169
+
170
+ switch(nq) {
171
+ DISPATCH(1);
172
+ DISPATCH(2);
173
+ DISPATCH(3);
174
+ DISPATCH(4);
175
+ }
176
+ FAISS_THROW_FMT("accumulate nq=%d not instanciated",
177
+ nq);
178
+
179
+ #undef DISPATCH
180
+ }
181
+
182
+
183
+ } // anonumous namespace
184
+
185
+
186
+
187
+ template<class ResultHandler>
188
+ void pq4_accumulate_loop_qbs(
189
+ int qbs,
190
+ size_t ntotal2,
191
+ int nsq,
192
+ const uint8_t *codes,
193
+ const uint8_t *LUT0,
194
+ ResultHandler & res)
195
+ {
196
+
197
+ assert(nsq % 2 == 0);
198
+ assert(is_aligned_pointer(codes));
199
+ assert(is_aligned_pointer(LUT0));
200
+
201
+ // try out optimized versions
202
+ switch(qbs) {
203
+ #define DISPATCH(QBS) \
204
+ case QBS: accumulate_q_4step<QBS> \
205
+ (ntotal2, nsq, codes, LUT0, res); \
206
+ return;
207
+ DISPATCH(0x3333); // 12
208
+ DISPATCH(0x2333); // 11
209
+ DISPATCH(0x2233); // 10
210
+ DISPATCH(0x333); // 9
211
+ DISPATCH(0x2223); // 9
212
+ DISPATCH(0x233); // 8
213
+ DISPATCH(0x1223); // 8
214
+ DISPATCH(0x223); // 7
215
+ DISPATCH(0x34); // 7
216
+ DISPATCH(0x133); // 7
217
+ DISPATCH(0x6); // 6
218
+ DISPATCH(0x33); // 6
219
+ DISPATCH(0x123); // 6
220
+ DISPATCH(0x222); // 6
221
+ DISPATCH(0x23); // 5
222
+ DISPATCH(0x5); // 5
223
+ DISPATCH(0x13); // 4
224
+ DISPATCH(0x22); // 4
225
+ DISPATCH(0x4); // 4
226
+ DISPATCH(0x3); // 3
227
+ DISPATCH(0x21); // 3
228
+ DISPATCH(0x2); // 2
229
+ DISPATCH(0x1); // 1
230
+ #undef DISPATCH
231
+ }
232
+
233
+ // default implementation where qbs is not known at compile time
234
+
235
+ for (int64_t j0 = 0; j0 < ntotal2; j0 += 32) {
236
+ const uint8_t *LUT = LUT0;
237
+ int qi = qbs;
238
+ int i0 = 0;
239
+ while(qi) {
240
+ int nq = qi & 15;
241
+ qi >>= 4;
242
+ res.set_block_origin(i0, j0);
243
+ #define DISPATCH(NQ) \
244
+ case NQ: \
245
+ kernel_accumulate_block<NQ, ResultHandler> \
246
+ (nsq, codes, LUT, res); \
247
+ break
248
+ switch(nq) {
249
+ DISPATCH(1);
250
+ DISPATCH(2);
251
+ DISPATCH(3);
252
+ DISPATCH(4);
253
+ #undef DISPATCH
254
+ default:
255
+ FAISS_THROW_FMT("accumulate nq=%d not instanciated",
256
+ nq);
257
+ }
258
+ i0 += nq;
259
+ LUT += nq * nsq * 16;
260
+ }
261
+ codes += 32 * nsq / 2;
262
+ }
263
+ }
264
+
265
+
266
+
267
+ // explicit template instantiations
268
+
269
+
270
+ #define INSTANTIATE_ACCUMULATE_Q(RH) \
271
+ template void pq4_accumulate_loop_qbs<RH> \
272
+ (int, size_t, int, const uint8_t *, const uint8_t *, RH &);
273
+
274
+ using Csi = CMax<uint16_t, int>;
275
+ INSTANTIATE_ACCUMULATE_Q(SingleResultHandler<Csi>)
276
+ INSTANTIATE_ACCUMULATE_Q(HeapHandler<Csi>)
277
+ INSTANTIATE_ACCUMULATE_Q(ReservoirHandler<Csi>)
278
+ using Csi2 = CMin<uint16_t, int>;
279
+ INSTANTIATE_ACCUMULATE_Q(SingleResultHandler<Csi2>)
280
+ INSTANTIATE_ACCUMULATE_Q(HeapHandler<Csi2>)
281
+ INSTANTIATE_ACCUMULATE_Q(ReservoirHandler<Csi2>)
282
+
283
+ using Cfl = CMax<uint16_t, int64_t>;
284
+ using HHCsl = HeapHandler<Cfl, true>;
285
+ using RHCsl = ReservoirHandler<Cfl, true>;
286
+ using SHCsl = SingleResultHandler<Cfl, true>;
287
+ INSTANTIATE_ACCUMULATE_Q(HHCsl)
288
+ INSTANTIATE_ACCUMULATE_Q(RHCsl)
289
+ INSTANTIATE_ACCUMULATE_Q(SHCsl)
290
+ using Cfl2 = CMin<uint16_t, int64_t>;
291
+ using HHCsl2 = HeapHandler<Cfl2, true>;
292
+ using RHCsl2 = ReservoirHandler<Cfl2, true>;
293
+ using SHCsl2 = SingleResultHandler<Cfl2, true>;
294
+ INSTANTIATE_ACCUMULATE_Q(HHCsl2)
295
+ INSTANTIATE_ACCUMULATE_Q(RHCsl2)
296
+ INSTANTIATE_ACCUMULATE_Q(SHCsl2)
297
+
298
+
299
+ /***************************************************************
300
+ * Packing functions
301
+ ***************************************************************/
302
+
303
+ int pq4_qbs_to_nq(int qbs) {
304
+ int i0 = 0;
305
+ int qi = qbs;
306
+ while(qi) {
307
+ int nq = qi & 15;
308
+ qi >>= 4;
309
+ i0 += nq;
310
+ }
311
+ return i0;
312
+ }
313
+
314
+
315
+
316
+ void accumulate_to_mem(
317
+ int nq,
318
+ size_t ntotal2,
319
+ int nsq,
320
+ const uint8_t *codes,
321
+ const uint8_t *LUT,
322
+ uint16_t* accu)
323
+ {
324
+ FAISS_THROW_IF_NOT(ntotal2 % 32 == 0);
325
+ StoreResultHandler handler(accu, ntotal2);
326
+ accumulate(nq, ntotal2, nsq, codes, LUT, handler);
327
+ }
328
+
329
+
330
+ int pq4_preferred_qbs(int n) {
331
+ // from timmings in P141901742, P141902828
332
+ static int map[12] = {
333
+ 0, 1, 2, 3, 0x13,
334
+ 0x23, 0x33, 0x223, 0x233, 0x333,
335
+ 0x2233, 0x2333
336
+ };
337
+ if (n <= 11) {
338
+ return map[n];
339
+ } else if (n <= 24) {
340
+ // override qbs: all first stages with 3 steps
341
+ // then 1 stage with the rest
342
+ int nbit = 4 * (n / 3); // nbits with only 3s
343
+ int qbs = 0x33333333 & ((1 << nbit) - 1);
344
+ qbs |= (n % 3) << nbit;
345
+ return qbs;
346
+ } else {
347
+ FAISS_THROW_FMT("number of queries %d too large", n);
348
+ }
349
+ }
350
+
351
+
352
+
353
+ } // namespace faiss
354
+