mirror of
https://github.com/Z3Prover/z3
synced 2025-05-04 14:25:46 +00:00
retire deprecated functionality
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
8ec5ccbb9a
commit
8db711bc3c
15 changed files with 395 additions and 1100 deletions
|
@ -10,133 +10,349 @@ Author:
|
|||
Nikolaj Bjorner (nbjorner) 2021-03-19
|
||||
Jakob Rath 2021-04-6
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
#include "util/debug.h"
|
||||
#include "math/polysat/viable.h"
|
||||
#include "math/polysat/solver.h"
|
||||
|
||||
|
||||
namespace polysat {
|
||||
|
||||
viable::viable(solver& s):
|
||||
s(s),
|
||||
m_bdd(1000)
|
||||
{}
|
||||
viable::viable(solver& s) : s(s) {}
|
||||
|
||||
viable::~viable() {
|
||||
for (entry* e : m_alloc)
|
||||
dealloc(e);
|
||||
}
|
||||
|
||||
void viable::push_viable(pvar v) {
|
||||
s.m_trail.push_back(trail_instr_t::viable_add_i);
|
||||
m_viable_trail.push_back(std::make_pair(v, m_viable[v]));
|
||||
|
||||
viable::entry* viable::alloc_entry() {
|
||||
if (m_alloc.empty())
|
||||
return alloc(entry);
|
||||
auto* e = m_alloc.back();
|
||||
e->side_cond.reset();
|
||||
m_alloc.pop_back();
|
||||
return e;
|
||||
}
|
||||
|
||||
void viable::pop_viable() {
|
||||
auto const & p = m_viable_trail.back();
|
||||
m_viable.set(p.first, p.second);
|
||||
m_viable_trail.pop_back();
|
||||
auto& [v, e] = m_trail.back();
|
||||
e->remove_from(m_viable[v], e);
|
||||
m_alloc.push_back(e);
|
||||
m_trail.pop_back();
|
||||
}
|
||||
|
||||
void viable::push_viable() {
|
||||
auto& [v, e] = m_trail.back();
|
||||
SASSERT(e->prev() != e || !m_viable[v]);
|
||||
SASSERT(e->prev() != e || e->next() == e);
|
||||
if (e->prev() != e) {
|
||||
e->prev()->insert_after(e);
|
||||
if (e->interval.lo_val() < e->next()->interval.lo_val())
|
||||
m_viable[v] = e;
|
||||
}
|
||||
else
|
||||
m_viable[v] = e;
|
||||
m_trail.pop_back();
|
||||
}
|
||||
|
||||
// a*v + b == 0 or a*v + b != 0
|
||||
void viable::intersect_eq(rational const& a, pvar v, rational const& b, bool is_positive) {
|
||||
|
||||
bddv const& x = var2bits(v).var();
|
||||
if (b == 0 && a.is_odd()) {
|
||||
// hacky test optimizing special case.
|
||||
// general case is compute inverse(a)*-b for equality 2^k*a*x + b == 0
|
||||
// then constrain x.
|
||||
//
|
||||
intersect_viable(v, is_positive ? x.all0() : !x.all0());
|
||||
}
|
||||
else if (a.is_odd()) {
|
||||
rational a_inv;
|
||||
VERIFY(a.mult_inverse(x.size(), a_inv));
|
||||
bdd eq = x == mod(a_inv * -b, rational::power_of_two(x.size()));
|
||||
intersect_viable(v, is_positive ? eq : !eq);
|
||||
}
|
||||
void viable::intersect(pvar v, signed_constraint const& c) {
|
||||
auto& fi = s.m_forbidden_intervals;
|
||||
entry* ne = alloc_entry();
|
||||
if (!fi.get_interval(c, v, ne->interval, ne->side_cond) || ne->interval.is_currently_empty())
|
||||
m_alloc.push_back(ne);
|
||||
else {
|
||||
IF_VERBOSE(10, verbose_stream() << a << "*x + " << b << "\n");
|
||||
|
||||
bddv lhs = a * x + b;
|
||||
bdd xs = is_positive ? lhs.all0() : !lhs.all0();
|
||||
intersect_viable(v, xs);
|
||||
ne->src = c;
|
||||
intersect(v, ne);
|
||||
}
|
||||
}
|
||||
|
||||
void viable::intersect_ule(pvar v, rational const& a, rational const& b, rational const& c, rational const& d, bool is_positive) {
|
||||
bddv const& x = var2bits(v).var();
|
||||
// hacky special case
|
||||
if (a == 1 && b == 0 && c == 0 && d == 0)
|
||||
// x <= 0
|
||||
intersect_viable(v, is_positive ? x.all0() : !x.all0());
|
||||
void viable::intersect(pvar v, entry* ne) {
|
||||
entry* e = m_viable[v];
|
||||
if (e && e->interval.is_full())
|
||||
return;
|
||||
|
||||
if (ne->interval.is_currently_empty()) {
|
||||
m_alloc.push_back(ne);
|
||||
return;
|
||||
}
|
||||
|
||||
auto create_entry = [&]() {
|
||||
m_trail.push_back({ v, ne });
|
||||
s.m_trail.push_back(trail_instr_t::viable_add_i);
|
||||
ne->init(ne);
|
||||
return ne;
|
||||
};
|
||||
|
||||
auto remove_entry = [&](entry* e) {
|
||||
m_trail.push_back({ v, e });
|
||||
s.m_trail.push_back(trail_instr_t::viable_rem_i);
|
||||
e->remove_from(m_viable[v], e);
|
||||
};
|
||||
|
||||
//LOG("intersect " << ne->interval);
|
||||
|
||||
if (!e)
|
||||
m_viable[v] = create_entry();
|
||||
else {
|
||||
IF_VERBOSE(10, verbose_stream() << a << "*x + " << b << (is_positive ? " <= " : " > ") << c << "*x + " << d << "\n");
|
||||
bddv l = a * x + b;
|
||||
bddv r = c * x + d;
|
||||
bdd xs = is_positive ? (l <= r) : (l > r);
|
||||
intersect_viable(v, xs);
|
||||
entry* first = e;
|
||||
do {
|
||||
if (e->interval.contains(ne->interval)) {
|
||||
m_alloc.push_back(ne);
|
||||
return;
|
||||
}
|
||||
while (ne->interval.contains(e->interval)) {
|
||||
entry* n = e->next();
|
||||
remove_entry(e);
|
||||
if (!m_viable[v]) {
|
||||
m_viable[v] = create_entry();
|
||||
return;
|
||||
}
|
||||
if (e == first)
|
||||
first = n;
|
||||
e = n;
|
||||
}
|
||||
SASSERT(e->interval.lo_val() != ne->interval.lo_val());
|
||||
if (e->interval.lo_val() > ne->interval.lo_val()) {
|
||||
if (first->prev()->interval.contains(ne->interval)) {
|
||||
m_alloc.push_back(ne);
|
||||
return;
|
||||
}
|
||||
e->insert_before(create_entry());
|
||||
if (e == first)
|
||||
m_viable[v] = e->prev();
|
||||
SASSERT(well_formed(m_viable[v]));
|
||||
return;
|
||||
}
|
||||
e = e->next();
|
||||
}
|
||||
while (e != first);
|
||||
// otherwise, append to end of list
|
||||
first->insert_before(create_entry());
|
||||
}
|
||||
SASSERT(well_formed(m_viable[v]));
|
||||
}
|
||||
|
||||
bool viable::has_viable(pvar v) {
|
||||
return !m_viable[v].is_false();
|
||||
bool viable::has_viable(pvar v) {
|
||||
auto* e = m_viable[v];
|
||||
if (!e)
|
||||
return true;
|
||||
entry* first = e;
|
||||
auto const& max_value = s.var2pdd(v).max_value();
|
||||
do {
|
||||
if (e->interval.is_full())
|
||||
return false;
|
||||
entry* n = e->next();
|
||||
if (n == e)
|
||||
return true;
|
||||
if (e->interval.hi_val() < n->interval.lo_val())
|
||||
return true;
|
||||
if (n == first)
|
||||
return e->interval.lo_val() <= e->interval.hi_val();
|
||||
e = n;
|
||||
}
|
||||
while (e != first);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool viable::is_viable(pvar v, rational const& val) {
|
||||
return var2bits(v).contains(m_viable[v], val);
|
||||
bool viable::is_viable(pvar v, rational const& val) {
|
||||
auto* e = m_viable[v];
|
||||
if (!e)
|
||||
return true;
|
||||
entry* first = e;
|
||||
entry* last = first->prev();
|
||||
if (last->interval.currently_contains(val))
|
||||
return false;
|
||||
for (; e != last; e = e->next()) {
|
||||
if (e->interval.currently_contains(val))
|
||||
return false;
|
||||
if (val < e->interval.lo_val())
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void viable::intersect_viable(pvar v, bdd vals) {
|
||||
push_viable(v);
|
||||
m_viable[v] &= vals;
|
||||
if (m_viable[v].is_false())
|
||||
s.set_conflict(v);
|
||||
rational viable::min_viable(pvar v) {
|
||||
rational lo(0);
|
||||
auto* e = m_viable[v];
|
||||
if (!e)
|
||||
return lo;
|
||||
entry* first = e;
|
||||
entry* last = first->prev();
|
||||
if (last->interval.currently_contains(lo))
|
||||
lo = last->interval.hi_val();
|
||||
do {
|
||||
if (!e->interval.currently_contains(lo))
|
||||
break;
|
||||
lo = e->interval.hi_val();
|
||||
e = e->next();
|
||||
}
|
||||
while (e != first);
|
||||
SASSERT(is_viable(v, lo));
|
||||
return lo;
|
||||
}
|
||||
|
||||
dd::find_t viable::find_viable(pvar v, rational & val) {
|
||||
return var2bits(v).find_hint(m_viable[v], s.m_value[v], val);
|
||||
rational viable::max_viable(pvar v) {
|
||||
rational hi = s.var2pdd(v).max_value();
|
||||
auto* e = m_viable[v];
|
||||
if (!e)
|
||||
return hi;
|
||||
entry* last = e->prev();
|
||||
e = last;
|
||||
do {
|
||||
if (!e->interval.currently_contains(hi))
|
||||
break;
|
||||
hi = e->interval.lo_val() - 1;
|
||||
e = e->prev();
|
||||
}
|
||||
while (e != last);
|
||||
SASSERT(is_viable(v, hi));
|
||||
return hi;
|
||||
}
|
||||
|
||||
rational viable::min_viable(pvar v) {
|
||||
return var2bits(v).min(m_viable[v]);
|
||||
dd::find_t viable::find_viable(pvar v, rational& lo) {
|
||||
lo = 0;
|
||||
auto* e = m_viable[v];
|
||||
if (!e)
|
||||
return dd::find_t::multiple;
|
||||
if (e->interval.is_full())
|
||||
return dd::find_t::empty;
|
||||
|
||||
entry* first = e;
|
||||
entry* last = first->prev();
|
||||
if (last->interval.currently_contains(lo))
|
||||
lo = last->interval.hi_val();
|
||||
do {
|
||||
if (!e->interval.currently_contains(lo))
|
||||
break;
|
||||
lo = e->interval.hi_val();
|
||||
e = e->next();
|
||||
}
|
||||
while (e != first);
|
||||
|
||||
if (e->interval.currently_contains(lo))
|
||||
return dd::find_t::empty;
|
||||
|
||||
rational hi = s.var2pdd(v).max_value();
|
||||
e = last;
|
||||
do {
|
||||
if (!e->interval.currently_contains(hi))
|
||||
break;
|
||||
hi = e->interval.lo_val() - 1;
|
||||
e = e->prev();
|
||||
}
|
||||
while (e != last);
|
||||
if (lo == hi)
|
||||
return dd::find_t::singleton;
|
||||
else
|
||||
return dd::find_t::multiple;
|
||||
}
|
||||
|
||||
rational viable::max_viable(pvar v) {
|
||||
return var2bits(v).max(m_viable[v]);
|
||||
}
|
||||
bool viable::resolve(pvar v, conflict& core) {
|
||||
if (has_viable(v))
|
||||
return false;
|
||||
auto* e = m_viable[v];
|
||||
entry* first = e;
|
||||
SASSERT(e);
|
||||
core.reset();
|
||||
do {
|
||||
// Build constraint: upper bound of each interval is not contained in the next interval,
|
||||
// using the equivalence: t \in [l;h[ <=> t-l < h-l
|
||||
entry* n = e->next();
|
||||
if (!e->interval.is_full()) {
|
||||
auto const& hi = e->interval.hi();
|
||||
auto const& next_lo = n->interval.lo();
|
||||
auto const& next_hi = n->interval.hi();
|
||||
auto lhs = hi - next_lo;
|
||||
auto rhs = next_hi - next_lo;
|
||||
signed_constraint c = s.m_constraints.ult(lhs, rhs);
|
||||
core.insert(c);
|
||||
}
|
||||
for (auto sc : e->side_cond)
|
||||
core.insert(sc);
|
||||
e->src->set_var_dependent(); // ?
|
||||
core.insert(e->src);
|
||||
e = n;
|
||||
}
|
||||
while (e != first);
|
||||
|
||||
dd::fdd const& viable::sz2bits(unsigned sz) {
|
||||
m_bits.reserve(sz + 1);
|
||||
auto* bits = m_bits[sz];
|
||||
if (!bits) {
|
||||
m_bits.set(sz, alloc(dd::fdd, m_bdd, sz));
|
||||
bits = m_bits[sz];
|
||||
core.set_bailout();
|
||||
for (auto c : core) {
|
||||
if (c.bvalue(s) == l_false) {
|
||||
core.reset();
|
||||
core.set(~c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return *bits;
|
||||
}
|
||||
|
||||
void viable::log() {
|
||||
// only for small problems
|
||||
for (pvar v = 0; v < std::min(10u, m_viable.size()); ++v)
|
||||
log(v);
|
||||
return true;
|
||||
}
|
||||
|
||||
void viable::log(pvar v) {
|
||||
if (s.size(v) <= 5) {
|
||||
vector<rational> xs;
|
||||
for (rational x = rational::zero(); x < rational::power_of_two(s.size(v)); x += 1)
|
||||
if (is_viable(v, x))
|
||||
xs.push_back(x);
|
||||
|
||||
LOG("Viable for v" << v << ": " << xs);
|
||||
}
|
||||
if (!well_formed(m_viable[v]))
|
||||
LOG("v" << v << " not well formed");
|
||||
auto* e = m_viable[v];
|
||||
if (!e)
|
||||
return;
|
||||
entry* first = e;
|
||||
do {
|
||||
LOG("v" << v << ": " << e->interval << " " << e->side_cond << " " << e->src);
|
||||
e = e->next();
|
||||
}
|
||||
while (e != first);
|
||||
}
|
||||
|
||||
dd::fdd const& viable::var2bits(pvar v) { return sz2bits(s.size(v)); }
|
||||
void viable::log() {
|
||||
for (pvar v = 0; v < std::min(10u, m_viable.size()); ++v)
|
||||
log(v);
|
||||
}
|
||||
|
||||
std::ostream& viable::display(std::ostream& out, pvar v) const {
|
||||
auto* e = m_viable[v];
|
||||
if (!e)
|
||||
return out;
|
||||
entry* first = e;
|
||||
do {
|
||||
out << "v" << v << ": " << e->interval << " " << e->side_cond << " " << e->src << "\n";
|
||||
e = e->next();
|
||||
}
|
||||
while (e != first);
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream& viable::display(std::ostream& out) const {
|
||||
for (pvar v = 0; v < m_viable.size(); ++v)
|
||||
display(out, v);
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Lower bounds are strictly ascending.
|
||||
* intervals don't contain each-other (since lower bounds are ascending,
|
||||
* it suffices to check containment in one direction).
|
||||
*/
|
||||
bool viable::well_formed(entry* e) {
|
||||
if (!e)
|
||||
return true;
|
||||
entry* first = e;
|
||||
while (true) {
|
||||
if (e->interval.is_full())
|
||||
return e->next() == e;
|
||||
if (e->interval.is_currently_empty())
|
||||
return false;
|
||||
|
||||
auto* n = e->next();
|
||||
if (n != e && e->interval.contains(n->interval))
|
||||
return false;
|
||||
|
||||
if (n == first)
|
||||
break;
|
||||
if (e->interval.lo_val() >= n->interval.lo_val())
|
||||
return false;
|
||||
e = n;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue