3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-30 04:15:51 +00:00

Polysat: conflict explanation prototype (#5353)

* display constraint's extra info in one place

* Add stub for conflict explainer

* Add helper functions to check whether constraint is active at base level

* Add helper class tmp_assign

* Add clause_builder; it skips unnecessary literals during clause creation

* some fixes

* Use clause_builder for forbidden intervals

* remove old comments

* fixes/comments in solver

* print redundant clauses

* First pass at conflict_explainer

* remove unused model class

* Choose value for k

* also print min/max k
This commit is contained in:
Jakob Rath 2021-06-17 17:35:32 +02:00 committed by GitHub
parent 1fe7dc40fe
commit 3e1cfcd538
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 449 additions and 60 deletions

View file

@ -93,7 +93,7 @@ namespace polysat {
unsigned m_ref_count = 0;
// bool m_stored = false; ///< Whether it has been inserted into the constraint_manager to be tracked by level
unsigned m_storage_level; ///< Controls lifetime of the constraint object. Always a base level (for external dependencies the level at which it was created, and for others the maximum storage level of its external dependencies).
unsigned m_active_level = UINT_MAX; ///< Level at which the constraint was activated. Possibly different from m_storage_level because constraints in lemmas may become activated only at a higher level.
// unsigned m_active_level = UINT_MAX; ///< Level at which the constraint was activated. Possibly different from m_storage_level because constraints in lemmas may become activated only at a higher level. NOTE: this is actually the level of the corresponding bool_var.
ckind_t m_kind;
p_dependency_ref m_dep;
unsigned_vector m_vars;
@ -108,6 +108,9 @@ namespace polysat {
m_manager->insert_bv2c(bvar(), this);
}
protected:
std::ostream& display_extra(std::ostream& out) const;
public:
void inc_ref() { m_ref_count++; }
void dec_ref() { SASSERT(m_ref_count > 0); m_ref_count--; if (!m_ref_count) dealloc(this); }
@ -138,6 +141,13 @@ namespace polysat {
unsigned_vector& vars() { return m_vars; }
unsigned_vector const& vars() const { return m_vars; }
unsigned level() const { return m_storage_level; }
// unsigned active_level() const {
// SASSERT(!is_undef());
// return m_manager->m_bvars.level(bvar());
// }
// unsigned active_at_base_level(solver& s) const {
// return !is_undef() && active_level() <= s.base_level();
// }
sat::bool_var bvar() const { return m_bvar; }
sat::literal blit() const { SASSERT(m_bvalue != l_undef); return m_bvalue == l_true ? sat::literal(m_bvar) : ~sat::literal(m_bvar); }
bool sign() const { return m_sign; }
@ -230,6 +240,33 @@ namespace polysat {
inline std::ostream& operator<<(std::ostream& out, clause const& c) { return c.display(out); }
/// Builds a clause from literals and constraints.
/// Takes care to
/// - skip literals that are active at the base level,
/// - skip trivial new constraints such as "4 <= 1".
class clause_builder {
solver& m_solver;
sat::literal_vector m_literals;
constraint_ref_vector m_new_constraints;
public:
clause_builder(solver& s): m_solver(s) {}
bool empty() const { return m_literals.empty() && m_new_constraints.empty(); }
void reset();
/// Build the clause. This will reset the clause builder so it can be reused.
clause_ref build(unsigned lvl, p_dependency_ref const& d);
/// Add a literal to the clause.
/// Intended to be used for literals representing a constraint that already exists.
void push_literal(sat::literal lit);
/// Add a constraint to the clause that does not yet exist in the solver so far.
/// By convention, this will add the positive literal for this constraint.
/// (TODO: we might need to change this later; but then we will add a second argument for the literal or the sign.)
void push_new_constraint(constraint_ref c);
};
// Container for unit constraints and clauses.
class constraints_and_clauses {
constraint_ref_vector m_units;
@ -289,4 +326,37 @@ namespace polysat {
inline std::ostream& operator<<(std::ostream& out, constraints_and_clauses const& c) { return c.display(out); }
/// Temporarily assign a constraint according to the sign of the given literal.
class tmp_assign final {
constraint* m_constraint;
bool m_should_unassign = false;
public:
tmp_assign(constraint* c, sat::literal lit):
m_constraint(c) {
SASSERT(c);
SASSERT(c->bvar() == lit.var());
if (c->is_undef()) {
c->assign(!lit.sign());
m_should_unassign = true;
}
else
SASSERT(c->blit() == lit);
}
tmp_assign(constraint_ref const& c, sat::literal lit): tmp_assign(c.get(), lit) {}
void revert() {
if (m_should_unassign) {
m_constraint->unassign();
m_should_unassign = false;
}
}
~tmp_assign() {
revert();
}
tmp_assign(tmp_assign&) = delete;
tmp_assign(tmp_assign&&) = delete;
tmp_assign& operator=(tmp_assign&) = delete;
tmp_assign& operator=(tmp_assign&&) = delete;
};
}