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:
commit
ab5022888c
396 changed files with 86387 additions and 3294 deletions
|
@ -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();
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
168
src/util/fixed_bit_vector.cpp
Normal file
168
src/util/fixed_bit_vector.cpp
Normal 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
146
src/util/fixed_bit_vector.h
Normal 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_ */
|
||||
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
767
src/util/sorting_network.h
Normal 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
|
|
@ -69,6 +69,7 @@ public:
|
|||
#undef ARRAYSIZE
|
||||
#define ARRAYSIZE ARRAYSIZE_TEMP
|
||||
#undef max
|
||||
#undef min
|
||||
|
||||
|
||||
#elif defined(__APPLE__) && defined (__MACH__) // Mac OS X
|
||||
|
|
|
@ -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
360
src/util/trail.h
Normal 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
177
src/util/union_find.h
Normal 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_ */
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue