/root/doris/contrib/faiss/faiss/utils/Heap.h
Line | Count | Source |
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 | | /* |
9 | | * C++ support for heaps. The set of functions is tailored for efficient |
10 | | * similarity search. |
11 | | * |
12 | | * There is no specific object for a heap, and the functions that operate on a |
13 | | * single heap are inlined, because heaps are often small. More complex |
14 | | * functions are implemented in Heaps.cpp |
15 | | * |
16 | | * All heap functions rely on a C template class that define the type of the |
17 | | * keys and values and their ordering (increasing with CMax and decreasing with |
18 | | * Cmin). The C types are defined in ordered_key_value.h |
19 | | */ |
20 | | |
21 | | #ifndef FAISS_Heap_h |
22 | | #define FAISS_Heap_h |
23 | | |
24 | | #include <climits> |
25 | | #include <cmath> |
26 | | #include <cstring> |
27 | | |
28 | | #include <stdint.h> |
29 | | #include <cassert> |
30 | | #include <cstdio> |
31 | | |
32 | | #include <limits> |
33 | | #include <utility> |
34 | | |
35 | | #include <faiss/utils/ordered_key_value.h> |
36 | | |
37 | | namespace faiss { |
38 | | |
39 | | /******************************************************************* |
40 | | * Basic heap ops: push and pop |
41 | | *******************************************************************/ |
42 | | |
43 | | /** Pops the top element from the heap defined by bh_val[0..k-1] and |
44 | | * bh_ids[0..k-1]. on output the element at k-1 is undefined. |
45 | | */ |
46 | | template <class C> |
47 | 6.25k | inline void heap_pop(size_t k, typename C::T* bh_val, typename C::TI* bh_ids) { |
48 | 6.25k | bh_val--; /* Use 1-based indexing for easier node->child translation */ |
49 | 6.25k | bh_ids--; |
50 | 6.25k | typename C::T val = bh_val[k]; |
51 | 6.25k | typename C::TI id = bh_ids[k]; |
52 | 6.25k | size_t i = 1, i1, i2; |
53 | 38.4k | while (1) { |
54 | 38.4k | i1 = i << 1; |
55 | 38.4k | i2 = i1 + 1; |
56 | 38.4k | if (i1 > k) |
57 | 5.32k | break; |
58 | 33.1k | if ((i2 == k + 1) || |
59 | 33.1k | C::cmp2(bh_val[i1], bh_val[i2], bh_ids[i1], bh_ids[i2])) { |
60 | 19.0k | if (C::cmp2(val, bh_val[i1], id, bh_ids[i1])) { |
61 | 468 | break; |
62 | 468 | } |
63 | 18.5k | bh_val[i] = bh_val[i1]; |
64 | 18.5k | bh_ids[i] = bh_ids[i1]; |
65 | 18.5k | i = i1; |
66 | 18.5k | } else { |
67 | 14.0k | if (C::cmp2(val, bh_val[i2], id, bh_ids[i2])) { |
68 | 466 | break; |
69 | 466 | } |
70 | 13.5k | bh_val[i] = bh_val[i2]; |
71 | 13.5k | bh_ids[i] = bh_ids[i2]; |
72 | 13.5k | i = i2; |
73 | 13.5k | } |
74 | 33.1k | } |
75 | 6.25k | bh_val[i] = bh_val[k]; |
76 | 6.25k | bh_ids[i] = bh_ids[k]; |
77 | 6.25k | } Unexecuted instantiation: _ZN5faiss8heap_popINS_4CMinIflEEEEvmPNT_1TEPNS3_2TIE _ZN5faiss8heap_popINS_4CMaxIflEEEEvmPNT_1TEPNS3_2TIE Line | Count | Source | 47 | 3.97k | inline void heap_pop(size_t k, typename C::T* bh_val, typename C::TI* bh_ids) { | 48 | 3.97k | bh_val--; /* Use 1-based indexing for easier node->child translation */ | 49 | 3.97k | bh_ids--; | 50 | 3.97k | typename C::T val = bh_val[k]; | 51 | 3.97k | typename C::TI id = bh_ids[k]; | 52 | 3.97k | size_t i = 1, i1, i2; | 53 | 27.8k | while (1) { | 54 | 27.8k | i1 = i << 1; | 55 | 27.8k | i2 = i1 + 1; | 56 | 27.8k | if (i1 > k) | 57 | 3.46k | break; | 58 | 24.3k | if ((i2 == k + 1) || | 59 | 24.3k | C::cmp2(bh_val[i1], bh_val[i2], bh_ids[i1], bh_ids[i2])) { | 60 | 13.0k | if (C::cmp2(val, bh_val[i1], id, bh_ids[i1])) { | 61 | 267 | break; | 62 | 267 | } | 63 | 12.7k | bh_val[i] = bh_val[i1]; | 64 | 12.7k | bh_ids[i] = bh_ids[i1]; | 65 | 12.7k | i = i1; | 66 | 12.7k | } else { | 67 | 11.2k | if (C::cmp2(val, bh_val[i2], id, bh_ids[i2])) { | 68 | 244 | break; | 69 | 244 | } | 70 | 11.0k | bh_val[i] = bh_val[i2]; | 71 | 11.0k | bh_ids[i] = bh_ids[i2]; | 72 | 11.0k | i = i2; | 73 | 11.0k | } | 74 | 24.3k | } | 75 | 3.97k | bh_val[i] = bh_val[k]; | 76 | 3.97k | bh_ids[i] = bh_ids[k]; | 77 | 3.97k | } |
_ZN5faiss8heap_popINS_4CMaxIfiEEEEvmPNT_1TEPNS3_2TIE Line | Count | Source | 47 | 2.28k | inline void heap_pop(size_t k, typename C::T* bh_val, typename C::TI* bh_ids) { | 48 | 2.28k | bh_val--; /* Use 1-based indexing for easier node->child translation */ | 49 | 2.28k | bh_ids--; | 50 | 2.28k | typename C::T val = bh_val[k]; | 51 | 2.28k | typename C::TI id = bh_ids[k]; | 52 | 2.28k | size_t i = 1, i1, i2; | 53 | 10.6k | while (1) { | 54 | 10.6k | i1 = i << 1; | 55 | 10.6k | i2 = i1 + 1; | 56 | 10.6k | if (i1 > k) | 57 | 1.85k | break; | 58 | 8.77k | if ((i2 == k + 1) || | 59 | 8.77k | C::cmp2(bh_val[i1], bh_val[i2], bh_ids[i1], bh_ids[i2])) { | 60 | 5.99k | if (C::cmp2(val, bh_val[i1], id, bh_ids[i1])) { | 61 | 201 | break; | 62 | 201 | } | 63 | 5.79k | bh_val[i] = bh_val[i1]; | 64 | 5.79k | bh_ids[i] = bh_ids[i1]; | 65 | 5.79k | i = i1; | 66 | 5.79k | } else { | 67 | 2.77k | if (C::cmp2(val, bh_val[i2], id, bh_ids[i2])) { | 68 | 222 | break; | 69 | 222 | } | 70 | 2.55k | bh_val[i] = bh_val[i2]; | 71 | 2.55k | bh_ids[i] = bh_ids[i2]; | 72 | 2.55k | i = i2; | 73 | 2.55k | } | 74 | 8.77k | } | 75 | 2.28k | bh_val[i] = bh_val[k]; | 76 | 2.28k | bh_ids[i] = bh_ids[k]; | 77 | 2.28k | } |
Unexecuted instantiation: _ZN5faiss8heap_popINS_4CMaxItiEEEEvmPNT_1TEPNS3_2TIE Unexecuted instantiation: _ZN5faiss8heap_popINS_4CMinItiEEEEvmPNT_1TEPNS3_2TIE Unexecuted instantiation: _ZN5faiss8heap_popINS_4CMaxItlEEEEvmPNT_1TEPNS3_2TIE Unexecuted instantiation: _ZN5faiss8heap_popINS_4CMinItlEEEEvmPNT_1TEPNS3_2TIE Unexecuted instantiation: _ZN5faiss8heap_popINS_4CMaxIilEEEEvmPNT_1TEPNS3_2TIE Unexecuted instantiation: _ZN5faiss8heap_popINS_4CMinIilEEEEvmPNT_1TEPNS3_2TIE Unexecuted instantiation: _ZN5faiss8heap_popINS_4CMinIfiEEEEvmPNT_1TEPNS3_2TIE Unexecuted instantiation: _ZN5faiss8heap_popINS_4CMinIiiEEEEvmPNT_1TEPNS3_2TIE Unexecuted instantiation: _ZN5faiss8heap_popINS_4CMaxIiiEEEEvmPNT_1TEPNS3_2TIE |
78 | | |
79 | | /** Pushes the element (val, ids) into the heap bh_val[0..k-2] and |
80 | | * bh_ids[0..k-2]. on output the element at k-1 is defined. |
81 | | */ |
82 | | template <class C> |
83 | | inline void heap_push( |
84 | | size_t k, |
85 | | typename C::T* bh_val, |
86 | | typename C::TI* bh_ids, |
87 | | typename C::T val, |
88 | 7.26k | typename C::TI id) { |
89 | 7.26k | bh_val--; /* Use 1-based indexing for easier node->child translation */ |
90 | 7.26k | bh_ids--; |
91 | 7.26k | size_t i = k, i_father; |
92 | 15.1k | while (i > 1) { |
93 | 14.6k | i_father = i >> 1; |
94 | 14.6k | if (!C::cmp2(val, bh_val[i_father], id, bh_ids[i_father])) { |
95 | | /* the heap structure is ok */ |
96 | 6.77k | break; |
97 | 6.77k | } |
98 | 7.85k | bh_val[i] = bh_val[i_father]; |
99 | 7.85k | bh_ids[i] = bh_ids[i_father]; |
100 | 7.85k | i = i_father; |
101 | 7.85k | } |
102 | 7.26k | bh_val[i] = val; |
103 | 7.26k | bh_ids[i] = id; |
104 | 7.26k | } Unexecuted instantiation: _ZN5faiss9heap_pushINS_4CMinIflEEEEvmPNT_1TEPNS3_2TIES4_S6_ Unexecuted instantiation: _ZN5faiss9heap_pushINS_4CMaxIflEEEEvmPNT_1TEPNS3_2TIES4_S6_ _ZN5faiss9heap_pushINS_4CMaxIfiEEEEvmPNT_1TEPNS3_2TIES4_S6_ Line | Count | Source | 88 | 7.26k | typename C::TI id) { | 89 | 7.26k | bh_val--; /* Use 1-based indexing for easier node->child translation */ | 90 | 7.26k | bh_ids--; | 91 | 7.26k | size_t i = k, i_father; | 92 | 15.1k | while (i > 1) { | 93 | 14.6k | i_father = i >> 1; | 94 | 14.6k | if (!C::cmp2(val, bh_val[i_father], id, bh_ids[i_father])) { | 95 | | /* the heap structure is ok */ | 96 | 6.77k | break; | 97 | 6.77k | } | 98 | 7.85k | bh_val[i] = bh_val[i_father]; | 99 | 7.85k | bh_ids[i] = bh_ids[i_father]; | 100 | 7.85k | i = i_father; | 101 | 7.85k | } | 102 | 7.26k | bh_val[i] = val; | 103 | 7.26k | bh_ids[i] = id; | 104 | 7.26k | } |
Unexecuted instantiation: _ZN5faiss9heap_pushINS_4CMaxItiEEEEvmPNT_1TEPNS3_2TIES4_S6_ Unexecuted instantiation: _ZN5faiss9heap_pushINS_4CMinItiEEEEvmPNT_1TEPNS3_2TIES4_S6_ Unexecuted instantiation: _ZN5faiss9heap_pushINS_4CMaxItlEEEEvmPNT_1TEPNS3_2TIES4_S6_ Unexecuted instantiation: _ZN5faiss9heap_pushINS_4CMinItlEEEEvmPNT_1TEPNS3_2TIES4_S6_ Unexecuted instantiation: _ZN5faiss9heap_pushINS_4CMaxIilEEEEvmPNT_1TEPNS3_2TIES4_S6_ Unexecuted instantiation: _ZN5faiss9heap_pushINS_4CMinIilEEEEvmPNT_1TEPNS3_2TIES4_S6_ Unexecuted instantiation: _ZN5faiss9heap_pushINS_4CMinIfiEEEEvmPNT_1TEPNS3_2TIES4_S6_ Unexecuted instantiation: _ZN5faiss9heap_pushINS_4CMinIiiEEEEvmPNT_1TEPNS3_2TIES4_S6_ Unexecuted instantiation: _ZN5faiss9heap_pushINS_4CMaxIiiEEEEvmPNT_1TEPNS3_2TIES4_S6_ |
105 | | |
106 | | /** |
107 | | * Replaces the top element from the heap defined by bh_val[0..k-1] and |
108 | | * bh_ids[0..k-1], and for identical bh_val[] values also sorts by bh_ids[] |
109 | | * values. |
110 | | */ |
111 | | template <class C> |
112 | | inline void heap_replace_top( |
113 | | size_t k, |
114 | | typename C::T* bh_val, |
115 | | typename C::TI* bh_ids, |
116 | | typename C::T val, |
117 | 3.75k | typename C::TI id) { |
118 | 3.75k | bh_val--; /* Use 1-based indexing for easier node->child translation */ |
119 | 3.75k | bh_ids--; |
120 | 3.75k | size_t i = 1, i1, i2; |
121 | 28.4k | while (1) { |
122 | 28.4k | i1 = i << 1; |
123 | 28.4k | i2 = i1 + 1; |
124 | 28.4k | if (i1 > k) { |
125 | 2.87k | break; |
126 | 2.87k | } |
127 | | |
128 | | // Note that C::cmp2() is a bool function answering |
129 | | // `(a1 > b1) || ((a1 == b1) && (a2 > b2))` for max |
130 | | // heap and same with the `<` sign for min heap. |
131 | 25.5k | if ((i2 == k + 1) || |
132 | 25.5k | C::cmp2(bh_val[i1], bh_val[i2], bh_ids[i1], bh_ids[i2])) { |
133 | 12.9k | if (C::cmp2(val, bh_val[i1], id, bh_ids[i1])) { |
134 | 479 | break; |
135 | 479 | } |
136 | 12.5k | bh_val[i] = bh_val[i1]; |
137 | 12.5k | bh_ids[i] = bh_ids[i1]; |
138 | 12.5k | i = i1; |
139 | 12.6k | } else { |
140 | 12.6k | if (C::cmp2(val, bh_val[i2], id, bh_ids[i2])) { |
141 | 409 | break; |
142 | 409 | } |
143 | 12.2k | bh_val[i] = bh_val[i2]; |
144 | 12.2k | bh_ids[i] = bh_ids[i2]; |
145 | 12.2k | i = i2; |
146 | 12.2k | } |
147 | 25.5k | } |
148 | 3.75k | bh_val[i] = val; |
149 | 3.75k | bh_ids[i] = id; |
150 | 3.75k | } Unexecuted instantiation: _ZN5faiss16heap_replace_topINS_4CMinIflEEEEvmPNT_1TEPNS3_2TIES4_S6_ _ZN5faiss16heap_replace_topINS_4CMaxIflEEEEvmPNT_1TEPNS3_2TIES4_S6_ Line | Count | Source | 117 | 3.75k | typename C::TI id) { | 118 | 3.75k | bh_val--; /* Use 1-based indexing for easier node->child translation */ | 119 | 3.75k | bh_ids--; | 120 | 3.75k | size_t i = 1, i1, i2; | 121 | 28.4k | while (1) { | 122 | 28.4k | i1 = i << 1; | 123 | 28.4k | i2 = i1 + 1; | 124 | 28.4k | if (i1 > k) { | 125 | 2.87k | break; | 126 | 2.87k | } | 127 | | | 128 | | // Note that C::cmp2() is a bool function answering | 129 | | // `(a1 > b1) || ((a1 == b1) && (a2 > b2))` for max | 130 | | // heap and same with the `<` sign for min heap. | 131 | 25.5k | if ((i2 == k + 1) || | 132 | 25.5k | C::cmp2(bh_val[i1], bh_val[i2], bh_ids[i1], bh_ids[i2])) { | 133 | 12.9k | if (C::cmp2(val, bh_val[i1], id, bh_ids[i1])) { | 134 | 479 | break; | 135 | 479 | } | 136 | 12.5k | bh_val[i] = bh_val[i1]; | 137 | 12.5k | bh_ids[i] = bh_ids[i1]; | 138 | 12.5k | i = i1; | 139 | 12.6k | } else { | 140 | 12.6k | if (C::cmp2(val, bh_val[i2], id, bh_ids[i2])) { | 141 | 409 | break; | 142 | 409 | } | 143 | 12.2k | bh_val[i] = bh_val[i2]; | 144 | 12.2k | bh_ids[i] = bh_ids[i2]; | 145 | 12.2k | i = i2; | 146 | 12.2k | } | 147 | 25.5k | } | 148 | 3.75k | bh_val[i] = val; | 149 | 3.75k | bh_ids[i] = id; | 150 | 3.75k | } |
Unexecuted instantiation: _ZN5faiss16heap_replace_topINS_4CMaxIfiEEEEvmPNT_1TEPNS3_2TIES4_S6_ Unexecuted instantiation: _ZN5faiss16heap_replace_topINS_4CMaxItiEEEEvmPNT_1TEPNS3_2TIES4_S6_ Unexecuted instantiation: _ZN5faiss16heap_replace_topINS_4CMinItiEEEEvmPNT_1TEPNS3_2TIES4_S6_ Unexecuted instantiation: _ZN5faiss16heap_replace_topINS_4CMaxItlEEEEvmPNT_1TEPNS3_2TIES4_S6_ Unexecuted instantiation: _ZN5faiss16heap_replace_topINS_4CMinItlEEEEvmPNT_1TEPNS3_2TIES4_S6_ Unexecuted instantiation: _ZN5faiss16heap_replace_topINS_4CMaxIilEEEEvmPNT_1TEPNS3_2TIES4_S6_ Unexecuted instantiation: _ZN5faiss16heap_replace_topINS_4CMinIfiEEEEvmPNT_1TEPNS3_2TIES4_S6_ Unexecuted instantiation: _ZN5faiss16heap_replace_topINS_4CMinIilEEEEvmPNT_1TEPNS3_2TIES4_S6_ |
151 | | |
152 | | /* Partial instanciation for heaps with TI = int64_t */ |
153 | | |
154 | | template <typename T> |
155 | | inline void minheap_pop(size_t k, T* bh_val, int64_t* bh_ids) { |
156 | | heap_pop<CMin<T, int64_t>>(k, bh_val, bh_ids); |
157 | | } |
158 | | |
159 | | template <typename T> |
160 | | inline void minheap_push( |
161 | | size_t k, |
162 | | T* bh_val, |
163 | | int64_t* bh_ids, |
164 | | T val, |
165 | | int64_t ids) { |
166 | | heap_push<CMin<T, int64_t>>(k, bh_val, bh_ids, val, ids); |
167 | | } |
168 | | |
169 | | template <typename T> |
170 | | inline void minheap_replace_top( |
171 | | size_t k, |
172 | | T* bh_val, |
173 | | int64_t* bh_ids, |
174 | | T val, |
175 | 0 | int64_t ids) { |
176 | 0 | heap_replace_top<CMin<T, int64_t>>(k, bh_val, bh_ids, val, ids); |
177 | 0 | } |
178 | | |
179 | | template <typename T> |
180 | | inline void maxheap_pop(size_t k, T* bh_val, int64_t* bh_ids) { |
181 | | heap_pop<CMax<T, int64_t>>(k, bh_val, bh_ids); |
182 | | } |
183 | | |
184 | | template <typename T> |
185 | | inline void maxheap_push( |
186 | | size_t k, |
187 | | T* bh_val, |
188 | | int64_t* bh_ids, |
189 | | T val, |
190 | 0 | int64_t ids) { |
191 | 0 | heap_push<CMax<T, int64_t>>(k, bh_val, bh_ids, val, ids); |
192 | 0 | } |
193 | | |
194 | | template <typename T> |
195 | | inline void maxheap_replace_top( |
196 | | size_t k, |
197 | | T* bh_val, |
198 | | int64_t* bh_ids, |
199 | | T val, |
200 | 0 | int64_t ids) { |
201 | 0 | heap_replace_top<CMax<T, int64_t>>(k, bh_val, bh_ids, val, ids); |
202 | 0 | } Unexecuted instantiation: _ZN5faiss19maxheap_replace_topIfEEvmPT_PlS1_l Unexecuted instantiation: _ZN5faiss19maxheap_replace_topIiEEvmPT_PlS1_l |
203 | | |
204 | | /******************************************************************* |
205 | | * Basic heap<std:pair<>> ops: push and pop |
206 | | *******************************************************************/ |
207 | | |
208 | | // This section contains a heap implementation that works with |
209 | | // std::pair<Priority, Value> elements. |
210 | | |
211 | | /** Pops the top element from the heap defined by bh_val[0..k-1] and |
212 | | * bh_ids[0..k-1]. on output the element at k-1 is undefined. |
213 | | */ |
214 | | template <class C> |
215 | | inline void heap_pop(size_t k, std::pair<typename C::T, typename C::TI>* bh) { |
216 | | bh--; /* Use 1-based indexing for easier node->child translation */ |
217 | | typename C::T val = bh[k].first; |
218 | | typename C::TI id = bh[k].second; |
219 | | size_t i = 1, i1, i2; |
220 | | while (1) { |
221 | | i1 = i << 1; |
222 | | i2 = i1 + 1; |
223 | | if (i1 > k) |
224 | | break; |
225 | | if ((i2 == k + 1) || |
226 | | C::cmp2(bh[i1].first, bh[i2].first, bh[i1].second, bh[i2].second)) { |
227 | | if (C::cmp2(val, bh[i1].first, id, bh[i1].second)) { |
228 | | break; |
229 | | } |
230 | | bh[i] = bh[i1]; |
231 | | i = i1; |
232 | | } else { |
233 | | if (C::cmp2(val, bh[i2].first, id, bh[i2].second)) { |
234 | | break; |
235 | | } |
236 | | bh[i] = bh[i2]; |
237 | | i = i2; |
238 | | } |
239 | | } |
240 | | bh[i] = bh[k]; |
241 | | } |
242 | | |
243 | | /** Pushes the element (val, ids) into the heap bh_val[0..k-2] and |
244 | | * bh_ids[0..k-2]. on output the element at k-1 is defined. |
245 | | */ |
246 | | template <class C> |
247 | | inline void heap_push( |
248 | | size_t k, |
249 | | std::pair<typename C::T, typename C::TI>* bh, |
250 | | typename C::T val, |
251 | | typename C::TI id) { |
252 | | bh--; /* Use 1-based indexing for easier node->child translation */ |
253 | | size_t i = k, i_father; |
254 | | while (i > 1) { |
255 | | i_father = i >> 1; |
256 | | auto bh_v = bh[i_father]; |
257 | | if (!C::cmp2(val, bh_v.first, id, bh_v.second)) { |
258 | | /* the heap structure is ok */ |
259 | | break; |
260 | | } |
261 | | bh[i] = bh_v; |
262 | | i = i_father; |
263 | | } |
264 | | bh[i] = std::make_pair(val, id); |
265 | | } |
266 | | |
267 | | /** |
268 | | * Replaces the top element from the heap defined by bh_val[0..k-1] and |
269 | | * bh_ids[0..k-1], and for identical bh_val[] values also sorts by bh_ids[] |
270 | | * values. |
271 | | */ |
272 | | template <class C> |
273 | | inline void heap_replace_top( |
274 | | size_t k, |
275 | | std::pair<typename C::T, typename C::TI>* bh, |
276 | | typename C::T val, |
277 | | typename C::TI id) { |
278 | | bh--; /* Use 1-based indexing for easier node->child translation */ |
279 | | size_t i = 1, i1, i2; |
280 | | while (1) { |
281 | | i1 = i << 1; |
282 | | i2 = i1 + 1; |
283 | | if (i1 > k) { |
284 | | break; |
285 | | } |
286 | | |
287 | | // Note that C::cmp2() is a bool function answering |
288 | | // `(a1 > b1) || ((a1 == b1) && (a2 > b2))` for max |
289 | | // heap and same with the `<` sign for min heap. |
290 | | if ((i2 == k + 1) || |
291 | | C::cmp2(bh[i1].first, bh[i2].first, bh[i1].second, bh[i2].second)) { |
292 | | if (C::cmp2(val, bh[i1].first, id, bh[i1].second)) { |
293 | | break; |
294 | | } |
295 | | bh[i] = bh[i1]; |
296 | | i = i1; |
297 | | } else { |
298 | | if (C::cmp2(val, bh[i2].first, id, bh[i2].second)) { |
299 | | break; |
300 | | } |
301 | | bh[i] = bh[i2]; |
302 | | i = i2; |
303 | | } |
304 | | } |
305 | | bh[i] = std::make_pair(val, id); |
306 | | } |
307 | | |
308 | | /******************************************************************* |
309 | | * Heap initialization |
310 | | *******************************************************************/ |
311 | | |
312 | | /* Initialization phase for the heap (with unconditionnal pushes). |
313 | | * Store k0 elements in a heap containing up to k values. Note that |
314 | | * (bh_val, bh_ids) can be the same as (x, ids) */ |
315 | | template <class C> |
316 | | inline void heap_heapify( |
317 | | size_t k, |
318 | | typename C::T* bh_val, |
319 | | typename C::TI* bh_ids, |
320 | | const typename C::T* x = nullptr, |
321 | | const typename C::TI* ids = nullptr, |
322 | 37 | size_t k0 = 0) { |
323 | 37 | if (k0 > 0) |
324 | 37 | assert(x); |
325 | | |
326 | 37 | if (ids) { |
327 | 0 | for (size_t i = 0; i < k0; i++) |
328 | 0 | heap_push<C>(i + 1, bh_val, bh_ids, x[i], ids[i]); |
329 | 37 | } else { |
330 | 37 | for (size_t i = 0; i < k0; i++) |
331 | 0 | heap_push<C>(i + 1, bh_val, bh_ids, x[i], i); |
332 | 37 | } |
333 | | |
334 | 4.01k | for (size_t i = k0; i < k; i++) { |
335 | 3.97k | bh_val[i] = C::neutral(); |
336 | 3.97k | bh_ids[i] = -1; |
337 | 3.97k | } |
338 | 37 | } Unexecuted instantiation: _ZN5faiss12heap_heapifyINS_4CMinIflEEEEvmPNT_1TEPNS3_2TIEPKS4_PKS6_m _ZN5faiss12heap_heapifyINS_4CMaxIflEEEEvmPNT_1TEPNS3_2TIEPKS4_PKS6_m Line | Count | Source | 322 | 37 | size_t k0 = 0) { | 323 | 37 | if (k0 > 0) | 324 | 37 | assert(x); | 325 | | | 326 | 37 | if (ids) { | 327 | 0 | for (size_t i = 0; i < k0; i++) | 328 | 0 | heap_push<C>(i + 1, bh_val, bh_ids, x[i], ids[i]); | 329 | 37 | } else { | 330 | 37 | for (size_t i = 0; i < k0; i++) | 331 | 0 | heap_push<C>(i + 1, bh_val, bh_ids, x[i], i); | 332 | 37 | } | 333 | | | 334 | 4.01k | for (size_t i = k0; i < k; i++) { | 335 | 3.97k | bh_val[i] = C::neutral(); | 336 | 3.97k | bh_ids[i] = -1; | 337 | 3.97k | } | 338 | 37 | } |
Unexecuted instantiation: _ZN5faiss12heap_heapifyINS_4CMaxItiEEEEvmPNT_1TEPNS3_2TIEPKS4_PKS6_m Unexecuted instantiation: _ZN5faiss12heap_heapifyINS_4CMinItiEEEEvmPNT_1TEPNS3_2TIEPKS4_PKS6_m Unexecuted instantiation: _ZN5faiss12heap_heapifyINS_4CMaxItlEEEEvmPNT_1TEPNS3_2TIEPKS4_PKS6_m Unexecuted instantiation: _ZN5faiss12heap_heapifyINS_4CMinItlEEEEvmPNT_1TEPNS3_2TIEPKS4_PKS6_m Unexecuted instantiation: _ZN5faiss12heap_heapifyINS_4CMaxIilEEEEvmPNT_1TEPNS3_2TIEPKS4_PKS6_m Unexecuted instantiation: _ZN5faiss12heap_heapifyINS_4CMinIilEEEEvmPNT_1TEPNS3_2TIEPKS4_PKS6_m Unexecuted instantiation: _ZN5faiss12heap_heapifyINS_4CMinIfiEEEEvmPNT_1TEPNS3_2TIEPKS4_PKS6_m Unexecuted instantiation: _ZN5faiss12heap_heapifyINS_4CMaxIfiEEEEvmPNT_1TEPNS3_2TIEPKS4_PKS6_m |
339 | | |
340 | | template <typename T> |
341 | | inline void minheap_heapify( |
342 | | size_t k, |
343 | | T* bh_val, |
344 | | int64_t* bh_ids, |
345 | | const T* x = nullptr, |
346 | | const int64_t* ids = nullptr, |
347 | 0 | size_t k0 = 0) { |
348 | 0 | heap_heapify<CMin<T, int64_t>>(k, bh_val, bh_ids, x, ids, k0); |
349 | 0 | } |
350 | | |
351 | | template <typename T> |
352 | | inline void maxheap_heapify( |
353 | | size_t k, |
354 | | T* bh_val, |
355 | | int64_t* bh_ids, |
356 | | const T* x = nullptr, |
357 | | const int64_t* ids = nullptr, |
358 | 0 | size_t k0 = 0) { |
359 | 0 | heap_heapify<CMax<T, int64_t>>(k, bh_val, bh_ids, x, ids, k0); |
360 | 0 | } |
361 | | |
362 | | /******************************************************************* |
363 | | * Add n elements to the heap |
364 | | *******************************************************************/ |
365 | | |
366 | | /* Add some elements to the heap */ |
367 | | template <class C> |
368 | | inline void heap_addn( |
369 | | size_t k, |
370 | | typename C::T* bh_val, |
371 | | typename C::TI* bh_ids, |
372 | | const typename C::T* x, |
373 | | const typename C::TI* ids, |
374 | 0 | size_t n) { |
375 | 0 | size_t i; |
376 | 0 | if (ids) |
377 | 0 | for (i = 0; i < n; i++) { |
378 | 0 | if (C::cmp(bh_val[0], x[i])) { |
379 | 0 | heap_replace_top<C>(k, bh_val, bh_ids, x[i], ids[i]); |
380 | 0 | } |
381 | 0 | } |
382 | 0 | else |
383 | 0 | for (i = 0; i < n; i++) { |
384 | 0 | if (C::cmp(bh_val[0], x[i])) { |
385 | 0 | heap_replace_top<C>(k, bh_val, bh_ids, x[i], i); |
386 | 0 | } |
387 | 0 | } |
388 | 0 | } Unexecuted instantiation: _ZN5faiss9heap_addnINS_4CMinIflEEEEvmPNT_1TEPNS3_2TIEPKS4_PKS6_m Unexecuted instantiation: _ZN5faiss9heap_addnINS_4CMaxIflEEEEvmPNT_1TEPNS3_2TIEPKS4_PKS6_m Unexecuted instantiation: _ZN5faiss9heap_addnINS_4CMaxIfiEEEEvmPNT_1TEPNS3_2TIEPKS4_PKS6_m |
389 | | |
390 | | /* Partial instanciation for heaps with TI = int64_t */ |
391 | | |
392 | | template <typename T> |
393 | | inline void minheap_addn( |
394 | | size_t k, |
395 | | T* bh_val, |
396 | | int64_t* bh_ids, |
397 | | const T* x, |
398 | | const int64_t* ids, |
399 | 0 | size_t n) { |
400 | 0 | heap_addn<CMin<T, int64_t>>(k, bh_val, bh_ids, x, ids, n); |
401 | 0 | } |
402 | | |
403 | | template <typename T> |
404 | | inline void maxheap_addn( |
405 | | size_t k, |
406 | | T* bh_val, |
407 | | int64_t* bh_ids, |
408 | | const T* x, |
409 | | const int64_t* ids, |
410 | | size_t n) { |
411 | | heap_addn<CMax<T, int64_t>>(k, bh_val, bh_ids, x, ids, n); |
412 | | } |
413 | | |
414 | | /******************************************************************* |
415 | | * Heap finalization (reorder elements) |
416 | | *******************************************************************/ |
417 | | |
418 | | /* This function maps a binary heap into a sorted structure. |
419 | | It returns the number */ |
420 | | template <typename C> |
421 | | inline size_t heap_reorder( |
422 | | size_t k, |
423 | | typename C::T* bh_val, |
424 | 37 | typename C::TI* bh_ids) { |
425 | 37 | size_t i, ii; |
426 | | |
427 | 4.01k | for (i = 0, ii = 0; i < k; i++) { |
428 | | /* top element should be put at the end of the list */ |
429 | 3.97k | typename C::T val = bh_val[0]; |
430 | 3.97k | typename C::TI id = bh_ids[0]; |
431 | | |
432 | | /* boundary case: we will over-ride this value if not a true element */ |
433 | 3.97k | heap_pop<C>(k - i, bh_val, bh_ids); |
434 | 3.97k | bh_val[k - ii - 1] = val; |
435 | 3.97k | bh_ids[k - ii - 1] = id; |
436 | 3.97k | if (id != -1) |
437 | 3.30k | ii++; |
438 | 3.97k | } |
439 | | /* Count the number of elements which are effectively returned */ |
440 | 37 | size_t nel = ii; |
441 | | |
442 | 37 | memmove(bh_val, bh_val + k - ii, ii * sizeof(*bh_val)); |
443 | 37 | memmove(bh_ids, bh_ids + k - ii, ii * sizeof(*bh_ids)); |
444 | | |
445 | 712 | for (; ii < k; ii++) { |
446 | 675 | bh_val[ii] = C::neutral(); |
447 | 675 | bh_ids[ii] = -1; |
448 | 675 | } |
449 | 37 | return nel; |
450 | 37 | } Unexecuted instantiation: _ZN5faiss12heap_reorderINS_4CMinIflEEEEmmPNT_1TEPNS3_2TIE _ZN5faiss12heap_reorderINS_4CMaxIflEEEEmmPNT_1TEPNS3_2TIE Line | Count | Source | 424 | 37 | typename C::TI* bh_ids) { | 425 | 37 | size_t i, ii; | 426 | | | 427 | 4.01k | for (i = 0, ii = 0; i < k; i++) { | 428 | | /* top element should be put at the end of the list */ | 429 | 3.97k | typename C::T val = bh_val[0]; | 430 | 3.97k | typename C::TI id = bh_ids[0]; | 431 | | | 432 | | /* boundary case: we will over-ride this value if not a true element */ | 433 | 3.97k | heap_pop<C>(k - i, bh_val, bh_ids); | 434 | 3.97k | bh_val[k - ii - 1] = val; | 435 | 3.97k | bh_ids[k - ii - 1] = id; | 436 | 3.97k | if (id != -1) | 437 | 3.30k | ii++; | 438 | 3.97k | } | 439 | | /* Count the number of elements which are effectively returned */ | 440 | 37 | size_t nel = ii; | 441 | | | 442 | 37 | memmove(bh_val, bh_val + k - ii, ii * sizeof(*bh_val)); | 443 | 37 | memmove(bh_ids, bh_ids + k - ii, ii * sizeof(*bh_ids)); | 444 | | | 445 | 712 | for (; ii < k; ii++) { | 446 | 675 | bh_val[ii] = C::neutral(); | 447 | 675 | bh_ids[ii] = -1; | 448 | 675 | } | 449 | 37 | return nel; | 450 | 37 | } |
Unexecuted instantiation: _ZN5faiss12heap_reorderINS_4CMaxItiEEEEmmPNT_1TEPNS3_2TIE Unexecuted instantiation: _ZN5faiss12heap_reorderINS_4CMinItiEEEEmmPNT_1TEPNS3_2TIE Unexecuted instantiation: _ZN5faiss12heap_reorderINS_4CMaxItlEEEEmmPNT_1TEPNS3_2TIE Unexecuted instantiation: _ZN5faiss12heap_reorderINS_4CMinItlEEEEmmPNT_1TEPNS3_2TIE Unexecuted instantiation: _ZN5faiss12heap_reorderINS_4CMaxIilEEEEmmPNT_1TEPNS3_2TIE Unexecuted instantiation: _ZN5faiss12heap_reorderINS_4CMinIilEEEEmmPNT_1TEPNS3_2TIE Unexecuted instantiation: _ZN5faiss12heap_reorderINS_4CMaxIfiEEEEmmPNT_1TEPNS3_2TIE Unexecuted instantiation: _ZN5faiss12heap_reorderINS_4CMinIfiEEEEmmPNT_1TEPNS3_2TIE |
451 | | |
452 | | template <typename T> |
453 | 0 | inline size_t minheap_reorder(size_t k, T* bh_val, int64_t* bh_ids) { |
454 | 0 | return heap_reorder<CMin<T, int64_t>>(k, bh_val, bh_ids); |
455 | 0 | } |
456 | | |
457 | | template <typename T> |
458 | 0 | inline size_t maxheap_reorder(size_t k, T* bh_val, int64_t* bh_ids) { |
459 | 0 | return heap_reorder<CMax<T, int64_t>>(k, bh_val, bh_ids); |
460 | 0 | } |
461 | | |
462 | | /******************************************************************* |
463 | | * Operations on heap arrays |
464 | | *******************************************************************/ |
465 | | |
466 | | /** a template structure for a set of [min|max]-heaps it is tailored |
467 | | * so that the actual data of the heaps can just live in compact |
468 | | * arrays. |
469 | | */ |
470 | | template <typename C> |
471 | | struct HeapArray { |
472 | | typedef typename C::TI TI; |
473 | | typedef typename C::T T; |
474 | | |
475 | | size_t nh; ///< number of heaps |
476 | | size_t k; ///< allocated size per heap |
477 | | TI* ids; ///< identifiers (size nh * k) |
478 | | T* val; ///< values (distances or similarities), size nh * k |
479 | | |
480 | | /// Return the list of values for a heap |
481 | 0 | T* get_val(size_t key) { |
482 | 0 | return val + key * k; |
483 | 0 | } Unexecuted instantiation: _ZN5faiss9HeapArrayINS_4CMinIflEEE7get_valEm Unexecuted instantiation: _ZN5faiss9HeapArrayINS_4CMaxIflEEE7get_valEm Unexecuted instantiation: _ZN5faiss9HeapArrayINS_4CMinIfiEEE7get_valEm Unexecuted instantiation: _ZN5faiss9HeapArrayINS_4CMaxIfiEEE7get_valEm Unexecuted instantiation: _ZN5faiss9HeapArrayINS_4CMinIilEEE7get_valEm Unexecuted instantiation: _ZN5faiss9HeapArrayINS_4CMaxIilEEE7get_valEm |
484 | | |
485 | | /// Correspponding identifiers |
486 | 0 | TI* get_ids(size_t key) { |
487 | 0 | return ids + key * k; |
488 | 0 | } Unexecuted instantiation: _ZN5faiss9HeapArrayINS_4CMinIflEEE7get_idsEm Unexecuted instantiation: _ZN5faiss9HeapArrayINS_4CMaxIflEEE7get_idsEm Unexecuted instantiation: _ZN5faiss9HeapArrayINS_4CMinIfiEEE7get_idsEm Unexecuted instantiation: _ZN5faiss9HeapArrayINS_4CMaxIfiEEE7get_idsEm Unexecuted instantiation: _ZN5faiss9HeapArrayINS_4CMinIilEEE7get_idsEm Unexecuted instantiation: _ZN5faiss9HeapArrayINS_4CMaxIilEEE7get_idsEm |
489 | | |
490 | | /// prepare all the heaps before adding |
491 | | void heapify(); |
492 | | |
493 | | /** add nj elements to heaps i0:i0+ni, with sequential ids |
494 | | * |
495 | | * @param nj nb of elements to add to each heap |
496 | | * @param vin elements to add, size ni * nj |
497 | | * @param j0 add this to the ids that are added |
498 | | * @param i0 first heap to update |
499 | | * @param ni nb of elements to update (-1 = use nh) |
500 | | */ |
501 | | void addn( |
502 | | size_t nj, |
503 | | const T* vin, |
504 | | TI j0 = 0, |
505 | | size_t i0 = 0, |
506 | | int64_t ni = -1); |
507 | | |
508 | | /** same as addn |
509 | | * |
510 | | * @param id_in ids of the elements to add, size ni * nj |
511 | | * @param id_stride stride for id_in |
512 | | */ |
513 | | void addn_with_ids( |
514 | | size_t nj, |
515 | | const T* vin, |
516 | | const TI* id_in = nullptr, |
517 | | int64_t id_stride = 0, |
518 | | size_t i0 = 0, |
519 | | int64_t ni = -1); |
520 | | |
521 | | /** same as addn_with_ids, but for just a subset of queries |
522 | | * |
523 | | * @param nsubset number of query entries to update |
524 | | * @param subset indexes of queries to update, in 0..nh-1, size nsubset |
525 | | */ |
526 | | void addn_query_subset_with_ids( |
527 | | size_t nsubset, |
528 | | const TI* subset, |
529 | | size_t nj, |
530 | | const T* vin, |
531 | | const TI* id_in = nullptr, |
532 | | int64_t id_stride = 0); |
533 | | |
534 | | /// reorder all the heaps |
535 | | void reorder(); |
536 | | |
537 | | /** this is not really a heap function. It just finds the per-line |
538 | | * extrema of each line of array D |
539 | | * @param vals_out extreme value of each line (size nh, or NULL) |
540 | | * @param idx_out index of extreme value (size nh or NULL) |
541 | | */ |
542 | | void per_line_extrema(T* vals_out, TI* idx_out) const; |
543 | | }; |
544 | | |
545 | | /* Define useful heaps */ |
546 | | typedef HeapArray<CMin<float, int64_t>> float_minheap_array_t; |
547 | | typedef HeapArray<CMin<int, int64_t>> int_minheap_array_t; |
548 | | |
549 | | typedef HeapArray<CMax<float, int64_t>> float_maxheap_array_t; |
550 | | typedef HeapArray<CMax<int, int64_t>> int_maxheap_array_t; |
551 | | |
552 | | // The heap templates are instantiated explicitly in Heap.cpp |
553 | | |
554 | | /********************************************************************* |
555 | | * Indirect heaps: instead of having |
556 | | * |
557 | | * node i = (bh_ids[i], bh_val[i]), |
558 | | * |
559 | | * in indirect heaps, |
560 | | * |
561 | | * node i = (bh_ids[i], bh_val[bh_ids[i]]), |
562 | | * |
563 | | *********************************************************************/ |
564 | | |
565 | | template <class C> |
566 | | inline void indirect_heap_pop( |
567 | | size_t k, |
568 | | const typename C::T* bh_val, |
569 | 0 | typename C::TI* bh_ids) { |
570 | 0 | bh_ids--; /* Use 1-based indexing for easier node->child translation */ |
571 | 0 | typename C::T val = bh_val[bh_ids[k]]; |
572 | 0 | size_t i = 1; |
573 | 0 | while (1) { |
574 | 0 | size_t i1 = i << 1; |
575 | 0 | size_t i2 = i1 + 1; |
576 | 0 | if (i1 > k) |
577 | 0 | break; |
578 | 0 | typename C::TI id1 = bh_ids[i1], id2 = bh_ids[i2]; |
579 | 0 | if (i2 == k + 1 || C::cmp(bh_val[id1], bh_val[id2])) { |
580 | 0 | if (C::cmp(val, bh_val[id1])) |
581 | 0 | break; |
582 | 0 | bh_ids[i] = id1; |
583 | 0 | i = i1; |
584 | 0 | } else { |
585 | 0 | if (C::cmp(val, bh_val[id2])) |
586 | 0 | break; |
587 | 0 | bh_ids[i] = id2; |
588 | 0 | i = i2; |
589 | 0 | } |
590 | 0 | } |
591 | 0 | bh_ids[i] = bh_ids[k]; |
592 | 0 | } |
593 | | |
594 | | template <class C> |
595 | | inline void indirect_heap_push( |
596 | | size_t k, |
597 | | const typename C::T* bh_val, |
598 | | typename C::TI* bh_ids, |
599 | 0 | typename C::TI id) { |
600 | 0 | bh_ids--; /* Use 1-based indexing for easier node->child translation */ |
601 | 0 | typename C::T val = bh_val[id]; |
602 | 0 | size_t i = k; |
603 | 0 | while (i > 1) { |
604 | 0 | size_t i_father = i >> 1; |
605 | 0 | if (!C::cmp(val, bh_val[bh_ids[i_father]])) |
606 | 0 | break; |
607 | 0 | bh_ids[i] = bh_ids[i_father]; |
608 | 0 | i = i_father; |
609 | 0 | } |
610 | 0 | bh_ids[i] = id; |
611 | 0 | } |
612 | | |
613 | | /** Merge result tables from several shards. The per-shard results are assumed |
614 | | * to be sorted. Note that the C comparator is reversed w.r.t. the usual top-k |
615 | | * element heap because we want the best (ie. lowest for L2) result to be on |
616 | | * top, not the worst. Also, it needs to hold an index of a shard id (ie. |
617 | | * usually int32 is more than enough). |
618 | | * |
619 | | * @param all_distances size (nshard, n, k) |
620 | | * @param all_labels size (nshard, n, k) |
621 | | * @param distances output distances, size (n, k) |
622 | | * @param labels output labels, size (n, k) |
623 | | */ |
624 | | template <class idx_t, class C> |
625 | | void merge_knn_results( |
626 | | size_t n, |
627 | | size_t k, |
628 | | typename C::TI nshard, |
629 | | const typename C::T* all_distances, |
630 | | const idx_t* all_labels, |
631 | | typename C::T* distances, |
632 | | idx_t* labels); |
633 | | |
634 | | } // namespace faiss |
635 | | |
636 | | #endif /* FAISS_Heap_h */ |