ACEC/hCaD_V2/src/heap.hpp
2022-10-21 19:34:18 +08:00

199 lines
5.4 KiB
C++

#ifndef _heap_hpp_INCLUDED
#define _heap_hpp_INCLUDED
#include "util.hpp" // Alphabetically after 'heap.hpp'.
namespace CaDiCaL {
using namespace std;
// This is a priority queue with updates for unsigned integers implemented
// as binary heap. We need to map integer elements added (through
// 'push_back') to positions on the binary heap in 'array'. This map is
// stored in the 'pos' array. This approach is really wasteful (at least in
// terms of memory) if only few and a sparse set of integers is added. So
// it should not be used in this situation. A generic priority queue would
// implement the mapping externally provided by another template parameter.
// Since we use 'UINT_MAX' as 'not contained' flag, we can only have
// 'UINT_MAX - 1' elements in the heap.
const unsigned invalid_heap_position = UINT_MAX;
template<class C> class heap {
vector<unsigned> array; // actual binary heap
vector<unsigned> pos; // positions of elements in array
C less; // less-than for elements
// Map an element to its position entry in the 'pos' map.
//
unsigned & index (unsigned e) {
while ((size_t) e >= pos.size ()) pos.push_back (invalid_heap_position);
unsigned & res = pos[e];
assert (res == invalid_heap_position || (size_t) res < array.size ());
return res;
}
bool has_parent (unsigned e) { return index (e) > 0; }
bool has_left (unsigned e) { return (size_t) 2*index (e) + 1 < size (); }
bool has_right (unsigned e) { return (size_t) 2*index (e) + 2 < size (); }
unsigned parent (unsigned e) {
assert(has_parent (e));
return array[(index(e)-1)/2];
}
unsigned left (unsigned e) {
assert(has_left (e));
return array[2*index(e)+1];
}
unsigned right (unsigned e) {
assert(has_right (e));
return array[2*index(e)+2];
}
// Exchange elements 'a' and 'b' in 'array' and fix their positions.
//
void exchange (unsigned a, unsigned b) {
unsigned & i = index (a), & j = index (b);
swap (array[i], array[j]);
swap (i, j);
}
// Bubble up an element as far as necessary.
//
void up (unsigned e) {
unsigned p;
while (has_parent (e) && less ((p = parent (e)), e))
exchange (p, e);
}
// Bubble down an element as far as necessary.
//
void down (unsigned e) {
while (has_left (e)) {
unsigned c = left (e);
if (has_right (e)) {
unsigned r = right (e);
if (less (c, r)) c = r;
}
if (!less (e, c)) break;
exchange (e, c);
}
}
// Very expensive checker for the main 'heap' invariant. Can be enabled
// to find violations of antisymmetry in the client implementation of
// 'less' and as well of course bugs in this heap implementation. It
// should be enabled during testing applications of the heap.
//
void check () {
#if 0 // EXPENSIVE HEAP CHECKING IF ENABLED
#warning "expensive checking in heap enabled"
assert (array.size () <= invalid_heap_position);
for (size_t i = 0; i < array.size (); i++) {
size_t l = 2*i + 1, r = 2*i + 2;
if (l < array.size ()) assert (!less (array[i], array[l]));
if (r < array.size ()) assert (!less (array[i], array[r]));
assert (array[i] >= 0);
{
assert ((size_t) array[i] < pos.size ());
assert (i == (size_t) pos[array[i]]);
}
}
for (size_t i = 0; i < pos.size (); i++) {
if (pos[i] == invalid_heap_position) continue;
assert (pos[i] < array.size ());
assert (array[pos[i]] == (unsigned) i);
}
#endif
}
public:
heap (const C & c) : less (c) { }
// Number of elements in the heap.
//
size_t size () const { return array.size (); }
// Check if no more elements are in the heap.
//
bool empty () const { return array.empty (); }
// Check whether 'e' is already in the heap.
//
bool contains (unsigned e) const {
if ((size_t) e >= pos.size ()) return false;
return pos[e] != invalid_heap_position;
}
// Add a new (not contained) element 'e' to the heap.
//
void push_back (unsigned e) {
assert (!contains (e));
size_t i = array.size ();
assert (i < (size_t) invalid_heap_position);
array.push_back (e);
index (e) = (unsigned) i;
up (e);
down (e);
check ();
}
// Returns the maximum element in the heap.
//
unsigned front () const { assert (!empty ()); return array[0]; }
// Removes the maximum element in the heap.
//
unsigned pop_front () {
assert (!empty ());
unsigned res = array[0], last = array.back ();
if (size () > 1) exchange (res, last);
index (res) = invalid_heap_position;
array.pop_back ();
if (size () > 1) down (last);
check ();
return res;
}
// Notify the heap, that evaluation of 'less' has changed for 'e'.
//
void update (unsigned e) {
assert (contains (e));
up (e);
down (e);
check ();
}
void clear () {
array.clear ();
pos.clear ();
}
void erase () {
erase_vector (array);
erase_vector (pos);
}
void shrink () {
shrink_vector (array);
shrink_vector (pos);
}
// Standard iterators 'inherited' from 'vector'.
//
typedef typename vector<unsigned>::iterator iterator;
typedef typename vector<unsigned>::const_iterator const_iterator;
iterator begin () { return array.begin (); }
iterator end () { return array.end (); }
const_iterator begin () const { return array.begin (); }
const_iterator end () const { return array.end (); }
};
}
#endif