mirror of
https://github.com/Z3Prover/z3
synced 2025-04-29 03:45:51 +00:00
emons branch
Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
This commit is contained in:
parent
14f00b3749
commit
b52e79b648
11 changed files with 955 additions and 236 deletions
286
src/util/lp/emonomials.cpp
Normal file
286
src/util/lp/emonomials.cpp
Normal file
|
@ -0,0 +1,286 @@
|
|||
/*++
|
||||
Copyright (c) 2019 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
emonomials.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
table that associate monomials to congruence class representatives modulo a union find structure.
|
||||
|
||||
Author:
|
||||
Nikolaj Bjorner (nbjorner)
|
||||
Lev Nachmanson (levnach)
|
||||
|
||||
Revision History:
|
||||
|
||||
to replace rooted_mons.h and rooted_mon, rooted_mon_tabled
|
||||
|
||||
--*/
|
||||
|
||||
#include "util/lp/emonomials.h"
|
||||
#include "util/lp/nla_defs.h"
|
||||
|
||||
namespace nla {
|
||||
|
||||
void emonomials::inc_canonical() {
|
||||
++m_canonical;
|
||||
if (m_canonical == 0) {
|
||||
for (auto& svt : m_canonized) {
|
||||
svt.m_canonical = 0;
|
||||
}
|
||||
++m_canonical;
|
||||
}
|
||||
}
|
||||
|
||||
void emonomials::inc_visited() const {
|
||||
++m_visited;
|
||||
if (m_visited == 0) {
|
||||
for (auto& svt : m_canonized) {
|
||||
svt.m_visited = 0;
|
||||
}
|
||||
++m_visited;
|
||||
}
|
||||
}
|
||||
|
||||
void emonomials::push() {
|
||||
m_lim.push_back(m_monomials.size());
|
||||
m_region.push_scope();
|
||||
m_ve.push();
|
||||
}
|
||||
|
||||
void emonomials::pop(unsigned n) {
|
||||
m_ve.pop(n);
|
||||
unsigned old_sz = m_lim[m_lim.size() - n];
|
||||
for (unsigned i = m_monomials.size(); i-- > old_sz; ) {
|
||||
monomial const& m = m_monomials[i];
|
||||
m_var2index[m.var()] = UINT_MAX;
|
||||
lpvar last_var = UINT_MAX;
|
||||
for (lpvar v : m.vars()) {
|
||||
if (v != last_var) {
|
||||
remove_var2monomials(v, i);
|
||||
last_var = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_monomials.shrink(old_sz);
|
||||
m_canonized.shrink(old_sz);
|
||||
m_region.pop_scope(n);
|
||||
m_lim.shrink(m_lim.size() - n);
|
||||
}
|
||||
|
||||
void emonomials::remove_var2monomials(lpvar v, unsigned mIndex) {
|
||||
cell*& cur_head = m_use_lists[v].m_head;
|
||||
cell*& cur_tail = m_use_lists[v].m_tail;
|
||||
cell* old_head = cur_head->m_next;
|
||||
if (old_head == cur_head) {
|
||||
cur_head = nullptr;
|
||||
cur_tail = nullptr;
|
||||
}
|
||||
else {
|
||||
cur_head = old_head;
|
||||
cur_tail->m_next = old_head;
|
||||
}
|
||||
}
|
||||
|
||||
void emonomials::insert_var2monomials(lpvar v, unsigned mIndex) {
|
||||
m_use_lists.reserve(v + 1);
|
||||
cell*& cur_head = m_use_lists[v].m_head;
|
||||
cell*& cur_tail = m_use_lists[v].m_tail;
|
||||
cell* new_head = new (m_region) cell(mIndex, cur_head);
|
||||
cur_head = new_head;
|
||||
if (!cur_tail) cur_tail = new_head;
|
||||
cur_tail->m_next = new_head;
|
||||
}
|
||||
|
||||
void emonomials::merge_var2monomials(lpvar root, lpvar other) {
|
||||
if (root == other) return;
|
||||
m_use_lists.reserve(std::max(root, other) + 1);
|
||||
cell*& root_head = m_use_lists[root].m_head;
|
||||
cell*& root_tail = m_use_lists[root].m_tail;
|
||||
cell* other_head = m_use_lists[other].m_head;
|
||||
cell* other_tail = m_use_lists[other].m_tail;
|
||||
if (root_head == nullptr) {
|
||||
root_head = other_head;
|
||||
root_tail = other_tail;
|
||||
}
|
||||
else if (other_head) {
|
||||
// other_head -> other_tail -> root_head --> root_tail -> other_head.
|
||||
root_tail->m_next = other_head;
|
||||
other_tail->m_next = root_head;
|
||||
root_head = other_head;
|
||||
}
|
||||
else {
|
||||
// other_head = other_tail = nullptr
|
||||
}
|
||||
}
|
||||
|
||||
void emonomials::unmerge_var2monomials(lpvar root, lpvar other) {
|
||||
if (root == other) return;
|
||||
cell*& root_head = m_use_lists[root].m_head;
|
||||
cell*& root_tail = m_use_lists[root].m_tail;
|
||||
cell* other_head = m_use_lists[other].m_head;
|
||||
cell* other_tail = m_use_lists[other].m_tail;
|
||||
if (other_head == nullptr) {
|
||||
// no-op
|
||||
}
|
||||
else if (root_tail == other_tail) {
|
||||
root_head = nullptr;
|
||||
root_tail = nullptr;
|
||||
}
|
||||
else {
|
||||
root_head = other_tail->m_next;
|
||||
root_tail->m_next = root_head;
|
||||
other_tail->m_next = other_head;
|
||||
}
|
||||
}
|
||||
|
||||
emonomials::cell* emonomials::head(lpvar v) const {
|
||||
v = m_ve.find(v).var();
|
||||
m_use_lists.reserve(v + 1);
|
||||
return m_use_lists[v].m_head;
|
||||
}
|
||||
|
||||
void emonomials::set_visited(monomial const& m) const {
|
||||
m_canonized[m_var2index[m.var()]].m_visited = m_visited;
|
||||
}
|
||||
|
||||
bool emonomials::is_visited(monomial const& m) const {
|
||||
return m_visited == m_canonized[m_var2index[m.var()]].m_visited;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief insert a new monomial.
|
||||
|
||||
Assume that the variables are canonical, that is, not equal in current
|
||||
context so another variable. To support equal in current context we
|
||||
could track sign information in monomials, or ensure that insert_var2monomials
|
||||
works on the equivalence class roots.
|
||||
*/
|
||||
void emonomials::add(lpvar v, unsigned sz, lpvar const* vs) {
|
||||
unsigned idx = m_monomials.size();
|
||||
m_monomials.push_back(monomial(v, sz, vs));
|
||||
m_canonized.push_back(signed_vars_ts());
|
||||
lpvar last_var = UINT_MAX;
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
lpvar w = vs[i];
|
||||
SASSERT(m_ve.is_root(w));
|
||||
if (w != last_var) {
|
||||
insert_var2monomials(w, idx);
|
||||
last_var = w;
|
||||
}
|
||||
}
|
||||
SASSERT(m_ve.is_root(v));
|
||||
m_var2index.setx(v, idx, UINT_MAX);
|
||||
}
|
||||
|
||||
signed_vars const& emonomials::canonize(monomial const& mon) const {
|
||||
unsigned index = m_var2index[mon.var()];
|
||||
if (m_canonized[index].m_canonical != m_canonical) {
|
||||
m_vars.reset();
|
||||
bool sign = false;
|
||||
for (lpvar v : mon) {
|
||||
signed_var sv = m_ve.find(v);
|
||||
m_vars.push_back(sv.var());
|
||||
sign ^= sv.sign();
|
||||
}
|
||||
m_canonized[index].set_vars(m_vars.size(), m_vars.c_ptr());
|
||||
m_canonized[index].set_sign(sign);
|
||||
m_canonized[index].set_var(mon.var());
|
||||
m_canonized[index].m_canonical = m_canonical;
|
||||
}
|
||||
return m_canonized[index];
|
||||
}
|
||||
|
||||
bool emonomials::canonize_divides(monomial const& m1, monomial const& m2) const {
|
||||
if (m1.size() > m2.size()) return false;
|
||||
signed_vars const& s1 = canonize(m1);
|
||||
signed_vars const& s2 = canonize(m2);
|
||||
unsigned sz1 = s1.size(), sz2 = s2.size();
|
||||
unsigned i = 0, j = 0;
|
||||
while (true) {
|
||||
if (i == sz1) {
|
||||
return true;
|
||||
}
|
||||
else if (j == sz2) {
|
||||
return false;
|
||||
}
|
||||
else if (s1[i] == s2[j]) {
|
||||
++i; ++j;
|
||||
}
|
||||
else if (s1[i] < s2[j]) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
++j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void emonomials::explain_canonized(monomial const& m, lp::explanation& exp) {
|
||||
for (lpvar v : m) {
|
||||
signed_var w = m_ve.find(v);
|
||||
m_ve.explain(signed_var(v, false), w, exp);
|
||||
}
|
||||
}
|
||||
|
||||
// yes, assume that monomials are non-empty.
|
||||
emonomials::pf_iterator::pf_iterator(emonomials const& m, monomial const& mon, bool at_end):
|
||||
m(m), m_mon(mon), m_it(iterator(m, m.head(mon[0]), at_end)), m_end(iterator(m, m.head(mon[0]), true)) {
|
||||
fast_forward();
|
||||
}
|
||||
|
||||
void emonomials::pf_iterator::fast_forward() {
|
||||
for (; m_it != m_end; ++m_it) {
|
||||
if (m_mon.var() != (*m_it).var() && m.canonize_divides(m_mon, *m_it) && !m.is_visited(*m_it)) {
|
||||
m.set_visited(*m_it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void emonomials::merge_eh(signed_var r2, signed_var r1, signed_var v2, signed_var v1) {
|
||||
if (!r2.sign() && m_ve.find(~r2) != m_ve.find(r1)) {
|
||||
merge_var2monomials(r2.var(), r1.var());
|
||||
}
|
||||
inc_canonical();
|
||||
}
|
||||
|
||||
void emonomials::after_merge_eh(signed_var r2, signed_var r1, signed_var v2, signed_var v1) {
|
||||
// skip
|
||||
}
|
||||
|
||||
void emonomials::unmerge_eh(signed_var r2, signed_var r1) {
|
||||
if (!r2.sign() && m_ve.find(~r2) != m_ve.find(r1)) {
|
||||
unmerge_var2monomials(r2.var(), r1.var());
|
||||
}
|
||||
inc_canonical();
|
||||
}
|
||||
|
||||
std::ostream& emonomials::display(std::ostream& out) const {
|
||||
out << "monomials\n";
|
||||
unsigned idx = 0;
|
||||
for (auto const& m : m_monomials) {
|
||||
out << (idx++) << ": " << m << "\n";
|
||||
}
|
||||
out << "use lists\n";
|
||||
idx = 0;
|
||||
for (auto const& ht : m_use_lists) {
|
||||
cell* c = ht.m_head;
|
||||
if (c) {
|
||||
out << "v" << idx << ": ";
|
||||
do {
|
||||
out << c->m_index << " ";
|
||||
c = c->m_next;
|
||||
}
|
||||
while (c != ht.m_head);
|
||||
out << "\n";
|
||||
}
|
||||
++idx;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue