3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-15 05:18:44 +00:00

debug order lemma, introduce sign for factors

Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
This commit is contained in:
Lev Nachmanson 2019-05-05 11:12:50 -07:00
parent 218e155603
commit 54ba889b7b
8 changed files with 85 additions and 301 deletions

View file

@ -493,6 +493,8 @@ namespace smt {
TRACE("lemma", tout << strm.str() << "\n";);
display_lemma_as_smt_problem(out, num_antecedents, antecedents, num_eq_antecedents, eq_antecedents, consequent, logic);
out.close();
if (m_lemma_id==6184)
exit(0);
return m_lemma_id;
}

View file

@ -14,7 +14,7 @@ void const_iterator_mon::init_vars_by_the_mask(unsigned_vector & k_vars, unsigne
}
}
}
// todo : do we need the sign?
bool const_iterator_mon::get_factors(factor& k, factor& j, rational& sign) const {
unsigned_vector k_vars;
unsigned_vector j_vars;
@ -30,7 +30,7 @@ bool const_iterator_mon::get_factors(factor& k, factor& j, rational& sign) const
if (!m_ff->find_rm_monomial_of_vars(k_vars, i)) {
return false;
}
k.set(i, factor_type::RM);
k.set(i, factor_type::MON);
}
if (j_vars.size() == 1) {
@ -40,7 +40,7 @@ bool const_iterator_mon::get_factors(factor& k, factor& j, rational& sign) const
if (!m_ff->find_rm_monomial_of_vars(j_vars, i)) {
return false;
}
j.set(i, factor_type::RM);
j.set(i, factor_type::MON);
}
return true;
}

View file

@ -27,14 +27,16 @@ namespace nla {
struct factorization_factory;
typedef unsigned lpvar;
enum class factor_type { VAR, RM }; // RM stands for rooted monomial
enum class factor_type { VAR, MON };
class factor {
lpvar m_var;
factor_type m_type;
bool m_sign;
public:
factor(): m_var(UINT_MAX), m_type(factor_type::VAR) {}
explicit factor(lpvar v, factor_type t) : m_var(v), m_type(t) {}
factor(): factor(false) {}
factor(bool sign): m_var(UINT_MAX), m_type(factor_type::VAR), m_sign(sign) {}
explicit factor(lpvar v, factor_type t) : m_var(v), m_type(t), m_sign(false) {}
unsigned var() const { return m_var; }
factor_type type() const { return m_type; }
void set(lpvar v, factor_type t) { m_var = v; m_type = t; }
@ -45,6 +47,9 @@ public:
bool operator!=(factor const& other) const {
return m_var != other.var() || m_type != other.type();
}
bool sign() const { return m_sign; }
bool& sign() { return m_sign; }
rational rsign() const { return m_sign? rational(-1) : rational(1); }
};

View file

@ -36,7 +36,6 @@ template <typename T> rational common::val(T const& t) const { return c().val(t)
template rational common::val<monomial>(monomial const& t) const;
template rational common::val<factor>(factor const& t) const;
rational common::val(lpvar t) const { return c().val(t); }
rational common::rval(const monomial& m) const { return c().rval(m); }
template <typename T> lpvar common::var(T const& t) const { return c().var(t); }
template lpvar common::var<factor>(factor const& t) const;
template lpvar common::var<monomial>(monomial const& t) const;

View file

@ -76,10 +76,14 @@ bool core::lemma_holds(const lemma& l) const {
}
return false;
}
lpvar core::map_to_root(lpvar j) const {
return m_evars.find(j).var();
}
svector<lpvar> core::sorted_vars(const factor& f) const {
svector<lpvar> core::sorted_rvars(const factor& f) const {
if (f.is_var()) {
svector<lpvar> r; r.push_back(f.var());
svector<lpvar> r; r.push_back(map_to_root(f.var()));
return r;
}
TRACE("nla_solver", tout << "nv";);
@ -89,14 +93,23 @@ svector<lpvar> core::sorted_vars(const factor& f) const {
// the value of the factor is equal to the value of the variable multiplied
// by the canonize_sign
rational core::canonize_sign(const factor& f) const {
return f.is_var()? canonize_sign_of_var(f.var()) : m_emons[f.var()].rsign();
return f.rsign() * (f.is_var()? canonize_sign_of_var(f.var()) : m_emons[f.var()].rsign());
}
rational core::canonize_sign_of_var(lpvar j) const {
return m_evars.find(j).rsign();
}
bool core::canonize_sign_is_correct(const monomial& m) const {
rational r(1);
for (lpvar j : m.vars()) {
r *= canonize_sign_of_var(j);
}
return r == m.rsign();
}
rational core::canonize_sign(const monomial& m) const {
SASSERT(canonize_sign_is_correct(m));
return m.rsign();
}
@ -157,11 +170,13 @@ std::ostream& core::print_product(const T & m, std::ostream& out) const {
}
std::ostream & core::print_factor(const factor& f, std::ostream& out) const {
if (f.sign())
out << "- ";
if (f.is_var()) {
out << "VAR, ";
print_var(f.var(), out);
} else {
out << "PROD, ";
out << "MON, ";
print_product(m_emons[f.var()].rvars(), out);
}
out << "\n";
@ -1372,30 +1387,38 @@ std::unordered_set<lpvar> core::collect_vars(const lemma& l) const {
return vars;
}
// divides bc by c, so bc = b*c
bool core::divide(const monomial& bc, const factor& c, factor & b) const {
svector<lpvar> c_vars = sorted_vars(c);
TRACE("nla_solver_div",
tout << "c_vars = ";
print_product(c_vars, tout);
tout << "\nbc_vars = ";
svector<lpvar> c_rvars = sorted_rvars(c);
TRACE("nla_solver",
tout << "c_rvars = ";
print_product(c_rvars, tout);
tout << "\nbc_rvars = ";
print_product(bc.rvars(), tout););
if (!lp::is_proper_factor(c_vars, bc.rvars()))
if (!lp::is_proper_factor(c_rvars, bc.rvars()))
return false;
auto b_vars = lp::vector_div(bc.rvars(), c_vars);
TRACE("nla_solver_div", tout << "b_vars = "; print_product(b_vars, tout););
SASSERT(b_vars.size() > 0);
if (b_vars.size() == 1) {
b = factor(b_vars[0], factor_type::VAR);
return true;
auto b_rvars = lp::vector_div(bc.rvars(), c_rvars);
TRACE("nla_solver_div", tout << "b_rvars = "; print_product(b_rvars, tout););
SASSERT(b_rvars.size() > 0);
if (b_rvars.size() == 1) {
b = factor(b_rvars[0], factor_type::VAR);
} else {
monomial const* sv = m_emons.find_canonical(b_rvars);
if (!sv) {
TRACE("nla_solver_div", tout << "not in rooted";);
return false;
}
b = factor(sv->var(), factor_type::MON);
}
monomial const* sv = m_emons.find_canonical(b_vars);
if (!sv) {
TRACE("nla_solver_div", tout << "not in rooted";);
return false;
}
b = factor(sv->var(), factor_type::RM);
TRACE("nla_solver_div", tout << "success div:"; print_factor(b, tout););
SASSERT(!b.sign());
// we should have bc.vars()*canonize_sign(bc) = bc.rvar() = b.rvars()*c.rvars() =
// = canonize_sign(b)*b.vars()* canonize_sign(c)*c.vars().
// so bc.vars()*canonize_sign(bc) = canonize_sign(b)*b.vars()* canonize_sign(c)*c.vars().
// but canonize_sign(b) now is canonize_sign_of_var(b.m_var) or canonize_sign(m_monomials[b.m_var])
// so we are adjusting it
b.sign() = (canonize_sign(b) * canonize_sign(c) * canonize_sign(bc) == rational(1))? false: true;
TRACE("nla_solver", tout << "success div:"; print_factor(b, tout););
return true;
}
@ -1468,8 +1491,8 @@ void core::maybe_add_a_factor(lpvar i,
}
} else {
if (try_insert(i, found_rm)) {
r.push_back(factor(i, factor_type::RM));
TRACE("nla_solver", tout << "inserting factor = "; print_factor_with_vars(factor(i, factor_type::RM), tout); );
r.push_back(factor(i, factor_type::MON));
TRACE("nla_solver", tout << "inserting factor = "; print_factor_with_vars(factor(i, factor_type::MON), tout); );
}
}
}

View file

@ -100,17 +100,17 @@ public:
rational val(const monomial& m) const { return m_lar_solver.get_column_value_rational(m.var()); }
rational rval(const monomial& m) const { return val(m)*m.rsign(); }
bool canonize_sign_is_correct(const monomial& m) const;
lpvar var(monomial const& sv) const { return sv.var(); }
rational val_rooted(const monomial& m) const { return m.rsign()*val(m.var()); }
rational val(const factor& f) const { return f.is_var()? val(f.var()) : val(m_emons[f.var()]); }
rational val(const factor& f) const { return f.rsign() * (f.is_var()? val(f.var()) : val(m_emons[f.var()])); }
lpvar var(const factor& f) const { return f.var(); }
svector<lpvar> sorted_vars(const factor& f) const;
svector<lpvar> sorted_rvars(const factor& f) const;
bool done() const;
void add_empty_lemma();
@ -338,6 +338,7 @@ public:
bool no_lemmas_hold() const;
lbool test_check(vector<lemma>& l);
lpvar map_to_root(lpvar) const;
}; // end of core
struct pp_mon {

View file

@ -95,14 +95,15 @@ void order::order_lemma_on_binomial_sign(const monomial& xy, lpvar x, lpvar y, i
}
// We look for monomials e = m.rvars()[k]*d and see if we can create an order lemma for m and e
void order::order_lemma_on_factor_binomial_explore(const monomial& m, bool k) {
TRACE("nla_solver", tout << "m = " << pp_rmon(c(), m););
SASSERT(m.size() == 2);
lpvar c = m.vars()[k];
void order::order_lemma_on_factor_binomial_explore(const monomial& ac, bool k) {
TRACE("nla_solver", tout << "ac = " << pp_rmon(c(), ac););
SASSERT(ac.size() == 2);
lpvar c = ac.vars()[k];
for (monomial const& m2 : _().m_emons.get_products_of(c)) {
TRACE("nla_solver", tout << "m2 = " << pp_rmon(_(), m2););
order_lemma_on_factor_binomial_rm(m, k, m2);
for (monomial const& bd : _().m_emons.get_products_of(c)) {
if (bd.var() == ac.var()) continue;
TRACE("nla_solver", tout << "bd = " << pp_rmon(_(), bd););
order_lemma_on_factor_binomial_rm(ac, k, bd);
if (done()) {
break;
}
@ -118,18 +119,19 @@ void order::order_lemma_on_factor_binomial_rm(const monomial& ac, bool k, const
tout << "bd=" << pp_rmon(_(), bd) << "\n";
);
factor d(_().m_evars.find(ac.vars()[k]).var(), factor_type::VAR);
factor b;
factor b(false);
if (c().divide(bd, d, b)) {
order_lemma_on_binomial_ac_bd(ac, k, bd, b, d.var());
}
}
// suppose ac >= bd and |c| = |d| => then ac/|c| >= bd/|d|
// ac >= bd && |c| = |d| => ac/|c| >= bd/|d|
void order::order_lemma_on_binomial_ac_bd(const monomial& ac, bool k, const monomial& bd, const factor& b, lpvar d) {
TRACE("nla_solver",
tout << "ac=" << pp_rmon(_(), ac) << "\nrm= " << pp_rmon(_(), bd) << ", b= " << pp_fac(_(), b) << ", d= " << pp_var(_(), d) << "\n";);
lpvar a = ac.vars()[!k];
lpvar c = ac.vars()[k];
TRACE("nla_solver",
tout << "ac = " << pp_mon(_(), ac) << "a = " << pp_var(_(), a) << "c = " << pp_var(_(), c) << "\nbd = " << pp_mon(_(), bd) << "b = " << pp_fac(_(), b) << "d = " << pp_var(_(), d) << "\n";
);
SASSERT(_().m_evars.find(c).var() == d);
rational acv = val(ac);
rational av = val(a);
@ -139,7 +141,10 @@ void order::order_lemma_on_binomial_ac_bd(const monomial& ac, bool k, const mono
rational bv = val(b);
// Notice that ac/|c| = a*c_sign , and bd/|d| = b*d_sign
auto av_c_s = av*c_sign; auto bv_d_s = bv*d_sign;
TRACE("nla_solver",
tout << "acv = " << acv << ", av = " << av << ", c_sign = " << c_sign << ", d_sign = " << d_sign << ", bdv = " << bdv <<
"\nbv = " << bv << ", av_c_s = " << av_c_s << ", bv_d_s = " << bv_d_s << "\n";);
if (acv >= bdv && av_c_s < bv_d_s)
generate_mon_ol(ac, a, c_sign, c, bd, b, d_sign, d, llc::LT);
else if (acv <= bdv && av_c_s > bv_d_s)
@ -198,7 +203,7 @@ bool order::order_lemma_on_ac_and_bc(const monomial& rm_ac,
tout << "rm_bd = " << pp_rmon(_(), rm_bd) << "\n";
tout << "ac_f[k] = ";
c().print_factor_with_vars(ac_f[k], tout););
factor b;
factor b(false);
return
c().divide(rm_bd, ac_f[k], b) &&
order_lemma_on_ac_and_bc_and_factors(rm_ac, ac_f[!k], ac_f[k], rm_bd, b);
@ -218,7 +223,7 @@ void order::order_lemma_on_factorization(const monomial& m, const factorization&
if (mv == fv)
return;
bool gt = mv > fv;
TRACE("nla_solver_f", tout << "m="; _().print_monomial_with_vars(m, tout); tout << "\nfactorization="; _().print_factorization(ab, tout););
TRACE("nla_solver", tout << "m="; _().print_monomial_with_vars(m, tout); tout << "\nfactorization="; _().print_factorization(ab, tout););
for (unsigned j = 0, k = 1; j < 2; j++, k--) {
order_lemma_on_ab(m, sign, var(ab[k]), var(ab[j]), gt);
explain(ab); explain(m);

View file

@ -1,251 +0,0 @@
/*++
Copyright (c) 2017 Microsoft Corporation
Module Name:
<name>
Abstract:
<abstract>
Author:
Nikolaj Bjorner (nbjorner)
Lev Nachmanson (levnach)
Revision History:
--*/
namespace nla {
typedef lp::constraint_index lpci;
typedef lp::explanation expl_set;
typedef lp::var_index lpvar;
struct hash_svector {
size_t operator()(const unsigned_vector & v) const {
return svector_hash<unsigned_hash>()(v);
}
};
struct vars_equivalence {
struct equiv {
lpvar m_i;
lpvar m_j;
rational m_sign;
lpci m_c0;
lpci m_c1;
equiv(lpvar i, lpvar j, rational const& sign, lpci c0, lpci c1) :
m_i(i),
m_j(j),
m_sign(sign),
m_c0(c0),
m_c1(c1) {
SASSERT(m_i != m_j);
}
};
struct node {
unsigned m_parent; // points to m_equivs
svector<unsigned> m_children; // point to m_equivs
node() : m_parent(-1) {}
};
//fields
// The map from the variables to m_nodes
// m_tree is a spanning tree of the graph of equivs represented by m_equivs
std::unordered_map<unsigned, node> m_tree;
// If m_tree[v] == -1 then the variable is a root.
// if m_tree[v] is not equal to -1 then m_equivs[m_tree[v]] = (k, v) or (v, k), where k is the parent of v
vector<equiv> m_equivs; // all equivalences extracted from constraints
std::function<rational(lpvar)> m_val;
// constructor
vars_equivalence(std::function<rational(lpvar)> val) : m_val(val) {}
void clear() {
m_equivs.clear();
m_tree.clear();
}
// j itself is also included
svector<lpvar> eq_vars(lpvar j) const {
svector<lpvar> r = path_to_root(j);
r.append(children(j));
r.push_back(j);
return r;
}
svector<lpvar> children(lpvar j) const {
svector<lpvar> r;
auto it = m_tree.find(j);
if (it == m_tree.end())
return r;
const node& n = it->second;
for (unsigned e_k: n.m_children) {
const equiv & e = m_equivs[e_k];
lpvar oj = e.m_i == j? e.m_j : e.m_i;
r.push_back(oj);
for (lpvar k : children(oj)) {
r.push_back(k);
}
}
return r;
}
svector<lpvar> path_to_root(lpvar j) const {
svector<lpvar> r;
while (true) {
auto it = m_tree.find(j);
if (it == m_tree.end() || it->second.m_parent == static_cast<unsigned>(-1))
return r;
const equiv & e = m_equivs[it->second.m_parent];
j = get_parent_node(j, e);
r.push_back(j);
}
SASSERT(false);
}
unsigned size() const { return static_cast<unsigned>(m_tree.size()); }
// we create a spanning tree on all variables participating in an equivalence
void create_tree() {
for (unsigned k = 0; k < m_equivs.size(); k++)
connect_equiv_to_tree(k);
}
void add_equiv(lpvar i, lpvar j, rational const& sign, lpci c0, lpci c1) {
m_equivs.push_back(equiv(i, j, sign, c0, c1));
}
void connect_equiv_to_tree(unsigned k) {
// m_tree is the tree with the edges formed by m_equivs
const equiv &e = m_equivs[k];
TRACE("nla_vars_eq", tout << "m_i = " << e.m_i << ", " << "m_j = " << e.m_j ;);
auto it_i = m_tree.find(e.m_i);
auto it_j = m_tree.find(e.m_j);
bool i_is_in = it_i != m_tree.end();
bool j_is_in = it_j != m_tree.end();
if (!(i_is_in || j_is_in)) {
// none of the edge vertices is in the tree
// let m_i be the parent, and m_j be the child
TRACE("nla_vars_eq", tout << "create nodes for " << e.m_i << " and " << e.m_j; );
node parent;
node child;
child.m_parent = k;
parent.m_children.push_back(k);
m_tree.emplace(e.m_i, parent);
m_tree.emplace(e.m_j, child);
} else if (i_is_in && (!j_is_in)) {
// create a node for m_j, with m_i is the parent
node child;
child.m_parent = k;
TRACE("nla_vars_eq", tout << "create a node for " << e.m_j; );
m_tree.emplace(e.m_j, child);
it_i->second.m_children.push_back(k);
} else if ((!i_is_in) && j_is_in) {
TRACE("nla_vars_eq", tout << "create a node for " << e.m_i; );
node child;
child.m_parent = k;
m_tree.emplace(e.m_i, child);
it_j->second.m_children.push_back(k);
} else {
TRACE("nla_vars_eq", tout << "both vertices are in the tree";);
}
}
bool empty() const {
return m_tree.empty();
}
bool is_root(unsigned j) const {
auto it = m_tree.find(j);
if (it == m_tree.end())
return true;
return it->second.m_parent == static_cast<unsigned>(-1);
}
static unsigned get_parent_node(unsigned j, const equiv& e) {
SASSERT(e.m_i == j || e.m_j == j);
return e.m_i == j? e.m_j : e.m_i;
}
bool vars_are_equiv(lpvar a, lpvar b) const {
return map_to_root(a) == map_to_root(b);
}
// Finds the root var which is equivalent to j.
// The sign is flipped if needed
lpvar map_to_root(lpvar j, rational& sign) const {
TRACE("nla_vars_eq", tout << "j = " << j << "\n";);
while (true) {
auto it = m_tree.find(j);
if (it == m_tree.end())
return j;
if (it->second.m_parent == static_cast<unsigned>(-1)) {
TRACE("nla_vars_eq", tout << "mapped to " << j << "\n";);
return j;
}
const equiv & e = m_equivs[it->second.m_parent];
sign *= e.m_sign;
j = get_parent_node(j, e);
}
}
// Finds the root var which is equivalent to j.
// The sign is flipped if needed
lpvar map_to_root(lpvar j) const {
while (true) {
auto it = m_tree.find(j);
if (it == m_tree.end())
return j;
if (it->second.m_parent == static_cast<unsigned>(-1))
return j;
const equiv & e = m_equivs[it->second.m_parent];
j = get_parent_node(j, e);
}
}
template <typename T>
void explain(const T& collection, expl_set & exp) const {
for (lpvar j : collection) {
explain(j, exp);
}
}
void explain(lpvar j, expl_set& exp) const {
while (true) {
auto it = m_tree.find(j);
if (it == m_tree.end())
return;
if (it->second.m_parent == static_cast<unsigned>(-1))
return;
const equiv & e = m_equivs[it->second.m_parent];
exp.add(e.m_c0);
exp.add(e.m_c1);
j = get_parent_node(j, e);
}
}
template <typename T>
void add_explanation_of_reducing_to_rooted_monomial(const T & m, expl_set & exp) const {
for (lpvar j : m)
explain(j, exp);
}
}; // end of vars_equivalence
}