mirror of
https://github.com/Z3Prover/z3
synced 2025-04-24 01:25:31 +00:00
Arith min max (#6864)
* prepare for dependencies Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * snapshot Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * more refactoring Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * more refactoring Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * build Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * pass in u_dependency_manager Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * address NYIs Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * more refactoring names Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * eq_explanation update Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * add outline of bounds improvement functionality Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * fix unit tests Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * remove unused structs Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * more bounds Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * more bounds Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * convert more internals to use u_dependency instead of constraint_index Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * convert more internals to use u_dependency instead of constraint_index Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * remember to push/pop scopes Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * use the main function for updating bounds Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * na Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * na Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * remove reset of shared dep manager Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * disable improve-bounds, add statistics Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --------- Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
c3b344ec47
commit
5e3df9ee77
40 changed files with 630 additions and 529 deletions
|
@ -42,7 +42,8 @@ namespace sat {
|
|||
|
||||
void anf_simplifier::operator()() {
|
||||
dd::pdd_manager m(20, dd::pdd_manager::semantics::mod2_e);
|
||||
pdd_solver solver(s.rlimit(), m);
|
||||
u_dependency_manager dm;
|
||||
pdd_solver solver(s.rlimit(), dm, m);
|
||||
report _report(*this);
|
||||
configure_solver(solver);
|
||||
clauses2anf(solver);
|
||||
|
|
|
@ -524,7 +524,7 @@ namespace arith {
|
|||
return all_divs_valid;
|
||||
}
|
||||
|
||||
void solver::fixed_var_eh(theory_var v, lp::constraint_index ci1, lp::constraint_index ci2, rational const& bound) {
|
||||
void solver::fixed_var_eh(theory_var v, u_dependency* dep, rational const& bound) {
|
||||
theory_var w = euf::null_theory_var;
|
||||
enode* x = var2enode(v);
|
||||
if (bound.is_zero())
|
||||
|
@ -540,8 +540,8 @@ namespace arith {
|
|||
return;
|
||||
reset_evidence();
|
||||
m_explanation.clear();
|
||||
consume(rational::one(), ci1);
|
||||
consume(rational::one(), ci2);
|
||||
for (auto ci : lp().flatten(dep))
|
||||
consume(rational::one(), ci);
|
||||
++m_stats.m_fixed_eqs;
|
||||
auto* hint = explain_implied_eq(m_explanation, x, y);
|
||||
auto* jst = euf::th_explain::propagate(*this, m_core, m_eqs, x, y, hint);
|
||||
|
|
|
@ -402,12 +402,13 @@ namespace arith {
|
|||
}
|
||||
|
||||
void solver::propagate_eqs(lp::tv t, lp::constraint_index ci1, lp::lconstraint_kind k, api_bound& b, rational const& value) {
|
||||
lp::constraint_index ci2;
|
||||
if (k == lp::GE && set_lower_bound(t, ci1, value) && has_upper_bound(t.index(), ci2, value)) {
|
||||
fixed_var_eh(b.get_var(), ci1, ci2, value);
|
||||
u_dependency* dep;
|
||||
auto& dm = lp().dep_manager();
|
||||
if (k == lp::GE && set_lower_bound(t, ci1, value) && has_upper_bound(t.index(), dep, value)) {
|
||||
fixed_var_eh(b.get_var(), dm.mk_join(dm.mk_leaf(ci1), dep), value);
|
||||
}
|
||||
else if (k == lp::LE && set_upper_bound(t, ci1, value) && has_lower_bound(t.index(), ci2, value)) {
|
||||
fixed_var_eh(b.get_var(), ci1, ci2, value);
|
||||
else if (k == lp::LE && set_upper_bound(t, ci1, value) && has_lower_bound(t.index(), dep, value)) {
|
||||
fixed_var_eh(b.get_var(), dm.mk_join(dm.mk_leaf(ci1), dep), value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -433,11 +434,12 @@ namespace arith {
|
|||
// m_solver already tracks bounds on proper variables, but not on terms.
|
||||
bool is_strict = false;
|
||||
rational b;
|
||||
u_dependency* dep = nullptr;
|
||||
if (is_lower) {
|
||||
return lp().has_lower_bound(tv.id(), ci, b, is_strict) && !is_strict && b == v;
|
||||
return lp().has_lower_bound(tv.id(), dep, b, is_strict) && !is_strict && b == v;
|
||||
}
|
||||
else {
|
||||
return lp().has_upper_bound(tv.id(), ci, b, is_strict) && !is_strict && b == v;
|
||||
return lp().has_upper_bound(tv.id(), dep, b, is_strict) && !is_strict && b == v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -692,7 +694,7 @@ namespace arith {
|
|||
|
||||
void solver::report_equality_of_fixed_vars(unsigned vi1, unsigned vi2) {
|
||||
rational bound;
|
||||
lp::constraint_index ci1, ci2, ci3, ci4;
|
||||
u_dependency* ci1 = nullptr, *ci2 = nullptr, *ci3 = nullptr, *ci4 = nullptr;
|
||||
theory_var v1 = lp().local_to_external(vi1);
|
||||
theory_var v2 = lp().local_to_external(vi2);
|
||||
TRACE("arith", tout << "fixed: " << mk_pp(var2expr(v1), m) << " " << mk_pp(var2expr(v2), m) << "\n";);
|
||||
|
@ -714,10 +716,10 @@ namespace arith {
|
|||
++m_stats.m_fixed_eqs;
|
||||
reset_evidence();
|
||||
m_explanation.clear();
|
||||
consume(rational::one(), ci1);
|
||||
consume(rational::one(), ci2);
|
||||
consume(rational::one(), ci3);
|
||||
consume(rational::one(), ci4);
|
||||
auto& dm = lp().dep_manager();
|
||||
auto* d = dm.mk_join(dm.mk_join(ci1, ci2), dm.mk_join(ci3, ci4));
|
||||
for (auto ci : lp().flatten(d))
|
||||
consume(rational::one(), ci);
|
||||
enode* x = var2enode(v1);
|
||||
enode* y = var2enode(v2);
|
||||
auto* ex = explain_implied_eq(m_explanation, x, y);
|
||||
|
@ -729,26 +731,28 @@ namespace arith {
|
|||
return x == y || var2enode(x)->get_root() == var2enode(y)->get_root();
|
||||
}
|
||||
|
||||
bool solver::has_upper_bound(lpvar vi, lp::constraint_index& ci, rational const& bound) { return has_bound(vi, ci, bound, false); }
|
||||
bool solver::has_upper_bound(lpvar vi, u_dependency*& ci, rational const& bound) { return has_bound(vi, ci, bound, false); }
|
||||
|
||||
bool solver::has_lower_bound(lpvar vi, lp::constraint_index& ci, rational const& bound) { return has_bound(vi, ci, bound, true); }
|
||||
bool solver::has_lower_bound(lpvar vi, u_dependency*& ci, rational const& bound) { return has_bound(vi, ci, bound, true); }
|
||||
|
||||
bool solver::has_bound(lpvar vi, lp::constraint_index& ci, rational const& bound, bool is_lower) {
|
||||
bool solver::has_bound(lpvar vi, u_dependency*& dep, rational const& bound, bool is_lower) {
|
||||
if (lp::tv::is_term(vi)) {
|
||||
theory_var v = lp().local_to_external(vi);
|
||||
rational val;
|
||||
TRACE("arith", tout << lp().get_variable_name(vi) << " " << v << "\n";);
|
||||
if (v != euf::null_theory_var && a.is_numeral(var2expr(v), val) && bound == val) {
|
||||
ci = UINT_MAX;
|
||||
dep = nullptr;
|
||||
return bound == val;
|
||||
}
|
||||
|
||||
auto& vec = is_lower ? m_lower_terms : m_upper_terms;
|
||||
lpvar ti = lp::tv::unmask_term(vi);
|
||||
if (vec.size() > ti) {
|
||||
constraint_bound& b = vec[ti];
|
||||
ci = b.first;
|
||||
return ci != UINT_MAX && bound == b.second;
|
||||
auto& [ci, coeff] = vec[ti];
|
||||
if (ci == UINT_MAX)
|
||||
return false;
|
||||
dep = lp().dep_manager().mk_leaf(ci);
|
||||
return bound == coeff;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
|
@ -758,10 +762,10 @@ namespace arith {
|
|||
bool is_strict = false;
|
||||
rational b;
|
||||
if (is_lower) {
|
||||
return lp().has_lower_bound(vi, ci, b, is_strict) && b == bound && !is_strict;
|
||||
return lp().has_lower_bound(vi, dep, b, is_strict) && b == bound && !is_strict;
|
||||
}
|
||||
else {
|
||||
return lp().has_upper_bound(vi, ci, b, is_strict) && b == bound && !is_strict;
|
||||
return lp().has_upper_bound(vi, dep, b, is_strict) && b == bound && !is_strict;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -359,7 +359,7 @@ namespace arith {
|
|||
void assert_idiv_mod_axioms(theory_var u, theory_var v, theory_var w, rational const& r);
|
||||
api_bound* mk_var_bound(sat::literal lit, theory_var v, lp_api::bound_kind bk, rational const& bound);
|
||||
lp::lconstraint_kind bound2constraint_kind(bool is_int, lp_api::bound_kind bk, bool is_true);
|
||||
void fixed_var_eh(theory_var v1, lp::constraint_index ci1, lp::constraint_index ci2, rational const& bound);
|
||||
void fixed_var_eh(theory_var v1, u_dependency* dep, rational const& bound);
|
||||
bool set_upper_bound(lp::tv t, lp::constraint_index ci, rational const& v) { return set_bound(t, ci, v, false); }
|
||||
bool set_lower_bound(lp::tv t, lp::constraint_index ci, rational const& v) { return set_bound(t, ci, v, true); }
|
||||
bool set_bound(lp::tv tv, lp::constraint_index ci, rational const& v, bool is_lower);
|
||||
|
@ -412,9 +412,9 @@ namespace arith {
|
|||
nlsat::anum const& nl_value(theory_var v, scoped_anum& r) const;
|
||||
|
||||
|
||||
bool has_bound(lpvar vi, lp::constraint_index& ci, rational const& bound, bool is_lower);
|
||||
bool has_lower_bound(lpvar vi, lp::constraint_index& ci, rational const& bound);
|
||||
bool has_upper_bound(lpvar vi, lp::constraint_index& ci, rational const& bound);
|
||||
bool has_bound(lpvar vi, u_dependency*& ci, rational const& bound, bool is_lower);
|
||||
bool has_lower_bound(lpvar vi, u_dependency*& ci, rational const& bound);
|
||||
bool has_upper_bound(lpvar vi, u_dependency*& ci, rational const& bound);
|
||||
|
||||
/*
|
||||
* Facility to put a small box around integer variables used in branch and bounds.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue