faiss 0.6.1 → 0.6.3

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 (186) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/lib/faiss/version.rb +1 -1
  4. data/vendor/faiss/faiss/AutoTune.cpp +3 -1
  5. data/vendor/faiss/faiss/Clustering.cpp +9 -1
  6. data/vendor/faiss/faiss/IVFlib.cpp +14 -3
  7. data/vendor/faiss/faiss/Index.h +2 -2
  8. data/vendor/faiss/faiss/IndexAdditiveQuantizer.cpp +9 -10
  9. data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.cpp +2 -3
  10. data/vendor/faiss/faiss/IndexBinaryFromFloat.cpp +1 -2
  11. data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +10 -12
  12. data/vendor/faiss/faiss/IndexBinaryHash.cpp +5 -9
  13. data/vendor/faiss/faiss/IndexBinaryIVF.cpp +5 -7
  14. data/vendor/faiss/faiss/IndexEDEN.cpp +273 -0
  15. data/vendor/faiss/faiss/IndexEDEN.h +57 -0
  16. data/vendor/faiss/faiss/IndexFastScan.cpp +15 -4
  17. data/vendor/faiss/faiss/IndexFlat.cpp +13 -50
  18. data/vendor/faiss/faiss/IndexHNSW.cpp +177 -148
  19. data/vendor/faiss/faiss/IndexIDMap.cpp +16 -3
  20. data/vendor/faiss/faiss/IndexIDMap.h +2 -0
  21. data/vendor/faiss/faiss/IndexIVF.cpp +19 -8
  22. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +3 -3
  23. data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.cpp +3 -4
  24. data/vendor/faiss/faiss/IndexIVFEDEN.cpp +302 -0
  25. data/vendor/faiss/faiss/IndexIVFEDEN.h +70 -0
  26. data/vendor/faiss/faiss/IndexIVFFastScan.cpp +5 -6
  27. data/vendor/faiss/faiss/IndexIVFFlat.cpp +6 -5
  28. data/vendor/faiss/faiss/IndexIVFFlatPanorama.cpp +3 -3
  29. data/vendor/faiss/faiss/IndexIVFIndependentQuantizer.cpp +1 -1
  30. data/vendor/faiss/faiss/IndexIVFPQ.cpp +42 -25
  31. data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +0 -1
  32. data/vendor/faiss/faiss/IndexIVFPQR.cpp +2 -3
  33. data/vendor/faiss/faiss/IndexIVFRaBitQ.cpp +23 -62
  34. data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.cpp +180 -76
  35. data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.h +5 -4
  36. data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +8 -6
  37. data/vendor/faiss/faiss/IndexLSH.cpp +2 -3
  38. data/vendor/faiss/faiss/IndexLattice.cpp +5 -0
  39. data/vendor/faiss/faiss/IndexNNDescent.cpp +10 -3
  40. data/vendor/faiss/faiss/IndexNSG.cpp +8 -4
  41. data/vendor/faiss/faiss/IndexPQ.cpp +6 -8
  42. data/vendor/faiss/faiss/IndexPreTransform.cpp +15 -0
  43. data/vendor/faiss/faiss/IndexRaBitQ.cpp +2 -2
  44. data/vendor/faiss/faiss/IndexRaBitQFastScan.cpp +1 -2
  45. data/vendor/faiss/faiss/IndexRaBitQFastScan.h +5 -1
  46. data/vendor/faiss/faiss/IndexRefine.cpp +30 -1
  47. data/vendor/faiss/faiss/IndexReplicas.cpp +1 -2
  48. data/vendor/faiss/faiss/IndexScalarQuantizer.cpp +68 -6
  49. data/vendor/faiss/faiss/IndexScalarQuantizer.h +10 -0
  50. data/vendor/faiss/faiss/IndexShards.cpp +2 -2
  51. data/vendor/faiss/faiss/IndexShardsIVF.cpp +2 -2
  52. data/vendor/faiss/faiss/MetaIndexes.cpp +2 -4
  53. data/vendor/faiss/faiss/SuperKMeans.cpp +256 -240
  54. data/vendor/faiss/faiss/SuperKMeans.h +30 -0
  55. data/vendor/faiss/faiss/VectorTransform.cpp +33 -2
  56. data/vendor/faiss/faiss/clone_index.cpp +5 -0
  57. data/vendor/faiss/faiss/cppcontrib/SaDecodeKernels.h +1 -1
  58. data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-neon-inl.h +902 -12
  59. data/vendor/faiss/faiss/cppcontrib/sa_decode/PQ-neon-inl.h +702 -10
  60. data/vendor/faiss/faiss/factory_tools.cpp +51 -4
  61. data/vendor/faiss/faiss/gpu/GpuCloner.cpp +11 -11
  62. data/vendor/faiss/faiss/gpu/GpuIndex.h +34 -11
  63. data/vendor/faiss/faiss/gpu/GpuIndexCagra.h +47 -0
  64. data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +17 -0
  65. data/vendor/faiss/faiss/gpu/GpuIndexIVFScalarQuantizer.h +16 -0
  66. data/vendor/faiss/faiss/gpu/GpuResources.h +3 -2
  67. data/vendor/faiss/faiss/gpu/StandardGpuResources.cpp +11 -12
  68. data/vendor/faiss/faiss/gpu/StandardGpuResources.h +3 -3
  69. data/vendor/faiss/faiss/gpu/perf/PerfClustering.cpp +1 -1
  70. data/vendor/faiss/faiss/gpu/perf/PerfIVFPQAdd.cpp +2 -2
  71. data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFScalarQuantizer.cpp +180 -0
  72. data/vendor/faiss/faiss/gpu_metal/MetalDistance.h +87 -0
  73. data/vendor/faiss/faiss/gpu_metal/MetalIndex.h +7 -0
  74. data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFFlat.h +177 -0
  75. data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFPQ.h +88 -0
  76. data/vendor/faiss/faiss/gpu_metal/MetalKernels.h +48 -3
  77. data/vendor/faiss/faiss/gpu_metal/MetalPythonBridge.h +45 -0
  78. data/vendor/faiss/faiss/gpu_metal/impl/MetalIVFFlat.h +193 -0
  79. data/vendor/faiss/faiss/gpu_metal/impl/MetalIVFPQ.h +134 -0
  80. data/vendor/faiss/faiss/impl/ClusteringInitialization.cpp +2 -2
  81. data/vendor/faiss/faiss/impl/DistanceComputer.h +34 -0
  82. data/vendor/faiss/faiss/impl/EDENQuantizer.h +119 -0
  83. data/vendor/faiss/faiss/impl/HNSW.cpp +658 -344
  84. data/vendor/faiss/faiss/impl/HNSW.h +51 -13
  85. data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +2 -2
  86. data/vendor/faiss/faiss/impl/NSG.cpp +18 -12
  87. data/vendor/faiss/faiss/impl/Panorama.h +20 -7
  88. data/vendor/faiss/faiss/impl/PolysemousTraining.cpp +152 -84
  89. data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +59 -24
  90. data/vendor/faiss/faiss/impl/RaBitQUtils.cpp +45 -37
  91. data/vendor/faiss/faiss/impl/RaBitQUtils.h +35 -0
  92. data/vendor/faiss/faiss/impl/RaBitQuantizer.cpp +175 -68
  93. data/vendor/faiss/faiss/impl/RaBitQuantizer.h +19 -0
  94. data/vendor/faiss/faiss/impl/RaBitQuantizerMultiBit.cpp +2 -11
  95. data/vendor/faiss/faiss/impl/ResultHandler.h +26 -31
  96. data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +522 -58
  97. data/vendor/faiss/faiss/impl/ScalarQuantizer.h +70 -0
  98. data/vendor/faiss/faiss/impl/ThreadedIndex-inl.h +2 -2
  99. data/vendor/faiss/faiss/impl/VisitedTable.cpp +33 -13
  100. data/vendor/faiss/faiss/impl/VisitedTable.h +88 -33
  101. data/vendor/faiss/faiss/impl/binary_hamming/IndexBinaryIVF_impl.h +1 -1
  102. data/vendor/faiss/faiss/impl/binary_hamming/avx2.cpp +4 -4
  103. data/vendor/faiss/faiss/impl/fast_scan/dispatching.h +38 -3
  104. data/vendor/faiss/faiss/impl/hnsw/LockVector.cpp +1 -1
  105. data/vendor/faiss/faiss/impl/hnsw/MinimaxHeap.cpp +35 -43
  106. data/vendor/faiss/faiss/impl/hnsw/MinimaxHeap.h +64 -15
  107. data/vendor/faiss/faiss/impl/hnsw/avx2.cpp +86 -40
  108. data/vendor/faiss/faiss/impl/hnsw/avx512.cpp +81 -50
  109. data/vendor/faiss/faiss/impl/index_read.cpp +476 -75
  110. data/vendor/faiss/faiss/impl/index_write.cpp +56 -4
  111. data/vendor/faiss/faiss/impl/io_macros.h +25 -0
  112. data/vendor/faiss/faiss/impl/lattice_Zn.cpp +8 -9
  113. data/vendor/faiss/faiss/impl/platform_macros.h +15 -9
  114. data/vendor/faiss/faiss/impl/polysemous_training/avx512.cpp +284 -0
  115. data/vendor/faiss/faiss/impl/polysemous_training/dispatch.h +115 -0
  116. data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQ_QueryTables.cpp +0 -1
  117. data/vendor/faiss/faiss/impl/pq_code_distance/PQDistanceComputer_impl.h +26 -15
  118. data/vendor/faiss/faiss/impl/pq_code_distance/avx2.cpp +6 -4
  119. data/vendor/faiss/faiss/impl/pq_code_distance/avx512.cpp +2 -0
  120. data/vendor/faiss/faiss/impl/pq_code_distance/neon.cpp +2 -0
  121. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-generic.cpp +20 -0
  122. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-inl.h +36 -0
  123. data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-sve.cpp +5 -0
  124. data/vendor/faiss/faiss/impl/pq_code_distance/pq_scan_impl.h +105 -0
  125. data/vendor/faiss/faiss/impl/pq_code_distance/rvv.cpp +2 -0
  126. data/vendor/faiss/faiss/impl/result_handler/ResultHandler.cpp +195 -0
  127. data/vendor/faiss/faiss/impl/result_handler/avx2.cpp +133 -0
  128. data/vendor/faiss/faiss/impl/result_handler/avx512.cpp +281 -0
  129. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx2.cpp +72 -0
  130. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx512.cpp +228 -0
  131. data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer.cpp +882 -0
  132. data/vendor/faiss/faiss/impl/scalar_quantizer/distance_computers.h +6 -0
  133. data/vendor/faiss/faiss/impl/scalar_quantizer/quantizers.h +336 -26
  134. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx2.cpp +331 -32
  135. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-impl.h +553 -0
  136. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-spr.cpp +558 -0
  137. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512.cpp +284 -45
  138. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-dispatch.h +502 -3
  139. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-neon.cpp +157 -32
  140. data/vendor/faiss/faiss/impl/scalar_quantizer/sq-rvv.cpp +26 -0
  141. data/vendor/faiss/faiss/impl/simd_dispatch.h +86 -8
  142. data/vendor/faiss/faiss/index_factory.cpp +37 -7
  143. data/vendor/faiss/faiss/index_io.h +16 -0
  144. data/vendor/faiss/faiss/invlists/DirectMap.cpp +5 -2
  145. data/vendor/faiss/faiss/invlists/InvertedLists.cpp +15 -15
  146. data/vendor/faiss/faiss/invlists/InvertedLists.h +2 -2
  147. data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +19 -4
  148. data/vendor/faiss/faiss/python/python_callbacks.cpp +3 -1
  149. data/vendor/faiss/faiss/svs/IndexSVSFaissUtils.h +60 -0
  150. data/vendor/faiss/faiss/svs/IndexSVSFlat.cpp +26 -1
  151. data/vendor/faiss/faiss/svs/IndexSVSFlat.h +13 -0
  152. data/vendor/faiss/faiss/svs/IndexSVSIVF.cpp +1 -1
  153. data/vendor/faiss/faiss/svs/IndexSVSIVFLeanVec.cpp +1 -1
  154. data/vendor/faiss/faiss/svs/IndexSVSVamana.cpp +150 -23
  155. data/vendor/faiss/faiss/svs/IndexSVSVamana.h +30 -7
  156. data/vendor/faiss/faiss/svs/IndexSVSVamanaLVQ.cpp +3 -2
  157. data/vendor/faiss/faiss/svs/IndexSVSVamanaLVQ.h +2 -1
  158. data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.cpp +65 -25
  159. data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.h +3 -2
  160. data/vendor/faiss/faiss/utils/approx_topk_hamming/approx_topk_hamming.h +1 -1
  161. data/vendor/faiss/faiss/utils/bf16.h +34 -0
  162. data/vendor/faiss/faiss/utils/distances.cpp +14 -2
  163. data/vendor/faiss/faiss/utils/distances_simd.cpp +4 -4
  164. data/vendor/faiss/faiss/utils/extra_distances.cpp +4 -14
  165. data/vendor/faiss/faiss/utils/extra_distances.h +1 -2
  166. data/vendor/faiss/faiss/utils/hamming.cpp +9 -9
  167. data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx2.cpp +2 -1
  168. data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512_spr.cpp +15 -0
  169. data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-avx512.h +6 -30
  170. data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-avx512_spr.h +171 -0
  171. data/vendor/faiss/faiss/utils/partitioning.cpp +0 -2
  172. data/vendor/faiss/faiss/utils/quantize_lut.cpp +29 -8
  173. data/vendor/faiss/faiss/utils/rabitq_simd.h +202 -0
  174. data/vendor/faiss/faiss/utils/simd_impl/distances_avx2.cpp +0 -1
  175. data/vendor/faiss/faiss/utils/simd_impl/distances_avx512.cpp +263 -15
  176. data/vendor/faiss/faiss/utils/simd_impl/distances_rvv.cpp +160 -18
  177. data/vendor/faiss/faiss/utils/simd_impl/partitioning_simdlib256.h +14 -68
  178. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx2.cpp +245 -0
  179. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512.cpp +273 -0
  180. data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512_spr.cpp +435 -0
  181. data/vendor/faiss/faiss/utils/simd_impl/rabitq_neon.cpp +11 -0
  182. data/vendor/faiss/faiss/utils/simd_impl/rabitq_rvv.cpp +143 -6
  183. data/vendor/faiss/faiss/utils/simd_levels.cpp +56 -2
  184. data/vendor/faiss/faiss/utils/simd_levels.h +14 -0
  185. data/vendor/faiss/faiss/utils/utils.cpp +9 -27
  186. metadata +27 -2
@@ -0,0 +1,281 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and 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
+ // AVX-512 specialisations of Top1 and Reservoir add_results.
9
+ //
10
+ // Top-1: 16-wide branchless argmin/argmax via mask_blend.
11
+ // Reservoir: VPCOMPRESSPS / VPCOMPRESSD bulk-insert of passing elements,
12
+ // eliminating the per-element threshold branch entirely.
13
+
14
+ #ifdef COMPILE_SIMD_AVX512
15
+
16
+ #include <faiss/impl/ResultHandler.h>
17
+ #include <faiss/utils/popcount.h>
18
+
19
+ #include <immintrin.h>
20
+ #include <type_traits>
21
+
22
+ namespace faiss {
23
+
24
+ namespace {
25
+
26
+ /// Templated AVX-512 implementation of Top1 add_results for both CMax (keeps
27
+ /// the smallest distance) and CMin (keeps the largest similarity).
28
+ template <class C, bool use_sel>
29
+ void top1_add_results_avx512(
30
+ Top1BlockResultHandler<C, use_sel>* self,
31
+ size_t j0,
32
+ size_t j1,
33
+ const float* dis_tab_in) {
34
+ static_assert(
35
+ std::is_same<typename C::T, float>::value,
36
+ "This code expects float distances");
37
+ using TI = typename C::TI;
38
+ const __m512i vstep = _mm512_set_epi32(
39
+ 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
40
+
41
+ for (size_t qi = self->i0; qi < self->i1; qi++) {
42
+ const float* dis_tab_i = dis_tab_in + (j1 - j0) * (qi - self->i0) - j0;
43
+
44
+ // Hoist best_dis / best_idx into locals so the compiler keeps them in
45
+ // registers across the inner loop (no aliasing with dis_tab reads).
46
+ float best_dis = self->dis_tab[qi];
47
+ TI best_idx = self->ids_tab[qi];
48
+ size_t j = j0;
49
+
50
+ __m512 vbest = _mm512_set1_ps(best_dis);
51
+ __m512i vbest_idx = _mm512_set1_epi32((int32_t)best_idx);
52
+
53
+ for (; j + 16 <= j1; j += 16) {
54
+ __m512 vdis = _mm512_loadu_ps(dis_tab_i + j);
55
+ __m512i vidx =
56
+ _mm512_add_epi32(_mm512_set1_epi32((int32_t)j), vstep);
57
+
58
+ // CMax (L2 nearest neighbour): keep lane if dis < best.
59
+ // CMin (inner product): keep lane if dis > best.
60
+ __mmask16 mask;
61
+ if constexpr (C::is_max) {
62
+ mask = _mm512_cmp_ps_mask(vdis, vbest, _CMP_LT_OS);
63
+ } else {
64
+ mask = _mm512_cmp_ps_mask(vdis, vbest, _CMP_GT_OS);
65
+ }
66
+ vbest = _mm512_mask_blend_ps(mask, vbest, vdis);
67
+ vbest_idx = _mm512_mask_blend_epi32(mask, vbest_idx, vidx);
68
+ }
69
+
70
+ // Horizontal reduction across 16 lanes.
71
+ alignas(64) float best_arr[16];
72
+ alignas(64) int32_t idx_arr[16];
73
+ _mm512_store_ps(best_arr, vbest);
74
+ _mm512_store_si512((__m512i*)idx_arr, vbest_idx);
75
+ for (int k = 0; k < 16; k++) {
76
+ if (C::cmp(best_dis, best_arr[k])) {
77
+ best_dis = best_arr[k];
78
+ best_idx = (TI)idx_arr[k];
79
+ }
80
+ }
81
+
82
+ // Scalar tail.
83
+ for (; j < j1; j++) {
84
+ if (C::cmp(best_dis, dis_tab_i[j])) {
85
+ best_dis = dis_tab_i[j];
86
+ best_idx = (TI)j;
87
+ }
88
+ }
89
+
90
+ self->dis_tab[qi] = best_dis;
91
+ self->ids_tab[qi] = best_idx;
92
+ }
93
+ }
94
+
95
+ /// Templated AVX-512 implementation of Reservoir add_results for both CMax
96
+ /// and CMin. Uses VPCOMPRESSPS / VPCOMPRESSD to bulk-insert all elements that
97
+ /// beat the current threshold in a single pass, avoiding the per-element branch
98
+ /// that dominates the scalar path.
99
+ ///
100
+ /// Falls back to the scalar NONE path for small reservoirs (capacity < 32)
101
+ /// where the compress-path setup cost outweighs its throughput benefit.
102
+ template <class C, bool use_sel>
103
+ void reservoir_add_results_avx512(
104
+ ReservoirBlockResultHandler<C, use_sel>* self,
105
+ size_t j0,
106
+ size_t j1,
107
+ const float* dis_in) {
108
+ static_assert(
109
+ std::is_same<typename C::T, float>::value,
110
+ "This code expects float distances");
111
+ static_assert(
112
+ std::is_same<typename C::TI, int64_t>::value,
113
+ "This code expects int64_t indices");
114
+
115
+ // AVX-512 compress amortizes its setup cost only for large reservoirs.
116
+ // Benchmarks show a ~9% regression at k=10 (capacity≈20) and a ~25%
117
+ // gain at k=100 (capacity≈200). 32 = 2 × lane-width is the crossover.
118
+ // All reservoirs in a handler share the same capacity, so check once.
119
+ constexpr size_t AVX512_RESERVOIR_MIN_CAPACITY = 32;
120
+ if (self->i0 < self->i1 &&
121
+ self->reservoirs[0].capacity < AVX512_RESERVOIR_MIN_CAPACITY) {
122
+ reservoir_add_results_tpl<C, use_sel, SIMDLevel::NONE>(
123
+ self, j0, j1, dis_in);
124
+ return;
125
+ }
126
+
127
+ const __m512i vstep = _mm512_set_epi32(
128
+ 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
129
+
130
+ #pragma omp parallel for
131
+ for (int64_t qi = (int64_t)self->i0; qi < (int64_t)self->i1; qi++) {
132
+ ReservoirTopN<C>& res = self->reservoirs[qi - (int64_t)self->i0];
133
+ const float* dis_tab_i =
134
+ dis_in + (j1 - j0) * (qi - (int64_t)self->i0) - j0;
135
+ size_t j = j0;
136
+
137
+ for (; j + 16 <= j1; j += 16) {
138
+ // Near-capacity: fewer than 16 free slots remain. Fall back to
139
+ // the scalar add_result which handles overflow correctly.
140
+ if (res.i + 16 > res.capacity) {
141
+ for (size_t jj = j; jj < j + 16; jj++)
142
+ res.add_result(dis_tab_i[jj], jj);
143
+ continue;
144
+ }
145
+
146
+ __m512 vthresh = _mm512_set1_ps(res.threshold);
147
+ __m512 vdis = _mm512_loadu_ps(dis_tab_i + j);
148
+
149
+ // CMax (L2): keep elements with dis < threshold.
150
+ // CMin (IP): keep elements with dis > threshold.
151
+ __mmask16 mask;
152
+ if constexpr (C::is_max) {
153
+ mask = _mm512_cmp_ps_mask(vdis, vthresh, _CMP_LT_OS);
154
+ } else {
155
+ mask = _mm512_cmp_ps_mask(vdis, vthresh, _CMP_GT_OS);
156
+ }
157
+ if (mask == 0)
158
+ continue;
159
+
160
+ int count = popcount32(mask);
161
+
162
+ // Compress passing distances into a contiguous run (VPCOMPRESSPS).
163
+ __m512 passing_dis = _mm512_maskz_compress_ps(mask, vdis);
164
+
165
+ // Compress the sequential indices j..j+15 (VPCOMPRESSD).
166
+ __m512i vidx32 =
167
+ _mm512_add_epi32(_mm512_set1_epi32((int32_t)j), vstep);
168
+ __m512i passing_idx32 = _mm512_maskz_compress_epi32(mask, vidx32);
169
+
170
+ // Unconditional 16-element stores are safe: the res.i + 16 <=
171
+ // res.capacity check above guarantees slots res.i .. res.i+15
172
+ // are all unused. The (count .. 15) tail positions get garbage
173
+ // that res.i never reaches.
174
+ _mm512_storeu_ps(res.vals + res.i, passing_dis);
175
+
176
+ // Widen int32 indices to int64 (TI = int64_t) in two 8-element
177
+ // halves and store them.
178
+ _mm512_storeu_si512(
179
+ (void*)(res.ids + res.i),
180
+ _mm512_cvtepi32_epi64(
181
+ _mm512_castsi512_si256(passing_idx32)));
182
+ _mm512_storeu_si512(
183
+ (void*)(res.ids + res.i + 8),
184
+ _mm512_cvtepi32_epi64(
185
+ _mm512_extracti64x4_epi64(passing_idx32, 1)));
186
+
187
+ res.i += count;
188
+ if (res.i >= res.capacity) {
189
+ res.shrink_fuzzy();
190
+ }
191
+ }
192
+
193
+ // Scalar tail.
194
+ for (; j < j1; j++)
195
+ res.add_result(dis_tab_i[j], j);
196
+ }
197
+ }
198
+
199
+ } // namespace
200
+
201
+ // Explicit specialisations for AVX-512
202
+
203
+ template <>
204
+ void top1_add_results_tpl<CMax<float, int64_t>, false, SIMDLevel::AVX512>(
205
+ Top1BlockResultHandler<CMax<float, int64_t>, false>* self,
206
+ size_t j0,
207
+ size_t j1,
208
+ const float* dis_tab) {
209
+ top1_add_results_avx512<CMax<float, int64_t>, false>(self, j0, j1, dis_tab);
210
+ }
211
+
212
+ template <>
213
+ void top1_add_results_tpl<CMax<float, int64_t>, true, SIMDLevel::AVX512>(
214
+ Top1BlockResultHandler<CMax<float, int64_t>, true>* self,
215
+ size_t j0,
216
+ size_t j1,
217
+ const float* dis_tab) {
218
+ top1_add_results_avx512<CMax<float, int64_t>, true>(self, j0, j1, dis_tab);
219
+ }
220
+
221
+ template <>
222
+ void top1_add_results_tpl<CMin<float, int64_t>, false, SIMDLevel::AVX512>(
223
+ Top1BlockResultHandler<CMin<float, int64_t>, false>* self,
224
+ size_t j0,
225
+ size_t j1,
226
+ const float* dis_tab) {
227
+ top1_add_results_avx512<CMin<float, int64_t>, false>(self, j0, j1, dis_tab);
228
+ }
229
+
230
+ template <>
231
+ void top1_add_results_tpl<CMin<float, int64_t>, true, SIMDLevel::AVX512>(
232
+ Top1BlockResultHandler<CMin<float, int64_t>, true>* self,
233
+ size_t j0,
234
+ size_t j1,
235
+ const float* dis_tab) {
236
+ top1_add_results_avx512<CMin<float, int64_t>, true>(self, j0, j1, dis_tab);
237
+ }
238
+
239
+ template <>
240
+ void reservoir_add_results_tpl<CMax<float, int64_t>, false, SIMDLevel::AVX512>(
241
+ ReservoirBlockResultHandler<CMax<float, int64_t>, false>* self,
242
+ size_t j0,
243
+ size_t j1,
244
+ const float* dis_in) {
245
+ reservoir_add_results_avx512<CMax<float, int64_t>, false>(
246
+ self, j0, j1, dis_in);
247
+ }
248
+
249
+ template <>
250
+ void reservoir_add_results_tpl<CMax<float, int64_t>, true, SIMDLevel::AVX512>(
251
+ ReservoirBlockResultHandler<CMax<float, int64_t>, true>* self,
252
+ size_t j0,
253
+ size_t j1,
254
+ const float* dis_in) {
255
+ reservoir_add_results_avx512<CMax<float, int64_t>, true>(
256
+ self, j0, j1, dis_in);
257
+ }
258
+
259
+ template <>
260
+ void reservoir_add_results_tpl<CMin<float, int64_t>, false, SIMDLevel::AVX512>(
261
+ ReservoirBlockResultHandler<CMin<float, int64_t>, false>* self,
262
+ size_t j0,
263
+ size_t j1,
264
+ const float* dis_in) {
265
+ reservoir_add_results_avx512<CMin<float, int64_t>, false>(
266
+ self, j0, j1, dis_in);
267
+ }
268
+
269
+ template <>
270
+ void reservoir_add_results_tpl<CMin<float, int64_t>, true, SIMDLevel::AVX512>(
271
+ ReservoirBlockResultHandler<CMin<float, int64_t>, true>* self,
272
+ size_t j0,
273
+ size_t j1,
274
+ const float* dis_in) {
275
+ reservoir_add_results_avx512<CMin<float, int64_t>, true>(
276
+ self, j0, j1, dis_in);
277
+ }
278
+
279
+ } // namespace faiss
280
+
281
+ #endif // COMPILE_SIMD_AVX512
@@ -0,0 +1,72 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and 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
+ #ifdef COMPILE_SIMD_AVX2
9
+
10
+ #include <faiss/impl/EDENQuantizer.h>
11
+ #include <faiss/impl/simdlib/simdlib_avx2.h>
12
+
13
+ #include <immintrin.h>
14
+
15
+ namespace faiss {
16
+
17
+ namespace eden_distance {
18
+
19
+ namespace {
20
+
21
+ constexpr int kCodeDotLUTKindHalfByte = 2;
22
+
23
+ inline __m256i load_code_bytes_8(const uint8_t* const code[8], size_t i) {
24
+ return _mm256_setr_epi32(
25
+ code[0][i],
26
+ code[1][i],
27
+ code[2][i],
28
+ code[3][i],
29
+ code[4][i],
30
+ code[5][i],
31
+ code[6][i],
32
+ code[7][i]);
33
+ }
34
+
35
+ } // namespace
36
+
37
+ void compute_code_dot_lut_batch_8_avx2(
38
+ const uint8_t* const code[8],
39
+ const float* lut,
40
+ int lut_kind,
41
+ size_t packed_size,
42
+ float dots[8]) {
43
+ __m256 acc = _mm256_setzero_ps();
44
+ const __m256i low_mask = _mm256_set1_epi32(0x0f);
45
+ const __m256i high_offset = _mm256_set1_epi32(16);
46
+
47
+ if (lut_kind == kCodeDotLUTKindHalfByte) {
48
+ for (size_t i = 0; i < packed_size; i++) {
49
+ const __m256i bytes = load_code_bytes_8(code, i);
50
+ const __m256i low = _mm256_and_si256(bytes, low_mask);
51
+ const __m256i high =
52
+ _mm256_add_epi32(_mm256_srli_epi32(bytes, 4), high_offset);
53
+ acc = _mm256_add_ps(acc, _mm256_i32gather_ps(lut, low, 4));
54
+ acc = _mm256_add_ps(acc, _mm256_i32gather_ps(lut, high, 4));
55
+ lut += 32;
56
+ }
57
+ } else {
58
+ for (size_t i = 0; i < packed_size; i++) {
59
+ const __m256i bytes = load_code_bytes_8(code, i);
60
+ acc = _mm256_add_ps(acc, _mm256_i32gather_ps(lut, bytes, 4));
61
+ lut += 256;
62
+ }
63
+ }
64
+
65
+ _mm256_storeu_ps(dots, acc);
66
+ }
67
+
68
+ } // namespace eden_distance
69
+
70
+ } // namespace faiss
71
+
72
+ #endif
@@ -0,0 +1,228 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and 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
+ #ifdef COMPILE_SIMD_AVX512
9
+
10
+ #include <faiss/impl/EDENQuantizer.h>
11
+ #include <faiss/impl/simdlib/simdlib_avx2.h>
12
+ #include <faiss/impl/simdlib/simdlib_avx512.h>
13
+
14
+ #include <immintrin.h>
15
+
16
+ namespace faiss {
17
+
18
+ namespace eden_distance {
19
+
20
+ namespace {
21
+
22
+ constexpr int kCodeDotLUTKindHalfByte = 2;
23
+
24
+ inline __m512i load_byte_indexes_16(const uint8_t* const code[16], size_t i) {
25
+ return _mm512_set_epi32(
26
+ code[15][i],
27
+ code[14][i],
28
+ code[13][i],
29
+ code[12][i],
30
+ code[11][i],
31
+ code[10][i],
32
+ code[9][i],
33
+ code[8][i],
34
+ code[7][i],
35
+ code[6][i],
36
+ code[5][i],
37
+ code[4][i],
38
+ code[3][i],
39
+ code[2][i],
40
+ code[1][i],
41
+ code[0][i]);
42
+ }
43
+
44
+ inline __m512i load_low_half_byte_indexes_16(
45
+ const uint8_t* const code[16],
46
+ size_t i) {
47
+ return _mm512_set_epi32(
48
+ code[15][i] & 0x0f,
49
+ code[14][i] & 0x0f,
50
+ code[13][i] & 0x0f,
51
+ code[12][i] & 0x0f,
52
+ code[11][i] & 0x0f,
53
+ code[10][i] & 0x0f,
54
+ code[9][i] & 0x0f,
55
+ code[8][i] & 0x0f,
56
+ code[7][i] & 0x0f,
57
+ code[6][i] & 0x0f,
58
+ code[5][i] & 0x0f,
59
+ code[4][i] & 0x0f,
60
+ code[3][i] & 0x0f,
61
+ code[2][i] & 0x0f,
62
+ code[1][i] & 0x0f,
63
+ code[0][i] & 0x0f);
64
+ }
65
+
66
+ inline __m512i load_high_half_byte_indexes_16(
67
+ const uint8_t* const code[16],
68
+ size_t i) {
69
+ return _mm512_set_epi32(
70
+ 16 + (code[15][i] >> 4),
71
+ 16 + (code[14][i] >> 4),
72
+ 16 + (code[13][i] >> 4),
73
+ 16 + (code[12][i] >> 4),
74
+ 16 + (code[11][i] >> 4),
75
+ 16 + (code[10][i] >> 4),
76
+ 16 + (code[9][i] >> 4),
77
+ 16 + (code[8][i] >> 4),
78
+ 16 + (code[7][i] >> 4),
79
+ 16 + (code[6][i] >> 4),
80
+ 16 + (code[5][i] >> 4),
81
+ 16 + (code[4][i] >> 4),
82
+ 16 + (code[3][i] >> 4),
83
+ 16 + (code[2][i] >> 4),
84
+ 16 + (code[1][i] >> 4),
85
+ 16 + (code[0][i] >> 4));
86
+ }
87
+
88
+ inline __m512i load_byte_indexes_8(const uint8_t* const code[8], size_t i) {
89
+ const __m256i indexes = _mm256_setr_epi32(
90
+ code[0][i],
91
+ code[1][i],
92
+ code[2][i],
93
+ code[3][i],
94
+ code[4][i],
95
+ code[5][i],
96
+ code[6][i],
97
+ code[7][i]);
98
+ return _mm512_castsi256_si512(indexes);
99
+ }
100
+
101
+ inline __m512 gather_lower_8_lanes(const float* table, __m512i indexes) {
102
+ constexpr __mmask16 active_lanes = 0x00ff;
103
+ return _mm512_mask_i32gather_ps(
104
+ _mm512_setzero_ps(), active_lanes, indexes, table, 4);
105
+ }
106
+
107
+ inline __m512i load_half_byte_indexes_8(
108
+ const uint8_t* const code[8],
109
+ size_t i) {
110
+ return _mm512_set_epi32(
111
+ 16 + (code[7][i] >> 4),
112
+ 16 + (code[6][i] >> 4),
113
+ 16 + (code[5][i] >> 4),
114
+ 16 + (code[4][i] >> 4),
115
+ 16 + (code[3][i] >> 4),
116
+ 16 + (code[2][i] >> 4),
117
+ 16 + (code[1][i] >> 4),
118
+ 16 + (code[0][i] >> 4),
119
+ code[7][i] & 0x0f,
120
+ code[6][i] & 0x0f,
121
+ code[5][i] & 0x0f,
122
+ code[4][i] & 0x0f,
123
+ code[3][i] & 0x0f,
124
+ code[2][i] & 0x0f,
125
+ code[1][i] & 0x0f,
126
+ code[0][i] & 0x0f);
127
+ }
128
+
129
+ inline __m512i load_byte_pair_indexes_8(
130
+ const uint8_t* const code[8],
131
+ size_t i) {
132
+ return _mm512_set_epi32(
133
+ 256 + code[7][i + 1],
134
+ 256 + code[6][i + 1],
135
+ 256 + code[5][i + 1],
136
+ 256 + code[4][i + 1],
137
+ 256 + code[3][i + 1],
138
+ 256 + code[2][i + 1],
139
+ 256 + code[1][i + 1],
140
+ 256 + code[0][i + 1],
141
+ code[7][i],
142
+ code[6][i],
143
+ code[5][i],
144
+ code[4][i],
145
+ code[3][i],
146
+ code[2][i],
147
+ code[1][i],
148
+ code[0][i]);
149
+ }
150
+
151
+ } // namespace
152
+
153
+ void compute_code_dot_lut_batch_8_avx512(
154
+ const uint8_t* const code[8],
155
+ const float* lut,
156
+ int lut_kind,
157
+ size_t packed_size,
158
+ float dots[8]) {
159
+ __m512 acc = _mm512_setzero_ps();
160
+
161
+ if (lut_kind == kCodeDotLUTKindHalfByte) {
162
+ for (size_t i = 0; i < packed_size; i++) {
163
+ acc = _mm512_add_ps(
164
+ acc,
165
+ _mm512_i32gather_ps(
166
+ load_half_byte_indexes_8(code, i), lut, 4));
167
+ lut += 32;
168
+ }
169
+ } else {
170
+ size_t i = 0;
171
+ for (; i + 1 < packed_size; i += 2) {
172
+ acc = _mm512_add_ps(
173
+ acc,
174
+ _mm512_i32gather_ps(
175
+ load_byte_pair_indexes_8(code, i), lut, 4));
176
+ lut += 512;
177
+ }
178
+ if (i < packed_size) {
179
+ acc = _mm512_add_ps(
180
+ acc,
181
+ gather_lower_8_lanes(lut, load_byte_indexes_8(code, i)));
182
+ }
183
+ }
184
+
185
+ alignas(64) float lanes[16];
186
+ _mm512_store_ps(lanes, acc);
187
+ for (size_t i = 0; i < 8; i++) {
188
+ dots[i] = lanes[i] + lanes[i + 8];
189
+ }
190
+ }
191
+
192
+ void compute_code_dot_lut_batch_16_avx512(
193
+ const uint8_t* const code[16],
194
+ const float* lut,
195
+ int lut_kind,
196
+ size_t packed_size,
197
+ float dots[16]) {
198
+ __m512 acc = _mm512_setzero_ps();
199
+
200
+ if (lut_kind == kCodeDotLUTKindHalfByte) {
201
+ for (size_t i = 0; i < packed_size; i++) {
202
+ acc = _mm512_add_ps(
203
+ acc,
204
+ _mm512_i32gather_ps(
205
+ load_low_half_byte_indexes_16(code, i), lut, 4));
206
+ acc = _mm512_add_ps(
207
+ acc,
208
+ _mm512_i32gather_ps(
209
+ load_high_half_byte_indexes_16(code, i), lut, 4));
210
+ lut += 32;
211
+ }
212
+ } else {
213
+ for (size_t i = 0; i < packed_size; i++) {
214
+ acc = _mm512_add_ps(
215
+ acc,
216
+ _mm512_i32gather_ps(load_byte_indexes_16(code, i), lut, 4));
217
+ lut += 256;
218
+ }
219
+ }
220
+
221
+ _mm512_storeu_ps(dots, acc);
222
+ }
223
+
224
+ } // namespace eden_distance
225
+
226
+ } // namespace faiss
227
+
228
+ #endif