NVBIO
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
interval_heap.h
Go to the documentation of this file.
1 /*
2  * nvbio
3  * Copyright (c) 2011-2014, NVIDIA CORPORATION. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of the NVIDIA CORPORATION nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 //
29 // This software is a modification of:
30 //
31 // https://github.com/nmcclatchey/Priority-Deque/blob/master/interval_heap.hpp
32 //
33 //
34 
35 /*----------------------------------------------------------------------------*\
36 | Copyright (C) 2013 Nathaniel McClatchey |
37 | Released under the Boost Software License Version 1.0, which may be found |
38 | at http://www.boost.org/LICENSE_1_0.txt |
39 \*----------------------------------------------------------------------------*/
40 
61 #pragma once
62 
63 // Grab iterator data, for better use of templates.
64 #include <iterator>
65 
66 namespace nvbio {
67 namespace heap {
68 //------------------------------User-Accessible---------------------------------
70 template <typename Iterator, typename Compare>
72 void make_interval_heap (Iterator first, Iterator last, Compare compare);
73 
75 template <typename Iterator, typename Compare>
77 void push_interval_heap (Iterator first, Iterator last, Compare compare);
78 
81 template <typename Iterator, typename Compare>
83 void pop_interval_heap_min (Iterator first, Iterator last, Compare compare);
85 template <typename Iterator, typename Compare>
87 void pop_interval_heap_max (Iterator first, Iterator last, Compare compare);
88 
90 template <typename Iterator, typename Compare>
92 void pop_interval_heap (Iterator first, Iterator last,
93  typename std::iterator_traits<Iterator>::difference_type index,
94  Compare compare);
97 template <typename Iterator, typename Compare>
99 void update_interval_heap (Iterator first, Iterator last,
100  typename std::iterator_traits<Iterator>::difference_type index,
101  Compare compare);
102 
104 template <typename Iterator, typename Compare>
106 void sort_interval_heap (Iterator first, Iterator last, Compare compare);
108 template <typename Iterator, typename Compare>
110 Iterator is_interval_heap_until (Iterator first, Iterator last,Compare compare);
112 template <typename Iterator, typename Compare>
114 bool is_interval_heap (Iterator first, Iterator last, Compare compare);
115 
116 // utility swap
117 template <typename T>
119 void swap(T& a, T& b)
120 {
121  T tmp = a;
122  a = b;
123  b = tmp;
124 }
125 
126 //-------------------------------Book-Keeping-----------------------------------
127 namespace interval_heap_internal {
129 template <typename Iterator, typename Compare>
131 void sift_leaf (Iterator first, Iterator last,
132  typename std::iterator_traits<Iterator>::difference_type index,
133  Compare compare);
135 template <bool left_bound, typename Iterator, typename Offset, typename Compare>
137 void sift_up (Iterator first, Offset index, Compare compare,Offset limit_child);
139 template <typename Iterator, typename Offset, typename Compare>
141 void sift_leaf_max (Iterator first, Iterator last, Offset index,
142  Compare compare, Offset limit_child);
144 template <typename Iterator, typename Offset, typename Compare>
146 void sift_leaf_min (Iterator first, Iterator last, Offset index,
147  Compare compare, Offset limit_child);
149 template <bool left_bound, typename Iterator, typename Offset, typename Compare>
151 void sift_down (Iterator first, Iterator last, Offset index, Compare compare,
152  Offset limit_child);
153 } // Namespace interval_heap_internal
154 
169 template <typename Iterator, typename Compare>
170 void update_interval_heap (Iterator first, Iterator last,
171  typename std::iterator_traits<Iterator>::difference_type index,
172  Compare compare)
173 {
174  using namespace std;
176  typedef typename iterator_traits<Iterator>::difference_type Offset;
177  if (index & 1)
178  sift_down<false, Iterator, Offset, Compare>(first, last, index, compare,2);
179  else
180  sift_down<true, Iterator, Offset, Compare>(first, last, index, compare, 2);
181 }
182 
194 template <typename Iterator, typename Compare>
195 void push_interval_heap (Iterator first, Iterator last, Compare compare) {
197  sift_leaf<Iterator, Compare>(first, last, (last - first) - 1, compare);
198 }
199 
215 template <typename Iterator, typename Compare>
216 void pop_interval_heap (Iterator first, Iterator last,
217  typename std::iterator_traits<Iterator>::difference_type index,
218  Compare compare)
219 {
220  using namespace std;
221  --last;
222  swap(*(first + index), *last);
223 
224  update_interval_heap<Iterator, Compare>(first, last, index, compare);
225 }
226 
240 template <typename Iterator, typename Compare>
241 void pop_interval_heap_min (Iterator first, Iterator last, Compare compare) {
242  using namespace std;
244  typedef typename iterator_traits<Iterator>::difference_type Offset;
245  --last;
246  swap(*first, *last);
247 
248  sift_down<true, Iterator, Offset, Compare>(first, last, 0, compare, 2);
249 }
250 
264 template <typename Iterator, typename Compare>
265 void pop_interval_heap_max (Iterator first, Iterator last, Compare compare) {
266  using namespace std;
268  typedef typename iterator_traits<Iterator>::difference_type Offset;
269 // Nothing to be done.
270  if (last - first <= 2)
271  return;
272  --last;
273  swap(*(first + 1), *last);
274 
275  sift_down<false, Iterator, Offset, Compare>(first, last, 1, compare, 2);
276 }
277 
288 template <typename Iterator, typename Compare>
289 void sort_interval_heap (Iterator first, Iterator last, Compare compare) {
290  Iterator cursor = last;
291  while (cursor != first) {
292 // If this throws, anything I do to try to fix it is also likely to throw.
293  pop_interval_heap_max<Iterator, Compare>(first, cursor, compare);
294  --cursor;
295  }
296 }
297 
300 template <typename Iterator, typename Compare>
301 Iterator is_interval_heap_until (Iterator first, Iterator last, Compare compare)
302 {
303  using namespace std;
304  typedef typename iterator_traits<Iterator>::difference_type Offset;
305 
306  Offset index = static_cast<Offset>(0);
307 
308  try {
309  Offset index_end = last - first;
310  while (index < index_end) {
311  Iterator cursor = first + index;
312 // Check whether it is a valid interval.
313  if ((index & 1) && compare(*cursor, *(cursor - 1)))
314  return cursor;
315  if (index >= 2) {
316 // If there exists a parent interval, check for containment.
317  Iterator parent = first + ((index / 2 - 1) | 1);
318  if (index & 1) {
319  if (compare(*parent, *cursor))
320  return cursor;
321  } else {
322  if (compare(*parent, *cursor))
323  return cursor;
324  if (compare(*cursor, *(parent - 1)))
325  return cursor;
326  }
327  }
328  ++index;
329  }
330  } catch (...) {
331  return first + index;
332  }
333  return last;
334 }
335 
338 template <typename Iterator, typename Compare>
339 bool is_interval_heap (Iterator first, Iterator last, Compare compare) {
340  try {
341  return (is_interval_heap_until<Iterator,Compare>(first, last, compare)
342  == last);
343  } catch (...) {
344  return false;
345  }
346 }
347 
355 
356 template <typename Iterator, typename Compare>
357 void make_interval_heap (Iterator first, Iterator last, Compare compare) {
358  using namespace std;
360  typedef typename iterator_traits<Iterator>::difference_type Offset;
361 
362  Offset index_end = last - first;
363 // Double-heap property holds vacuously.
364  if (index_end <= 1)
365  return;
366 // Prevents overflow when number of elements approaches maximum possible index.
367  const Offset end_parent = index_end / 2 - 1;
368 // If the final interval is a singleton, it's already OK. Skip it.
369  Offset index = index_end ^ (index_end & 1);
370  do {
371  index -= 2;
372  const Offset stop = (index <= end_parent) ? (index * 2 + 2) : index_end;
373 // If compare throws, heap property cannot be verified or enforced.
374 // If swap throws, heap property is violated and cannot be enforced.
375  if (compare(*(first + index + 1), *(first + index)))
376  swap(*(first + index + 1), *(first + index));
377 
378  sift_down<false, Iterator, Offset, Compare>(first, last, index + 1,
379  compare, stop);
380  sift_down<true , Iterator, Offset, Compare>(first, last, index,
381  compare, stop);
382 
383  } while (index >= 2);
384 }
385 
386 namespace interval_heap_internal {
387 
389 template <bool left_bound, typename Iterator, typename Offset, typename Compare>
390 void sift_up (Iterator first, Offset origin, Compare compare, Offset limit_child)
391 {
392 // Use the most specialized available functions.
393  using namespace std;
394  typedef typename iterator_traits<Iterator>::value_type Value;
395 // Keeping the information about the origin permits strong exception guarantee.
396  Offset index = origin;
397 
398  while (index >= limit_child) {
399  const Offset parent = ((index / 2 - 1) | 1) ^ (left_bound ? 1 : 0);
400 
401  if (compare(*(first + (left_bound ? index : parent)),
402  *(first + (left_bound ? parent : index)))) {
403  swap(*(first + index), *(first + parent));
404 
405  index = parent;
406  } else
407  break;
408  }
409 }
410 
412 template <typename Iterator, typename Offset, typename Compare>
413 void sift_leaf_max (Iterator first, Iterator last, Offset index,
414  Compare compare, Offset limit_child)
415 {
416 // Use the most specialized swap function.
417  using namespace std;
418  const Offset index_end = last - first;
419 
420 // Index of corresponding element
421  const Offset co_index = (index * 2 < index_end) ? (index * 2) : (index ^ 1);
422  if (compare(*(first + index), *(first + co_index))) {
423  swap(*(first + index), *(first + co_index));
424 
425  sift_up<true, Iterator, Offset, Compare>(first, co_index, compare,limit_child);
426  } else
427  sift_up<false, Iterator, Offset, Compare>(first, index, compare,
428  limit_child);
429 }
430 
432 template <typename Iterator, typename Offset, typename Compare>
433 void sift_leaf_min (Iterator first, Iterator last, Offset index,
434  Compare compare, Offset limit_child)
435 {
436 // Use the most specialized swap function.
437  using namespace std;
438  const Offset index_end = last - first;
439 
440 // Index of corresponding element (initial assumption)
441  Offset co_index = index | 1;
442 // Co-index is past the end of the heap. Move to its parent, if possible.
443  if (co_index >= index_end) {
444 // Only one element.
445  if (co_index == 1)
446  return;
447  co_index = (co_index / 2 - 1) | 1;
448  }
449  if (compare(*(first + co_index), *(first + index))) {
450  swap(*(first + index), *(first + co_index));
451 
452  sift_up<false, Iterator, Offset, Compare>(first, co_index, compare, limit_child);
453  } else
454  sift_up<true, Iterator, Offset, Compare>(first, index, compare, limit_child);
455 }
456 
458 template <bool left_bound, typename Iterator, typename Offset, typename Compare>
459 void sift_down (Iterator first, Iterator last, Offset origin, Compare compare,
460  Offset limit_child)
461 {
462 // Use the most specialized available functions.
463  using namespace std;
464  typedef typename iterator_traits<Iterator>::value_type Value;
465 // By keeping track of where I started, I can roll back all changes.
466  Offset index = origin;
467 
468  const Offset index_end = last - first;
469 // One past the last element with two children.
470  const Offset end_parent = index_end / 2 -
471  ((left_bound && ((index_end & 3) == 0)) ? 2 : 1);
472 
473  while (index < end_parent) {
474  Offset child = index * 2 + (left_bound ? 2 : 1);
475 // If compare throws, heap property cannot be verified or enforced.
476  if (compare(*(first + child + (left_bound ? 2 : 0)),
477  *(first + child + (left_bound ? 0 : 2))))
478  child += 2;
479 
480  swap(*(first + index), *(first + child));
481  index = child;
482  }
483 // Special case when index has exactly one child.
484  if (index <= end_parent + (left_bound ? 0 : 1)) {
485  Offset child = index * 2 + (left_bound ? 2 : 1);
486  if (child < index_end) {
487 // Need to treat singletons (child + 1) as both upper and lower bounds.
488  if (!left_bound && (child + 1 < index_end)) {
489 // Calculating this outside the if-statement simplifies exception-handling.
490  bool swap_required = compare(*(first + child), *(first + child + 1));
491 
492  if (swap_required) {
493  ++child;
494 
495  swap(*(first + index), *(first + child));
496 
497 // Important for the rollback.
498  index = child;
499  sift_leaf_min<Iterator, Offset, Compare>(first, last, index,
500  compare, limit_child);
501  return;
502  }
503  }
504 
505  swap(*(first + index), *(first + child));
506  index = child;
507  }
508  }
509 
510  if (left_bound)
511  sift_leaf_min<Iterator, Offset, Compare>(first, last, index, compare,
512  limit_child);
513  else
514  sift_leaf_max<Iterator, Offset, Compare>(first, last, index, compare,
515  limit_child);
516 }
517 
519 template <typename Iterator, typename Compare>
520 void sift_leaf (Iterator first, Iterator last,
521  typename std::iterator_traits<Iterator>::difference_type index,
522  Compare compare)
523 {
524  using namespace std;
525  typedef typename iterator_traits<Iterator>::difference_type Offset;
526  if (index & 1)
527  sift_leaf_max<Iterator, Offset, Compare>(first, last, index, compare, 2);
528  else
529  sift_leaf_min<Iterator, Offset, Compare>(first, last, index, compare, 2);
530 }
531 } // Namespace interval_heap_internal
532 } // Namespace heap
533 } // namespace nvbio