3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-23 17:15:31 +00:00

Merge branch 'opt' of https://github.com/Z3Prover/z3 into unstable

This commit is contained in:
Nikolaj Bjorner 2015-05-14 12:11:17 +01:00
commit ab5022888c
396 changed files with 86387 additions and 3294 deletions

View file

@ -206,6 +206,34 @@ void bit_vector::display(std::ostream & out) const {
#endif
}
bool bit_vector::contains(bit_vector const& other) const {
unsigned n = num_words();
if (n == 0)
return true;
for (unsigned i = 0; i < n - 1; ++i) {
if ((m_data[i] & other.m_data[i]) != other.m_data[i])
return false;
}
unsigned bit_rest = m_num_bits % 32;
unsigned mask = (1U << bit_rest) - 1;
if (mask == 0) mask = UINT_MAX;
unsigned other_data = other.m_data[n-1] & mask;
return (m_data[n-1] & other_data) == other_data;
}
unsigned bit_vector::get_hash() const {
return string_hash(reinterpret_cast<char const* const>(m_data), size()/8, 0);
}
bit_vector& bit_vector::neg() {
unsigned n = num_words();
for (unsigned i = 0; i < n; ++i) {
m_data[i] = ~m_data[i];
}
return *this;
}
void fr_bit_vector::reset() {
unsigned sz = size();
unsigned_vector::const_iterator it = m_one_idxs.begin();

View file

@ -126,6 +126,8 @@ public:
unsigned get_word(unsigned word_idx) const {
return m_data[word_idx];
}
unsigned get_hash() const;
bool get(unsigned bit_idx) const {
SASSERT(bit_idx < size());
@ -202,8 +204,13 @@ public:
bit_vector & operator|=(bit_vector const & source);
bit_vector & operator&=(bit_vector const & source);
bit_vector & neg();
void display(std::ostream & out) const;
bool contains(const bit_vector & other) const;
};
inline std::ostream & operator<<(std::ostream & out, bit_vector const & b) {

View file

@ -171,7 +171,7 @@ public:
m_todo.push_back(d);
unsigned qhead = 0;
while (qhead < m_todo.size()) {
dependency * d = m_todo[qhead];
d = m_todo[qhead];
qhead++;
if (d->is_leaf()) {
if (to_leaf(d)->m_value == v) {
@ -201,7 +201,7 @@ public:
m_todo.push_back(d);
unsigned qhead = 0;
while (qhead < m_todo.size()) {
dependency * d = m_todo[qhead];
d = m_todo[qhead];
qhead++;
if (d->is_leaf()) {
vs.push_back(to_leaf(d)->m_value);

View file

@ -0,0 +1,168 @@
/*++
Copyright (c) 2014 Microsoft Corporation
Module Name:
fixed_bit_vector.cpp
Abstract:
Simple bitvector implementation for fixed size bit-vectors.
Author:
Nikolaj Bjorner (nbjorner) 2014-9-15.
Leonardo de Moura (leonardo) 2006-10-03.
Revision History:
Based on bit_vector.cpp
--*/
#include<limits.h>
#include"fixed_bit_vector.h"
#include"trace.h"
#include"hash.h"
void fixed_bit_vector::set(fixed_bit_vector const& other, unsigned hi, unsigned lo) {
if ((lo % 32) == 0) {
unsigned sz32 = (hi-lo+1)/32;
unsigned lo32 = lo/32;
for (unsigned i = 0; i < sz32; ++i) {
m_data[lo32 + i] = other.m_data[i];
}
for (unsigned i = sz32*32; i < hi - lo + 1; ++i) {
set(lo + i, other.get(i));
}
return;
}
for (unsigned i = 0; i < hi - lo + 1; ++i) {
set(lo + i, other.get(i));
}
}
fixed_bit_vector_manager::fixed_bit_vector_manager(unsigned num_bits):
m_alloc("fixed_bit_vector") {
m_num_bits = num_bits;
m_num_words = num_words(num_bits);
m_num_bytes = m_num_words * sizeof(unsigned);
unsigned bit_rest = m_num_bits % 32;
m_mask = (1U << bit_rest) - 1;
if (m_mask == 0) m_mask = UINT_MAX;
}
fixed_bit_vector* fixed_bit_vector_manager::allocate() {
if (m_num_bytes == 0) return &m_0;
return static_cast<fixed_bit_vector*>(m_alloc.allocate(m_num_bytes));
}
fixed_bit_vector* fixed_bit_vector_manager::allocate0() {
fixed_bit_vector* result = allocate();
fill0(*result);
return result;
}
fixed_bit_vector* fixed_bit_vector_manager::allocate1() {
fixed_bit_vector* result = allocate();
fill1(*result);
return result;
}
fixed_bit_vector* fixed_bit_vector_manager::allocate(fixed_bit_vector const& bv) {
fixed_bit_vector* result = allocate();
copy(*result, bv);
return result;
}
void fixed_bit_vector_manager::deallocate(fixed_bit_vector* bv) {
if (m_num_bytes > 0) m_alloc.deallocate(m_num_bytes, bv);
}
void fixed_bit_vector_manager::copy(fixed_bit_vector& dst, fixed_bit_vector const& src) const {
memcpy(dst.m_data, src.m_data, num_bytes());
}
fixed_bit_vector&
fixed_bit_vector_manager::fill0(fixed_bit_vector& bv) const {
memset(bv.m_data, 0, num_bytes());
return bv;
}
fixed_bit_vector&
fixed_bit_vector_manager::fill1(fixed_bit_vector& bv) const {
memset(bv.m_data, 0xFF, num_bytes());
return bv;
}
fixed_bit_vector&
fixed_bit_vector_manager::set_and(fixed_bit_vector& dst, fixed_bit_vector const& src) const {
for (unsigned i = 0; i < m_num_words; i++)
dst.m_data[i] &= src.m_data[i];
return dst;
}
fixed_bit_vector&
fixed_bit_vector_manager::set_or(fixed_bit_vector& dst, fixed_bit_vector const& src) const {
for (unsigned i = 0; i < m_num_words; i++)
dst.m_data[i] |= src.m_data[i];
return dst;
}
fixed_bit_vector&
fixed_bit_vector_manager::set_neg(fixed_bit_vector& dst) const {
for (unsigned i = 0; i < m_num_words; i++)
dst.m_data[i] = ~dst.m_data[i];
return dst;
}
unsigned fixed_bit_vector_manager::last_word(fixed_bit_vector const& bv) const {
unsigned n = num_words();
if (n == 0) return 0;
return bv.m_data[n-1] & m_mask;
}
bool fixed_bit_vector_manager::equals(fixed_bit_vector const& a, fixed_bit_vector const& b) const {
if (&a == &b) return true;
unsigned n = num_words();
if (n == 0)
return true;
for (unsigned i = 0; i < n - 1; i++) {
if (a.m_data[i] != b.m_data[i])
return false;
}
return last_word(a) == last_word(b);
}
unsigned fixed_bit_vector_manager::hash(fixed_bit_vector const& src) const {
return string_hash(reinterpret_cast<char const* const>(src.m_data), num_bits()/8, num_bits());
}
bool fixed_bit_vector_manager::contains(fixed_bit_vector const& a, fixed_bit_vector const& b) const {
unsigned n = num_words();
if (n == 0)
return true;
for (unsigned i = 0; i < n - 1; ++i) {
if ((a.m_data[i] & b.m_data[i]) != b.m_data[i])
return false;
}
unsigned b_data = last_word(b);
return (last_word(a) & b_data) == b_data;
}
std::ostream& fixed_bit_vector_manager::display(std::ostream& out, fixed_bit_vector const& b) const {
unsigned i = num_bits();
while (i > 0) {
--i;
if (b.get(i))
out << "1";
else
out << "0";
}
return out;
}

146
src/util/fixed_bit_vector.h Normal file
View file

@ -0,0 +1,146 @@
/*++
Copyright (c) 2014 Microsoft Corporation
Module Name:
fixed_bit_vector.h
Abstract:
Simple bitvector implementation for fixed size bit-vectors.
Author:
Nikolaj Bjorner (nbjorner) 2014-9-15.
Revision History:
Related to bit_vector, but is based on a manager.
--*/
#ifndef _FIXED_BIT_VECTOR_H_
#define _FIXED_BIT_VECTOR_H_
#include<string.h>
#include"debug.h"
#include"small_object_allocator.h"
class fixed_bit_vector {
friend class fixed_bit_vector_manager;
friend class tbv_manager;
unsigned m_data[1];
static unsigned get_pos_mask(unsigned bit_idx) {
return 1 << (bit_idx % 32);
}
unsigned get_bit_word(unsigned bit_idx) const {
return m_data[bit_idx / 32];
}
unsigned & get_bit_word(unsigned bit_idx) {
return m_data[bit_idx / 32];
}
public:
fixed_bit_vector() {}
~fixed_bit_vector() {}
unsigned get_word(unsigned word_idx) const { return m_data[word_idx]; }
bool operator[](unsigned bit_idx) const {
return get(bit_idx);
}
bool get(unsigned bit_idx) const {
return (get_bit_word(bit_idx) & get_pos_mask(bit_idx)) != 0;
}
private:
void set(unsigned bit_idx) {
get_bit_word(bit_idx) |= get_pos_mask(bit_idx);
}
void unset(unsigned bit_idx) {
get_bit_word(bit_idx) &= ~get_pos_mask(bit_idx);
}
void set(unsigned bit_idx, bool val) {
int _val = static_cast<int>(val);
get_bit_word(bit_idx) ^= (-_val ^ get_bit_word(bit_idx)) & get_pos_mask(bit_idx);
}
// assign bits this[lo:hi] := other[0:hi-lo+1]
void set(fixed_bit_vector const& other, unsigned hi, unsigned lo);
};
class fixed_bit_vector_manager {
friend class fixed_bit_vector;
small_object_allocator m_alloc;
unsigned m_num_bits;
unsigned m_num_bytes;
unsigned m_num_words;
unsigned m_mask;
fixed_bit_vector m_0;
static unsigned num_words(unsigned num_bits) {
return (num_bits + 31) / 32;
}
public:
fixed_bit_vector_manager(unsigned num_bits);
void reset() { m_alloc.reset(); }
fixed_bit_vector* allocate();
fixed_bit_vector* allocate1();
fixed_bit_vector* allocate0();
fixed_bit_vector* allocate(fixed_bit_vector const& bv);
void deallocate(fixed_bit_vector* bv);
void copy(fixed_bit_vector& dst, fixed_bit_vector const& src) const;
unsigned num_words() const { return m_num_words; }
unsigned num_bytes() const { return m_num_bytes; }
unsigned num_bits() const { return m_num_bits; }
fixed_bit_vector& reset(fixed_bit_vector& bv) const { return fill0(bv); }
fixed_bit_vector& fill0(fixed_bit_vector& bv) const;
fixed_bit_vector& fill1(fixed_bit_vector& bv) const;
fixed_bit_vector& set_and(fixed_bit_vector& dst, fixed_bit_vector const& src) const;
fixed_bit_vector& set_or(fixed_bit_vector& dst, fixed_bit_vector const& src) const;
fixed_bit_vector& set_neg(fixed_bit_vector& dst) const;
unsigned last_word(fixed_bit_vector const& bv) const;
unsigned get_mask() const { return m_mask; }
bool equals(fixed_bit_vector const& a, fixed_bit_vector const& b) const;
unsigned hash(fixed_bit_vector const& src) const;
bool contains(fixed_bit_vector const& a, fixed_bit_vector const& b) const;
std::ostream& display(std::ostream& out, fixed_bit_vector const& b) const;
void set(fixed_bit_vector& dst, unsigned bit_idx) {
SASSERT(bit_idx < num_bits());
dst.set(bit_idx);
}
void unset(fixed_bit_vector& dst, unsigned bit_idx) {
SASSERT(bit_idx < num_bits());
dst.unset(bit_idx);
}
void set(fixed_bit_vector& dst, unsigned bit_idx, bool val) {
SASSERT(bit_idx < num_bits());
dst.set(bit_idx, val);
}
// assign bits this[lo:hi] := other[0:hi-lo+1]
void set(fixed_bit_vector& dst, fixed_bit_vector const& other, unsigned hi, unsigned lo) {
SASSERT(lo <= hi && hi < num_bits());
dst.set(other, hi, lo);
}
};
#endif /* _FIXED_BIT_VECTOR_H_ */

View file

@ -266,6 +266,7 @@ public:
}
}
void set(param_descrs const & d, symbol const & param_name, char const * value, symbol const & mod_name) {
param_kind k = d.get_kind(param_name);
params_ref & ps = get_params(mod_name);

View file

@ -127,6 +127,10 @@ class inf_eps_rational {
return m_r.get_uint64();
}
Numeral const& get_numeral() const {
return m_r;
}
rational const& get_rational() const {
return m_r.get_rational();
}
@ -139,16 +143,37 @@ class inf_eps_rational {
return m_infty;
}
bool is_finite() const {
return m_infty.is_zero();
}
static inf_eps_rational zero() {
return inf_eps_rational(Numeral::zero());
}
static inf_eps_rational one() {
return inf_eps_rational(Numeral::one());
}
static inf_eps_rational minus_one() {
return inf_eps_rational(Numeral::minus_one());
}
static inf_eps_rational infinity() {
return inf_eps_rational(rational::one(), Numeral::zero());
}
inf_eps_rational & operator=(const inf_eps_rational & r) {
m_infty = r.m_infty;
m_r = r.m_r;
return *this;
}
inf_eps_rational & operator=(const rational & r) {
inf_eps_rational & operator=(const Numeral & r) {
m_infty.reset();
m_r = r;
return *this;
return *this;
}
inf_eps_rational & operator+=(const inf_eps_rational & r) {
@ -163,6 +188,16 @@ class inf_eps_rational {
return *this;
}
inf_eps_rational & operator-=(const inf_rational & r) {
m_r -= r;
return *this;
}
inf_eps_rational & operator+=(const inf_rational & r) {
m_r += r;
return *this;
}
inf_eps_rational & operator+=(const rational & r) {
m_r += r;
return *this;
@ -272,12 +307,12 @@ class inf_eps_rational {
}
friend inline rational floor(const inf_eps_rational & r) {
SASSERT(r.m_infty.is_zero());
// SASSERT(r.m_infty.is_zero());
return floor(r.m_r);
}
friend inline rational ceil(const inf_eps_rational & r) {
SASSERT(r.m_infty.is_zero());
// SASSERT(r.m_infty.is_zero());
return ceil(r.m_r);
}

View file

@ -155,6 +155,17 @@ class inf_int_rational {
return *this;
}
inf_int_rational & operator*=(const rational & r) {
if (!r.is_int32()) {
throw default_exception("multiplication with large rational is not possible");
}
m_first *= r;
m_second *= r.get_int32();
return *this;
}
inf_int_rational & operator-=(const inf_int_rational & r) {
m_first -= r.m_first;
m_second -= r.m_second;
@ -344,6 +355,10 @@ inline inf_int_rational operator+(const inf_int_rational & r1, const inf_int_rat
return inf_int_rational(r1) += r2;
}
inline inf_int_rational operator*(const rational & r1, const inf_int_rational & r2) {
return inf_int_rational(r2) *= r1;
}
inline inf_int_rational operator-(const inf_int_rational & r1, const inf_int_rational & r2) {
return inf_int_rational(r1) -= r2;
}

View file

@ -88,7 +88,7 @@ class inf_rational {
m_second(pos_inf?rational(1):rational(-1))
{}
explicit inf_rational(rational const& r):
inf_rational(rational const& r):
m_first(r)
{
m_second.reset();

View file

@ -46,7 +46,7 @@ class mpf {
mpz significand;
mpf_exp_t exponent;
mpf & operator=(mpf const & other) { UNREACHABLE(); return *this; }
void set(unsigned ebits, unsigned sbits);
void set(unsigned _ebits, unsigned _sbits);
public:
mpf();
mpf(unsigned ebits, unsigned sbits);

View file

@ -19,7 +19,7 @@ Revision History:
#include"mpq_inf.h"
template<bool SYNCH>
std::string mpq_inf_manager<SYNCH>::to_string(mpq_inf const & a) const {
std::string mpq_inf_manager<SYNCH>::to_string(mpq_inf const & a) {
if (m.is_zero(a.second))
return m.to_string(a.first);
@ -38,5 +38,6 @@ std::string mpq_inf_manager<SYNCH>::to_string(mpq_inf const & a) const {
return s;
}
template class mpq_inf_manager<true>;
template class mpq_inf_manager<false>;

View file

@ -26,12 +26,12 @@ typedef std::pair<mpq, mpq> mpq_inf;
template<bool SYNCH = true>
class mpq_inf_manager {
mpq_manager<SYNCH> & m;
mpq_manager<SYNCH> m;
double m_inf;
public:
typedef mpq_inf numeral;
mpq_inf_manager(mpq_manager<SYNCH> & _m, double inf = 0.0001):m(_m) {
mpq_inf_manager(double inf = 0.0001) {
set_inf(inf);
}
@ -83,6 +83,14 @@ public:
}
bool is_int(mpq_inf const & a) const { return m.is_int(a.first) && m.is_zero(a.second); }
bool is_pos(mpq_inf const & a) const {
return m.is_pos(a.first) || (m.is_zero(a.first) && m.is_pos(a.second));
}
bool is_neg(mpq_inf const & a) const {
return m.is_neg(a.first) || (m.is_zero(a.first) && m.is_neg(a.second));
}
bool is_rational(mpq_inf const & a) const { return m.is_zero(a.second); }
@ -104,15 +112,15 @@ public:
return m.is_zero(a.first) && m.is_zero(a.second);
}
bool eq(mpq_inf const & a, mpq_inf const & b) const {
bool eq(mpq_inf const & a, mpq_inf const & b) {
return m.eq(a.first, b.first) && m.eq(a.second, b.second);
}
bool eq(mpq_inf const & a, mpq const & b) const {
bool eq(mpq_inf const & a, mpq const & b) {
return m.eq(a.first, b) && m.is_zero(a.second);
}
bool eq(mpq_inf const & a, mpq const & b, inf_kind k) const {
bool eq(mpq_inf const & a, mpq const & b, inf_kind k) {
if (!m.eq(a.first, b))
return false;
switch (k) {
@ -124,15 +132,15 @@ public:
return false;
}
bool lt(mpq_inf const & a, mpq_inf const & b) const {
bool lt(mpq_inf const & a, mpq_inf const & b) {
return m.lt(a.first, b.first) || (m.lt(a.second, b.second) && m.eq(a.first, b.first));
}
bool lt(mpq_inf const & a, mpq const & b) const {
bool lt(mpq_inf const & a, mpq const & b) {
return m.lt(a.first, b) || (m.is_neg(a.second) && m.eq(a.first, b));
}
bool lt(mpq_inf const & a, mpq const & b, inf_kind k) const {
bool lt(mpq_inf const & a, mpq const & b, inf_kind k) {
if (m.lt(a.first, b))
return true;
if (m.eq(a.first, b)) {
@ -146,13 +154,13 @@ public:
return false;
}
bool gt(mpq_inf const & a, mpq_inf const & b) const { return lt(b, a); }
bool gt(mpq_inf const & a, mpq_inf const & b) { return lt(b, a); }
bool gt(mpq_inf const & a, mpq const & b) const {
bool gt(mpq_inf const & a, mpq const & b) {
return m.gt(a.first, b) || (m.is_pos(a.second) && m.eq(a.first, b));
}
bool gt(mpq_inf const & a, mpq const & b, inf_kind k) const {
bool gt(mpq_inf const & a, mpq const & b, inf_kind k) {
if (m.gt(a.first, b))
return true;
if (m.eq(a.first, b)) {
@ -166,17 +174,17 @@ public:
return false;
}
bool le(mpq_inf const & a, mpq_inf const & b) const { return !gt(a, b); }
bool le(mpq_inf const & a, mpq_inf const & b) { return !gt(a, b); }
bool le(mpq_inf const & a, mpq const & b) const { return !gt(a, b); }
bool le(mpq_inf const & a, mpq const & b) { return !gt(a, b); }
bool le(mpq_inf const & a, mpq const & b, inf_kind k) const { return !gt(a, b, k); }
bool le(mpq_inf const & a, mpq const & b, inf_kind k) { return !gt(a, b, k); }
bool ge(mpq_inf const & a, mpq_inf const & b) const { return !lt(a, b); }
bool ge(mpq_inf const & a, mpq_inf const & b) { return !lt(a, b); }
bool ge(mpq_inf const & a, mpq const & b) const { return !lt(a, b); }
bool ge(mpq_inf const & a, mpq const & b) { return !lt(a, b); }
bool ge(mpq_inf const & a, mpq const & b, inf_kind k) const { return !lt(a, b, k); }
bool ge(mpq_inf const & a, mpq const & b, inf_kind k) { return !lt(a, b, k); }
void add(mpq_inf const & a, mpq_inf const & b, mpq_inf & c) {
m.add(a.first, b.first, c.first);
@ -208,6 +216,16 @@ public:
m.mul(b, a.second, c.second);
}
void div(mpq_inf const & a, mpq const & b, mpq_inf & c) {
m.div(a.first, b, c.first);
m.div(a.second, b, c.second);
}
void div(mpq_inf const & a, mpz const & b, mpq_inf & c) {
m.div(a.first, b, c.first);
m.div(a.second, b, c.second);
}
void inc(mpq_inf & a) {
m.inc(a.first);
}
@ -221,10 +239,16 @@ public:
m.neg(a.second);
}
void abs(mpq_inf & a) {
if (is_neg(a)) {
neg(a);
}
}
void ceil(mpq_inf const & a, mpq & b) {
if (m.is_int(a.first)) {
// special cases for k - delta*epsilon where k is an integer
if (m.is_pos(a.first))
if (m.is_pos(a.second))
m.add(a.first, mpq(1), b); // ceil(k + delta*epsilon) --> k+1
else
m.set(b, a.first);
@ -246,7 +270,13 @@ public:
}
}
std::string to_string(mpq_inf const & a) const;
std::string to_string(mpq_inf const & a);
void display(std::ostream & out, mpq_inf const & a) {
out << to_string(a);
}
mpq_manager<SYNCH>& get_mpq_manager() { return m; }
};
typedef mpq_inf_manager<true> synch_mpq_inf_manager;

View file

@ -111,6 +111,11 @@ public:
return INT_MIN <= v && v <= INT_MAX;
}
int get_int32() const {
SASSERT(is_int32());
return (int)get_int64();
}
double get_double() const { return m().get_double(m_val); }
rational const & get_rational() const { return *this; }

View file

@ -53,6 +53,7 @@ public:
m_scopes.push_back(m_chuncks.size());
}
void pop_scope() {
unsigned old_size = m_scopes.back();
m_scopes.pop_back();

View file

@ -67,7 +67,7 @@ public:
s_integer const& get_s_integer() const { return *this; }
s_integer const& get_infinitesimal() const { return zero(); }
static bool is_rational() { return true; }
s_integer const& get_rational() const { return *this; }
s_integer const& get_rational() const { return *this; }
s_integer & operator=(const s_integer & r) { m_val = r.m_val; return *this; }
friend inline s_integer numerator(const s_integer & r) { return r; }
friend inline s_integer denominator(const s_integer & r) { return one(); }

View file

@ -39,7 +39,7 @@ public:
numeral const & get() const { return m_num; }
numeral & get() { return m_num; }
_scoped_numeral & operator=(_scoped_numeral & n) {
_scoped_numeral & operator=(_scoped_numeral const & n) {
if (this == &n)
return *this;
m().set(m_num, n.m_num);
@ -97,6 +97,10 @@ public:
return a.m().eq(a, b);
}
friend bool operator!=(_scoped_numeral const & a, numeral const & b) {
return !a.m().eq(a, b);
}
friend bool operator<(_scoped_numeral const & a, numeral const & b) {
return a.m().lt(a, b);
}
@ -113,6 +117,26 @@ public:
return a.m().ge(a, b);
}
bool is_zero() const {
return m().is_zero(*this);
}
bool is_pos() const {
return m().is_pos(*this);
}
bool is_neg() const {
return m().is_neg(*this);
}
bool is_nonpos() const {
return m().is_nonpos(*this);
}
bool is_nonneg() const {
return m().is_nonneg(*this);
}
friend bool is_zero(_scoped_numeral const & a) {
return a.m().is_zero(a);
}
@ -133,6 +157,12 @@ public:
return a.m().is_nonpos(a);
}
friend _scoped_numeral abs(_scoped_numeral const& a) {
_scoped_numeral res(a);
a.m().abs(res);
return res;
}
void neg() {
m().neg(m_num);
}

View file

@ -46,6 +46,10 @@ public:
m_manager.set(this->back(), v);
}
void pop_back() {
shrink(this->size()-1);
}
void shrink(unsigned sz) {
unsigned old_sz = this->size();
if (old_sz == sz)

767
src/util/sorting_network.h Normal file
View file

@ -0,0 +1,767 @@
/*++
Copyright (c) 2013 Microsoft Corporation
Module Name:
sorting_network.h
Abstract:
Utility for creating a sorting network.
Author:
Nikolaj Bjorner (nbjorner) 2013-11-07
Notes:
Same routine is used in Formula.
--*/
#include "vector.h"
#ifndef _SORTING_NETWORK_H_
#define _SORTING_NETWORK_H_
template <typename Ext>
class sorting_network {
typedef typename Ext::vector vect;
Ext& m_ext;
svector<unsigned> m_currentv;
svector<unsigned> m_nextv;
svector<unsigned>* m_current;
svector<unsigned>* m_next;
unsigned& current(unsigned i) { return (*m_current)[i]; }
unsigned& next(unsigned i) { return (*m_next)[i]; }
void exchange(unsigned i, unsigned j, vect& out) {
SASSERT(i <= j);
if (i < j) {
typename Ext::T ei = out.get(i);
typename Ext::T ej = out.get(j);
out.set(i, m_ext.mk_ite(m_ext.mk_le(ei, ej), ei, ej));
out.set(j, m_ext.mk_ite(m_ext.mk_le(ej, ei), ei, ej));
}
}
void sort(unsigned k, vect& out) {
SASSERT(is_power_of2(k) && k > 0);
if (k == 2) {
for (unsigned i = 0; i < out.size()/2; ++i) {
exchange(current(2*i), current(2*i+1), out);
next(2*i) = current(2*i);
next(2*i+1) = current(2*i+1);
}
std::swap(m_current, m_next);
}
else {
for (unsigned i = 0; i < out.size()/k; ++i) {
unsigned ki = k * i;
for (unsigned j = 0; j < k / 2; ++j) {
next(ki + j) = current(ki + (2 * j));
next(ki + (k / 2) + j) = current(ki + (2 * j) + 1);
}
}
std::swap(m_current, m_next);
sort(k / 2, out);
for (unsigned i = 0; i < out.size() / k; ++i) {
unsigned ki = k * i;
for (unsigned j = 0; j < k / 2; ++j) {
next(ki + (2 * j)) = current(ki + j);
next(ki + (2 * j) + 1) = current(ki + (k / 2) + j);
}
for (unsigned j = 0; j < (k / 2) - 1; ++j) {
exchange(next(ki + (2 * j) + 1), next(ki + (2 * (j + 1))), out);
}
}
std::swap(m_current, m_next);
}
}
bool is_power_of2(unsigned n) const {
return n != 0 && ((n-1) & n) == 0;
}
public:
sorting_network(Ext& ext):
m_ext(ext),
m_current(&m_currentv),
m_next(&m_nextv)
{}
void operator()(vect const& in, vect& out) {
out.reset();
out.append(in);
if (in.size() <= 1) {
return;
}
while (!is_power_of2(out.size())) {
out.push_back(m_ext.mk_default());
}
for (unsigned i = 0; i < out.size(); ++i) {
m_currentv.push_back(i);
m_nextv.push_back(i);
}
unsigned k = 2;
while (k <= out.size()) {
sort(k, out);
k *= 2;
}
}
};
// parametric sorting network
// Described in Abio et.al. CP 2013.
template<class psort_expr>
class psort_nw {
typedef typename psort_expr::literal literal;
typedef typename psort_expr::literal_vector literal_vector;
class vc {
unsigned v; // number of vertices
unsigned c; // number of clauses
static const unsigned lambda = 5;
public:
vc(unsigned v, unsigned c):v(v), c(c) {}
bool operator<(vc const& other) const {
return to_int() < other.to_int();
}
vc operator+(vc const& other) const {
return vc(v + other.v, c + other.c);
}
unsigned to_int() const {
return lambda*v + c;
}
vc operator*(unsigned n) const {
return vc(n*v, n*c);
}
};
static vc mk_min(vc const& v1, vc const& v2) {
return (v1.to_int() < v2.to_int())?v1:v2;
}
enum cmp_t { LE, GE, EQ, GE_FULL, LE_FULL };
psort_expr& ctx;
cmp_t m_t;
// for testing
static const bool m_disable_dcard = false;
static const bool m_disable_dsorting = false;
static const bool m_disable_dsmerge = false;
static const bool m_force_dcard = false;
static const bool m_force_dsorting = false;
static const bool m_force_dsmerge = false;
public:
struct stats {
unsigned m_num_compiled_vars;
unsigned m_num_compiled_clauses;
void reset() { memset(this, 0, sizeof(*this)); }
stats() { reset(); }
};
stats m_stats;
psort_nw(psort_expr& c): ctx(c) {}
literal ge(bool full, unsigned k, unsigned n, literal const* xs) {
if (k > n) {
return ctx.mk_false();
}
if (k == 0) {
return ctx.mk_true();
}
SASSERT(0 < k && k <= n);
literal_vector in, out;
if (dualize(k, n, xs, in)) {
return le(full, k, in.size(), in.c_ptr());
}
else {
SASSERT(2*k <= n);
m_t = full?GE_FULL:GE;
psort_nw<psort_expr>::card(k, n, xs, out);
return out[k-1];
}
}
literal le(bool full, unsigned k, unsigned n, literal const* xs) {
if (k >= n) {
return ctx.mk_true();
}
SASSERT(k < n);
literal_vector in, out;
if (dualize(k, n, xs, in)) {
return ge(full, k, n, in.c_ptr());
}
else {
SASSERT(2*k <= n);
m_t = full?LE_FULL:LE;
card(k + 1, n, xs, out);
return ctx.mk_not(out[k]);
}
}
literal eq(unsigned k, unsigned n, literal const* xs) {
if (k > n) {
return ctx.mk_false();
}
SASSERT(k <= n);
literal_vector in, out;
if (dualize(k, n, xs, in)) {
return eq(k, n, in.c_ptr());
}
else {
SASSERT(2*k <= n);
m_t = EQ;
card(k+1, n, xs, out);
SASSERT(out.size() >= k+1);
return ctx.mk_min(out[k-1], ctx.mk_not(out[k]));
}
}
private:
std::ostream& pp(std::ostream& out, unsigned n, literal const* lits) {
for (unsigned i = 0; i < n; ++i) ctx.pp(out, lits[i]) << " ";
return out;
}
std::ostream& pp(std::ostream& out, literal_vector const& lits) {
for (unsigned i = 0; i < lits.size(); ++i) ctx.pp(out, lits[i]) << " ";
return out;
}
// 0 <= k <= N
// SUM x_i >= k
// <=>
// SUM ~x_i <= N - k
// suppose k > N/2, then it is better to solve dual.
bool dualize(unsigned& k, unsigned N, literal const* xs, literal_vector& in) {
SASSERT(0 <= k && k <= N);
if (2*k <= N) {
return false;
}
k = N - k;
for (unsigned i = 0; i < N; ++i) {
in.push_back(ctx.mk_not(xs[i]));
}
TRACE("pb",
pp(tout << N << ": ", in);
tout << " ~ " << k << "\n";);
return true;
}
bool even(unsigned n) const { return (0 == (n & 0x1)); }
bool odd(unsigned n) const { return !even(n); }
unsigned ceil2(unsigned n) const { return n/2 + odd(n); }
unsigned floor2(unsigned n) const { return n/2; }
unsigned power2(unsigned n) const { SASSERT(n < 10); return 1 << n; }
literal mk_max(literal a, literal b) {
if (a == b) return a;
m_stats.m_num_compiled_vars++;
return ctx.mk_max(a, b);
}
literal mk_min(literal a, literal b) {
if (a == b) return a;
m_stats.m_num_compiled_vars++;
return ctx.mk_min(a, b);
}
literal fresh() {
m_stats.m_num_compiled_vars++;
return ctx.fresh();
}
void add_clause(literal l1, literal l2, literal l3) {
literal lits[3] = { l1, l2, l3 };
add_clause(3, lits);
}
void add_clause(literal l1, literal l2) {
literal lits[2] = { l1, l2 };
add_clause(2, lits);
}
void add_clause(unsigned n, literal const* ls) {
m_stats.m_num_compiled_clauses++;
literal_vector tmp(n, ls);
ctx.mk_clause(n, tmp.c_ptr());
}
// y1 <= mk_max(x1,x2)
// y2 <= mk_min(x1,x2)
void cmp_ge(literal x1, literal x2, literal y1, literal y2) {
add_clause(ctx.mk_not(y2), x1);
add_clause(ctx.mk_not(y2), x2);
add_clause(ctx.mk_not(y1), x1, x2);
}
// mk_max(x1,x2) <= y1
// mk_min(x1,x2) <= y2
void cmp_le(literal x1, literal x2, literal y1, literal y2) {
add_clause(ctx.mk_not(x1), y1);
add_clause(ctx.mk_not(x2), y1);
add_clause(ctx.mk_not(x1), ctx.mk_not(x2), y2);
}
void cmp_eq(literal x1, literal x2, literal y1, literal y2) {
cmp_ge(x1, x2, y1, y2);
cmp_le(x1, x2, y1, y2);
}
void cmp(literal x1, literal x2, literal y1, literal y2) {
switch(m_t) {
case LE: case LE_FULL: cmp_le(x1, x2, y1, y2); break;
case GE: case GE_FULL: cmp_ge(x1, x2, y1, y2); break;
case EQ: cmp_eq(x1, x2, y1, y2); break;
}
}
vc vc_cmp() {
return vc(2, (m_t==EQ)?6:3);
}
void card(unsigned k, unsigned n, literal const* xs, literal_vector& out) {
TRACE("pb", tout << "card k:" << k << " n: " << n << "\n";);
if (n <= k) {
psort_nw<psort_expr>::sorting(n, xs, out);
}
else if (use_dcard(k, n)) {
dsorting(k, n, xs, out);
}
else {
literal_vector out1, out2;
unsigned l = n/2; // TBD
card(k, l, xs, out1);
card(k, n-l, xs + l, out2);
smerge(k, out1.size(), out1.c_ptr(), out2.size(), out2.c_ptr(), out);
}
TRACE("pb", tout << "card k:" << k << " n: " << n << "\n";
pp(tout << "in:", n, xs) << "\n";
pp(tout << "out:", out) << "\n";);
}
vc vc_card(unsigned k, unsigned n) {
if (n <= k) {
return vc_sorting(n);
}
else if (use_dcard(k, n)) {
return vc_dsorting(k, n);
}
else {
return vc_card_rec(k, n);
}
}
vc vc_card_rec(unsigned k, unsigned n) {
unsigned l = n/2;
return vc_card(k, l) + vc_card(k, n-l) + vc_smerge(k, l, n-l);
}
bool use_dcard(unsigned k, unsigned n) {
return m_force_dcard || (!m_disable_dcard && n < 10 && vc_dsorting(k, n) < vc_card_rec(k, n));
}
void merge(unsigned a, literal const* as,
unsigned b, literal const* bs,
literal_vector& out) {
TRACE("pb", tout << "merge a: " << a << " b: " << b << "\n";);
if (a == 1 && b == 1) {
literal y1 = mk_max(as[0], bs[0]);
literal y2 = mk_min(as[0], bs[0]);
out.push_back(y1);
out.push_back(y2);
psort_nw<psort_expr>::cmp(as[0], bs[0], y1, y2);
}
else if (a == 0) {
out.append(b, bs);
}
else if (b == 0) {
out.append(a, as);
}
else if (use_dsmerge(a, b, a + b)) {
dsmerge(a + b, a, as, b, bs, out);
}
else if (even(a) && odd(b)) {
merge(b, bs, a, as, out);
}
else {
literal_vector even_a, odd_a;
literal_vector even_b, odd_b;
literal_vector out1, out2;
SASSERT(a > 1 || b > 1);
split(a, as, even_a, odd_a);
split(b, bs, even_b, odd_b);
SASSERT(!even_a.empty());
SASSERT(!even_b.empty());
merge(even_a.size(), even_a.c_ptr(),
even_b.size(), even_b.c_ptr(), out1);
merge(odd_a.size(), odd_a.c_ptr(),
odd_b.size(), odd_b.c_ptr(), out2);
interleave(out1, out2, out);
}
TRACE("pb", tout << "merge a: " << a << " b: " << b << "\n";
pp(tout << "a:", a, as) << "\n";
pp(tout << "b:", b, bs) << "\n";
pp(tout << "out:", out) << "\n";);
}
vc vc_merge(unsigned a, unsigned b) {
if (a == 1 && b == 1) {
return vc_cmp();
}
else if (a == 0 || b == 0) {
return vc(0, 0);
}
else if (use_dsmerge(a, b, a + b)) {
return vc_dsmerge(a, b, a + b);
}
else {
return vc_merge_rec(a, b);
}
}
vc vc_merge_rec(unsigned a, unsigned b) {
return
vc_merge(ceil2(a), ceil2(b)) +
vc_merge(floor2(a), floor2(b)) +
vc_interleave(ceil2(a) + ceil2(b), floor2(a) + floor2(b));
}
void split(unsigned n, literal const* ls, literal_vector& even, literal_vector& odd) {
for (unsigned i = 0; i < n; i += 2) {
even.push_back(ls[i]);
}
for (unsigned i = 1; i < n; i += 2) {
odd.push_back(ls[i]);
}
}
void interleave(literal_vector const& as,
literal_vector const& bs,
literal_vector& out) {
TRACE("pb", tout << "interleave: " << as.size() << " " << bs.size() << "\n";);
SASSERT(as.size() >= bs.size());
SASSERT(as.size() <= bs.size() + 2);
SASSERT(!as.empty());
out.push_back(as[0]);
unsigned sz = std::min(as.size()-1, bs.size());
for (unsigned i = 0; i < sz; ++i) {
literal y1 = mk_max(as[i+1],bs[i]);
literal y2 = mk_min(as[i+1],bs[i]);
psort_nw<psort_expr>::cmp(as[i+1], bs[i], y1, y2);
out.push_back(y1);
out.push_back(y2);
}
if (as.size() == bs.size()) {
out.push_back(bs[sz]);
}
else if (as.size() == bs.size() + 2) {
out.push_back(as[sz+1]);
}
SASSERT(out.size() == as.size() + bs.size());
TRACE("pb", tout << "interleave: " << as.size() << " " << bs.size() << "\n";
pp(tout << "a: ", as) << "\n";
pp(tout << "b: ", bs) << "\n";
pp(tout << "out: ", out) << "\n";);
}
vc vc_interleave(unsigned a, unsigned b) {
return vc_cmp()*std::min(a-1,b);
}
void sorting(unsigned n, literal const* xs, literal_vector& out) {
TRACE("pb", tout << "sorting: " << n << "\n";);
switch(n) {
case 0:
break;
case 1:
out.push_back(xs[0]);
break;
case 2:
psort_nw<psort_expr>::merge(1, xs, 1, xs+1, out);
break;
default:
if (use_dsorting(n)) {
dsorting(n, n, xs, out);
}
else {
literal_vector out1, out2;
unsigned l = n/2; // TBD
sorting(l, xs, out1);
sorting(n-l, xs+l, out2);
merge(out1.size(), out1.c_ptr(),
out2.size(), out2.c_ptr(),
out);
}
break;
}
TRACE("pb", tout << "sorting: " << n << "\n";
pp(tout << "in:", n, xs) << "\n";
pp(tout << "out:", out) << "\n";);
}
vc vc_sorting(unsigned n) {
switch(n) {
case 0: return vc(0,0);
case 1: return vc(0,0);
case 2: return vc_merge(1,1);
default:
if (use_dsorting(n)) {
return vc_dsorting(n, n);
}
else {
return vc_sorting_rec(n);
}
}
}
vc vc_sorting_rec(unsigned n) {
SASSERT(n > 2);
unsigned l = n/2;
return vc_sorting(l) + vc_sorting(n-l) + vc_merge(l, n-l);
}
bool use_dsorting(unsigned n) {
SASSERT(n > 2);
return m_force_dsorting ||
(!m_disable_dsorting && n < 10 && vc_dsorting(n, n) < vc_sorting_rec(n));
}
void smerge(unsigned c,
unsigned a, literal const* as,
unsigned b, literal const* bs,
literal_vector& out) {
TRACE("pb", tout << "smerge: c:" << c << " a:" << a << " b:" << b << "\n";);
if (a == 1 && b == 1 && c == 1) {
literal y = mk_max(as[0], bs[0]);
if (m_t != GE) {
// x1 <= mk_max(x1,x2)
// x2 <= mk_max(x1,x2)
add_clause(ctx.mk_not(as[0]), y);
add_clause(ctx.mk_not(bs[0]), y);
}
if (m_t != LE) {
// mk_max(x1,x2) <= x1, x2
add_clause(ctx.mk_not(y), as[0], bs[0]);
}
out.push_back(y);
}
else if (a == 0) {
out.append(std::min(c, b), bs);
}
else if (b == 0) {
out.append(std::min(c, a), as);
}
else if (a > c) {
smerge(c, c, as, b, bs, out);
}
else if (b > c) {
smerge(c, a, as, c, bs, out);
}
else if (a + b <= c) {
merge(a, as, b, bs, out);
}
else if (use_dsmerge(a, b, c)) {
dsmerge(c, a, as, b, bs, out);
}
else {
literal_vector even_a, odd_a;
literal_vector even_b, odd_b;
literal_vector out1, out2;
split(a, as, even_a, odd_a);
split(b, bs, even_b, odd_b);
SASSERT(!even_a.empty());
SASSERT(!even_b.empty());
unsigned c1, c2;
if (even(c)) {
c1 = 1 + c/2; c2 = c/2;
}
else {
c1 = (c + 1)/2; c2 = (c - 1)/2;
}
smerge(c1, even_a.size(), even_a.c_ptr(),
even_b.size(), even_b.c_ptr(), out1);
smerge(c2, odd_a.size(), odd_a.c_ptr(),
odd_b.size(), odd_b.c_ptr(), out2);
SASSERT(out1.size() == std::min(even_a.size()+even_b.size(), c1));
SASSERT(out2.size() == std::min(odd_a.size()+odd_b.size(), c2));
literal y;
if (even(c)) {
literal z1 = out1.back();
literal z2 = out2.back();
out1.pop_back();
out2.pop_back();
y = mk_max(z1, z2);
if (m_t != GE) {
add_clause(ctx.mk_not(z1), y);
add_clause(ctx.mk_not(z2), y);
}
if (m_t != LE) {
add_clause(ctx.mk_not(y), z1, z2);
}
}
interleave(out1, out2, out);
if (even(c)) {
out.push_back(y);
}
}
TRACE("pb", tout << "smerge: c:" << c << " a:" << a << " b:" << b << "\n";
pp(tout << "a:", a, as) << "\n";
pp(tout << "b:", b, bs) << "\n";
pp(tout << "out:", out) << "\n";
);
SASSERT(out.size() == std::min(a + b, c));
}
vc vc_smerge(unsigned a, unsigned b, unsigned c) {
if (a == 1 && b == 1 && c == 1) {
vc v(1,0);
if (m_t != GE) v = v + vc(0, 2);
if (m_t != LE) v = v + vc(0, 1);
return v;
}
if (a == 0 || b == 0) return vc(0, 0);
if (a > c) return vc_smerge(c, b, c);
if (b > c) return vc_smerge(a, c, c);
if (a + b <= c) return vc_merge(a, b);
if (use_dsmerge(a, b, c)) return vc_dsmerge(a, b, c);
return vc_smerge_rec(a, b, c);
}
vc vc_smerge_rec(unsigned a, unsigned b, unsigned c) {
return
vc_smerge(ceil2(a), ceil2(b), even(c)?(1+c/2):((c+1)/2)) +
vc_smerge(floor2(a), floor2(b), even(c)?(c/2):((c-1)/2)) +
vc_interleave(ceil2(a)+ceil2(b),floor2(a)+floor2(b)) +
vc(1, 0) +
((m_t != GE)?vc(0, 2):vc(0, 0)) +
((m_t != LE)?vc(0, 1):vc(0, 0));
}
bool use_dsmerge(unsigned a, unsigned b, unsigned c) {
return
m_force_dsmerge ||
(!m_disable_dsmerge &&
a < (1 << 15) && b < (1 << 15) &&
vc_dsmerge(a, b, a + b) < vc_smerge_rec(a, b, c));
}
void dsmerge(
unsigned c,
unsigned a, literal const* as,
unsigned b, literal const* bs,
literal_vector& out) {
TRACE("pb", tout << "dsmerge: c:" << c << " a:" << a << " b:" << b << "\n";);
SASSERT(a <= c);
SASSERT(b <= c);
SASSERT(a + b >= c);
for (unsigned i = 0; i < c; ++i) {
out.push_back(fresh());
}
if (m_t != GE) {
for (unsigned i = 0; i < a; ++i) {
add_clause(ctx.mk_not(as[i]), out[i]);
}
for (unsigned i = 0; i < b; ++i) {
add_clause(ctx.mk_not(bs[i]), out[i]);
}
for (unsigned i = 1; i <= a; ++i) {
for (unsigned j = 1; j <= b && i + j <= c; ++j) {
add_clause(ctx.mk_not(as[i-1]),ctx.mk_not(bs[j-1]),out[i+j-1]);
}
}
}
if (m_t != LE) {
literal_vector ls;
for (unsigned k = 0; k < c; ++k) {
ls.reset();
ls.push_back(ctx.mk_not(out[k]));
if (a <= k) {
add_clause(ctx.mk_not(out[k]), bs[k-a]);
}
if (b <= k) {
add_clause(ctx.mk_not(out[k]), as[k-b]);
}
for (unsigned i = 0; i < std::min(a,k + 1); ++i) {
unsigned j = k - i;
SASSERT(i + j == k);
if (j < b) {
ls.push_back(as[i]);
ls.push_back(bs[j]);
add_clause(ls.size(), ls.c_ptr());
ls.pop_back();
ls.pop_back();
}
}
}
}
}
vc vc_dsmerge(unsigned a, unsigned b, unsigned c) {
vc v(c, 0);
if (m_t != GE) {
v = v + vc(0, a + b + std::min(a, c)*std::min(b, c)/2);
}
if (m_t != LE) {
v = v + vc(0, std::min(a, c)*std::min(b, c)/2);
}
return v;
}
void dsorting(unsigned m, unsigned n, literal const* xs,
literal_vector& out) {
TRACE("pb", tout << "dsorting m: " << m << " n: " << n << "\n";);
SASSERT(m <= n);
literal_vector lits;
for (unsigned i = 0; i < m; ++i) {
out.push_back(fresh());
}
if (m_t != GE) {
for (unsigned k = 1; k <= m; ++k) {
lits.push_back(out[k-1]);
add_subset(true, k, 0, lits, n, xs);
lits.pop_back();
}
}
if (m_t != LE) {
for (unsigned k = 1; k <= m; ++k) {
lits.push_back(ctx.mk_not(out[k-1]));
add_subset(false, n-k+1, 0, lits, n, xs);
lits.pop_back();
}
}
}
vc vc_dsorting(unsigned m, unsigned n) {
SASSERT(m <= n && n < 10);
vc v(m, 0);
if (m_t != GE) {
v = v + vc(0, power2(n-1));
}
if (m_t != LE) {
v = v + vc(0, power2(n-1));
}
return v;
}
void add_subset(bool polarity, unsigned k, unsigned offset, literal_vector& lits,
unsigned n, literal const* xs) {
TRACE("pb", tout << "k:" << k << " offset: " << offset << " n: " << n << " ";
pp(tout, lits) << "\n";);
SASSERT(k + offset <= n);
if (k == 0) {
add_clause(lits.size(), lits.c_ptr());
return;
}
for (unsigned i = offset; i < n - k + 1; ++i) {
lits.push_back(polarity?ctx.mk_not(xs[i]):xs[i]);
add_subset(polarity, k-1, i+1, lits, n, xs);
lits.pop_back();
}
}
};
#endif

View file

@ -69,6 +69,7 @@ public:
#undef ARRAYSIZE
#define ARRAYSIZE ARRAYSIZE_TEMP
#undef max
#undef min
#elif defined(__APPLE__) && defined (__MACH__) // Mac OS X

View file

@ -24,6 +24,10 @@ Revision History:
#undef max
#undef min
#endif
#ifdef __APPLE__
#undef max
#undef min
#endif
#include<fstream>
#ifdef _TRACE

360
src/util/trail.h Normal file
View file

@ -0,0 +1,360 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
trail.h
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-06-02.
Revision History:
--*/
#ifndef _TRAIL_H_
#define _TRAIL_H_
#include"obj_hashtable.h"
#include"region.h"
#include"obj_ref.h"
template<typename Ctx>
class trail {
public:
virtual ~trail() {
}
virtual void undo(Ctx & ctx) = 0;
};
template<typename Ctx, typename T>
class value_trail : public trail<Ctx> {
T & m_value;
T m_old_value;
public:
value_trail(T & value):
m_value(value),
m_old_value(value) {
}
virtual ~value_trail() {
}
virtual void undo(Ctx & ctx) {
m_value = m_old_value;
}
};
template<typename Ctx>
class reset_flag_trail : public trail<Ctx> {
bool & m_value;
public:
reset_flag_trail(bool & value):
m_value(value) {
}
virtual ~reset_flag_trail() {
}
virtual void undo(Ctx & ctx) {
m_value = false;
}
};
template<typename Ctx, typename T>
class set_ptr_trail : public trail<Ctx> {
T * & m_ptr;
public:
set_ptr_trail(T * & ptr):
m_ptr(ptr) {
SASSERT(m_ptr == 0);
}
virtual void undo(Ctx & ctx) {
m_ptr = 0;
}
};
template<typename Ctx, typename T, bool CallDestructors=true>
class restore_size_trail : public trail<Ctx> {
vector<T, CallDestructors> & m_vector;
unsigned m_old_size;
public:
restore_size_trail(vector<T, CallDestructors> & v, unsigned sz):
m_vector(v),
m_old_size(sz) {
}
restore_size_trail(vector<T, CallDestructors> & v):
m_vector(v),
m_old_size(v.size()) {
}
virtual ~restore_size_trail() {
}
virtual void undo(Ctx & ctx) {
m_vector.shrink(m_old_size);
}
};
template<typename Ctx, typename T, bool CallDestructors=true>
class vector_value_trail : public trail<Ctx> {
vector<T, CallDestructors> & m_vector;
unsigned m_idx;
T m_old_value;
public:
vector_value_trail(vector<T, CallDestructors> & v, unsigned idx):
m_vector(v),
m_idx(idx),
m_old_value(v[idx]) {
}
virtual ~vector_value_trail() {
}
virtual void undo(Ctx & ctx) {
m_vector[m_idx] = m_old_value;
}
};
template<typename Ctx, typename D, typename R>
class insert_obj_map : public trail<Ctx> {
obj_map<D,R>& m_map;
D* m_obj;
public:
insert_obj_map(obj_map<D,R>& t, D* o) : m_map(t), m_obj(o) {}
virtual ~insert_obj_map() {}
virtual void undo(Ctx & ctx) { m_map.remove(m_obj); }
};
template<typename Ctx, typename M, typename D>
class insert_map : public trail<Ctx> {
M& m_map;
D m_obj;
public:
insert_map(M& t, D o) : m_map(t), m_obj(o) {}
virtual ~insert_map() {}
virtual void undo(Ctx & ctx) { m_map.remove(m_obj); }
};
template<typename Ctx, typename V>
class push_back_vector : public trail<Ctx> {
V & m_vector;
public:
push_back_vector(V & v):
m_vector(v) {
}
virtual void undo(Ctx & ctx) {
m_vector.pop_back();
}
};
template<typename Ctx, typename T>
class set_vector_idx_trail : public trail<Ctx> {
ptr_vector<T> & m_vector;
unsigned m_idx;
public:
set_vector_idx_trail(ptr_vector<T> & v, unsigned idx):
m_vector(v),
m_idx(idx) {
}
virtual ~set_vector_idx_trail() {
}
virtual void undo(Ctx & ctx) {
m_vector[m_idx] = 0;
}
};
template<typename Ctx, typename T, bool CallDestructors=true>
class pop_back_trail : public trail<Ctx> {
vector<T, CallDestructors> & m_vector;
T m_value;
public:
pop_back_trail(vector<T, CallDestructors> & v):
m_vector(v),
m_value(m_vector.back()) {
}
virtual void undo(Ctx & ctx) {
m_vector.push_back(m_value);
}
};
template<typename Ctx, typename T, bool CallDestructors=true>
class pop_back2_trail : public trail<Ctx> {
vector<T, CallDestructors> & m_vector;
typedef vector<vector<T, CallDestructors>, true> vector_t;
unsigned m_index;
T m_value;
public:
pop_back2_trail(vector<T, CallDestructors> & v, unsigned index):
m_vector(v),
m_index(index),
m_value(m_vector[index].back()) {
}
virtual void undo(Ctx & ctx) {
m_vector[m_index].push_back(m_value);
}
};
template<typename Ctx, typename T, bool CallDestructors=true>
class push_back_trail : public trail<Ctx> {
vector<T, CallDestructors> & m_vector;
public:
push_back_trail(vector<T, CallDestructors> & v):
m_vector(v) {
}
virtual void undo(Ctx & ctx) {
m_vector.pop_back();
}
};
template<typename Ctx, typename T, bool CallDestructors=true>
class push_back2_trail : public trail<Ctx> {
typedef vector<vector<T, CallDestructors>, true> vector_t;
vector_t & m_vector;
unsigned m_index;
public:
push_back2_trail(vector_t & v, unsigned index) :
m_vector(v),
m_index(index) {
}
virtual void undo(Ctx & ctx) {
m_vector[m_index].pop_back();
}
};
template<typename Ctx>
class set_bitvector_trail : public trail<Ctx> {
svector<bool> & m_vector;
unsigned m_idx;
public:
set_bitvector_trail(svector<bool> & v, unsigned idx):
m_vector(v),
m_idx(idx) {
SASSERT(m_vector[m_idx] == false);
m_vector[m_idx] = true;
}
virtual void undo(Ctx & ctx) {
m_vector[m_idx] = false;
}
};
template<typename Ctx, typename T>
class new_obj_trail : public trail<Ctx> {
T * m_obj;
public:
new_obj_trail(T * obj):
m_obj(obj) {
}
virtual void undo(Ctx & ctx) {
dealloc(m_obj);
}
};
template<typename Ctx, typename M, typename T>
class obj_ref_trail : public trail<Ctx> {
obj_ref<T,M> m_obj;
public:
obj_ref_trail(obj_ref<T,M>& obj):
m_obj(obj) {
}
virtual void undo(Ctx & ctx) {
m_obj.reset();
}
};
template<typename Ctx, typename T>
class insert_obj_trail : public trail<Ctx> {
obj_hashtable<T>& m_table;
T* m_obj;
public:
insert_obj_trail(obj_hashtable<T>& t, T* o) : m_table(t), m_obj(o) {}
virtual ~insert_obj_trail() {}
virtual void undo(Ctx & ctx) { m_table.remove(m_obj); }
};
template<typename Ctx, typename T>
class remove_obj_trail : public trail<Ctx> {
obj_hashtable<T>& m_table;
T* m_obj;
public:
remove_obj_trail(obj_hashtable<T>& t, T* o) : m_table(t), m_obj(o) {}
virtual ~remove_obj_trail() {}
virtual void undo(Ctx & ctx) { m_table.insert(m_obj); }
};
template<typename Ctx>
void undo_trail_stack(Ctx & ctx, ptr_vector<trail<Ctx> > & s, unsigned old_size) {
SASSERT(old_size <= s.size());
typename ptr_vector<trail<Ctx> >::iterator begin = s.begin() + old_size;
typename ptr_vector<trail<Ctx> >::iterator it = s.end();
while (it != begin) {
--it;
(*it)->undo(ctx);
}
s.shrink(old_size);
}
template<typename Ctx>
class trail_stack {
Ctx & m_ctx;
ptr_vector<trail<Ctx> > m_trail_stack;
unsigned_vector m_scopes;
region m_region;
public:
trail_stack(Ctx & c):m_ctx(c) {}
~trail_stack() {}
region & get_region() { return m_region; }
void reset() {
pop_scope(m_scopes.size());
// Undo trail objects stored at lvl 0 (avoid memory leaks if lvl 0 contains new_obj_trail objects).
undo_trail_stack(m_ctx, m_trail_stack, 0);
}
void push_ptr(trail<Ctx> * t) { m_trail_stack.push_back(t); }
template<typename TrailObject>
void push(TrailObject const & obj) { m_trail_stack.push_back(new (m_region) TrailObject(obj)); }
unsigned get_num_scopes() const { return m_scopes.size(); }
void push_scope() { m_region.push_scope(); m_scopes.push_back(m_trail_stack.size()); }
void pop_scope(unsigned num_scopes) {
if (num_scopes == 0) return;
unsigned lvl = m_scopes.size();
SASSERT(num_scopes <= lvl);
unsigned new_lvl = lvl - num_scopes;
unsigned old_size = m_scopes[new_lvl];
undo_trail_stack(m_ctx, m_trail_stack, old_size);
m_scopes.shrink(new_lvl);
m_region.pop_scope(num_scopes);
}
};
#endif /* _TRAIL_H_ */

177
src/util/union_find.h Normal file
View file

@ -0,0 +1,177 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
union_find.h
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-05-31.
Revision History:
--*/
#ifndef _UNION_FIND_H_
#define _UNION_FIND_H_
#include "trail.h"
#include "trace.h"
class union_find_default_ctx {
public:
typedef trail_stack<union_find_default_ctx> _trail_stack;
union_find_default_ctx() : m_stack(*this) {}
void unmerge_eh(unsigned, unsigned) {}
void merge_eh(unsigned, unsigned, unsigned, unsigned) {}
void after_merge_eh(unsigned, unsigned, unsigned, unsigned) {}
_trail_stack& get_trail_stack() { return m_stack; }
private:
_trail_stack m_stack;
};
template<typename Ctx = union_find_default_ctx>
class union_find {
Ctx & m_ctx;
trail_stack<Ctx> & m_trail_stack;
svector<unsigned> m_find;
svector<unsigned> m_size;
svector<unsigned> m_next;
class mk_var_trail;
friend class mk_var_trail;
class mk_var_trail : public trail<Ctx> {
union_find & m_owner;
public:
mk_var_trail(union_find & o):m_owner(o) {}
virtual ~mk_var_trail() {}
virtual void undo(Ctx & ctx) {
m_owner.m_find.pop_back();
m_owner.m_size.pop_back();
m_owner.m_next.pop_back();
}
};
mk_var_trail m_mk_var_trail;
class merge_trail;
friend class merge_trail;
class merge_trail : public trail<Ctx> {
union_find & m_owner;
unsigned m_r1;
public:
merge_trail(union_find & o, unsigned r1):m_owner(o), m_r1(r1) {}
virtual ~merge_trail() {}
virtual void undo(Ctx & ctx) { m_owner.unmerge(m_r1); }
};
void unmerge(unsigned r1) {
unsigned r2 = m_find[r1];
TRACE("union_find", tout << "unmerging " << r1 << " " << r2 << "\n";);
SASSERT(find(r2) == r2);
m_size[r2] -= m_size[r1];
m_find[r1] = r1;
std::swap(m_next[r1], m_next[r2]);
m_ctx.unmerge_eh(r2, r1);
CASSERT("union_find", check_invariant());
}
public:
union_find(Ctx & ctx):m_ctx(ctx), m_trail_stack(ctx.get_trail_stack()), m_mk_var_trail(*this) {}
unsigned mk_var() {
unsigned r = m_find.size();
m_find.push_back(r);
m_size.push_back(1);
m_next.push_back(r);
m_trail_stack.push_ptr(&m_mk_var_trail);
return r;
}
unsigned get_num_vars() const { return m_find.size(); }
unsigned find(unsigned v) const {
while (true) {
unsigned new_v = m_find[v];
if (new_v == v)
return v;
v = new_v;
}
}
unsigned next(unsigned v) const { return m_next[v]; }
unsigned size(unsigned v) const { return m_size[find(v)]; }
bool is_root(unsigned v) const { return m_find[v] == v; }
void merge(unsigned v1, unsigned v2) {
unsigned r1 = find(v1);
unsigned r2 = find(v2);
TRACE("union_find", tout << "merging " << r1 << " " << r2 << "\n";);
if (r1 == r2)
return;
if (m_size[r1] > m_size[r2])
std::swap(r1, r2);
m_ctx.merge_eh(r2, r1, v2, v1);
m_find[r1] = r2;
m_size[r2] += m_size[r1];
std::swap(m_next[r1], m_next[r2]);
m_trail_stack.push(merge_trail(*this, r1));
m_ctx.after_merge_eh(r2, r1, v2, v1);
CASSERT("union_find", check_invariant());
}
// dissolve equivalence class of v
// this method cannot be used with backtracking.
void dissolve(unsigned v) {
unsigned w;
do {
w = next(v);
m_size[v] = 1;
m_find[v] = v;
m_next[v] = v;
}
while (w != v);
}
void display(std::ostream & out) const {
unsigned num = get_num_vars();
for (unsigned v = 0; v < num; v++) {
out << "v" << v << " --> v" << m_find[v] << " (" << size(v) << ")\n";
}
}
#ifdef Z3DEBUG
bool check_invariant() const {
unsigned num = get_num_vars();
for (unsigned v = 0; v < num; v++) {
if (is_root(v)) {
unsigned curr = v;
unsigned sz = 0;
do {
SASSERT(find(curr) == v);
sz++;
curr = next(curr);
}
while (curr != v);
SASSERT(m_size[v] == sz);
}
}
return true;
}
#endif
};
#endif /* _UNION_FIND_H_ */