LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/util - bin_heap.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 154 156 98.7 %
Date: 2026-06-30 10:35:26 Functions: 94 94 100.0 %
Branches: 66 132 50.0 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * This file is part of the cvc5 project.
       3                 :            :  *
       4                 :            :  * Copyright (c) 2009-2026 by the authors listed in the file AUTHORS
       5                 :            :  * in the top-level source directory and their institutional affiliations.
       6                 :            :  * All rights reserved.  See the file COPYING in the top-level source
       7                 :            :  * directory for licensing information.
       8                 :            :  * ****************************************************************************
       9                 :            :  *
      10                 :            :  * An implementation of a binary heap
      11                 :            :  *
      12                 :            :  * Attempts to roughly follow the contract of Boost's d_ary_heap.
      13                 :            :  * (http://www.boost.org/doc/libs/1_49_0/doc/html/boost/heap/d_ary_heap.html)
      14                 :            :  * Also attempts to generalize ext/pd_bs/priority_queue.
      15                 :            :  * (http://gcc.gnu.org/onlinedocs/libstdc++/ext/pb_ds/priority_queue.html)
      16                 :            :  */
      17                 :            : 
      18                 :            : #include "cvc5_private.h"
      19                 :            : 
      20                 :            : #ifndef CVC5__BIN_HEAP_H
      21                 :            : #define CVC5__BIN_HEAP_H
      22                 :            : 
      23                 :            : #include <functional>
      24                 :            : #include <limits>
      25                 :            : 
      26                 :            : #include "base/check.h"
      27                 :            : #include "base/exception.h"
      28                 :            : 
      29                 :            : namespace cvc5::internal {
      30                 :            : 
      31                 :            : /**
      32                 :            :  * BinaryHeap that orders its elements greatest-first (i.e., in the opposite
      33                 :            :  * direction of the provided comparator).  Update of elements is permitted
      34                 :            :  * via handles, which are not invalidated by mutation (pushes and pops etc.).
      35                 :            :  * Handles are invalidted when their element is no longer a member of the
      36                 :            :  * heap.  Iteration over elements is supported but iteration is unsorted and
      37                 :            :  * iterators are immutable.
      38                 :            :  */
      39                 :            : template <class Elem, class CmpFcn = std::less<Elem> >
      40                 :            : class BinaryHeap
      41                 :            : {
      42                 :            :  private:
      43                 :            :   typedef Elem T;
      44                 :            :   struct HElement;
      45                 :            : 
      46                 :            :   typedef std::vector<HElement*> ElementVector;
      47                 :            : 
      48                 :            :   struct HElement
      49                 :            :   {
      50                 :    1026972 :     HElement(size_t pos, const T& elem) : d_pos(pos), d_elem(elem) {}
      51                 :            :     size_t d_pos;
      52                 :            :     T d_elem;
      53                 :            :   }; /* struct HElement */
      54                 :            : 
      55                 :            :   /** A 0 indexed binary heap. */
      56                 :            :   ElementVector d_heap;
      57                 :            : 
      58                 :            :   /** The comparator. */
      59                 :            :   CmpFcn d_cmp;
      60                 :            : 
      61                 :            :   // disallow copy and assignment
      62                 :            :   BinaryHeap(const BinaryHeap&) = delete;
      63                 :            :   BinaryHeap& operator=(const BinaryHeap&) = delete;
      64                 :            : 
      65                 :            :  public:
      66                 :     431758 :   BinaryHeap(const CmpFcn& c = CmpFcn()) : d_heap(), d_cmp(c) {}
      67                 :            : 
      68                 :     431410 :   ~BinaryHeap() { clear(); }
      69                 :            : 
      70                 :            :   class handle
      71                 :            :   {
      72                 :            :    private:
      73                 :            :     HElement* d_pointer;
      74                 :    1156107 :     handle(HElement* p) : d_pointer(p) {}
      75                 :            :     friend class BinaryHeap;
      76                 :            : 
      77                 :            :    public:
      78                 :    1662890 :     handle() : d_pointer(nullptr) {}
      79                 :      30011 :     const T& operator*() const
      80                 :            :     {
      81 [ -  + ][ -  + ]:      30011 :       Assert(d_pointer != nullptr);
                 [ -  - ]
      82                 :      30011 :       return d_pointer->d_elem;
      83                 :            :     }
      84                 :            : 
      85                 :          1 :     bool operator==(const handle& h) const { return d_pointer == h.d_pointer; }
      86                 :            : 
      87                 :          6 :     bool operator!=(const handle& h) const { return d_pointer != h.d_pointer; }
      88                 :            : 
      89                 :            :   }; /* BinaryHeap<>::handle */
      90                 :            : 
      91                 :            :   class const_iterator
      92                 :            :   {
      93                 :            :    public:
      94                 :            :     /* The following types are required by trait std::iterator_traits */
      95                 :            : 
      96                 :            :     /** Iterator tag */
      97                 :            :     using iterator_category = std::forward_iterator_tag;
      98                 :            : 
      99                 :            :     /** The type of the item */
     100                 :            :     using value_type = Elem;
     101                 :            : 
     102                 :            :     /** The pointer type of the item */
     103                 :            :     using pointer = const Elem*;
     104                 :            : 
     105                 :            :     /** The reference type of the item */
     106                 :            :     using reference = const Elem&;
     107                 :            : 
     108                 :            :     /** The type returned when two iterators are subtracted */
     109                 :            :     using difference_type = std::ptrdiff_t;
     110                 :            : 
     111                 :            :     /* End of std::iterator_traits required types */
     112                 :            : 
     113                 :            :    private:
     114                 :            :     typename ElementVector::const_iterator d_iter;
     115                 :            :     friend class BinaryHeap;
     116                 :     769074 :     const_iterator(const typename ElementVector::const_iterator& iter)
     117                 :     769074 :         : d_iter(iter)
     118                 :            :     {
     119                 :     769074 :     }
     120                 :            : 
     121                 :            :    public:
     122                 :            :     const_iterator() {}
     123                 :          3 :     inline bool operator==(const const_iterator& ci) const
     124                 :            :     {
     125                 :          3 :       return d_iter == ci.d_iter;
     126                 :            :     }
     127                 :     737283 :     inline bool operator!=(const const_iterator& ci) const
     128                 :            :     {
     129                 :     737283 :       return d_iter != ci.d_iter;
     130                 :            :     }
     131                 :     352749 :     inline const_iterator& operator++()
     132                 :            :     {
     133                 :     352749 :       ++d_iter;
     134                 :     352749 :       return *this;
     135                 :            :     }
     136                 :          4 :     inline const_iterator operator++(int)
     137                 :            :     {
     138                 :          4 :       const_iterator i = *this;
     139                 :          4 :       ++d_iter;
     140                 :          4 :       return i;
     141                 :            :     }
     142                 :     352758 :     inline const T& operator*() const
     143                 :            :     {
     144                 :     352758 :       const HElement* he = *d_iter;
     145                 :     352758 :       return he->d_elem;
     146                 :            :     }
     147                 :            : 
     148                 :            :   }; /* BinaryHeap<>::const_iterator */
     149                 :            : 
     150                 :            :   typedef const_iterator iterator;
     151                 :            : 
     152                 :    4125628 :   inline size_t size() const { return d_heap.size(); }
     153                 :    4103592 :   inline bool empty() const { return d_heap.empty(); }
     154                 :            : 
     155                 :     384537 :   inline const_iterator begin() const { return const_iterator(d_heap.begin()); }
     156                 :            : 
     157                 :     384537 :   inline const_iterator end() const { return const_iterator(d_heap.end()); }
     158                 :            : 
     159                 :    1888627 :   void clear()
     160                 :            :   {
     161                 :    1888627 :     typename ElementVector::iterator i = d_heap.begin(), iend = d_heap.end();
     162         [ +  + ]:    2385730 :     for (; i != iend; ++i)
     163                 :            :     {
     164                 :     497103 :       HElement* he = *i;
     165         [ +  - ]:     497103 :       delete he;
     166                 :            :     }
     167                 :    1888627 :     d_heap.clear();
     168                 :    1888627 :   }
     169                 :            : 
     170                 :     380429 :   void swap(BinaryHeap& heap)
     171                 :            :   {
     172                 :     380429 :     std::swap(d_heap, heap.d_heap);
     173                 :     380429 :     std::swap(d_cmp, heap.d_cmp);
     174                 :     380429 :   }
     175                 :            : 
     176                 :    1026972 :   handle push(const T& toAdded)
     177                 :            :   {
     178 [ -  + ][ -  + ]:    1026972 :     Assert(size() < MAX_SIZE);
                 [ -  - ]
     179                 :    1026972 :     HElement* he = new HElement(size(), toAdded);
     180                 :    1026972 :     d_heap.push_back(he);
     181                 :    1026972 :     up_heap(he);
     182                 :    1026972 :     return handle(he);
     183                 :            :   }
     184                 :            : 
     185                 :     517857 :   void erase(handle h)
     186                 :            :   {
     187 [ -  + ][ -  + ]:     517857 :     Assert(!empty());
                 [ -  - ]
     188 [ -  + ][ -  + ]:     517857 :     Assert(debugHandle(h));
                 [ -  - ]
     189                 :            : 
     190                 :     517857 :     HElement* he = h.d_pointer;
     191                 :     517857 :     size_t pos = he->d_pos;
     192         [ +  + ]:     517857 :     if (pos == root())
     193                 :            :     {
     194                 :            :       // the top element can be efficiently removed by pop
     195                 :     331250 :       pop();
     196                 :            :     }
     197         [ +  + ]:     186607 :     else if (pos == last())
     198                 :            :     {
     199                 :            :       // the last element can be safely removed
     200                 :      57472 :       d_heap.pop_back();
     201         [ +  - ]:      57472 :       delete he;
     202                 :            :     }
     203                 :            :     else
     204                 :            :     {
     205                 :            :       // This corresponds to
     206                 :            :       // 1) swapping the elements at pos with the element at last:
     207                 :            :       // 2) deleting the new last element
     208                 :            :       // 3) updating the position of the new element at pos
     209                 :     129135 :       swapIndices(pos, last());
     210                 :     129135 :       d_heap.pop_back();
     211         [ +  - ]:     129135 :       delete he;
     212                 :     129135 :       update(handle(d_heap[pos]));
     213                 :            :     }
     214                 :     517857 :   }
     215                 :            : 
     216                 :     343255 :   void pop()
     217                 :            :   {
     218 [ -  + ][ -  + ]:     343255 :     Assert(!empty());
                 [ -  - ]
     219                 :     343255 :     swapIndices(root(), last());
     220                 :     343255 :     HElement* b = d_heap.back();
     221                 :     343255 :     d_heap.pop_back();
     222         [ +  - ]:     343255 :     delete b;
     223                 :            : 
     224         [ +  + ]:     343255 :     if (!empty())
     225                 :            :     {
     226                 :     175861 :       down_heap(d_heap.front());
     227                 :            :     }
     228                 :     343255 :   }
     229                 :            : 
     230                 :     355588 :   const T& top() const
     231                 :            :   {
     232 [ -  + ][ -  + ]:     355588 :     Assert(!empty());
                 [ -  - ]
     233                 :     355588 :     return (d_heap.front())->d_elem;
     234                 :            :   }
     235                 :            : 
     236                 :            :  private:
     237                 :     294393 :   void update(handle h)
     238                 :            :   {
     239 [ -  + ][ -  + ]:     294393 :     Assert(!empty());
                 [ -  - ]
     240 [ -  + ][ -  + ]:     294393 :     Assert(debugHandle(h));
                 [ -  - ]
     241                 :            : 
     242                 :            :     // The relationship between h and its parent, left and right has become
     243                 :            :     // unknown. But it is assumed that parent <= left, and parent <= right still
     244                 :            :     // hold. Figure out whether to up_heap or down_heap.
     245                 :            : 
     246 [ -  + ][ -  + ]:     294393 :     Assert(!empty());
                 [ -  - ]
     247                 :     294393 :     HElement* he = h.d_pointer;
     248                 :            : 
     249                 :     294393 :     size_t pos = he->d_pos;
     250         [ +  + ]:     294393 :     if (pos == root())
     251                 :            :     {
     252                 :            :       // no parent
     253                 :      14132 :       down_heap(he);
     254                 :            :     }
     255                 :            :     else
     256                 :            :     {
     257                 :     280261 :       size_t par = parent(pos);
     258                 :     280261 :       HElement* at_parent = d_heap[par];
     259         [ +  + ]:     280261 :       if (gt(he->d_elem, at_parent->d_elem))
     260                 :            :       {
     261                 :            :         // he > parent
     262                 :      45888 :         up_heap(he);
     263                 :            :       }
     264                 :            :       else
     265                 :            :       {
     266                 :     234373 :         down_heap(he);
     267                 :            :       }
     268                 :            :     }
     269                 :     294393 :   }
     270                 :            : 
     271                 :            :  public:
     272                 :     165258 :   void update(handle h, const T& val)
     273                 :            :   {
     274 [ -  + ][ -  + ]:     165258 :     Assert(!empty());
                 [ -  - ]
     275 [ -  + ][ -  + ]:     165258 :     Assert(debugHandle(h));
                 [ -  - ]
     276                 :     165258 :     h.d_pointer->d_elem = val;
     277                 :     165258 :     update(h);
     278                 :     165258 :   }
     279                 :            : 
     280                 :            :   /** (std::numeric_limits<size_t>::max()-2)/2; */
     281                 :            :   static const size_t MAX_SIZE;
     282                 :            : 
     283                 :            :  private:
     284                 :    1335335 :   inline bool gt(const T& a, const T& b) const
     285                 :            :   {
     286                 :            :     // cmp acts like an operator<
     287                 :    1335335 :     return d_cmp(b, a);
     288                 :            :   }
     289                 :            : 
     290                 :     875572 :   inline bool lt(const T& a, const T& b) const { return d_cmp(a, b); }
     291                 :            : 
     292                 :    1335335 :   inline static size_t parent(size_t p)
     293                 :            :   {
     294 [ -  + ][ -  + ]:    1335335 :     Assert(p != root());
                 [ -  - ]
     295                 :    1335335 :     return (p - 1) / 2;
     296                 :            :   }
     297                 :     776920 :   inline static size_t right(size_t p) { return 2 * p + 2; }
     298                 :     830319 :   inline static size_t left(size_t p) { return 2 * p + 1; }
     299                 :    4116237 :   inline static size_t root() { return 0; }
     300                 :     658997 :   inline size_t last() const
     301                 :            :   {
     302 [ -  + ][ -  + ]:     658997 :     Assert(!empty());
                 [ -  - ]
     303                 :     658997 :     return size() - 1;
     304                 :            :   }
     305                 :            : 
     306                 :     472390 :   inline void swapIndices(size_t i, size_t j)
     307                 :            :   {
     308                 :     472390 :     HElement* at_i = d_heap[i];
     309                 :     472390 :     HElement* at_j = d_heap[j];
     310                 :     472390 :     swap(i, j, at_i, at_j);
     311                 :     472390 :   }
     312                 :            : 
     313                 :            :   inline void swapPointers(HElement* at_i, HElement* at_j)
     314                 :            :   {
     315                 :            :     // still works if at_i == at_j
     316                 :            :     size_t i = at_i->d_pos;
     317                 :            :     size_t j = at_j->d_pos;
     318                 :            :     swap(i, j, at_i, at_j);
     319                 :            :   }
     320                 :            : 
     321                 :    1401781 :   inline void swap(size_t i, size_t j, HElement* at_i, HElement* at_j)
     322                 :            :   {
     323                 :            :     // still works if i == j
     324 [ -  + ][ -  + ]:    1401781 :     Assert(i == at_i->d_pos);
                 [ -  - ]
     325 [ -  + ][ -  + ]:    1401781 :     Assert(j == at_j->d_pos);
                 [ -  - ]
     326                 :    1401781 :     d_heap[i] = at_j;
     327                 :    1401781 :     d_heap[j] = at_i;
     328                 :    1401781 :     at_i->d_pos = j;
     329                 :    1401781 :     at_j->d_pos = i;
     330                 :    1401781 :   }
     331                 :            : 
     332                 :    1072860 :   void up_heap(HElement* he)
     333                 :            :   {
     334                 :    1072860 :     const size_t& curr = he->d_pos;
     335                 :            :     // The value of curr changes implicitly during swap operations.
     336         [ +  + ]:    1625397 :     while (curr != root())
     337                 :            :     {
     338                 :            :       // he->d_elem > parent
     339                 :    1055074 :       size_t par = parent(curr);
     340                 :    1055074 :       HElement* at_parent = d_heap[par];
     341         [ +  + ]:    1055074 :       if (gt(he->d_elem, at_parent->d_elem))
     342                 :            :       {
     343                 :     552537 :         swap(curr, par, he, at_parent);
     344                 :            :       }
     345                 :            :       else
     346                 :            :       {
     347                 :     502537 :         break;
     348                 :            :       }
     349                 :            :     }
     350                 :    1072860 :   }
     351                 :            : 
     352                 :     424366 :   void down_heap(HElement* he)
     353                 :            :   {
     354                 :     424366 :     const size_t& curr = he->d_pos;
     355                 :            :     // The value of curr changes implicitly during swap operations.
     356                 :     424366 :     size_t N = size();
     357                 :            :     size_t r, l;
     358                 :            : 
     359         [ +  + ]:     776920 :     while ((r = right(curr)) < N)
     360                 :            :     {
     361                 :     405953 :       l = left(curr);
     362                 :            : 
     363                 :            :       // if at_left == at_right, favor left
     364                 :     405953 :       HElement* at_left = d_heap[l];
     365                 :     405953 :       HElement* at_right = d_heap[r];
     366         [ +  + ]:     405953 :       if (lt(he->d_elem, at_left->d_elem))
     367                 :            :       {
     368                 :            :         // he < at_left
     369         [ +  + ]:     330460 :         if (lt(at_left->d_elem, at_right->d_elem))
     370                 :            :         {
     371                 :            :           // he < at_left < at_right
     372                 :     141142 :           swap(curr, r, he, at_right);
     373                 :            :         }
     374                 :            :         else
     375                 :            :         {
     376                 :            :           //       he <  at_left
     377                 :            :           // at_right <= at_left
     378                 :     189318 :           swap(curr, l, he, at_left);
     379                 :            :         }
     380                 :            :       }
     381                 :            :       else
     382                 :            :       {
     383                 :            :         // at_left <= he
     384         [ +  + ]:      75493 :         if (lt(he->d_elem, at_right->d_elem))
     385                 :            :         {
     386                 :            :           // at_left <= he < at_right
     387                 :      22094 :           swap(curr, r, he, at_right);
     388                 :            :         }
     389                 :            :         else
     390                 :            :         {
     391                 :            :           // at_left  <= he
     392                 :            :           // at_right <= he
     393                 :      53399 :           break;
     394                 :            :         }
     395                 :            :       }
     396                 :            :     }
     397                 :     424366 :     l = left(curr);
     398 [ +  + ][ +  + ]:     424366 :     if (r >= N && l < N)
     399                 :            :     {
     400                 :            :       // there is a left but not a right
     401                 :      63666 :       HElement* at_left = d_heap[l];
     402         [ +  + ]:      63666 :       if (lt(he->d_elem, at_left->d_elem))
     403                 :            :       {
     404                 :            :         // he < at_left
     405                 :      24300 :         swap(curr, l, he, at_left);
     406                 :            :       }
     407                 :            :     }
     408                 :     424366 :   }
     409                 :            : 
     410                 :     977508 :   bool debugHandle(handle h) const
     411                 :            :   {
     412                 :     977508 :     HElement* he = h.d_pointer;
     413         [ -  + ]:     977508 :     if (he == nullptr)
     414                 :            :     {
     415                 :          0 :       return true;
     416                 :            :     }
     417         [ -  + ]:     977508 :     else if (he->d_pos >= size())
     418                 :            :     {
     419                 :          0 :       return false;
     420                 :            :     }
     421                 :            :     else
     422                 :            :     {
     423                 :     977508 :       return he == d_heap[he->d_pos];
     424                 :            :     }
     425                 :            :   }
     426                 :            : 
     427                 :            : }; /* class BinaryHeap<> */
     428                 :            : 
     429                 :            : template <class Elem, class CmpFcn>
     430                 :            : const size_t BinaryHeap<Elem, CmpFcn>::MAX_SIZE =
     431                 :            :     (std::numeric_limits<size_t>::max() - 2) / 2;
     432                 :            : 
     433                 :            : }  // namespace cvc5::internal
     434                 :            : 
     435                 :            : #endif /* CVC5__BIN_HEAP_H */

Generated by: LCOV version 1.14