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

compile constraints during internalization

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2020-02-07 19:26:40 -08:00
parent 824c2674b9
commit 02b074e28b
5 changed files with 122 additions and 113 deletions

View file

@ -65,24 +65,31 @@ std::ostream& operator<<(std::ostream& out, bound_kind const& k) {
class bound {
smt::bool_var m_bv;
smt::theory_var m_var;
lpvar m_vi;
bool m_is_int;
rational m_value;
bound_kind m_bound_kind;
lp::constraint_index m_constraints[2];
public:
bound(smt::bool_var bv, smt::theory_var v, bool is_int, rational const & val, bound_kind k):
bound(smt::bool_var bv, smt::theory_var v, lpvar vi, bool is_int, rational const & val, bound_kind k, lp::constraint_index ct, lp::constraint_index cf):
m_bv(bv),
m_var(v),
m_vi(vi),
m_is_int(is_int),
m_value(val),
m_bound_kind(k) {
m_constraints[0] = cf;
m_constraints[1] = ct;
}
virtual ~bound() {}
smt::theory_var get_var() const { return m_var; }
lpvar lp_solver_var() const { return m_vi; }
smt::bool_var get_bv() const { return m_bv; }
bound_kind get_bound_kind() const { return m_bound_kind; }
bool is_int() const { return m_is_int; }
rational const& get_value() const { return m_value; }
lp::constraint_index get_constraint(bool b) const { return m_constraints[b]; }
inf_rational get_value(bool is_true) const {
if (is_true) return inf_rational(m_value); // v >= value or v <= value
if (m_is_int) {
@ -1050,7 +1057,7 @@ public:
if (is_int(v) && !r.is_int()) {
r = (k == lp_api::upper_t) ? floor(r) : ceil(r);
}
lp_api::bound* b = alloc(lp_api::bound, bv, v, is_int(v), r, k);
lp_api::bound* b = mk_var_bound(bv, v, k, r);
m_bounds[v].push_back(b);
updt_unassigned_bounds(v, +1);
m_bounds_trail.push_back(v);
@ -2587,7 +2594,7 @@ public:
rational const& k2 = b2.get_value();
lp_api::bound_kind kind1 = b1.get_bound_kind();
lp_api::bound_kind kind2 = b2.get_bound_kind();
bool v_is_int = is_int(v);
bool v_is_int = b1.is_int();
SASSERT(v == b2.get_var());
if (k1 == k2 && kind1 == kind2) return;
SASSERT(k1 != k2 || kind1 != kind2);
@ -2794,7 +2801,7 @@ public:
SASSERT(!bounds.empty());
if (bounds.size() == 1) return;
if (m_unassigned_bounds[v] == 0) return;
bool v_is_int = is_int(v);
bool v_is_int = b.is_int();
literal lit1(bv, !is_true);
literal lit2 = null_literal;
bool find_glb = (is_true == (k == lp_api::lower_t));
@ -3007,47 +3014,59 @@ public:
return true;
}
void assert_bound(bool_var bv, bool is_true, lp_api::bound& b) {
if (is_infeasible()) return;
scoped_internalize_state st(*this);
st.vars().push_back(b.get_var());
st.coeffs().push_back(rational::one());
init_left_side(st);
lp::lconstraint_kind k = lp::EQ;
bool is_int = b.is_int();
switch (b.get_bound_kind()) {
lp::lconstraint_kind bound2constraint_kind(bool is_int, lp_api::bound_kind bk, bool is_true) {
switch (bk) {
case lp_api::lower_t:
k = is_true ? lp::GE : (is_int ? lp::LE : lp::LT);
break;
return is_true ? lp::GE : (is_int ? lp::LE : lp::LT);
case lp_api::upper_t:
k = is_true ? lp::LE : (is_int ? lp::GE : lp::GT);
break;
}
return is_true ? lp::LE : (is_int ? lp::GE : lp::GT);
}
UNREACHABLE();
return lp::EQ;
}
void assert_bound(bool_var bv, bool is_true, lp_api::bound& b) {
lp::constraint_index ci = b.get_constraint(is_true);
m_solver->activate(ci);
if (is_infeasible()) {
return;
}
lp::lconstraint_kind k = bound2constraint_kind(b.is_int(), b.get_bound_kind(), is_true);
if (k == lp::LT || k == lp::LE) {
++m_stats.m_assert_lower;
}
else {
++m_stats.m_assert_upper;
}
auto vi = register_theory_var_in_lar_solver(b.get_var());
rational bound = b.get_value();
lp::constraint_index ci;
TRACE("arith", tout << "v" << b.get_var() << ", vi = " << vi;);
if (is_int && !is_true) {
rational bound = b.get_value(false).get_rational();
ci = m_solver->add_var_bound(vi, k, bound);
TRACE("arith", tout << "\bbound = " << bound << ", ci = " << ci << "\n";);
propagate_eqs(b.lp_solver_var(), ci, k, b);
}
lp_api::bound* mk_var_bound(bool_var bv, theory_var v, lp_api::bound_kind bk, rational const& bound) {
scoped_internalize_state st(*this);
st.vars().push_back(v);
st.coeffs().push_back(rational::one());
init_left_side(st);
lp::constraint_index cT, cF;
bool v_is_int = is_int(v);
auto vi = register_theory_var_in_lar_solver(v);
lp::lconstraint_kind kT = bound2constraint_kind(v_is_int, bk, true);
lp::lconstraint_kind kF = bound2constraint_kind(v_is_int, bk, false);
cT = m_solver->mk_var_bound(vi, kT, bound);
if (v_is_int) {
rational boundF = (bk == lp_api::lower_t) ? bound - 1 : bound + 1;
cF = m_solver->mk_var_bound(vi, kF, boundF);
}
else {
ci = m_solver->add_var_bound(vi, k, b.get_value());
TRACE("arith", tout << "\nbound = " << bound << ", ci = " << ci << "\n";);
cF = m_solver->mk_var_bound(vi, kF, bound);
}
add_ineq_constraint(ci, literal(bv, !is_true));
if (is_infeasible()) {
return;
}
propagate_eqs(vi, ci, k, b);
add_ineq_constraint(cT, literal(bv, false));
add_ineq_constraint(cF, literal(bv, true));
return alloc(lp_api::bound, bv, v, vi, v_is_int, bound, bk, cT, cF);
}
//
// fixed equalities.
// A fixed equality is inferred if there are two variables v1, v2 whose
@ -3761,7 +3780,7 @@ public:
// ctx().set_enode_flag(bv, true);
lp_api::bound_kind bkind = lp_api::bound_kind::lower_t;
if (is_strict) bkind = lp_api::bound_kind::upper_t;
lp_api::bound* a = alloc(lp_api::bound, bv, v, is_int, r, bkind);
lp_api::bound* a = mk_var_bound(bv, v, bkind, r);
mk_bound_axioms(*a);
updt_unassigned_bounds(v, +1);
m_bounds[v].push_back(a);