MLIR-AIE
d_ary_heap.h
Go to the documentation of this file.
1// clang-format off
2//
3//=======================================================================
4// Copyright 2009 Trustees of Indiana University
5// Authors: Jeremiah J. Willcock, Andrew Lumsdaine
6//
7// Distributed under the Boost Software License, Version 1.0. (See
8// accompanying file LICENSE_1_0.txt or copy at
9// http://www.boost.org/LICENSE_1_0.txt)
10//=======================================================================
11//
12// Pulled from libboost-system-dev 1.74.0.3 (ubuntu 22.04)
13// https://www.boost.org/doc/libs/1_74_0/boost/heap/d_ary_heap.hpp
14
15#ifndef D_ARY_HEAP_HPP
16#define D_ARY_HEAP_HPP
17
18#include <vector>
19#include <cstddef>
20#include <algorithm>
21#include <utility>
22
23// WARNING: it is not safe to copy a d_ary_heap_indirect and then modify one of
24// the copies. The class is required to be copyable so it can be passed around
25// (without move support from C++11), but it deep-copies the heap contents yet
26// shallow-copies the index_in_heap_map.
27
28// Swap two elements in a property map without assuming they model
29// LvaluePropertyMap -- currently not used
30// template < typename PropMap >
31// inline void property_map_swap(PropMap prop_map,
32// const typename boost::property_traits< PropMap >::key_type& ka,
33// const typename boost::property_traits< PropMap >::key_type& kb)
34// {
35// typename boost::property_traits< PropMap >::value_type va
36// = get(prop_map, ka);
37// put(prop_map, ka, get(prop_map, kb));
38// put(prop_map, kb, va);
39// }
40
41// namespace detail
42// {
43// template < typename Value > class fixed_max_size_vector
44// {
45// boost::shared_array< Value > m_data;
46// std::size_t m_size;
47//
48// public:
49// typedef std::size_t size_type;
50// fixed_max_size_vector(std::size_t max_size)
51// : m_data(new Value[max_size]), m_size(0)
52// {
53// }
54// std::size_t size() const { return m_size; }
55// bool empty() const { return m_size == 0; }
56// Value& operator[](std::size_t i) { return m_data[i]; }
57// const Value& operator[](std::size_t i) const { return m_data[i]; }
58// void push_back(Value v) { m_data[m_size++] = v; }
59// void pop_back() { --m_size; }
60// Value& back() { return m_data[m_size - 1]; }
61// const Value& back() const { return m_data[m_size - 1]; }
62// };
63// }
64
65template <class T, class K, class V>
66inline void put(T& pa, K k, const V& val) { pa[k] = val; }
67
68template <class K, class V>
69inline const V& get(const std::map<K, V>& pa, K k) { return pa.at(k); }
70
71// D-ary heap using an indirect compare operator (use identity_property_map
72// as DistanceMap to get a direct compare operator). This heap appears to be
73// commonly used for Dijkstra's algorithm for its good practical performance
74// on some platforms; asymptotically, it has an O(lg N) decrease-key
75// operation while that can be done in constant time on a relaxed heap. The
76// implementation is mostly based on the binary heap page on Wikipedia and
77// online sources that state that the operations are the same for d-ary
78// heaps. This code is not based on the old Boost d-ary heap code.
79//
80// - d_ary_heap_indirect is a model of UpdatableQueue as is needed for
81// dijkstra_shortest_paths.
82//
83// - Value must model Assignable.
84// - Arity must be at least 2 (optimal value appears to be 4, both in my and
85// third-party experiments).
86// - IndexInHeapMap must be a ReadWritePropertyMap from Value to
87// Container::size_type (to store the index of each stored value within the
88// heap for decrease-key aka update).
89// - DistanceMap must be a ReadablePropertyMap from Value to something
90// (typedef'ed as distance_type).
91// - Compare must be a BinaryPredicate used as a less-than operator on
92// distance_type.
93// - Container must be a random-access, contiguous container (in practice,
94// the operations used probably require that it is std::vector<Value>).
95//
96template < typename Value, std::size_t Arity, typename IndexInHeapPropertyMap,
97 typename DistanceMap, typename Compare = std::less< Value >,
98 typename Container = std::vector< Value > >
100{
101 // BOOST_STATIC_ASSERT(Arity >= 2);
102
103public:
104 typedef typename Container::size_type size_type;
105 typedef Value value_type;
106 // typedef typename boost::property_traits< DistanceMap >::value_type key_type;
107 // typedef DistanceMap key_map;
108
109 d_ary_heap_indirect(DistanceMap distance,
110 IndexInHeapPropertyMap index_in_heap,
111 const Compare& compare = Compare(), const Container& data = Container())
112 : compare(compare)
113 , data(data)
114 , distance(distance)
115 , index_in_heap(index_in_heap)
116 {
117 }
118 /* Implicit copy constructor */
119 /* Implicit assignment operator */
120
121 size_type size() const { return data.size(); }
122
123 bool empty() const { return data.empty(); }
124
125 void push(const Value& v)
126 {
127 size_type index = data.size();
128 data.push_back(v);
129 put(index_in_heap, v, index);
130 preserve_heap_property_up(index);
131 verify_heap();
132 }
133
134 Value& top()
135 {
136 // BOOST_ASSERT(!this->empty());
137 return data[0];
138 }
139
140 const Value& top() const
141 {
142 // BOOST_ASSERT(!this->empty());
143 return data[0];
144 }
145
146 void pop()
147 {
148 // BOOST_ASSERT(!this->empty());
149 put(index_in_heap, data[0], (size_type)(-1));
150 if (data.size() != 1)
151 {
152 data[0] = data.back();
153 put(index_in_heap, data[0], (size_type)(0));
154 data.pop_back();
155 preserve_heap_property_down();
156 verify_heap();
157 }
158 else
159 {
160 data.pop_back();
161 }
162 }
163
164 // This function assumes the key has been updated (using an external write
165 // to the distance map or such)
166 // See
167 // http://coding.derkeiler.com/Archive/General/comp.theory/2007-05/msg00043.html
168 void update(const Value& v)
169 { /* decrease-key */
170 size_type index = get(index_in_heap, v);
171 preserve_heap_property_up(index);
172 verify_heap();
173 }
174
175 bool contains(const Value& v) const
176 {
177 size_type index = get(index_in_heap, v);
178 return (index != (size_type)(-1));
179 }
180
181 void push_or_update(const Value& v)
182 { /* insert if not present, else update */
183 size_type index = get(index_in_heap, v);
184 if (index == (size_type)(-1))
185 {
186 index = data.size();
187 data.push_back(v);
188 put(index_in_heap, v, index);
189 }
190 preserve_heap_property_up(index);
191 verify_heap();
192 }
193
194 DistanceMap keys() const { return distance; }
195
196private:
197 Compare compare;
198 Container data;
199 DistanceMap distance;
200 IndexInHeapPropertyMap index_in_heap;
201
202 // The distances being compared using compare and that are stored in the
203 // distance map
204 // typedef typename boost::property_traits< DistanceMap >::value_type
205 // distance_type;
206 typedef typename std::remove_reference<DistanceMap>::type::mapped_type distance_type;
207
208 // Get the parent of a given node in the heap
209 static size_type parent(size_type index) { return (index - 1) / Arity; }
210
211 // Get the child_idx'th child of a given node; 0 <= child_idx < Arity
212 static size_type child(size_type index, std::size_t child_idx)
213 {
214 return index * Arity + child_idx + 1;
215 }
216
217 // Swap two elements in the heap by index, updating index_in_heap
218 void swap_heap_elements(size_type index_a, size_type index_b)
219 {
220 using std::swap;
221 Value value_a = data[index_a];
222 Value value_b = data[index_b];
223 data[index_a] = value_b;
224 data[index_b] = value_a;
225 put(index_in_heap, value_a, index_b);
226 put(index_in_heap, value_b, index_a);
227 }
228
229 // Emulate the indirect_cmp that is now folded into this heap class
230 bool compare_indirect(const Value& a, const Value& b) const
231 {
232 return compare(get(distance, a), get(distance, b));
233 }
234
235 // Verify that the array forms a heap; commented out by default
236 void verify_heap() const
237 {
238 // This is a very expensive test so it should be disabled even when
239 // NDEBUG is not defined
240#if 0
241 for (size_t i = 1; i < data.size(); ++i) {
242 if (compare_indirect(data[i], data[parent(i)])) {
243 // BOOST_ASSERT (!"Element is smaller than its parent");
244 }
245 }
246#endif
247 }
248
249 // Starting at a node, move up the tree swapping elements to preserve the
250 // heap property
251 void preserve_heap_property_up(size_type index)
252 {
253 size_type orig_index = index;
254 size_type num_levels_moved = 0;
255 // The first loop just saves swaps that need to be done in order to
256 // avoid aliasing issues in its search; there is a second loop that does
257 // the necessary swap operations
258 if (index == 0)
259 return; // Do nothing on root
260 Value currently_being_moved = data[index];
261 distance_type currently_being_moved_dist
262 = get(distance, currently_being_moved);
263 for (;;)
264 {
265 if (index == 0)
266 break; // Stop at root
267 size_type parent_index = parent(index);
268 Value parent_value = data[parent_index];
269 if (compare(
270 currently_being_moved_dist, get(distance, parent_value)))
271 {
272 ++num_levels_moved;
273 index = parent_index;
274 continue;
275 }
276 else
277 {
278 break; // Heap property satisfied
279 }
280 }
281 // Actually do the moves -- move num_levels_moved elements down in the
282 // tree, then put currently_being_moved at the top
283 index = orig_index;
284 for (size_type i = 0; i < num_levels_moved; ++i)
285 {
286 size_type parent_index = parent(index);
287 Value parent_value = data[parent_index];
288 put(index_in_heap, parent_value, index);
289 data[index] = parent_value;
290 index = parent_index;
291 }
292 data[index] = currently_being_moved;
293 put(index_in_heap, currently_being_moved, index);
294 verify_heap();
295 }
296
297 // From the root, swap elements (each one with its smallest child) if there
298 // are any parent-child pairs that violate the heap property
299 void preserve_heap_property_down()
300 {
301 if (data.empty())
302 return;
303 size_type index = 0;
304 Value currently_being_moved = data[0];
305 distance_type currently_being_moved_dist
306 = get(distance, currently_being_moved);
307 size_type heap_size = data.size();
308 Value* data_ptr = &data[0];
309 for (;;)
310 {
311 size_type first_child_index = child(index, 0);
312 if (first_child_index >= heap_size)
313 break; /* No children */
314 Value* child_base_ptr = data_ptr + first_child_index;
315 size_type smallest_child_index = 0;
316 distance_type smallest_child_dist
317 = get(distance, child_base_ptr[smallest_child_index]);
318 if (first_child_index + Arity <= heap_size)
319 {
320 // Special case for a statically known loop count (common case)
321 for (size_t i = 1; i < Arity; ++i)
322 {
323 Value i_value = child_base_ptr[i];
324 distance_type i_dist = get(distance, i_value);
325 if (compare(i_dist, smallest_child_dist))
326 {
327 smallest_child_index = i;
328 smallest_child_dist = i_dist;
329 }
330 }
331 }
332 else
333 {
334 for (size_t i = 1; i < heap_size - first_child_index; ++i)
335 {
336 distance_type i_dist = get(distance, child_base_ptr[i]);
337 if (compare(i_dist, smallest_child_dist))
338 {
339 smallest_child_index = i;
340 smallest_child_dist = i_dist;
341 }
342 }
343 }
344 if (compare(smallest_child_dist, currently_being_moved_dist))
345 {
346 swap_heap_elements(
347 smallest_child_index + first_child_index, index);
348 index = smallest_child_index + first_child_index;
349 continue;
350 }
351 else
352 {
353 break; // Heap property satisfied
354 }
355 }
356 verify_heap();
357 }
358};
359
360#endif // D_ARY_HEAP_HPP
361// clang-format on
bool contains(const Value &v) const
Definition d_ary_heap.h:175
Container::size_type size_type
Definition d_ary_heap.h:104
DistanceMap keys() const
Definition d_ary_heap.h:194
void update(const Value &v)
Definition d_ary_heap.h:168
d_ary_heap_indirect(DistanceMap distance, IndexInHeapPropertyMap index_in_heap, const Compare &compare=Compare(), const Container &data=Container())
Definition d_ary_heap.h:109
const Value & top() const
Definition d_ary_heap.h:140
void push_or_update(const Value &v)
Definition d_ary_heap.h:181
size_type size() const
Definition d_ary_heap.h:121
bool empty() const
Definition d_ary_heap.h:123
void push(const Value &v)
Definition d_ary_heap.h:125
void put(T &pa, K k, const V &val)
Definition d_ary_heap.h:66
const V & get(const std::map< K, V > &pa, K k)
Definition d_ary_heap.h:69