mirror of
https://github.com/Z3Prover/z3
synced 2025-06-21 05:13:39 +00:00
na
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
5708de4301
commit
d073583d88
7 changed files with 146 additions and 39 deletions
|
@ -94,6 +94,17 @@ namespace polysat {
|
||||||
else
|
else
|
||||||
return val < hi_val() || val >= lo_val();
|
return val < hi_val() || val >= lo_val();
|
||||||
}
|
}
|
||||||
|
bool contains(eval_interval const& other) const {
|
||||||
|
if (is_full())
|
||||||
|
return true;
|
||||||
|
if (lo_val() <= other.lo_val() && other.hi_val() <= hi_val())
|
||||||
|
return true;
|
||||||
|
if (hi_val() < lo_val() && lo_val() <= other.lo_val() && other.lo_val() <= other.hi_val())
|
||||||
|
return true;
|
||||||
|
if (hi_val() < lo_val() && other.lo_val() < hi_val() && other.hi_val() <= hi_val())
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::ostream& operator<<(std::ostream& os, eval_interval const& i) {
|
inline std::ostream& operator<<(std::ostream& os, eval_interval const& i) {
|
||||||
|
|
|
@ -268,10 +268,14 @@ namespace polysat {
|
||||||
--num_levels;
|
--num_levels;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case trail_instr_t::viable_i: {
|
case trail_instr_t::viable_add_i: {
|
||||||
m_viable.pop_viable();
|
m_viable.pop_viable();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case trail_instr_t::viable_rem_i: {
|
||||||
|
m_viable.push_viable();
|
||||||
|
break;
|
||||||
|
}
|
||||||
case trail_instr_t::assign_i: {
|
case trail_instr_t::assign_i: {
|
||||||
auto v = m_search.back().var();
|
auto v = m_search.back().var();
|
||||||
LOG_V("Undo assign_i: v" << v);
|
LOG_V("Undo assign_i: v" << v);
|
||||||
|
@ -311,7 +315,7 @@ namespace polysat {
|
||||||
m_constraints.release_level(m_level + 1);
|
m_constraints.release_level(m_level + 1);
|
||||||
SASSERT(m_level == target_level);
|
SASSERT(m_level == target_level);
|
||||||
for (unsigned j = replay.size(); j-- > 0; ) {
|
for (unsigned j = replay.size(); j-- > 0; ) {
|
||||||
auto lit = replay[j];
|
sat::literal lit = replay[j];
|
||||||
m_trail.push_back(trail_instr_t::assign_bool_i);
|
m_trail.push_back(trail_instr_t::assign_bool_i);
|
||||||
m_search.push_boolean(lit);
|
m_search.push_boolean(lit);
|
||||||
}
|
}
|
||||||
|
@ -777,7 +781,7 @@ namespace polysat {
|
||||||
for (auto item : m_search) {
|
for (auto item : m_search) {
|
||||||
if (item.is_assignment()) {
|
if (item.is_assignment()) {
|
||||||
pvar v = item.var();
|
pvar v = item.var();
|
||||||
auto j = m_justification[v];
|
auto const& j = m_justification[v];
|
||||||
out << "\t" << assignment_pp(*this, v, get_value(v)) << " @" << j.level();
|
out << "\t" << assignment_pp(*this, v, get_value(v)) << " @" << j.level();
|
||||||
if (j.is_propagation())
|
if (j.is_propagation())
|
||||||
out << " " << m_cjust[v];
|
out << " " << m_cjust[v];
|
||||||
|
@ -795,8 +799,8 @@ namespace polysat {
|
||||||
for (auto c : m_constraints)
|
for (auto c : m_constraints)
|
||||||
out << "\t" << c->bvar2string() << ": " << *c << "\n";
|
out << "\t" << c->bvar2string() << ": " << *c << "\n";
|
||||||
out << "Clauses:\n";
|
out << "Clauses:\n";
|
||||||
for (auto cls : m_constraints.clauses()) {
|
for (auto const& cls : m_constraints.clauses()) {
|
||||||
for (auto cl : cls) {
|
for (auto const& cl : cls) {
|
||||||
out << "\t" << *cl << "\n";
|
out << "\t" << *cl << "\n";
|
||||||
for (auto lit : *cl)
|
for (auto lit : *cl)
|
||||||
out << "\t\t" << lit << ": " << lit2cnstr(lit) << "\n";
|
out << "\t\t" << lit << ": " << lit2cnstr(lit) << "\n";
|
||||||
|
@ -806,7 +810,7 @@ namespace polysat {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& assignments_pp::display(std::ostream& out) const {
|
std::ostream& assignments_pp::display(std::ostream& out) const {
|
||||||
for (auto [var, val] : s.assignment())
|
for (auto const& [var, val] : s.assignment())
|
||||||
out << assignment_pp(s, var, val) << " ";
|
out << assignment_pp(s, var, val) << " ";
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,8 @@ namespace polysat {
|
||||||
qhead_i,
|
qhead_i,
|
||||||
add_var_i,
|
add_var_i,
|
||||||
inc_level_i,
|
inc_level_i,
|
||||||
viable_i,
|
viable_add_i,
|
||||||
|
viable_rem_i,
|
||||||
assign_i,
|
assign_i,
|
||||||
just_i,
|
just_i,
|
||||||
assign_bool_i
|
assign_bool_i
|
||||||
|
|
|
@ -29,13 +29,13 @@ namespace polysat {
|
||||||
}
|
}
|
||||||
|
|
||||||
void viable::push_viable(pvar v) {
|
void viable::push_viable(pvar v) {
|
||||||
s.m_trail.push_back(trail_instr_t::viable_i);
|
s.m_trail.push_back(trail_instr_t::viable_add_i);
|
||||||
m_viable_trail.push_back(std::make_pair(v, m_viable[v]));
|
m_viable_trail.push_back(std::make_pair(v, m_viable[v]));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void viable::pop_viable() {
|
void viable::pop_viable() {
|
||||||
auto p = m_viable_trail.back();
|
auto const & p = m_viable_trail.back();
|
||||||
m_viable.set(p.first, p.second);
|
m_viable.set(p.first, p.second);
|
||||||
m_viable_trail.pop_back();
|
m_viable_trail.pop_back();
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,6 +66,7 @@ namespace polysat {
|
||||||
|
|
||||||
void pop_viable();
|
void pop_viable();
|
||||||
|
|
||||||
|
void push_viable() {}
|
||||||
/**
|
/**
|
||||||
* update state of viable for pvar v
|
* update state of viable for pvar v
|
||||||
* based on affine constraints
|
* based on affine constraints
|
||||||
|
|
|
@ -23,12 +23,35 @@ namespace polysat {
|
||||||
|
|
||||||
viable2::viable2(solver& s) : s(s) {}
|
viable2::viable2(solver& s) : s(s) {}
|
||||||
|
|
||||||
viable2::~viable2() {}
|
viable2::~viable2() {
|
||||||
|
for (entry* e : m_alloc)
|
||||||
|
dealloc(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
viable2::entry* viable2::alloc_entry() {
|
||||||
|
if (m_alloc.empty())
|
||||||
|
return alloc(entry);
|
||||||
|
auto* e = m_alloc.back();
|
||||||
|
m_alloc.pop_back();
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
void viable2::pop_viable() {
|
void viable2::pop_viable() {
|
||||||
auto& [v, e] = m_trail.back();
|
auto& [v, e] = m_trail.back();
|
||||||
e->remove_from(m_viable[v], e);
|
e->remove_from(m_viable[v], e);
|
||||||
dealloc(e);
|
m_alloc.push_back(e);
|
||||||
|
m_trail.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
void viable2::push_viable() {
|
||||||
|
auto& [v, e] = m_trail.back();
|
||||||
|
if (e->prev() != e)
|
||||||
|
e->prev()->insert_after(e);
|
||||||
|
else {
|
||||||
|
SASSERT(!m_viable[v]);
|
||||||
|
SASSERT(e->next() == e);
|
||||||
|
m_viable[v] = e;
|
||||||
|
}
|
||||||
m_trail.pop_back();
|
m_trail.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,31 +61,50 @@ namespace polysat {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto& fi = s.m_forbidden_intervals;
|
auto& fi = s.m_forbidden_intervals;
|
||||||
fi_record r = { eval_interval::full(), {}, c };
|
entry* ne = alloc_entry();
|
||||||
if (!fi.get_interval(c, v, r.interval, r.side_cond))
|
if (!fi.get_interval(c, v, ne->interval, ne->side_cond)) {
|
||||||
|
m_alloc.push_back(ne);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
ne->init(ne);
|
||||||
|
|
||||||
auto create_entry = [&]() {
|
auto create_entry = [&]() {
|
||||||
entry* ne = alloc(entry);
|
|
||||||
*static_cast<fi_record*>(ne) = r;
|
|
||||||
ne->init(ne);
|
|
||||||
m_trail.push_back({ v, ne });
|
m_trail.push_back({ v, ne });
|
||||||
s.m_trail.push_back(trail_instr_t::viable_i);
|
s.m_trail.push_back(trail_instr_t::viable_add_i);
|
||||||
return 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);
|
||||||
|
};
|
||||||
|
|
||||||
if (!e)
|
if (!e)
|
||||||
m_viable[v] = create_entry();
|
m_viable[v] = create_entry();
|
||||||
else {
|
else {
|
||||||
entry* first = e;
|
entry* first = e;
|
||||||
do {
|
do {
|
||||||
if (e->interval.lo_val() == r.interval.lo_val() &&
|
if (e->interval.contains(ne->interval)) {
|
||||||
e->interval.current_len() >= r.interval.current_len())
|
m_alloc.push_back(ne);
|
||||||
return;
|
return;
|
||||||
if (e->interval.lo_val() >= r.interval.lo_val()) {
|
}
|
||||||
|
if (ne->interval.contains(e->interval)) {
|
||||||
|
entry* n = e->next();
|
||||||
|
remove_entry(e);
|
||||||
|
if (e == n) {
|
||||||
|
m_viable[v] = create_entry();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
e = n;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
SASSERT(e->interval.lo_val() != ne->interval.lo_val());
|
||||||
|
if (e->interval.lo_val() >= ne->interval.lo_val()) {
|
||||||
e->insert_before(create_entry());
|
e->insert_before(create_entry());
|
||||||
if (e == first)
|
if (e == first)
|
||||||
m_viable[v] = e->prev();
|
m_viable[v] = e->prev();
|
||||||
|
SASSERT(well_formed(m_viable[v]));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
e = e->next();
|
e = e->next();
|
||||||
|
@ -71,7 +113,7 @@ namespace polysat {
|
||||||
// otherwise, append to end of list
|
// otherwise, append to end of list
|
||||||
first->insert_before(create_entry());
|
first->insert_before(create_entry());
|
||||||
}
|
}
|
||||||
SASSERT(is_sorted(m_viable[v]));
|
SASSERT(well_formed(m_viable[v]));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool viable2::has_viable(pvar v) {
|
bool viable2::has_viable(pvar v) {
|
||||||
|
@ -79,19 +121,21 @@ namespace polysat {
|
||||||
if (!e)
|
if (!e)
|
||||||
return true;
|
return true;
|
||||||
entry* first = e;
|
entry* first = e;
|
||||||
rational lo(0);
|
|
||||||
do {
|
do {
|
||||||
if (e->interval.is_full())
|
if (e->interval.is_full())
|
||||||
return false;
|
return false;
|
||||||
if (!e->interval.currently_contains(lo))
|
entry* n = e->next();
|
||||||
|
if (n == e)
|
||||||
return true;
|
return true;
|
||||||
lo = e->interval.hi_val();
|
if (n == first)
|
||||||
e = e->next();
|
return e->interval.hi_val() != e->interval.hi().manager().max_value();
|
||||||
|
|
||||||
|
if (e->interval.hi_val() < n->interval.lo_val())
|
||||||
|
return true;
|
||||||
|
e = n;
|
||||||
}
|
}
|
||||||
while (e != first);
|
while (e != first);
|
||||||
// ???
|
return false;
|
||||||
return !first->prev()->interval.currently_contains(lo) &&
|
|
||||||
first->interval.hi_val() <= lo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool viable2::is_viable(pvar v, rational const& val) {
|
bool viable2::is_viable(pvar v, rational const& val) {
|
||||||
|
@ -102,6 +146,8 @@ namespace polysat {
|
||||||
do {
|
do {
|
||||||
if (e->interval.currently_contains(val))
|
if (e->interval.currently_contains(val))
|
||||||
return false;
|
return false;
|
||||||
|
if (e->interval.lo_val() < val)
|
||||||
|
return !first->prev()->interval.currently_contains(val);
|
||||||
e = e->next();
|
e = e->next();
|
||||||
}
|
}
|
||||||
while (e != first);
|
while (e != first);
|
||||||
|
@ -113,7 +159,21 @@ namespace polysat {
|
||||||
}
|
}
|
||||||
|
|
||||||
rational viable2::min_viable(pvar v) {
|
rational viable2::min_viable(pvar v) {
|
||||||
return rational::zero();
|
rational lo(0);
|
||||||
|
auto* e = m_viable[v];
|
||||||
|
if (!e)
|
||||||
|
return lo;
|
||||||
|
entry* first = e;
|
||||||
|
if (first->prev()->interval.currently_contains(lo))
|
||||||
|
lo = first->prev()->interval.hi_val();
|
||||||
|
do {
|
||||||
|
if (!e->interval.currently_contains(lo))
|
||||||
|
return lo;
|
||||||
|
lo = e->interval.hi_val();
|
||||||
|
e = e->next();
|
||||||
|
}
|
||||||
|
while (e != first);
|
||||||
|
return lo;
|
||||||
}
|
}
|
||||||
|
|
||||||
rational viable2::max_viable(pvar v) {
|
rational viable2::max_viable(pvar v) {
|
||||||
|
@ -126,6 +186,27 @@ namespace polysat {
|
||||||
if (!e)
|
if (!e)
|
||||||
return dd::find_t::multiple;
|
return dd::find_t::multiple;
|
||||||
|
|
||||||
|
|
||||||
|
entry* first = e;
|
||||||
|
do {
|
||||||
|
if (e->interval.is_full())
|
||||||
|
return dd::find_t::empty;
|
||||||
|
entry* n = e->next();
|
||||||
|
if (n == e && e->interval.lo_val() != 0) {
|
||||||
|
val = 0;
|
||||||
|
if (e->interval.lo_val() > 1 || e->interval.hi_val() < e->interval.hi().manager().max_value())
|
||||||
|
return dd::find_t::multiple;
|
||||||
|
return dd::find_t::singleton;
|
||||||
|
}
|
||||||
|
if (n == first) {
|
||||||
|
if (e->interval.hi_val() == e->interval.hi().manager().max_value())
|
||||||
|
;
|
||||||
|
}
|
||||||
|
e = n;
|
||||||
|
}
|
||||||
|
while (e != first);
|
||||||
|
|
||||||
|
#if 0
|
||||||
// TODO
|
// TODO
|
||||||
entry* first = e;
|
entry* first = e;
|
||||||
do {
|
do {
|
||||||
|
@ -136,6 +217,7 @@ namespace polysat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (e != first);
|
while (e != first);
|
||||||
|
#endif
|
||||||
|
|
||||||
return dd::find_t::multiple;
|
return dd::find_t::multiple;
|
||||||
}
|
}
|
||||||
|
@ -157,18 +239,22 @@ namespace polysat {
|
||||||
log(v);
|
log(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool viable2::is_sorted(entry* e) {
|
/*
|
||||||
|
* 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 viable2::well_formed(entry* e) {
|
||||||
entry* first = e;
|
entry* first = e;
|
||||||
while (true) {
|
while (true) {
|
||||||
if (e->interval.is_full())
|
if (e->interval.is_full())
|
||||||
return true;
|
return e->next() == e;
|
||||||
auto* n = e->next();
|
auto* n = e->next();
|
||||||
|
if (n != e && e->interval.contains(n->interval))
|
||||||
|
return false;
|
||||||
if (n == first)
|
if (n == first)
|
||||||
break;
|
break;
|
||||||
if (e->interval.lo_val() > n->interval.lo_val())
|
if (e->interval.lo_val() >= n->interval.lo_val())
|
||||||
return false;
|
|
||||||
if (e->interval.lo_val() == n->interval.lo_val() &&
|
|
||||||
e->interval.current_len() > n->interval.current_len())
|
|
||||||
return false;
|
return false;
|
||||||
e = n;
|
e = n;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,11 +38,13 @@ namespace polysat {
|
||||||
entry() : fi_record({ eval_interval::full(), {}, {} }) {}
|
entry() : fi_record({ eval_interval::full(), {}, {} }) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
small_object_allocator m_alloc;
|
ptr_vector<entry> m_alloc;
|
||||||
ptr_vector<entry> m_viable; // set of viable values.
|
ptr_vector<entry> m_viable; // set of viable values.
|
||||||
svector<std::pair<pvar, entry*>> m_trail; // undo stack
|
svector<std::pair<pvar, entry*>> m_trail; // undo stack
|
||||||
|
|
||||||
bool is_sorted(entry* e);
|
bool well_formed(entry* e);
|
||||||
|
|
||||||
|
entry* alloc_entry();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
viable2(solver& s);
|
viable2(solver& s);
|
||||||
|
@ -59,6 +61,8 @@ namespace polysat {
|
||||||
|
|
||||||
void pop_viable();
|
void pop_viable();
|
||||||
|
|
||||||
|
void push_viable();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* update state of viable for pvar v
|
* update state of viable for pvar v
|
||||||
* based on affine constraints
|
* based on affine constraints
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue