3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-28 03:15:50 +00:00

port to emonomials (#90)

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2019-04-18 13:17:24 -07:00 committed by Lev Nachmanson
parent b52e79b648
commit e28e83a25e
20 changed files with 666 additions and 683 deletions

View file

@ -36,17 +36,18 @@ namespace nla {
svector<lpvar> m_vars;
bool m_sign;
public:
signed_vars() : m_sign(false) {}
signed_vars(lpvar v) : m_var(v), m_sign(false) {}
lpvar var() const { return m_var; }
svector<lpvar> const& vars() const { return m_vars; }
svector<lp::var_index>::const_iterator begin() const { return vars().begin(); }
svector<lp::var_index>::const_iterator end() const { return vars().end(); }
unsigned size() const { return m_vars.size(); }
lpvar operator[](unsigned i) const { return m_vars[i]; }
bool sign() const { return m_sign; }
void set_sign(bool s) { m_sign = s; }
void set_var(lpvar v) { m_var = v; }
void set_vars(unsigned n, lpvar const* vars) {
m_vars.reset();
m_vars.append(n, vars);
rational rsign() const { return rational(m_sign ? -1 : 1); }
void reset() { m_sign = false; m_vars.reset(); }
void push_var(signed_var sv) { m_sign ^= sv.sign(); m_vars.push_back(sv.var()); }
void done_push() {
std::sort(m_vars.begin(), m_vars.end());
}
std::ostream& display(std::ostream& out) const {
@ -61,15 +62,6 @@ namespace nla {
class emonomials : public var_eqs_merge_handler {
/**
\brief private fields used by emonomials for maintaining state of canonized monomials.
*/
class signed_vars_ts : public signed_vars {
public:
signed_vars_ts(): m_canonical(0), m_visited(0) {}
unsigned m_canonical;
unsigned m_visited;
};
/**
\brief singly-lined cyclic list of monomial indices where variable occurs.
@ -90,24 +82,64 @@ namespace nla {
cell* m_tail;
};
var_eqs& m_ve;
vector<monomial> m_monomials; // set of monomials
unsigned_vector m_lim; // backtracking point
unsigned_vector m_var2index; // var_mIndex -> mIndex
unsigned m_canonical; // timestamp of last merge
mutable unsigned m_visited; // timestamp of visited monomials during pf_iterator
region m_region; // region for allocating linked lists
mutable vector<signed_vars_ts> m_canonized; // canonized versions of signed variables
mutable svector<lpvar> m_vars; // temporary vector of variables
mutable svector<head_tail> m_use_lists; // use list of monomials where variables occur.
void inc_canonical();
/**
\brief private fields used by emonomials for maintaining state of canonized monomials.
*/
class signed_vars_ts : public signed_vars {
public:
signed_vars_ts(lpvar v, unsigned idx): signed_vars(v), m_next(idx), m_prev(idx), m_visited(0) {}
unsigned m_next; // next congruent node.
unsigned m_prev; // previous congruent node
mutable unsigned m_visited;
};
struct hash_canonical {
emonomials& em;
hash_canonical(emonomials& em): em(em) {}
unsigned operator()(lpvar v) const {
auto const& vec = em.m_canonized[em.m_var2index[v]].vars();
return string_hash(reinterpret_cast<char const*>(vec.c_ptr()), sizeof(lpvar)*vec.size(), 10);
}
};
struct eq_canonical {
emonomials& em;
eq_canonical(emonomials& em): em(em) {}
bool operator()(lpvar u, lpvar v) const {
auto const& uvec = em.m_canonized[em.m_var2index[u]].vars();
auto const& vvec = em.m_canonized[em.m_var2index[v]].vars();
return uvec == vvec;
}
};
var_eqs& m_ve;
mutable vector<monomial> m_monomials; // set of monomials
mutable unsigned_vector m_var2index; // var_mIndex -> mIndex
unsigned_vector m_lim; // backtracking point
mutable unsigned m_visited; // timestamp of visited monomials during pf_iterator
region m_region; // region for allocating linked lists
mutable vector<signed_vars_ts> m_canonized; // canonized versions of signed variables
mutable svector<head_tail> m_use_lists; // use list of monomials where variables occur.
hash_canonical m_cg_hash;
eq_canonical m_cg_eq;
hashtable<lpvar, hash_canonical, eq_canonical> m_cg_table; // congruence (canonical) table.
void inc_visited() const;
void remove_var2monomials(lpvar v, unsigned mIndex);
void insert_var2monomials(lpvar v, unsigned mIndex);
void merge_var2monomials(lpvar root, lpvar other);
void unmerge_var2monomials(lpvar root, lpvar other);
void remove_cell(head_tail& v, unsigned mIndex);
void insert_cell(head_tail& v, unsigned mIndex);
void merge_cells(head_tail& root, head_tail& other);
void unmerge_cells(head_tail& root, head_tail& other);
void remove_cg(lpvar v);
void insert_cg(lpvar v);
void insert_cg(unsigned idx, monomial const& m);
void remove_cg(unsigned idx, monomial const& m);
void rehash_cg(lpvar v) { remove_cg(v); insert_cg(v); }
void do_canonize(monomial const& m) const;
cell* head(lpvar v) const;
void set_visited(monomial const& m) const;
@ -119,7 +151,15 @@ namespace nla {
push and pop on emonomials calls push/pop on var_eqs, so no
other calls to push/pop to the var_eqs should take place.
*/
emonomials(var_eqs& ve): m_ve(ve), m_canonical(1), m_visited(0) { m_ve.set_merge_handler(this); }
emonomials(var_eqs& ve):
m_ve(ve),
m_visited(0),
m_cg_hash(*this),
m_cg_eq(*this),
m_cg_table(DEFAULT_HASHTABLE_INITIAL_CAPACITY, m_cg_hash, m_cg_eq),
canonical(*this) {
m_ve.set_merge_handler(this);
}
/**
\brief push/pop scopes.
@ -140,13 +180,42 @@ namespace nla {
/**
\brief retrieve monomial corresponding to variable v from definition v := vs
*/
monomial const* var2monomial(lpvar v) const { unsigned idx = m_var2index.get(v, UINT_MAX); return idx == UINT_MAX ? nullptr : &m_monomials[idx]; }
monomial const& var2monomial(lpvar v) const { SASSERT(is_monomial_var(v)); return m_monomials[m_var2index[v]]; }
monomial const& operator[](lpvar v) const { return var2monomial(v); }
bool is_monomial_var(lpvar v) const { return m_var2index.get(v, UINT_MAX) != UINT_MAX; }
/**
\brief retrieve canonized monomial corresponding to variable v from definition v := vs
*/
signed_vars const& var2canonical(lpvar v) const { return canonize(var2monomial(v)); }
class canonical {
emonomials& m;
public:
canonical(emonomials& m): m(m) {}
signed_vars const& operator[](lpvar v) const { return m.var2canonical(v); }
signed_vars const& operator[](monomial const& mon) const { return m.var2canonical(mon.var()); }
};
canonical canonical;
/**
\brief obtain a canonized signed monomial
corresponding to current equivalence class.
*/
signed_vars const& canonize(monomial const& m) const;
signed_vars const& canonize(monomial const& m) const { return m_canonized[m_var2index[m.var()]]; }
/**
\brief obtain the representative canonized monomial up to sign.
*/
signed_vars const& rep(signed_vars const& sv) const { return m_canonized[m_var2index[m_cg_table[sv.var()]]]; }
/**
\brief the original sign is defined as a sign of the equivalence class representative.
*/
rational orig_sign(signed_vars const& sv) const { return rep(sv).rsign(); }
/**
\brief determine if m1 divides m2 over the canonization obtained from merged variables.
@ -192,7 +261,6 @@ namespace nla {
use_list get_use_list(lpvar v) const { return use_list(*this, v); }
/**
\brief retrieve monomials m' where m is a proper factor of modulo current equalities.
*/
@ -222,7 +290,49 @@ namespace nla {
};
factors_of get_factors_of(monomial const& m) const { inc_visited(); return factors_of(*this, m); }
factors_of get_factors_of(lpvar v) const { return get_factors_of(var2monomial(v)); }
signed_vars const* find_canonical(svector<lpvar> const& vars) const;
/**
\brief iterator over sign equivalent monomials.
These are monomials that are equivalent modulo m_var_eqs amd modulo signs.
*/
class sign_equiv_monomials_it {
emonomials const& m;
unsigned m_index;
bool m_touched;
public:
sign_equiv_monomials_it(emonomials const& m, unsigned idx, bool at_end): m(m), m_index(idx), m_touched(at_end) {}
monomial const& operator*() { return m.m_monomials[m_index]; }
sign_equiv_monomials_it& operator++() {
m_touched = true;
m_index = m.m_canonized[m_index].m_next;
return *this;
}
sign_equiv_monomials_it operator++(int) { sign_equiv_monomials_it tmp = *this; ++*this; return tmp; }
bool operator==(sign_equiv_monomials_it const& other) const {
return m_index == other.m_index && m_touched == other.m_touched;
}
bool operator!=(sign_equiv_monomials_it const& other) const {
return m_index != other.m_index || m_touched != other.m_touched;
}
};
class sign_equiv_monomials {
emonomials& em;
monomial const& m;
unsigned index() const { return em.m_var2index[m.var()]; }
public:
sign_equiv_monomials(emonomials & em, monomial const& m): em(em), m(m) {}
sign_equiv_monomials_it begin() { return sign_equiv_monomials_it(em, index(), false); }
sign_equiv_monomials_it end() { return sign_equiv_monomials_it(em, index(), true); }
};
sign_equiv_monomials enum_sign_equiv_monomials(monomial const& m) { return sign_equiv_monomials(*this, m); }
sign_equiv_monomials enum_sign_equiv_monomials(lpvar v) { return enum_sign_equiv_monomials((*this)[v]); }
sign_equiv_monomials enum_sign_equiv_monomials(signed_vars const& sv) { return enum_sign_equiv_monomials(sv.var()); }
/**
\brief display state of emonomials
*/