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