mirror of
https://github.com/Z3Prover/z3
synced 2025-07-03 03:15:41 +00:00
Add forbidden interval lemma separately
This commit is contained in:
parent
b4ee8cef1a
commit
dbe814d568
6 changed files with 41 additions and 24 deletions
|
@ -55,7 +55,7 @@ namespace polysat {
|
||||||
|
|
||||||
|
|
||||||
void clause_builder::push(sat::literal lit) {
|
void clause_builder::push(sat::literal lit) {
|
||||||
push(m_solver->m_constraints.lookup(lit));
|
push(m_solver->lit2cnstr(lit));
|
||||||
}
|
}
|
||||||
|
|
||||||
void clause_builder::push(signed_constraint c) {
|
void clause_builder::push(signed_constraint c) {
|
||||||
|
@ -73,4 +73,15 @@ namespace polysat {
|
||||||
#endif
|
#endif
|
||||||
m_literals.push_back(c.blit());
|
m_literals.push_back(c.blit());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clause_builder::insert_eval(sat::literal lit) {
|
||||||
|
insert_eval(m_solver->lit2cnstr(lit));
|
||||||
|
}
|
||||||
|
|
||||||
|
void clause_builder::insert_eval(signed_constraint c) {
|
||||||
|
if (c.bvalue(*m_solver) == l_undef) {
|
||||||
|
m_solver->assign_eval(~c.blit());
|
||||||
|
}
|
||||||
|
push(c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,9 +43,21 @@ namespace polysat {
|
||||||
/// Returns nullptr if the clause is a tautology and should not be added to the solver.
|
/// Returns nullptr if the clause is a tautology and should not be added to the solver.
|
||||||
clause_ref build();
|
clause_ref build();
|
||||||
|
|
||||||
|
/// Insert constraints into the clause.
|
||||||
void push(sat::literal lit);
|
void push(sat::literal lit);
|
||||||
void push(signed_constraint c);
|
void push(signed_constraint c);
|
||||||
void push(inequality const& i) { push(i.as_signed_constraint()); }
|
void push(inequality const& i) { push(i.as_signed_constraint()); }
|
||||||
|
// TODO: remove push
|
||||||
|
void insert(sat::literal lit) { push(lit); }
|
||||||
|
void insert(signed_constraint c) { push(c); }
|
||||||
|
void insert(inequality const& i) { insert(i.as_signed_constraint()); }
|
||||||
|
|
||||||
|
/// Inserting constraints into the clause.
|
||||||
|
/// If they are not yet on the search stack, add them as evaluated to false.
|
||||||
|
/// \pre Constraint must be false in the current assignment.
|
||||||
|
void insert_eval(sat::literal lit);
|
||||||
|
void insert_eval(signed_constraint c);
|
||||||
|
void insert_eval(inequality const& i) { insert_eval(i.as_signed_constraint()); }
|
||||||
|
|
||||||
using const_iterator = decltype(m_literals)::const_iterator;
|
using const_iterator = decltype(m_literals)::const_iterator;
|
||||||
const_iterator begin() const { return m_literals.begin(); }
|
const_iterator begin() const { return m_literals.begin(); }
|
||||||
|
|
|
@ -253,11 +253,6 @@ namespace polysat {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
logger().begin_conflict(header_with_var("forbidden interval lemma for v", v));
|
logger().begin_conflict(header_with_var("forbidden interval lemma for v", v));
|
||||||
// set_backtrack(); // TODO: add the FI-lemma as a side lemma.
|
|
||||||
// The FI-lemma should not be the new core, because that will break variable dependencies.
|
|
||||||
// Alternatively, we'll need different types of variable dependencies. (one where v=n is in the core, another which only ensures that we don't skip v during backtracking).
|
|
||||||
// But since we now also propagate evaluated literals at the right (earlier) levels,
|
|
||||||
// we don't need to follow the variable assignments backwards to find the backjumping level for the FI-lemma.
|
|
||||||
VERIFY(s.m_viable.resolve(v, *this));
|
VERIFY(s.m_viable.resolve(v, *this));
|
||||||
}
|
}
|
||||||
SASSERT(!empty());
|
SASSERT(!empty());
|
||||||
|
@ -320,9 +315,10 @@ namespace polysat {
|
||||||
void conflict::add_lemma(clause_ref lemma) {
|
void conflict::add_lemma(clause_ref lemma) {
|
||||||
SASSERT(lemma);
|
SASSERT(lemma);
|
||||||
lemma->set_redundant(true);
|
lemma->set_redundant(true);
|
||||||
LOG("Side lemma: " << *lemma);
|
LOG_H3("Side lemma: " << *lemma);
|
||||||
for (sat::literal lit : *lemma) {
|
for (sat::literal lit : *lemma) {
|
||||||
LOG(" " << lit_pp(s, lit));
|
LOG(lit_pp(s, lit));
|
||||||
|
SASSERT(s.m_bvars.value(lit) != l_true);
|
||||||
}
|
}
|
||||||
// TODO: call clause simplifier here?
|
// TODO: call clause simplifier here?
|
||||||
// maybe it reduces the level we have to consider.
|
// maybe it reduces the level we have to consider.
|
||||||
|
@ -351,6 +347,7 @@ namespace polysat {
|
||||||
}
|
}
|
||||||
if (has_unassigned)
|
if (has_unassigned)
|
||||||
jump_level = max_level;
|
jump_level = max_level;
|
||||||
|
LOG("Jump level: " << jump_level);
|
||||||
m_max_jump_level = std::min(m_max_jump_level, jump_level);
|
m_max_jump_level = std::min(m_max_jump_level, jump_level);
|
||||||
m_lemmas.push_back(std::move(lemma));
|
m_lemmas.push_back(std::move(lemma));
|
||||||
// If possible, we should set the new constraint to l_true;
|
// If possible, we should set the new constraint to l_true;
|
||||||
|
|
|
@ -959,8 +959,10 @@ namespace polysat {
|
||||||
|
|
||||||
void solver::assign_eval(sat::literal lit) {
|
void solver::assign_eval(sat::literal lit) {
|
||||||
// SASSERT(lit2cnstr(lit).is_currently_true(*this)); // "morally" this should hold, but currently fails because of pop_assignment during resolve_conflict
|
// SASSERT(lit2cnstr(lit).is_currently_true(*this)); // "morally" this should hold, but currently fails because of pop_assignment during resolve_conflict
|
||||||
|
SASSERT(!lit2cnstr(lit).is_currently_false(*this));
|
||||||
unsigned level = 0;
|
unsigned level = 0;
|
||||||
// NOTE: constraint may be evaluated even if some variables are still unassigned (e.g., 0*x doesn't depend on x).
|
// NOTE: constraint may be evaluated even if some variables are still unassigned (e.g., 0*x doesn't depend on x).
|
||||||
|
// TODO: level might be too low! because pop_assignment may already have removed necessary variables (cf. comment on assertion above).
|
||||||
for (auto v : lit2cnstr(lit)->vars())
|
for (auto v : lit2cnstr(lit)->vars())
|
||||||
if (is_assigned(v))
|
if (is_assigned(v))
|
||||||
level = std::max(get_level(v), level);
|
level = std::max(get_level(v), level);
|
||||||
|
|
|
@ -643,6 +643,7 @@ namespace polysat {
|
||||||
// If there is a full interval, all others would have been removed
|
// If there is a full interval, all others would have been removed
|
||||||
SASSERT(!e->interval.is_full() || e->next() == e);
|
SASSERT(!e->interval.is_full() || e->next() == e);
|
||||||
SASSERT(e->interval.is_full() || all_of(*e, [](entry const& f) { return !f.interval.is_full(); }));
|
SASSERT(e->interval.is_full() || all_of(*e, [](entry const& f) { return !f.interval.is_full(); }));
|
||||||
|
clause_builder lemma(s);
|
||||||
do {
|
do {
|
||||||
// Build constraint: upper bound of each interval is not contained in the next interval,
|
// 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
|
// using the equivalence: t \in [l;h[ <=> t-l < h-l
|
||||||
|
@ -694,26 +695,19 @@ namespace polysat {
|
||||||
auto lhs = hi - next_lo;
|
auto lhs = hi - next_lo;
|
||||||
auto rhs = next_hi - next_lo;
|
auto rhs = next_hi - next_lo;
|
||||||
signed_constraint c = s.m_constraints.ult(lhs, rhs);
|
signed_constraint c = s.m_constraints.ult(lhs, rhs);
|
||||||
core.insert_eval(c);
|
lemma.insert_eval(~c);
|
||||||
}
|
}
|
||||||
for (auto sc : e->side_cond)
|
for (auto sc : e->side_cond)
|
||||||
core.insert_eval(sc);
|
lemma.insert_eval(~sc);
|
||||||
|
lemma.insert(~e->src);
|
||||||
core.insert(e->src);
|
core.insert(e->src);
|
||||||
e = n;
|
e = n;
|
||||||
}
|
}
|
||||||
while (e != first);
|
while (e != first);
|
||||||
|
|
||||||
|
SASSERT(all_of(lemma, [this](sat::literal lit) { return s.m_bvars.value(lit) == l_false; }));
|
||||||
|
core.add_lemma(lemma.build());
|
||||||
core.logger().log(inf_fi(*this, v));
|
core.logger().log(inf_fi(*this, v));
|
||||||
|
|
||||||
// TODO: should not be here, too general
|
|
||||||
for (auto c : core) {
|
|
||||||
if (c.bvalue(s) == l_false) {
|
|
||||||
UNREACHABLE(); // an invariant of the new conflict state is that bvalue of all inserted constraints is l_true (cf. assertion in conflict::insert)
|
|
||||||
core.set(~c);
|
|
||||||
core.logger().log("");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -108,9 +108,10 @@ namespace polysat {
|
||||||
dd::find_t find_viable(pvar v, rational & val);
|
dd::find_t find_viable(pvar v, rational & val);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the unsat core for v.
|
* Retrieve the unsat core for v,
|
||||||
* \pre there are no viable values for v
|
* and add the forbidden interval lemma for v (which eliminates v from the unsat core).
|
||||||
*/
|
* \pre there are no viable values for v
|
||||||
|
*/
|
||||||
bool resolve(pvar v, conflict& core);
|
bool resolve(pvar v, conflict& core);
|
||||||
|
|
||||||
/** Log all viable values for the given variable.
|
/** Log all viable values for the given variable.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue