Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:37:10

0001 //
0002 //=======================================================================
0003 // Copyright 2009 Trustees of Indiana University
0004 // Authors: Jeremiah J. Willcock, Andrew Lumsdaine
0005 //
0006 // Distributed under the Boost Software License, Version 1.0. (See
0007 // accompanying file LICENSE_1_0.txt or copy at
0008 // http://www.boost.org/LICENSE_1_0.txt)
0009 //=======================================================================
0010 //
0011 #ifndef BOOST_D_ARY_HEAP_HPP
0012 #define BOOST_D_ARY_HEAP_HPP
0013 
0014 #include <vector>
0015 #include <cstddef>
0016 #include <algorithm>
0017 #include <utility>
0018 #include <boost/assert.hpp>
0019 #include <boost/static_assert.hpp>
0020 #include <boost/shared_array.hpp>
0021 #include <boost/property_map/property_map.hpp>
0022 
0023 // WARNING: it is not safe to copy a d_ary_heap_indirect and then modify one of
0024 // the copies.  The class is required to be copyable so it can be passed around
0025 // (without move support from C++11), but it deep-copies the heap contents yet
0026 // shallow-copies the index_in_heap_map.
0027 
0028 namespace boost
0029 {
0030 
0031 // Swap two elements in a property map without assuming they model
0032 // LvaluePropertyMap -- currently not used
0033 template < typename PropMap >
0034 inline void property_map_swap(PropMap prop_map,
0035     const typename boost::property_traits< PropMap >::key_type& ka,
0036     const typename boost::property_traits< PropMap >::key_type& kb)
0037 {
0038     typename boost::property_traits< PropMap >::value_type va
0039         = get(prop_map, ka);
0040     put(prop_map, ka, get(prop_map, kb));
0041     put(prop_map, kb, va);
0042 }
0043 
0044 namespace detail
0045 {
0046     template < typename Value > class fixed_max_size_vector
0047     {
0048         boost::shared_array< Value > m_data;
0049         std::size_t m_size;
0050 
0051     public:
0052         typedef std::size_t size_type;
0053         fixed_max_size_vector(std::size_t max_size)
0054         : m_data(new Value[max_size]), m_size(0)
0055         {
0056         }
0057         std::size_t size() const { return m_size; }
0058         bool empty() const { return m_size == 0; }
0059         Value& operator[](std::size_t i) { return m_data[i]; }
0060         const Value& operator[](std::size_t i) const { return m_data[i]; }
0061         void push_back(Value v) { m_data[m_size++] = v; }
0062         void pop_back() { --m_size; }
0063         Value& back() { return m_data[m_size - 1]; }
0064         const Value& back() const { return m_data[m_size - 1]; }
0065     };
0066 }
0067 
0068 // D-ary heap using an indirect compare operator (use identity_property_map
0069 // as DistanceMap to get a direct compare operator).  This heap appears to be
0070 // commonly used for Dijkstra's algorithm for its good practical performance
0071 // on some platforms; asymptotically, it has an O(lg N) decrease-key
0072 // operation while that can be done in constant time on a relaxed heap.  The
0073 // implementation is mostly based on the binary heap page on Wikipedia and
0074 // online sources that state that the operations are the same for d-ary
0075 // heaps.  This code is not based on the old Boost d-ary heap code.
0076 //
0077 // - d_ary_heap_indirect is a model of UpdatableQueue as is needed for
0078 //   dijkstra_shortest_paths.
0079 //
0080 // - Value must model Assignable.
0081 // - Arity must be at least 2 (optimal value appears to be 4, both in my and
0082 //   third-party experiments).
0083 // - IndexInHeapMap must be a ReadWritePropertyMap from Value to
0084 //   Container::size_type (to store the index of each stored value within the
0085 //   heap for decrease-key aka update).
0086 // - DistanceMap must be a ReadablePropertyMap from Value to something
0087 //   (typedef'ed as distance_type).
0088 // - Compare must be a BinaryPredicate used as a less-than operator on
0089 //   distance_type.
0090 // - Container must be a random-access, contiguous container (in practice,
0091 //   the operations used probably require that it is std::vector<Value>).
0092 //
0093 template < typename Value, std::size_t Arity, typename IndexInHeapPropertyMap,
0094     typename DistanceMap, typename Compare = std::less< Value >,
0095     typename Container = std::vector< Value > >
0096 class d_ary_heap_indirect
0097 {
0098     BOOST_STATIC_ASSERT(Arity >= 2);
0099 
0100 public:
0101     typedef typename Container::size_type size_type;
0102     typedef Value value_type;
0103     typedef typename boost::property_traits< DistanceMap >::value_type key_type;
0104     typedef DistanceMap key_map;
0105 
0106     d_ary_heap_indirect(DistanceMap distance,
0107         IndexInHeapPropertyMap index_in_heap,
0108         const Compare& compare = Compare(), const Container& data = Container())
0109     : compare(compare)
0110     , data(data)
0111     , distance(distance)
0112     , index_in_heap(index_in_heap)
0113     {
0114     }
0115     /* Implicit copy constructor */
0116     /* Implicit assignment operator */
0117 
0118     size_type size() const { return data.size(); }
0119 
0120     bool empty() const { return data.empty(); }
0121 
0122     void push(const Value& v)
0123     {
0124         size_type index = data.size();
0125         data.push_back(v);
0126         put(index_in_heap, v, index);
0127         preserve_heap_property_up(index);
0128         verify_heap();
0129     }
0130 
0131     Value& top()
0132     {
0133         BOOST_ASSERT(!this->empty());
0134         return data[0];
0135     }
0136 
0137     const Value& top() const
0138     {
0139         BOOST_ASSERT(!this->empty());
0140         return data[0];
0141     }
0142 
0143     void pop()
0144     {
0145         BOOST_ASSERT(!this->empty());
0146         put(index_in_heap, data[0], (size_type)(-1));
0147         if (data.size() != 1)
0148         {
0149             data[0] = data.back();
0150             put(index_in_heap, data[0], (size_type)(0));
0151             data.pop_back();
0152             preserve_heap_property_down();
0153             verify_heap();
0154         }
0155         else
0156         {
0157             data.pop_back();
0158         }
0159     }
0160 
0161     // This function assumes the key has been updated (using an external write
0162     // to the distance map or such)
0163     // See
0164     // http://coding.derkeiler.com/Archive/General/comp.theory/2007-05/msg00043.html
0165     void update(const Value& v)
0166     { /* decrease-key */
0167         size_type index = get(index_in_heap, v);
0168         preserve_heap_property_up(index);
0169         verify_heap();
0170     }
0171 
0172     bool contains(const Value& v) const
0173     {
0174         size_type index = get(index_in_heap, v);
0175         return (index != (size_type)(-1));
0176     }
0177 
0178     void push_or_update(const Value& v)
0179     { /* insert if not present, else update */
0180         size_type index = get(index_in_heap, v);
0181         if (index == (size_type)(-1))
0182         {
0183             index = data.size();
0184             data.push_back(v);
0185             put(index_in_heap, v, index);
0186         }
0187         preserve_heap_property_up(index);
0188         verify_heap();
0189     }
0190 
0191     DistanceMap keys() const { return distance; }
0192 
0193 private:
0194     Compare compare;
0195     Container data;
0196     DistanceMap distance;
0197     IndexInHeapPropertyMap index_in_heap;
0198 
0199     // The distances being compared using compare and that are stored in the
0200     // distance map
0201     typedef typename boost::property_traits< DistanceMap >::value_type
0202         distance_type;
0203 
0204     // Get the parent of a given node in the heap
0205     static size_type parent(size_type index) { return (index - 1) / Arity; }
0206 
0207     // Get the first child of a given node
0208     static size_type first_child(size_type index)
0209     {
0210         return index * Arity + 1;
0211     }
0212 
0213     // Swap two elements in the heap by index, updating index_in_heap
0214     void swap_heap_elements(size_type index_a, size_type index_b)
0215     {
0216         using std::swap;
0217         Value value_a = data[index_a];
0218         Value value_b = data[index_b];
0219         data[index_a] = value_b;
0220         data[index_b] = value_a;
0221         put(index_in_heap, value_a, index_b);
0222         put(index_in_heap, value_b, index_a);
0223     }
0224 
0225     // Emulate the indirect_cmp that is now folded into this heap class
0226     bool compare_indirect(const Value& a, const Value& b) const
0227     {
0228         return compare(get(distance, a), get(distance, b));
0229     }
0230 
0231     // Verify that the array forms a heap; commented out by default
0232     void verify_heap() const
0233     {
0234         // This is a very expensive test so it should be disabled even when
0235         // NDEBUG is not defined
0236 #if 0
0237       for (size_t i = 1; i < data.size(); ++i) {
0238         if (compare_indirect(data[i], data[parent(i)])) {
0239           BOOST_ASSERT (!"Element is smaller than its parent");
0240         }
0241       }
0242 #endif
0243     }
0244 
0245     // Starting at a node, move up the tree swapping elements to preserve the
0246     // heap property
0247     void preserve_heap_property_up(size_type index)
0248     {
0249         size_type orig_index = index;
0250         size_type num_levels_moved = 0;
0251         // The first loop just saves swaps that need to be done in order to
0252         // avoid aliasing issues in its search; there is a second loop that does
0253         // the necessary swap operations
0254         if (index == 0)
0255             return; // Do nothing on root
0256         Value currently_being_moved = data[index];
0257         distance_type currently_being_moved_dist
0258             = get(distance, currently_being_moved);
0259         for (;;)
0260         {
0261             if (index == 0)
0262                 break; // Stop at root
0263             size_type parent_index = parent(index);
0264             Value parent_value = data[parent_index];
0265             if (compare(
0266                     currently_being_moved_dist, get(distance, parent_value)))
0267             {
0268                 ++num_levels_moved;
0269                 index = parent_index;
0270                 continue;
0271             }
0272             else
0273             {
0274                 break; // Heap property satisfied
0275             }
0276         }
0277         // Actually do the moves -- move num_levels_moved elements down in the
0278         // tree, then put currently_being_moved at the top
0279         index = orig_index;
0280         for (size_type i = 0; i < num_levels_moved; ++i)
0281         {
0282             size_type parent_index = parent(index);
0283             Value parent_value = data[parent_index];
0284             put(index_in_heap, parent_value, index);
0285             data[index] = parent_value;
0286             index = parent_index;
0287         }
0288         data[index] = currently_being_moved;
0289         put(index_in_heap, currently_being_moved, index);
0290         verify_heap();
0291     }
0292 
0293     // From the root, swap elements (each one with its smallest child) if there
0294     // are any parent-child pairs that violate the heap property
0295     void preserve_heap_property_down()
0296     {
0297         if (data.empty())
0298             return;
0299         size_type index = 0;
0300         Value currently_being_moved = data[0];
0301         distance_type currently_being_moved_dist
0302             = get(distance, currently_being_moved);
0303         size_type heap_size = data.size();
0304         Value* data_ptr = &data[0];
0305         for (;;)
0306         {
0307             size_type first_child_index = first_child(index);
0308             if (first_child_index >= heap_size)
0309                 break; /* No children */
0310             Value* child_base_ptr = data_ptr + first_child_index;
0311             size_type smallest_child_index = 0;
0312             distance_type smallest_child_dist
0313                 = get(distance, child_base_ptr[smallest_child_index]);
0314             if (first_child_index + Arity <= heap_size)
0315             {
0316                 // Special case for a statically known loop count (common case)
0317                 for (size_t i = 1; i < Arity; ++i)
0318                 {
0319                     Value i_value = child_base_ptr[i];
0320                     distance_type i_dist = get(distance, i_value);
0321                     if (compare(i_dist, smallest_child_dist))
0322                     {
0323                         smallest_child_index = i;
0324                         smallest_child_dist = i_dist;
0325                     }
0326                 }
0327             }
0328             else
0329             {
0330                 for (size_t i = 1; i < heap_size - first_child_index; ++i)
0331                 {
0332                     distance_type i_dist = get(distance, child_base_ptr[i]);
0333                     if (compare(i_dist, smallest_child_dist))
0334                     {
0335                         smallest_child_index = i;
0336                         smallest_child_dist = i_dist;
0337                     }
0338                 }
0339             }
0340             if (compare(smallest_child_dist, currently_being_moved_dist))
0341             {
0342                 swap_heap_elements(
0343                     smallest_child_index + first_child_index, index);
0344                 index = smallest_child_index + first_child_index;
0345                 continue;
0346             }
0347             else
0348             {
0349                 break; // Heap property satisfied
0350             }
0351         }
0352         verify_heap();
0353     }
0354 };
0355 
0356 } // namespace boost
0357 
0358 #endif // BOOST_D_ARY_HEAP_HPP