3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-15 13:28:47 +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

@ -52,14 +52,16 @@ class lar_base_constraint {
lconstraint_kind m_kind; lconstraint_kind m_kind;
mpq m_right_side; mpq m_right_side;
bool m_active; bool m_active;
unsigned m_j;
public: public:
virtual vector<std::pair<mpq, var_index>> coeffs() const = 0; virtual vector<std::pair<mpq, var_index>> coeffs() const = 0;
lar_base_constraint(lconstraint_kind kind, const mpq& right_side) :m_kind(kind), m_right_side(right_side), m_active(false) {} lar_base_constraint(unsigned j, lconstraint_kind kind, const mpq& right_side) :m_kind(kind), m_right_side(right_side), m_active(false), m_j(j) {}
virtual ~lar_base_constraint() {} virtual ~lar_base_constraint() {}
lconstraint_kind kind() const { return m_kind; } lconstraint_kind kind() const { return m_kind; }
mpq const& rhs() const { return m_right_side; } mpq const& rhs() const { return m_right_side; }
unsigned column() const { return m_j; }
void activate() { m_active = true; } void activate() { m_active = true; }
void deactivate() { m_active = false; } void deactivate() { m_active = false; }
@ -70,14 +72,13 @@ public:
}; };
class lar_var_constraint: public lar_base_constraint { class lar_var_constraint: public lar_base_constraint {
unsigned m_j;
public: public:
lar_var_constraint(unsigned j, lconstraint_kind kind, const mpq& right_side) : lar_var_constraint(unsigned j, lconstraint_kind kind, const mpq& right_side) :
lar_base_constraint(kind, right_side), m_j(j) {} lar_base_constraint(j, kind, right_side) {}
vector<std::pair<mpq, var_index>> coeffs() const override { vector<std::pair<mpq, var_index>> coeffs() const override {
vector<std::pair<mpq, var_index>> ret; vector<std::pair<mpq, var_index>> ret;
ret.push_back(std::make_pair(one_of_type<mpq>(), m_j)); ret.push_back(std::make_pair(one_of_type<mpq>(), column()));
return ret; return ret;
} }
unsigned size() const override { return 1;} unsigned size() const override { return 1;}
@ -87,8 +88,8 @@ public:
class lar_term_constraint: public lar_base_constraint { class lar_term_constraint: public lar_base_constraint {
const lar_term * m_term; const lar_term * m_term;
public: public:
lar_term_constraint(const lar_term *t, lconstraint_kind kind, const mpq& right_side) : lar_term_constraint(unsigned j, const lar_term *t, lconstraint_kind kind, const mpq& right_side) :
lar_base_constraint(kind, right_side), m_term(t) {} lar_base_constraint(j, kind, right_side), m_term(t) {}
vector<std::pair<mpq, var_index>> coeffs() const override { return m_term->coeffs_as_vector(); } vector<std::pair<mpq, var_index>> coeffs() const override { return m_term->coeffs_as_vector(); }
unsigned size() const override { return m_term->size();} unsigned size() const override { return m_term->size();}
@ -150,7 +151,7 @@ public:
m_constraint_count = m_constraints.size(); m_constraint_count = m_constraints.size();
m_constraint_count.push(); m_constraint_count.push();
m_region.push_scope(); m_region.push_scope();
#if 0 #if 1
m_active_lim = m_active.size(); m_active_lim = m_active.size();
m_active_lim.push(); m_active_lim.push();
#endif #endif
@ -161,7 +162,7 @@ public:
for (unsigned i = m_constraints.size(); i-- > m_constraint_count; ) for (unsigned i = m_constraints.size(); i-- > m_constraint_count; )
m_constraints[i]->~lar_base_constraint(); m_constraints[i]->~lar_base_constraint();
m_constraints.shrink(m_constraint_count); m_constraints.shrink(m_constraint_count);
#if 0 #if 1
m_active_lim.pop(k); m_active_lim.pop(k);
for (unsigned i = m_active.size(); i-- > m_active_lim; ) { for (unsigned i = m_active.size(); i-- > m_active_lim; ) {
m_constraints[m_active[i]]->deactivate(); m_constraints[m_active[i]]->deactivate();
@ -175,11 +176,11 @@ public:
return add(new (m_region) lar_var_constraint(j, k, rhs)); return add(new (m_region) lar_var_constraint(j, k, rhs));
} }
constraint_index add_term_constraint(const lar_term* t, lconstraint_kind k, mpq const& rhs) { constraint_index add_term_constraint(unsigned j, const lar_term* t, lconstraint_kind k, mpq const& rhs) {
return add(new (m_region) lar_term_constraint(t, k, rhs)); return add(new (m_region) lar_term_constraint(j, t, k, rhs));
} }
#if 1 #if 0
bool is_active(constraint_index ci) const { return true; } bool is_active(constraint_index ci) const { return true; }
void activate(constraint_index ci) {} void activate(constraint_index ci) {}
@ -188,7 +189,7 @@ public:
// future behavior uses activation bit. // future behavior uses activation bit.
bool is_active(constraint_index ci) const { return m_constraints[ci]->is_active(); } bool is_active(constraint_index ci) const { return m_constraints[ci]->is_active(); }
void activate(constraint_index ci) { m_constraints[ci]->activate(); } void activate(constraint_index ci) { auto& c = *m_constraints[ci]; if (!c.is_active()) { c.activate(); m_active.push_back(ci); } }
#endif #endif
lar_base_constraint const& operator[](constraint_index ci) const { return *m_constraints[ci]; } lar_base_constraint const& operator[](constraint_index ci) const { return *m_constraints[ci]; }

View file

@ -1764,12 +1764,22 @@ bool lar_solver::bound_is_integer_for_integer_column(unsigned j, const mpq & rig
} }
constraint_index lar_solver::add_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side) { constraint_index lar_solver::add_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side) {
constraint_index ci = mk_var_bound(j, kind, right_side);
activate(ci);
return ci;
}
void lar_solver::activate(constraint_index ci) {
auto const& c = m_constraints[ci];
update_column_type_and_bound(c.column(), c.kind(), c.rhs(), ci);
}
constraint_index lar_solver::mk_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side) {
TRACE("lar_solver", tout << "j = " << j << " " << lconstraint_kind_string(kind) << " " << right_side<< std::endl;); TRACE("lar_solver", tout << "j = " << j << " " << lconstraint_kind_string(kind) << " " << right_side<< std::endl;);
constraint_index ci; constraint_index ci;
if (!is_term(j)) { // j is a var if (!is_term(j)) { // j is a var
lp_assert(bound_is_integer_for_integer_column(j, right_side)); lp_assert(bound_is_integer_for_integer_column(j, right_side));
ci = m_constraints.add_var_constraint(j, kind, right_side); ci = m_constraints.add_var_constraint(j, kind, right_side);
update_column_type_and_bound(j, kind, right_side, ci);
} }
else { else {
ci = add_var_bound_on_constraint_for_term(j, kind, right_side); ci = add_var_bound_on_constraint_for_term(j, kind, right_side);
@ -1811,26 +1821,20 @@ constraint_index lar_solver::add_var_bound_on_constraint_for_term(var_index j, l
unsigned adjusted_term_index = adjust_term_index(j); unsigned adjusted_term_index = adjust_term_index(j);
// lp_assert(!term_is_int(m_terms[adjusted_term_index]) || right_side.is_int()); // lp_assert(!term_is_int(m_terms[adjusted_term_index]) || right_side.is_int());
unsigned term_j; unsigned term_j;
constraint_index ci; lar_term const* term = m_terms[adjusted_term_index];
if (m_var_register.external_is_used(j, term_j)) { if (m_var_register.external_is_used(j, term_j)) {
ci = m_constraints.add_term_constraint(m_terms[adjusted_term_index], kind, right_side); return m_constraints.add_term_constraint(term_j, term, kind, right_side);
update_column_type_and_bound(term_j, kind, right_side, ci);
} }
else { else {
ci = add_constraint_from_term_and_create_new_column_row(j, m_terms[adjusted_term_index], kind, right_side); return add_constraint_from_term_and_create_new_column_row(j, term, kind, right_side);
} }
return ci;
} }
constraint_index lar_solver::add_constraint_from_term_and_create_new_column_row(unsigned term_j, const lar_term* term, constraint_index lar_solver::add_constraint_from_term_and_create_new_column_row(
lconstraint_kind kind, const mpq & right_side) { unsigned term_j, const lar_term* term, lconstraint_kind kind, const mpq & right_side) {
add_row_from_term_no_constraint(term, term_j); add_row_from_term_no_constraint(term, term_j);
unsigned j = A_r().column_count() - 1; unsigned j = A_r().column_count() - 1;
constraint_index ci = m_constraints.add_term_constraint(term, kind, right_side); return m_constraints.add_term_constraint(j, term, kind, right_side);
update_column_type_and_bound(j, kind, right_side, ci);
lp_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size());
return ci;
} }
void lar_solver::decide_on_strategy_and_adjust_initial_state() { void lar_solver::decide_on_strategy_and_adjust_initial_state() {

View file

@ -183,6 +183,10 @@ public:
void add_basic_var_to_core_fields(); void add_basic_var_to_core_fields();
constraint_index mk_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side);
void activate(constraint_index ci);
constraint_index add_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side) ; constraint_index add_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side) ;
bool compare_values(var_index j, lconstraint_kind kind, const mpq & right_side); bool compare_values(var_index j, lconstraint_kind kind, const mpq & right_side);

View file

@ -19,22 +19,25 @@ Revision History:
--*/ --*/
#pragma once #pragma once
#include <unordered_map>
#include <set>
#include <stack>
#include "util/vector.h" #include "util/vector.h"
namespace lp { namespace lp {
template < typename B> class stacked_vector { template < typename B> class stacked_vector {
struct log_entry {
unsigned m_i; unsigned m_ts; B b;
log_entry(unsigned i, unsigned t, B const& b): m_i(i), m_ts(t), b(b) {}
log_entry():m_i(UINT_MAX), m_ts(0) {}
};
svector<unsigned> m_stack_of_vector_sizes; svector<unsigned> m_stack_of_vector_sizes;
svector<unsigned> m_stack_of_change_sizes; svector<unsigned> m_stack_of_change_sizes;
vector<std::pair<unsigned, B>> m_changes; vector<log_entry> m_log;
vector<B> m_vector; vector<B> m_vector;
svector<unsigned> m_last_update;
public: public:
class ref { class ref {
stacked_vector<B> & m_vec; stacked_vector<B> & m_vec;
unsigned m_i; unsigned m_i;
public: public:
ref(stacked_vector<B> &m, unsigned key) :m_vec(m), m_i(key) { ref(stacked_vector<B> &m, unsigned key): m_vec(m), m_i(key) {
lp_assert(key < m.size()); lp_assert(key < m.size());
} }
ref & operator=(const B & b) { ref & operator=(const B & b) {
@ -77,14 +80,24 @@ public:
}; };
private: private:
unsigned now() const { return m_stack_of_change_sizes.size(); }
void emplace_replace(unsigned i,const B & b) { void emplace_replace(unsigned i,const B & b) {
if (m_vector[i] != b) { unsigned n = now();
m_changes.push_back(std::make_pair(i, m_vector[i])); if (m_last_update[i] == n) {
m_vector[i] = b; m_vector[i] = b;
} }
else if (m_vector[i] != b) {
m_log.push_back(log_entry(i, m_last_update[i], m_vector[i]));
m_vector[i] = b;
m_last_update[i] = n;
}
} }
public: public:
stacked_vector() { }
ref operator[] (unsigned a) { ref operator[] (unsigned a) {
return ref(*this, a); return ref(*this, a);
} }
@ -102,11 +115,10 @@ public:
unsigned size() const { unsigned size() const {
return m_vector.size(); return m_vector.size();
} }
void push() { void push() {
m_stack_of_change_sizes.push_back(m_changes.size()); m_stack_of_change_sizes.push_back(m_log.size());
m_stack_of_vector_sizes.push_back(m_vector.size()); m_stack_of_vector_sizes.push_back(m_vector.size());
} }
void pop() { void pop() {
@ -133,62 +145,31 @@ public:
void pop(unsigned k) { void pop(unsigned k) {
lp_assert(m_stack_of_vector_sizes.size() >= k); lp_assert(m_stack_of_vector_sizes.size() >= k);
lp_assert(k > 0); lp_assert(k > 0);
resize(m_vector, m_stack_of_vector_sizes[m_stack_of_vector_sizes.size() - k]); m_vector.resize(m_stack_of_vector_sizes[m_stack_of_vector_sizes.size() - k]);
m_last_update.resize(m_stack_of_vector_sizes[m_stack_of_vector_sizes.size() - k]);
pop_tail(m_stack_of_vector_sizes, k); pop_tail(m_stack_of_vector_sizes, k);
unsigned first_change = m_stack_of_change_sizes[m_stack_of_change_sizes.size() - k]; unsigned first_change = m_stack_of_change_sizes[m_stack_of_change_sizes.size() - k];
pop_tail(m_stack_of_change_sizes, k); pop_tail(m_stack_of_change_sizes, k);
for (unsigned j = m_changes.size(); j-- > first_change; ) { for (unsigned j = m_log.size(); j-- > first_change; ) {
const auto & p = m_changes[j]; const auto & p = m_log[j];
unsigned jc = p.first; unsigned jc = p.m_i;
if (jc < m_vector.size()) { if (jc < m_vector.size()) {
m_vector[jc] = p.second; // restore the old value m_vector[jc] = p.b; // restore the old value
m_vector[jc] = p.second; // restore the old value m_last_update[jc] = p.m_ts;
} }
} }
resize(m_changes, first_change); resize(m_log, first_change);
/*
while (k-- > 0) {
if (m_stack.empty())
return;
delta & d = m_stack.back();
lp_assert(m_vector.size() >= d.m_size);
while (m_vector.size() > d.m_size)
m_vector.pop_back();
for (auto & t : d.m_original_changed) {
lp_assert(t.first < m_vector.size());
m_vector[t.first] = t.second;
}
// lp_assert(d.m_deb_copy == m_vector);
m_stack.pop_back();*/
} }
// void clear() {
// if (m_stack.empty()) {
// m_vector.clear();
// return;
// }
// delta & d = m_stack.top();
// auto & oc = d.m_original_changed;
// for (auto & p : m_vector) {
// const auto & it = oc.find(p.first);
// if (it == oc.end() && d.m_new.find(p.first) == d.m_new.end())
// oc.emplace(p.first, p.second);
// }
// m_vector.clear();
// }
void push_back(const B & b) { void push_back(const B & b) {
m_vector.push_back(b); m_vector.push_back(b);
m_last_update.push_back(now());
} }
void increase_size_by_one() { void increase_size_by_one() {
m_vector.resize(m_vector.size() + 1); m_vector.resize(m_vector.size() + 1);
m_last_update.push_back(now());
} }
unsigned peek_size(unsigned k) const { unsigned peek_size(unsigned k) const {

View file

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