3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-25 10:05:32 +00:00

Add fallback lemma

This commit is contained in:
Jakob Rath 2021-09-06 18:00:21 +02:00
parent 381d13993c
commit 15c094fa32
3 changed files with 52 additions and 15 deletions

View file

@ -65,6 +65,10 @@ namespace polysat {
void push_boolean(sat::literal lit);
void pop();
using const_iterator = decltype(m_items)::const_iterator;
const_iterator begin() const { return m_items.begin(); }
const_iterator end() const { return m_items.end(); }
std::ostream& display(std::ostream& out) const;
};

View file

@ -661,17 +661,14 @@ namespace polysat {
LOG_H3("Reverting decision: pvar " << v << " := " << val);
SASSERT(m_justification[v].is_decision());
backjump(m_justification[v].level()-1);
if (m_conflict.is_bailout()) {
m_viable.add_non_viable(v, val);
// TODO: need to add fallback lemma
return;
}
clause_ref lemma = m_conflict.build_lemma();
clause_ref lemma;
if (m_conflict.is_bailout())
lemma = mk_fallback_lemma(m_justification[v].level());
else
lemma = m_conflict.build_lemma();
m_conflict.reset();
backjump(m_justification[v].level()-1);
// TODO: we need to decide_bool on the clause (learn_lemma takes care of this).
// if the lemma was asserting, then this will propagate the last literal. otherwise we do the enumerative guessing as normal.
// we need to exclude the current value of v. narrowing of the guessed constraint *should* take care of it but we cannot count on that.
@ -698,16 +695,45 @@ namespace polysat {
}
*/
}
bool solver::is_decision(search_item const& item) const {
if (item.is_assignment())
return m_justification[item.var()].is_decision();
else
return m_bvars.is_decision(item.lit().var());
}
/** Create fallback lemma that excludes the current search state */
clause_ref solver::mk_fallback_lemma(unsigned lvl) {
LOG_H3("Creating fallback lemma for level " << lvl);
LOG_V("m_search: " << m_search);
clause_builder lemma(*this);
unsigned todo = lvl;
unsigned i = 0;
while (todo > 0) {
auto const& item = m_search[i++];
if (!is_decision(item))
continue;
LOG_V("Adding: " << item);
if (item.is_assignment()) {
pvar v = item.var();
auto c = ~m_constraints.eq(0, var(v) - m_value[v]);
m_constraints.ensure_bvar(c.get());
lemma.push_literal(c.blit());
} else {
sat::literal lit = item.lit();
lemma.push_literal(~lit);
}
--todo;
}
return lemma.build();
}
void solver::revert_bool_decision(sat::literal lit) {
sat::bool_var const var = lit.var();
LOG_H3("Reverting boolean decision: " << lit);
SASSERT(m_bvars.is_decision(var));
if (m_conflict.is_bailout()) {
NOT_IMPLEMENTED_YET();
}
// TODO:
// Current situation: we have a decision for boolean literal L on top of the stack, and a conflict core.
//
@ -726,7 +752,11 @@ namespace polysat {
// (L')^{L' \/ ¬L \/ ...}
// again L is in core, unless we core-reduced it away
clause_ref reason = m_conflict.build_lemma();
clause_ref reason;
if (m_conflict.is_bailout())
reason = mk_fallback_lemma(m_bvars.level(var));
else
reason = m_conflict.build_lemma();
m_conflict.reset();
bool contains_lit = std::any_of(reason->begin(), reason->end(), [lit](auto reason_lit) { return reason_lit == ~lit; });
@ -747,6 +777,7 @@ namespace polysat {
}
// The lemma where 'lit' comes from.
// Currently, boolean decisions always come from guessing a literal of a learned non-unit lemma.
clause* lemma = m_bvars.lemma(var); // need to grab this while 'lit' is still assigned
SASSERT(lemma);

View file

@ -168,6 +168,7 @@ namespace polysat {
void assign_core(pvar v, rational const& val, justification const& j);
bool is_assigned(pvar v) const { return !m_justification[v].is_unassigned(); }
bool is_decision(search_item const& item) const;
bool should_search();
@ -216,6 +217,7 @@ namespace polysat {
void resolve_bool(sat::literal lit);
void revert_decision(pvar v);
void revert_bool_decision(sat::literal lit);
clause_ref mk_fallback_lemma(unsigned lvl);
void report_unsat();
void learn_lemma(pvar v, clause_ref lemma);