mirror of
https://github.com/Z3Prover/z3
synced 2025-08-26 13:06:05 +00:00
Merge branch 'polysat' of https://github.com/Z3Prover/z3 into polysat
This commit is contained in:
commit
dc95179ae5
23 changed files with 797 additions and 325 deletions
|
@ -85,42 +85,125 @@ namespace polysat {
|
|||
}
|
||||
}
|
||||
|
||||
// find literals that are not propagated to false
|
||||
// if clause is unsat then assign arbitrary
|
||||
// solver handles unsat clauses by creating a conflict.
|
||||
// solver also can propagate, but need to check that it does indeed.
|
||||
/**
|
||||
* Move literals to be watched to the front of the clause.
|
||||
*/
|
||||
void constraint_manager::normalize_watch(clause& cl) {
|
||||
SASSERT(cl.size() > 1);
|
||||
|
||||
// A literal may be watched if there is no unwatched literal at higher level,
|
||||
// where true and unassigned literals are considered at infinite level.
|
||||
// We prefer true literals to unassigned literals.
|
||||
auto get_watch_level = [&](sat::literal lit) -> unsigned {
|
||||
switch (s.m_bvars.value(lit)) {
|
||||
case l_false:
|
||||
return s.m_bvars.level(lit);
|
||||
case l_true:
|
||||
return UINT_MAX;
|
||||
case l_undef:
|
||||
return UINT_MAX - 1;
|
||||
}
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
};
|
||||
|
||||
unsigned lvl0 = get_watch_level(cl[0]);
|
||||
unsigned lvl1 = get_watch_level(cl[1]);
|
||||
if (lvl0 < lvl1) {
|
||||
std::swap(lvl0, lvl1);
|
||||
std::swap(cl[0], cl[1]);
|
||||
}
|
||||
SASSERT(lvl0 >= lvl1);
|
||||
for (unsigned i = 2; i < cl.size(); ++i) {
|
||||
sat::literal const lit = cl[i];
|
||||
unsigned const lvl = get_watch_level(lit);
|
||||
if (lvl > lvl0) {
|
||||
cl[i] = cl[1];
|
||||
cl[1] = cl[0];
|
||||
lvl1 = lvl0;
|
||||
cl[0] = lit;
|
||||
lvl0 = lvl;
|
||||
}
|
||||
else if (lvl > lvl1) {
|
||||
cl[i] = cl[1];
|
||||
cl[1] = lit;
|
||||
lvl1 = lvl;
|
||||
}
|
||||
SASSERT_EQ(lvl0, get_watch_level(cl[0]));
|
||||
SASSERT_EQ(lvl1, get_watch_level(cl[1]));
|
||||
SASSERT(lvl0 >= lvl1 && lvl1 >= get_watch_level(cl[i]));
|
||||
}
|
||||
SASSERT(all_of(cl, [&](auto lit) { return get_watch_level(lit) <= get_watch_level(cl[0]); }));
|
||||
SASSERT(std::all_of(cl.begin() + 1, cl.end(), [&](auto lit) { return get_watch_level(lit) <= get_watch_level(cl[1]); }));
|
||||
}
|
||||
|
||||
void constraint_manager::watch(clause& cl, bool value_propagate) {
|
||||
if (cl.empty())
|
||||
return;
|
||||
|
||||
bool first = true;
|
||||
for (unsigned i = 0; i < cl.size(); ++i) {
|
||||
if (s.m_bvars.is_false(cl[i]))
|
||||
continue;
|
||||
signed_constraint sc = s.lit2cnstr(cl[i]);
|
||||
if (value_propagate && sc.is_currently_false(s)) {
|
||||
if (s.m_bvars.is_true(cl[i])) {
|
||||
s.set_conflict(sc);
|
||||
return;
|
||||
if (value_propagate) {
|
||||
#if 1
|
||||
// First, try to bool-propagate.
|
||||
// Otherwise, we might get a clause-conflict and a missed propagation after resolving the conflict.
|
||||
// With this, we will get a constraint-conflict instead.
|
||||
// TODO: maybe it makes sense to choose bool vs. eval depending on which has the lower level?
|
||||
sat::literal undef_lit = sat::null_literal;
|
||||
for (sat::literal lit : cl) {
|
||||
if (s.m_bvars.is_false(lit))
|
||||
continue;
|
||||
if (s.m_bvars.is_true(lit)) {
|
||||
undef_lit = sat::null_literal;
|
||||
break;
|
||||
}
|
||||
SASSERT(!s.m_bvars.is_assigned(lit));
|
||||
if (undef_lit == sat::null_literal)
|
||||
undef_lit = lit;
|
||||
else {
|
||||
undef_lit = sat::null_literal;
|
||||
break;
|
||||
}
|
||||
s.assign_eval(~cl[i]);
|
||||
continue;
|
||||
}
|
||||
if (undef_lit != sat::null_literal)
|
||||
s.assign_propagate(undef_lit, cl);
|
||||
|
||||
s.m_bvars.watch(cl[i]).push_back(&cl);
|
||||
std::swap(cl[!first], cl[i]);
|
||||
if (!first)
|
||||
return;
|
||||
first = false;
|
||||
// this should be already done with insert_eval when constructing the clause (maybe not for non-redundant clauses?)
|
||||
// (this loop also masks the mistake of calling clause_builder::insert instead of clause_builder::insert_eval)
|
||||
for (sat::literal lit : cl) {
|
||||
if (s.m_bvars.is_false(lit))
|
||||
continue;
|
||||
signed_constraint sc = s.lit2cnstr(lit);
|
||||
if (sc.is_currently_false(s)) {
|
||||
if (s.m_bvars.is_true(lit)) {
|
||||
s.set_conflict(sc);
|
||||
return;
|
||||
}
|
||||
s.assign_eval(~lit);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (first)
|
||||
s.m_bvars.watch(cl[0]).push_back(&cl);
|
||||
if (cl.size() > 1)
|
||||
s.m_bvars.watch(cl[1]).push_back(&cl);
|
||||
if (cl.size() == 1) {
|
||||
if (s.m_bvars.is_false(cl[0]))
|
||||
s.set_conflict(cl);
|
||||
else if (!s.m_bvars.is_assigned(cl[0]))
|
||||
s.assign_propagate(cl[0], cl);
|
||||
return;
|
||||
}
|
||||
|
||||
normalize_watch(cl);
|
||||
|
||||
s.m_bvars.watch(cl[0]).push_back(&cl);
|
||||
s.m_bvars.watch(cl[1]).push_back(&cl);
|
||||
|
||||
if (s.m_bvars.is_true(cl[0]))
|
||||
return;
|
||||
if (first)
|
||||
SASSERT(!s.m_bvars.is_true(cl[1]));
|
||||
if (!s.m_bvars.is_false(cl[1])) {
|
||||
SASSERT(!s.m_bvars.is_assigned(cl[0]) && !s.m_bvars.is_assigned(cl[1]));
|
||||
return;
|
||||
}
|
||||
if (s.m_bvars.is_false(cl[0]))
|
||||
s.set_conflict(cl);
|
||||
else
|
||||
s.assign_propagate(cl[0], cl);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue