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

Begin reorganizing resolve_value

This commit is contained in:
Jakob Rath 2021-09-07 11:40:50 +02:00
parent b4e14c31d0
commit 7d58296ad2
6 changed files with 113 additions and 25 deletions

View file

@ -165,6 +165,30 @@ namespace polysat {
return clause::from_literals(lvl, std::move(dep), std::move(literals));
}
bool conflict_core::resolve_value(pvar v, vector<signed_constraint> const& cjust_v) {
// TODO: maybe don't do this automatically, because cjust-constraints are true and core constraints are false.
// issue: what if viable(v) is empty? then we only have cjust constraints and none of them is evaluable (at least not immediately because no value is set for this variable.)
// => think about what we want to do in this case (choose a value and evaluate? try all possible superpositions without caring about the value of the premises?)
// the last value_resolution method can then be the one that adds the cjusts and calls saturation and more general VE.
// No value resolution method was successful => fall back to saturation and variable elimination
for (auto c : cjust_v)
insert(c);
// Variable elimination
while (true) { // TODO: limit?
// TODO: maybe we shouldn't try to split up VE/Saturation in the implementation.
// it might be better to just have more general "core inferences" that may combine elimination/saturation steps that fit together...
// or even keep the whole "value resolution + VE/Saturation" as a single step. we might want to know which constraints come from the current cjusts?
// TODO: as a last resort, substitute v by m_value[v]?
if (!try_saturate(v))
break;
if (try_eliminate(v))
return true;
}
return false;
}
bool conflict_core::try_eliminate(pvar v) {
// TODO: could be tracked incrementally when constraints are added/removed
vector<signed_constraint> v_constraints;

View file

@ -82,6 +82,11 @@ namespace polysat {
*/
void resolve(constraint_manager const& m, sat::bool_var var, clause const& cl);
/** Perform value resolution by applying various inference rules.
* Returns true if it was possible to eliminate the variable 'v'.
*/
bool resolve_value(pvar v, vector<signed_constraint> const& cjust_v);
/** Convert the core into a lemma to be learned. */
clause_ref build_lemma();

View file

@ -17,6 +17,60 @@ Author:
namespace polysat {
constraint_manager& explainer::cm() { return s().m_constraints; }
bool ex_polynomial_superposition::try_explain(pvar v, vector<signed_constraint> const& cjust_v, conflict_core& core) {
// TODO: check superposition into disequality again (see notes)
// TODO: use indexing/marking for this instead of allocating a temporary vector
// TODO: core saturation premises are from \Gamma (i.e., has_bvar)... but here we further restrict to the core; might need to revise
// -- especially: should take into account results from previous saturations (they will be in \Gamma, but only if we use the constraint or one of its descendants for the lemma)
// actually: we want to take one from the current cjust (currently true) and one from the conflict (currently false)
vector<signed_constraint> candidates;
for (auto c : core)
if (c->has_bvar() && c.is_positive() && c->is_eq() && c->contains_var(v))
candidates.push_back(c);
// TODO: c1 should a currently true constraint, while c2 should take a currently false constraint.
// remove candidates vector (premature optimization)
// we may want to apply this multiple times (a single resolve might not eliminate the variable).
LOG_H3("Trying polynomial superposition...");
for (auto it1 = candidates.begin(); it1 != candidates.end(); ++it1) {
for (auto it2 = it1 + 1; it2 != candidates.end(); ++it2) {
signed_constraint c1 = *it1;
signed_constraint c2 = *it2;
SASSERT(c1 != c2);
LOG("c1: " << c1);
LOG("c2: " << c2);
pdd a = c1->to_eq().p();
pdd b = c2->to_eq().p();
pdd r = a;
if (!a.resolve(v, b, r) && !b.resolve(v, a, r))
continue;
unsigned const lvl = std::max(c1->level(), c2->level());
signed_constraint c = cm().eq(lvl, r);
LOG("resolved: " << c << " currently false? " << c.is_currently_false(s()));
if (!c.is_currently_false(s()))
continue;
vector<signed_constraint> premises;
premises.push_back(c1);
premises.push_back(c2);
core.insert(c, std::move(premises));
return true;
// clause_builder clause(m_solver);
// clause.push_literal(~c1->blit());
// clause.push_literal(~c2->blit());
// clause.push_new_constraint(m_solver.m_constraints.eq(lvl, r));
// return clause.build();
}
}
return false;
}
// LOG_H3("Attempting to explain conflict for v" << v);
// m_var = v;
// m_cjust_v = cjust;

View file

@ -19,6 +19,30 @@ Author:
namespace polysat {
class solver;
class constraint_manager;
class explainer {
friend class conflict_core;
solver* m_solver = nullptr;
void set_solver(solver& s) { m_solver = &s; }
protected:
solver& s() { return *m_solver; }
constraint_manager& cm();
public:
virtual ~explainer() {}
virtual bool try_explain(pvar v, vector<signed_constraint> const& cjust_v, conflict_core& core) = 0;
};
class ex_polynomial_superposition : public explainer {
bool try_explain(pvar v, vector<signed_constraint> const& cjust_v, conflict_core& core) override;
};
#if 0
class conflict_explainer {
@ -45,7 +69,7 @@ namespace polysat {
bool saturate();
/** resolve conflict state against assignment to v */
void resolve(pvar v, ptr_vector<constraint> const& cjust_v); // TODO: try variable elimination of 'v', if not possible, core saturation and core reduction. (actually reduction could be one specific VE method).
void resolve(pvar v, ptr_vector<constraint> const& cjust_v);
void resolve(sat::literal lit);
// TODO: move conflict resolution from solver into this class.

View file

@ -526,31 +526,11 @@ namespace polysat {
}
// Value Resolution
// TODO: maybe don't do this automatically, because cjust-constraints are true and core constraints are false.
// issue: what if viable(v) is empty? then we only have cjust constraints and none of them is evaluable (at least not immediately because no value is set for this variable.)
// => think about what we want to do in this case (choose a value and evaluate? try all possible superpositions without caring about the value of the premises?)
// the last value_resolution method can then be the one that adds the cjusts and calls saturation and more general VE.
for (auto c : m_cjust[v])
m_conflict.insert(c);
// Variable elimination
while (true) {
// TODO:
// 1. Try variable elimination of 'v'
// 2. If not possible, try saturation and core reduction (actually reduction could be one specific VE method?).
// 3. as a last resort, substitute v by m_value[v]?
// TODO: maybe we shouldn't try to split up VE/Saturation in the implementation.
// it might be better to just have more general "core inferences" that may combine elimination/saturation steps that fit together...
// or even keep the whole "value resolution + VE/Saturation" as a single step. we might want to know which constraints come from the current cjusts?
if (m_conflict.try_eliminate(v))
return;
if (!m_conflict.try_saturate(v))
break;
if (!m_conflict.resolve_value(v, m_cjust[v])) {
// Failed to resolve => bail out
++m_stats.m_num_bailouts;
m_conflict.set_bailout();
}
// Failed to resolve => bail out
++m_stats.m_num_bailouts;
m_conflict.set_bailout();
}
/** Conflict resolution case where boolean literal 'lit' is on top of the stack */

View file

@ -56,6 +56,7 @@ namespace polysat {
friend class clause_builder;
friend class conflict_core;
friend class conflict_explainer;
friend class explainer;
friend class inference_engine;
friend class forbidden_intervals;
friend class linear_solver;