3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-27 10:55:50 +00:00

Polysat: add simpler monotonicity unit test + minor changes (#5348)

* Add simpler versions of monotonicity puzzle

* band-aid fix to conflicts during revert_decision

* minor changes
This commit is contained in:
Jakob Rath 2021-06-15 19:18:37 +02:00 committed by GitHub
parent 9cc78ef98e
commit 1fe7dc40fe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 135 additions and 32 deletions

View file

@ -85,6 +85,15 @@ namespace polysat {
}
#if POLYSAT_LOGGING_ENABLED
void solver::log_viable() {
// only for small problems
if (m_viable.size() < 10) {
for (pvar v = 0; v < m_viable.size(); ++v) {
log_viable(v);
}
}
}
void solver::log_viable(pvar v) {
if (size(v) <= 5) {
vector<rational> xs;
@ -115,11 +124,7 @@ namespace polysat {
LOG("Free variables: " << m_free_vars);
LOG("Assignments: " << assignment());
LOG("Conflict: " << m_conflict);
IF_LOGGING({
for (pvar v = 0; v < m_viable.size(); ++v) {
log_viable(v);
}
});
IF_LOGGING(log_viable());
if (pending_disjunctive_lemma()) { LOG_H2("UNDEF (handle lemma externally)"); return l_undef; }
else if (is_conflict() && at_base_level()) { LOG_H2("UNSAT"); return l_false; }
@ -450,6 +455,12 @@ namespace polysat {
m_conflict.push_back(&c);
}
void solver::set_conflict(clause& cl) {
LOG("Conflict: " << cl);
SASSERT(!is_conflict());
m_conflict.push_back(&cl);
}
void solver::set_conflict(pvar v) {
SASSERT(!is_conflict());
m_conflict.append(m_cjust[v]);
@ -750,11 +761,7 @@ namespace polysat {
// Guess a literal from the given clause; returns the guessed constraint
sat::literal solver::decide_bool(clause& lemma) {
LOG_H3("Guessing literal in lemma: " << lemma);
IF_LOGGING({
for (pvar v = 0; v < m_viable.size(); ++v) {
log_viable(v);
}
});
IF_LOGGING(log_viable());
LOG("Boolean assignment: " << m_bvars);
auto is_suitable = [this](sat::literal lit) -> bool {
@ -775,15 +782,32 @@ namespace polysat {
unsigned num_choices = 0; // TODO: should probably cache this?
for (sat::literal lit : lemma) {
IF_LOGGING({
auto value = m_bvars.value(lit);
auto c = m_constraints.lookup(lit.var());
bool is_false;
if (value == l_undef) {
c->assign(!lit.sign());
is_false = c->is_currently_false(*this);
c->unassign();
}
else
is_false = c->is_currently_false(*this);
LOG_V("Checking: lit=" << lit << ", value=" << value << ", constraint=" << show_deref(c) << ", currently_false=" << is_false);
});
if (is_suitable(lit)) {
num_choices++;
if (choice == sat::null_literal)
choice = lit;
}
}
LOG_V("num_choices: " << num_choices);
SASSERT(choice != sat::null_literal); // must succeed for at least one
if (num_choices == 1)
if (num_choices == 0)
// This case may happen when all undefined literals are false under the current variable assignment.
// TODO: The question is whether such lemmas should be generated? Check test_monot() for such a case.
set_conflict(lemma);
else if (num_choices == 1)
propagate_bool(choice, &lemma);
else
decide_bool(choice, lemma);
@ -847,19 +871,33 @@ namespace polysat {
add_non_viable(v, val);
for (constraint* c : m_conflict.units()) {
auto confl = std::move(m_conflict);
m_conflict.reset();
for (constraint* c : confl.units()) {
// Add the conflict as justification for the exclusion of 'val'
push_cjust(v, c);
// NOTE: in general, narrow may change the conflict.
// But since we just backjumped, narrowing should not result in an additional conflict.
// TODO: this call to "narrow" may still lead to a conflict,
// because we do not detect all conflicts immediately.
// Consider:
// - Assert constraint zx > yx, watching y and z.
// - Guess x = 0.
// - We have a conflict but we don't know. It will be discovered when y and z are assigned,
// and then may lead to an assertion failure through this call to narrow.
c->narrow(*this);
if (is_conflict()) {
LOG_H1("Conflict during revert_decision/narrow!");
return;
}
}
m_conflict.reset();
// m_conflict.reset();
learn_lemma(v, std::move(reason));
if (is_conflict()) {
LOG_H1("Conflict during revert_decision!");
LOG_H1("Conflict during revert_decision/learn_lemma!");
return;
}
@ -896,6 +934,7 @@ namespace polysat {
// TODO: what to do when reason is NULL?
// * this means we were unable to build a lemma for the current conflict.
// * the reason for reverting this decision then needs to be the (negation of the) conflicting literals. Or we give up on resolving this lemma?
// TODO: do not include 'base' unit constraints (only in dependencies)
SASSERT(m_conflict.clauses().empty()); // not sure how to handle otherwise
unsigned reason_lvl = m_constraints.lookup(lit.var())->level();
p_dependency_ref reason_dep(m_constraints.lookup(lit.var())->dep(), m_dm);