3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-06-03 04:41:21 +00:00

going over niil_solver (#79)

* change conflict to th_axiom

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* going over niil_solver

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2018-08-26 19:31:49 -07:00 committed by Lev Nachmanson
parent a9a45b7b47
commit e16d8118ac
4 changed files with 138 additions and 118 deletions

View file

@ -1332,13 +1332,11 @@ std::ostream& lar_solver::print_term(lar_term const& term, std::ostream & out) c
mpq val = p.coeff(); mpq val = p.coeff();
if (first) { if (first) {
first = false; first = false;
} else if (is_pos(val)) {
out << " + ";
} else { } else {
if (is_pos(val)) { out << " - ";
out << " + "; val = -val;
} else {
out << " - ";
val = -val;
}
} }
if (val == -numeric_traits<mpq>::one()) if (val == -numeric_traits<mpq>::one())
out << " - "; out << " - ";
@ -1367,8 +1365,7 @@ mpq lar_solver::get_left_side_val(const lar_base_constraint & cns, const std::u
std::ostream& lar_solver::print_constraint(const lar_base_constraint * c, std::ostream & out) const { std::ostream& lar_solver::print_constraint(const lar_base_constraint * c, std::ostream & out) const {
print_left_side_of_constraint(c, out); print_left_side_of_constraint(c, out);
out << " " << lconstraint_kind_string(c->m_kind) << " " << c->m_right_side << std::endl; return out << " " << lconstraint_kind_string(c->m_kind) << " " << c->m_right_side << std::endl;
return out;
} }
void lar_solver::fill_var_set_for_random_update(unsigned sz, var_index const * vars, vector<unsigned>& column_list) { void lar_solver::fill_var_set_for_random_update(unsigned sz, var_index const * vars, vector<unsigned>& column_list) {

View file

@ -115,6 +115,7 @@ private:
public : public :
unsigned terms_start_index() const { return m_terms_start_index; } unsigned terms_start_index() const { return m_terms_start_index; }
const vector<lar_term*> & terms() const { return m_terms; } const vector<lar_term*> & terms() const { return m_terms; }
lar_term const& term(unsigned i) const { return *m_terms[i]; }
const vector<lar_base_constraint*>& constraints() const { const vector<lar_base_constraint*>& constraints() const {
return m_constraints; return m_constraints;
} }
@ -479,16 +480,13 @@ public:
std::string get_variable_name(var_index vi) const; std::string get_variable_name(var_index vi) const;
// print utilities // ********** print region start
std::ostream& print_constraint(constraint_index ci, std::ostream & out) const; std::ostream& print_constraint(constraint_index ci, std::ostream & out) const;
std::ostream& print_constraints(std::ostream& out) const ; std::ostream& print_constraints(std::ostream& out) const ;
std::ostream& print_terms(std::ostream& out) const; std::ostream& print_terms(std::ostream& out) const;
std::ostream& print_left_side_of_constraint(const lar_base_constraint * c, std::ostream & out) const;
std::ostream& print_term(lar_term const& term, std::ostream & out) const; std::ostream& print_term(lar_term const& term, std::ostream & out) const;
std::ostream& print_term_as_indices(lar_term const& term, std::ostream & out) const; std::ostream& print_term_as_indices(lar_term const& term, std::ostream & out) const;

View file

@ -29,14 +29,12 @@ typedef lp::var_index lpvar;
struct hash_svector { struct hash_svector {
size_t operator()(const svector<unsigned> & v) const { size_t operator()(const svector<unsigned> & v) const {
size_t seed = 0; return svector_hash<unsigned_hash>()(v);
for (unsigned t : v)
hash_combine(seed, t);
return seed;
} }
}; };
// TBD: already defined on vector template class
bool operator==(const svector<unsigned> & a, const svector<unsigned> & b) { bool operator==(const svector<unsigned> & a, const svector<unsigned> & b) {
if (a.size() != b.size()) if (a.size() != b.size())
return false; return false;
@ -47,40 +45,42 @@ bool operator==(const svector<unsigned> & a, const svector<unsigned> & b) {
} }
struct solver::imp { struct solver::imp {
struct vars_equivalence {
struct equiv {
lpvar m_i;
lpvar m_j;
int m_sign;
lpci m_c0;
lpci m_c1;
equiv(lpvar i, lpvar j, int sign, lpci c0, lpci c1) :
m_i(i),
m_j(j),
m_sign(sign),
m_c0(c0),
m_c1(c1)
{
SASSERT(i > j);
}
};
struct eq_var { struct equiv {
lpvar m_var; lpvar m_i;
int m_sign; lpvar m_j;
expl_set m_explanation; int m_sign;
eq_var(const equiv& e) : lpci m_c0;
m_var(e.m_j), lpci m_c1;
m_sign(e.m_sign) { equiv(lpvar i, lpvar j, int sign, lpci c0, lpci c1) :
m_explanation.insert(e.m_c0); m_explanation.insert(e.m_c1); m_i(i),
} m_j(j),
void improve(const equiv & e) { m_sign(sign),
SASSERT(e.m_j > m_var); m_c0(c0),
m_var = e.m_j; m_c1(c1)
m_sign *= e.m_sign; {
m_explanation.insert(e.m_c0); m_explanation.insert(e.m_c1); SASSERT(i > j);
} }
}; };
struct eq_var {
lpvar m_var;
int m_sign;
expl_set m_explanation;
eq_var(const equiv& e) :
m_var(e.m_j),
m_sign(e.m_sign) {
m_explanation.insert(e.m_c0); m_explanation.insert(e.m_c1);
}
void improve(const equiv & e) {
SASSERT(e.m_j > m_var);
m_var = e.m_j;
m_sign *= e.m_sign;
m_explanation.insert(e.m_c0); m_explanation.insert(e.m_c1);
}
};
struct vars_equivalence {
std::unordered_map<lpvar, eq_var> m_map; // the resulting mapping std::unordered_map<lpvar, eq_var> m_map; // the resulting mapping
vector<equiv> m_equivs; // all equivalences extracted from constraints vector<equiv> m_equivs; // all equivalences extracted from constraints
@ -90,15 +90,17 @@ struct solver::imp {
m_map.clear(); m_map.clear();
} }
size_t size() const {
return m_map.size();
}
size_t size() const { return m_map.size(); } void add_equivalence_maybe(lp::lar_term const& t, lpci c0, lpci c1) {
void add_equivalence_maybe(const lp::lar_term *t, lpci c0, lpci c1) { if (t.size() != 2 || !t.m_v.is_zero())
if (t->size() != 2 || ! t->m_v.is_zero())
return; return;
bool seen_minus = false; bool seen_minus = false;
bool seen_plus = false; bool seen_plus = false;
lpvar i = -1, j; lpvar i = -1, j;
for(const auto & p : *t) { for (const auto & p : t) {
const auto & c = p.coeff(); const auto & c = p.coeff();
if (c == 1) { if (c == 1) {
seen_plus = true; seen_plus = true;
@ -113,10 +115,8 @@ struct solver::imp {
j = p.var(); j = p.var();
} }
SASSERT(i != j && i != static_cast<lpvar>(-1)); SASSERT(i != j && i != static_cast<lpvar>(-1));
if (i < j) { // swap if (i < j) {
lpvar tmp = i; std::swap(i, j);
i = j;
j = tmp;
} }
int sign = (seen_minus && seen_plus)? 1 : -1; int sign = (seen_minus && seen_plus)? 1 : -1;
m_equivs.push_back(equiv(i, j, sign, c0, c1)); m_equivs.push_back(equiv(i, j, sign, c0, c1));
@ -128,13 +128,13 @@ struct solver::imp {
if (!s.term_is_used_as_row(ti)) if (!s.term_is_used_as_row(ti))
continue; continue;
lpvar j = s.external2local(ti); lpvar j = s.external2local(ti);
if (!s.column_has_upper_bound(j) ||
!s.column_has_lower_bound(j)) if (s.column_has_upper_bound(j) &&
continue; s.column_has_lower_bound(j) &&
if (s.get_upper_bound(j) != lp::zero_of_type<lp::impq>() || s.get_upper_bound(j) == lp::zero_of_type<lp::impq>() &&
s.get_lower_bound(j) != lp::zero_of_type<lp::impq>()) s.get_lower_bound(j) == lp::zero_of_type<lp::impq>()) {
continue; add_equivalence_maybe(s.term(i), s.get_column_upper_bound_witness(j), s.get_column_lower_bound_witness(j));
add_equivalence_maybe(s.terms()[i], s.get_column_upper_bound_witness(j), s.get_column_lower_bound_witness(j)); }
} }
} }
@ -148,14 +148,13 @@ struct solver::imp {
if (it == m_map.end()) { if (it == m_map.end()) {
m_map.emplace(i, eq_var(e)); m_map.emplace(i, eq_var(e));
progress = true; progress = true;
} else { } else if (it->second.m_var > e.m_j) {
if (it->second.m_var > e.m_j) { it->second.improve(e);
it->second.improve(e); progress = true;
progress = true;
}
} }
} }
} while(progress); }
while (progress);
} }
void init(const lp::lar_solver& s) { void init(const lp::lar_solver& s) {
@ -252,8 +251,9 @@ struct solver::imp {
return r == model_val; return r == model_val;
} }
/**
* \brief <TBD say what this function does>
*/
bool generate_basic_lemma_for_mon_sign_var_other_mon( bool generate_basic_lemma_for_mon_sign_var_other_mon(
unsigned i_mon, unsigned i_mon,
unsigned j_var, unsigned j_var,
@ -286,12 +286,21 @@ struct solver::imp {
m_vars_equivalence.add_explanation_of_reducing_to_mininal_monomial(m, eset); m_vars_equivalence.add_explanation_of_reducing_to_mininal_monomial(m, eset);
} }
void print_monomial(const mon_eq& m, std::ostream& out) { std::ostream& print_monomial(const mon_eq& m, std::ostream& out) {
out << m_lar_solver.get_column_name(m.var()) << " = "; out << m_lar_solver.get_column_name(m.var()) << " = ";
for (unsigned j : m) { for (unsigned j : m) {
out << m_lar_solver.get_column_name(j) << "*"; out << m_lar_solver.get_column_name(j) << "*";
} }
return out;
} }
std::ostream& print_explanation(std::ostream& out) {
for (auto &p : *m_expl) {
m_lar_solver.print_constraint(p.second, out) << "\n";
}
return out;
}
// the monomials should be equal by modulo sign, but they are not equal in the model module sign // the monomials should be equal by modulo sign, but they are not equal in the model module sign
void fill_explanation_and_lemma_sign(const mon_eq& a, const mon_eq & b, int sign) { void fill_explanation_and_lemma_sign(const mon_eq& a, const mon_eq & b, int sign) {
expl_set expl; expl_set expl;
@ -300,25 +309,23 @@ struct solver::imp {
add_explanation_of_reducing_to_mininal_monomial(b, expl); add_explanation_of_reducing_to_mininal_monomial(b, expl);
m_expl->clear(); m_expl->clear();
m_expl->add(expl); m_expl->add(expl);
TRACE("niil_solver", TRACE("niil_solver", print_explanation(tout););
for (auto &p : *m_expl)
m_lar_solver.print_constraint(p.second, tout); tout << "\n";
);
lp::lar_term t; lp::lar_term t;
t.add_monomial(rational(1), a.var()); t.add_monomial(rational(1), a.var());
t.add_monomial(rational(- sign), b.var()); t.add_monomial(rational(- sign), b.var());
TRACE("niil_solver", TRACE("niil_solver",
m_lar_solver.print_term(t, tout); m_lar_solver.print_term(t, tout) << "\n";
tout << "\n"; print_monomial(a, tout) << "\n";
print_monomial(a, tout); print_monomial(b, tout) << "\n";
tout << "\n";
print_monomial(b, tout);
); );
ineq in(lp::lconstraint_kind::NE, t); ineq in(lp::lconstraint_kind::NE, t);
m_lemma->push_back(in); m_lemma->push_back(in);
} }
/**
* \brief <TBD say what this function does>
*/
bool generate_basic_lemma_for_mon_sign_var(unsigned i_mon, bool generate_basic_lemma_for_mon_sign_var(unsigned i_mon,
unsigned j_var, const svector<lpvar>& mon_vars, int sign) { unsigned j_var, const svector<lpvar>& mon_vars, int sign) {
auto it = m_var_lists.find(j_var); auto it = m_var_lists.find(j_var);
@ -436,7 +443,7 @@ struct solver::imp {
for (lpvar j : m.m_vs) { for (lpvar j : m.m_vs) {
int s = get_mon_sign_zero_var(j, strict); int s = get_mon_sign_zero_var(j, strict);
if (s == 2) if (s == 2)
return 2;; return 2;
if (s == 0) if (s == 0)
return 0; return 0;
sign *= s; sign *= s;
@ -480,12 +487,11 @@ struct solver::imp {
m_lemma->push_back(in); m_lemma->push_back(in);
TRACE("niil_solver", TRACE("niil_solver",
tout << "used constraints:\n"; tout << "used constraints:\n";
for (auto &p : *m_expl) print_explanation(tout);
m_lar_solver.print_constraint(p.second, tout);
tout << "derived constraint "; tout << "derived constraint ";
m_lar_solver.print_term(t, tout); m_lar_solver.print_term(t, tout);
tout << " " << lp::lconstraint_kind_string(kind) << " 0\n"; tout << " " << lp::lconstraint_kind_string(kind) << " 0\n";
print_monomial(m_monomials[i_mon], tout); tout << "\n"; print_monomial(m_monomials[i_mon], tout) << "\n";
lpvar mon_var = m_monomials[i_mon].var(); lpvar mon_var = m_monomials[i_mon].var();
tout << m_lar_solver.get_column_name(mon_var) << " = " << m_lar_solver.get_column_value(mon_var); tout << m_lar_solver.get_column_name(mon_var) << " = " << m_lar_solver.get_column_value(mon_var);
@ -495,6 +501,9 @@ struct solver::imp {
return true; return true;
} }
/**
* \brief <TBD say what this function does>
*/
bool get_one_of_var(unsigned i, lpvar j, mono_index_with_sign & mi) { bool get_one_of_var(unsigned i, lpvar j, mono_index_with_sign & mi) {
lpci lci; lpci lci;
lpci uci; lpci uci;
@ -526,9 +535,9 @@ struct solver::imp {
vector<mono_index_with_sign> ret; vector<mono_index_with_sign> ret;
for (unsigned i = 0; i < vars.size(); i++) { for (unsigned i = 0; i < vars.size(); i++) {
mono_index_with_sign mi; mono_index_with_sign mi;
if (!get_one_of_var(i, vars[i], mi)) if (get_one_of_var(i, vars[i], mi)) {
continue; ret.push_back(mi);
ret.push_back(mi); }
} }
return ret; return ret;
} }
@ -537,31 +546,33 @@ struct solver::imp {
void get_large_and_small_indices_of_monomimal(const mon_eq& m, void get_large_and_small_indices_of_monomimal(const mon_eq& m,
vector<unsigned> & large, vector<unsigned> & large,
vector<unsigned> & _small) { vector<unsigned> & _small) {
for (unsigned i = 0; i < m.m_vs.size(); i++) { for (unsigned i = 0; i < m.m_vs.size(); ++i) {
unsigned j = m.m_vs[i]; unsigned j = m.m_vs[i];
lp::constraint_index lci = -1, uci = -1; lp::constraint_index lci = -1, uci = -1;
rational lb, ub; rational lb, ub;
bool is_strict; bool is_strict;
if (m_lar_solver.has_lower_bound(j, lci, lb, is_strict)) { if (m_lar_solver.has_lower_bound(j, lci, lb, is_strict) && !is_strict) {
SASSERT(!is_strict);
if (lb >= rational(1)) { if (lb >= rational(1)) {
large.push_back(i); large.push_back(i);
} }
} }
if (m_lar_solver.has_upper_bound(j, uci, ub, is_strict)) { if (m_lar_solver.has_upper_bound(j, uci, ub, is_strict) && !is_strict) {
SASSERT(!is_strict);
if (ub <= -rational(1)) { if (ub <= -rational(1)) {
large.push_back(i); large.push_back(i);
} }
} }
if (is_set(lci) && is_set(uci) && -rational(1) <= lb && ub <= rational(1)) if (is_set(lci) && is_set(uci) && -rational(1) <= lb && ub <= rational(1)) {
_small.push_back(i); _small.push_back(i);
}
} }
} }
// v is the value of monomial, vars is the array of reduced to minimum variables of the monomial /**
* \brief <TBD say what this function does>
* v is the value of monomial, vars is the array of reduced to minimum variables of the monomial
*/
bool generate_basic_neutral_for_reduced_monomial(const mon_eq & m, const rational & v, const svector<lpvar> & vars) { bool generate_basic_neutral_for_reduced_monomial(const mon_eq & m, const rational & v, const svector<lpvar> & vars) {
vector<mono_index_with_sign> ones_of_mon = get_ones_of_monomimal(vars); vector<mono_index_with_sign> ones_of_mon = get_ones_of_monomimal(vars);
@ -575,7 +586,9 @@ struct solver::imp {
return process_ones_of_mon(m, ones_of_mon, vars, v); return process_ones_of_mon(m, ones_of_mon, vars, v);
} }
/**
* \brief <TBD say what this function does>
*/
bool generate_basic_lemma_for_mon_neutral(unsigned i_mon) { bool generate_basic_lemma_for_mon_neutral(unsigned i_mon) {
std::cout << "generate_basic_lemma_for_mon_neutral\n"; std::cout << "generate_basic_lemma_for_mon_neutral\n";
const mon_eq & m = m_monomials[i_mon]; const mon_eq & m = m_monomials[i_mon];
@ -629,16 +642,12 @@ struct solver::imp {
for (unsigned k : mask) { for (unsigned k : mask) {
add_explanation_of_one(ones_of_monomial[k]); add_explanation_of_one(ones_of_monomial[k]);
} }
TRACE("niil_solver", TRACE("niil_solver", print_explanation(tout););
for (auto &p : *m_expl)
m_lar_solver.print_constraint(p.second, tout); tout << "\n";
);
lp::lar_term t; lp::lar_term t;
t.add_monomial(rational(1), m.var()); t.add_monomial(rational(1), m.var());
t.add_monomial(rational(- sign), j); t.add_monomial(rational(- sign), j);
TRACE("niil_solver", TRACE("niil_solver",
m_lar_solver.print_term(t, tout); m_lar_solver.print_term(t, tout) << "\n";
tout << "\n";
); );
ineq in(lp::lconstraint_kind::EQ, t); ineq in(lp::lconstraint_kind::EQ, t);
@ -652,7 +661,7 @@ struct solver::imp {
svector<unsigned> mask(ones_of_monomial.size(), (unsigned) 0); svector<unsigned> mask(ones_of_monomial.size(), (unsigned) 0);
auto vars = min_vars; auto vars = min_vars;
int sign = 1; int sign = 1;
// We crossing out the ones representing the mask from vars // We cross out the ones representing the mask from vars
do { do {
for (unsigned k = 0; k < mask.size(); k++) { for (unsigned k = 0; k < mask.size(); k++) {
if (mask[k] == 0) { if (mask[k] == 0) {
@ -674,7 +683,8 @@ struct solver::imp {
vars.push_back(min_vars[ones_of_monomial[k].m_i]); // vars becomes unsorted vars.push_back(min_vars[ones_of_monomial[k].m_i]); // vars becomes unsorted
} }
} }
} while(true); }
while(true);
return false; // we exhausted the mask and did not find the compliment monomial return false; // we exhausted the mask and did not find the compliment monomial
} }
@ -790,7 +800,7 @@ struct solver::imp {
to_refine.push_back(i); to_refine.push_back(i);
} }
if (to_refine.size() == 0) if (to_refine.empty())
return l_true; return l_true;
TRACE("niil_solver", tout << "to_refine.size() = " << to_refine.size() << std::endl;); TRACE("niil_solver", tout << "to_refine.size() = " << to_refine.size() << std::endl;);
@ -815,17 +825,32 @@ lbool solver::check(lp::explanation & ex, lemma& l) {
} }
void solver::push(){ }; // end of imp
m_imp->push();
}
void solver::pop(unsigned n) {
m_imp->pop(n);
}
void solver::add_monomial(lpvar v, unsigned sz, lpvar const* vs) {
m_imp->add(v, sz, vs);
}
bool solver::need_check() { return true; }
lbool solver::check(lp::explanation & ex, lemma& l) {
return m_imp->check(ex, l);
}
void solver::push(){
m_imp->push();
}
solver::solver(lp::lar_solver& s, reslimit& lim, params_ref const& p) { void solver::pop(unsigned n) {
m_imp = alloc(imp, s, lim, p); m_imp->pop(n);
} }
solver::solver(lp::lar_solver& s, reslimit& lim, params_ref const& p) {
m_imp = alloc(imp, s, lim, p);
}
solver::~solver() {
dealloc(m_imp);
}
} }

View file

@ -36,12 +36,12 @@ typedef vector<ineq> lemma;
// nonlinear integer incremental linear solver // nonlinear integer incremental linear solver
class solver { class solver {
public:
struct imp; struct imp;
imp* m_imp; imp* m_imp;
public:
void add_monomial(lp::var_index v, unsigned sz, lp::var_index const* vs); void add_monomial(lp::var_index v, unsigned sz, lp::var_index const* vs);
solver(lp::lar_solver& s, reslimit& lim, params_ref const& p); solver(lp::lar_solver& s, reslimit& lim, params_ref const& p);
imp* get_imp(); ~solver();
void push(); void push();
void pop(unsigned scopes); void pop(unsigned scopes);
bool need_check(); bool need_check();