mirror of
https://github.com/Z3Prover/z3
synced 2025-04-22 16:45:31 +00:00
add simplification routines
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
de6409f558
commit
65d818437a
5 changed files with 297 additions and 96 deletions
|
@ -87,7 +87,7 @@ namespace dd {
|
|||
}
|
||||
}
|
||||
SASSERT(well_formed());
|
||||
return 0;
|
||||
return null_pdd;
|
||||
}
|
||||
|
||||
bool pdd_manager::check_result(op_entry*& e1, op_entry const* e2, PDD a, PDD b, PDD c) {
|
||||
|
@ -112,21 +112,21 @@ namespace dd {
|
|||
if (is_zero(p)) return q;
|
||||
if (is_zero(q)) return p;
|
||||
if (is_val(p) && is_val(q)) return imk_val(val(p) + val(q));
|
||||
if (!is_val(p) && level(p) < level(q)) std::swap(p, q);
|
||||
if (is_val(p)) std::swap(p, q);
|
||||
else if (!is_val(q) && level(p) < level(q)) std::swap(p, q);
|
||||
break;
|
||||
case pdd_mul_op:
|
||||
if (is_zero(p) || is_zero(q)) return zero_pdd;
|
||||
if (is_one(p)) return q;
|
||||
if (is_one(q)) return p;
|
||||
if (is_val(p) && is_val(q)) return imk_val(val(p) * val(q));
|
||||
if (!is_val(p) && level(p) < level(q)) std::swap(p, q);
|
||||
if (is_val(p)) std::swap(p, q);
|
||||
else if (!is_val(q) && level(p) < level(q)) std::swap(p, q);
|
||||
break;
|
||||
case pdd_reduce_op:
|
||||
if (is_zero(q)) return p;
|
||||
if (is_val(p)) return p;
|
||||
if (level(p) < level(q)) return p;
|
||||
if (!is_val(q) && level(p) < level(q)) return p;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
|
@ -156,14 +156,12 @@ namespace dd {
|
|||
push(apply_rec(hi(p), hi(q), op));
|
||||
r = make_node(level_p, read(2), read(1));
|
||||
}
|
||||
else if (level_p > level_q) {
|
||||
else {
|
||||
SASSERT(level_p > level_q);
|
||||
push(apply_rec(lo(p), q, op));
|
||||
r = make_node(level_p, read(1), hi(p));
|
||||
npop = 1;
|
||||
}
|
||||
else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
case pdd_mul_op:
|
||||
SASSERT(!is_val(p));
|
||||
|
@ -179,7 +177,7 @@ namespace dd {
|
|||
// == x((a+b)(c+d)+bd) + bd
|
||||
//
|
||||
push(apply_rec(lo(p), lo(q), pdd_mul_op));
|
||||
unsigned bd = read(3);
|
||||
unsigned bd = read(1);
|
||||
push(apply_rec(hi(p), lo(p), pdd_add_op));
|
||||
push(apply_rec(hi(q), lo(q), pdd_add_op));
|
||||
push(apply_rec(read(1), read(2), pdd_mul_op));
|
||||
|
@ -239,9 +237,7 @@ namespace dd {
|
|||
UNREACHABLE();
|
||||
}
|
||||
pop(npop);
|
||||
e1->m_result = r;
|
||||
|
||||
// SASSERT(well_formed());
|
||||
e1->m_result = r;
|
||||
SASSERT(!m_free_nodes.contains(r));
|
||||
return r;
|
||||
}
|
||||
|
@ -852,6 +848,7 @@ namespace dd {
|
|||
out << "v" << v;
|
||||
}
|
||||
}
|
||||
if (first) out << "0";
|
||||
return out;
|
||||
}
|
||||
|
||||
|
|
|
@ -281,6 +281,7 @@ namespace dd {
|
|||
~pdd() { m.dec_ref(root); }
|
||||
pdd lo() const { return pdd(m.lo(root), m); }
|
||||
pdd hi() const { return pdd(m.hi(root), m); }
|
||||
unsigned index() const { return root; }
|
||||
unsigned var() const { return m.var(root); }
|
||||
rational const& val() const { SASSERT(is_val()); return m.val(root); }
|
||||
bool is_val() const { return m.is_val(root); }
|
||||
|
@ -317,6 +318,8 @@ namespace dd {
|
|||
inline pdd operator-(pdd const& b, int x) { return b + (-rational(x)); }
|
||||
inline pdd& operator*=(pdd & p, pdd const& q) { p = p * q; return p; }
|
||||
inline pdd& operator|=(pdd & p, pdd const& q) { p = p | q; return p; }
|
||||
inline pdd& operator-=(pdd & p, pdd const& q) { p = p - q; return p; }
|
||||
inline pdd& operator+=(pdd & p, pdd const& q) { p = p + q; return p; }
|
||||
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, pdd const& b);
|
||||
|
|
|
@ -151,10 +151,10 @@ namespace dd {
|
|||
scoped_detach sd(*this, e);
|
||||
equation& eq = *e;
|
||||
TRACE("grobner", display(tout << "eq = ", eq); display(tout););
|
||||
SASSERT(!eq.is_processed());
|
||||
SASSERT(eq.state() == to_simplify);
|
||||
if (!simplify_using(eq, m_processed)) return false;
|
||||
if (is_trivial(eq)) { sd.e = nullptr; retire(e); return true; }
|
||||
if (check_conflict(eq)) return false;
|
||||
if (check_conflict(eq)) { sd.e = nullptr; return false; }
|
||||
if (!simplify_using(m_processed, eq)) return false;
|
||||
superpose(eq);
|
||||
return simplify_using(m_to_simplify, eq);
|
||||
|
@ -167,7 +167,7 @@ namespace dd {
|
|||
eq = curr;
|
||||
}
|
||||
}
|
||||
if (eq) pop_equation(eq, m_to_simplify);
|
||||
if (eq) pop_equation(eq);
|
||||
return eq;
|
||||
}
|
||||
|
||||
|
@ -178,13 +178,13 @@ namespace dd {
|
|||
eq = curr;
|
||||
}
|
||||
}
|
||||
if (eq) pop_equation(eq, m_to_simplify);
|
||||
if (eq) pop_equation(eq);
|
||||
return eq;
|
||||
}
|
||||
|
||||
void grobner::simplify_linear() {
|
||||
void grobner::simplify() {
|
||||
try {
|
||||
while (simplify_linear_step()) {
|
||||
while (simplify_linear_step() /*|| simplify_cc_step() */ || simplify_elim_step()) {
|
||||
DEBUG_CODE(invariant(););
|
||||
}
|
||||
}
|
||||
|
@ -207,38 +207,149 @@ namespace dd {
|
|||
}
|
||||
}
|
||||
if (linear.empty()) return false;
|
||||
vector<equation_vector> use_list;
|
||||
for (equation * e : m_to_simplify) {
|
||||
add_to_use(e, use_list);
|
||||
}
|
||||
for (equation * e : m_processed) {
|
||||
add_to_use(e, use_list);
|
||||
}
|
||||
use_list_t use_list = get_use_list();
|
||||
compare_top_var ctv;
|
||||
std::stable_sort(linear.begin(), linear.end(), ctv);
|
||||
for (equation* src : linear) {
|
||||
equation_vector const& uses = use_list[src->poly().var()];
|
||||
bool changed_leading_term;
|
||||
for (equation* dst : uses) {
|
||||
if (src == dst || !simplify_source_target(*src, *dst, changed_leading_term)) {
|
||||
if (src == dst) {
|
||||
continue;
|
||||
}
|
||||
if (dst->is_processed() && changed_leading_term) {
|
||||
dst->set_processed(false);
|
||||
pop_equation(dst, m_processed);
|
||||
push_equation(dst, m_to_simplify);
|
||||
simplify_using(*dst, *src, changed_leading_term);
|
||||
if (check_conflict(*dst)) {
|
||||
return false;
|
||||
}
|
||||
if (is_trivial(*dst)) {
|
||||
SASSERT(false);
|
||||
}
|
||||
if (changed_leading_term) {
|
||||
pop_equation(dst);
|
||||
push_equation(to_simplify, dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (equation* src : linear) {
|
||||
pop_equation(src, m_to_simplify);
|
||||
push_equation(src, m_processed);
|
||||
src->set_processed(true);
|
||||
pop_equation(src);
|
||||
push_equation(solved, src);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void grobner::add_to_use(equation* e, vector<equation_vector>& use_list) {
|
||||
/**
|
||||
\brief simplify using congruences
|
||||
replace pair px + q and ry + q by
|
||||
px + q, px - ry
|
||||
since px = ry
|
||||
*/
|
||||
bool grobner::simplify_cc_step() {
|
||||
u_map<equation*> los;
|
||||
bool reduced = false;
|
||||
unsigned j = 0;
|
||||
for (equation* eq1 : m_to_simplify) {
|
||||
SASSERT(eq1->state() == to_simplify);
|
||||
pdd p = eq1->poly();
|
||||
auto* e = los.insert_if_not_there2(p.lo().index(), eq1);
|
||||
equation* eq2 = e->get_data().m_value;
|
||||
if (eq2 != eq1 && !p.lo().is_val()) {
|
||||
*eq1 = p - eq2->poly();
|
||||
*eq1 = m_dep_manager.mk_join(eq1->dep(), eq2->dep());
|
||||
reduced = true;
|
||||
if (is_trivial(*eq1)) {
|
||||
retire(eq1);
|
||||
continue;
|
||||
}
|
||||
else if (check_conflict(*eq1)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
m_to_simplify[j] = eq1;
|
||||
eq1->set_index(j++);
|
||||
}
|
||||
m_to_simplify.shrink(j);
|
||||
return reduced;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief treat equations as processed if top variable occurs only once.
|
||||
reduce equations where top variable occurs only twice and linear in one of the occurrences.
|
||||
*/
|
||||
bool grobner::simplify_elim_step() {
|
||||
use_list_t use_list = get_use_list();
|
||||
unsigned j = 0;
|
||||
for (equation* e : m_to_simplify) {
|
||||
pdd p = e->poly();
|
||||
if (!p.is_val() && p.hi().is_val() && use_list[p.var()].size() == 1) {
|
||||
push_equation(solved, e);
|
||||
}
|
||||
else {
|
||||
m_to_simplify[j] = e;
|
||||
e->set_index(j++);
|
||||
}
|
||||
}
|
||||
if (j != m_to_simplify.size()) {
|
||||
m_to_simplify.shrink(j);
|
||||
return true;
|
||||
}
|
||||
j = 0;
|
||||
for (unsigned i = 0; i < m_to_simplify.size(); ++i) {
|
||||
equation* e = m_to_simplify[i];
|
||||
pdd p = e->poly();
|
||||
// check that e is linear in top variable.
|
||||
if (e->state() != to_simplify) {
|
||||
// this was moved before this pass
|
||||
}
|
||||
else if (!done() && !is_trivial(*e) && p.hi().is_val() && use_list[p.var()].size() == 2) {
|
||||
for (equation* e2 : use_list[p.var()]) {
|
||||
if (e2 == e) continue;
|
||||
bool changed_leading_term;
|
||||
|
||||
remove_from_use(e2, use_list);
|
||||
simplify_using(*e2, *e, changed_leading_term);
|
||||
if (check_conflict(*e2)) {
|
||||
break;
|
||||
}
|
||||
if (is_trivial(*e2)) {
|
||||
break;
|
||||
}
|
||||
if (changed_leading_term) {
|
||||
pop_equation(e2);
|
||||
push_equation(to_simplify, e2);
|
||||
}
|
||||
add_to_use(e2, use_list);
|
||||
break;
|
||||
}
|
||||
push_equation(solved, e);
|
||||
}
|
||||
else {
|
||||
m_to_simplify[j] = e;
|
||||
e->set_index(j++);
|
||||
}
|
||||
}
|
||||
if (j != m_to_simplify.size()) {
|
||||
// clean up elements in m_to_simplify
|
||||
// they may have moved.
|
||||
m_to_simplify.shrink(j);
|
||||
j = 0;
|
||||
for (equation* e : m_to_simplify) {
|
||||
if (is_trivial(*e)) {
|
||||
retire(e);
|
||||
}
|
||||
else if (e->state() == to_simplify) {
|
||||
m_to_simplify[j] = e;
|
||||
e->set_index(j++);
|
||||
}
|
||||
}
|
||||
m_to_simplify.shrink(j);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void grobner::add_to_use(equation* e, use_list_t& use_list) {
|
||||
unsigned_vector const& fv = m.free_vars(e->poly());
|
||||
for (unsigned v : fv) {
|
||||
use_list.reserve(v + 1);
|
||||
|
@ -246,6 +357,25 @@ namespace dd {
|
|||
}
|
||||
}
|
||||
|
||||
void grobner::remove_from_use(equation* e, use_list_t& use_list) {
|
||||
unsigned_vector const& fv = m.free_vars(e->poly());
|
||||
for (unsigned v : fv) {
|
||||
use_list.reserve(v + 1);
|
||||
use_list[v].erase(e);
|
||||
}
|
||||
}
|
||||
|
||||
grobner::use_list_t grobner::get_use_list() {
|
||||
use_list_t use_list;
|
||||
for (equation * e : m_to_simplify) {
|
||||
add_to_use(e, use_list);
|
||||
}
|
||||
for (equation * e : m_processed) {
|
||||
add_to_use(e, use_list);
|
||||
}
|
||||
return use_list;
|
||||
}
|
||||
|
||||
void grobner::superpose(equation const & eq) {
|
||||
for (equation* target : m_processed) {
|
||||
superpose(eq, *target);
|
||||
|
@ -257,7 +387,6 @@ namespace dd {
|
|||
*/
|
||||
bool grobner::simplify_using(equation& eq, equation_vector const& eqs) {
|
||||
bool simplified, changed_leading_term;
|
||||
TRACE("grobner", display(tout << "simplifying: ", eq); tout << "using equalities of size " << eqs.size() << "\n";);
|
||||
do {
|
||||
simplified = false;
|
||||
for (equation* p : eqs) {
|
||||
|
@ -273,7 +402,6 @@ namespace dd {
|
|||
|
||||
TRACE("grobner", display(tout << "simplification result: ", eq););
|
||||
|
||||
check_conflict(eq);
|
||||
return !done();
|
||||
}
|
||||
|
||||
|
@ -281,7 +409,6 @@ namespace dd {
|
|||
Use the given equation to simplify equations in set
|
||||
*/
|
||||
bool grobner::simplify_using(equation_vector& set, equation const& eq) {
|
||||
TRACE("grobner", tout << "poly " << eq.poly() << "\n";);
|
||||
unsigned j = 0, sz = set.size();
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
equation& target = *set[i];
|
||||
|
@ -290,13 +417,15 @@ namespace dd {
|
|||
if (simplified && is_trivial(target)) {
|
||||
retire(&target);
|
||||
}
|
||||
else if (simplified && !check_conflict(target) && changed_leading_term) {
|
||||
SASSERT(target.is_processed());
|
||||
target.set_processed(false);
|
||||
else if (simplified && check_conflict(target)) {
|
||||
// pushed to solved
|
||||
}
|
||||
else if (simplified && changed_leading_term) {
|
||||
SASSERT(target.state() == processed);
|
||||
if (is_tuned()) {
|
||||
m_levelp1 = std::max(m_var2level[target.poly().var()]+1, m_levelp1);
|
||||
}
|
||||
push_equation(target, m_to_simplify);
|
||||
push_equation(to_simplify, target);
|
||||
}
|
||||
else {
|
||||
set[j] = set[i];
|
||||
|
@ -312,22 +441,44 @@ namespace dd {
|
|||
return true if the target was simplified.
|
||||
set changed_leading_term if the target is in the m_processed set and the leading term changed.
|
||||
*/
|
||||
bool grobner::simplify_source_target(equation const& source, equation& target, bool& changed_leading_term) {
|
||||
TRACE("grobner", tout << "simplifying: " << target.poly() << "\nusing: " << source.poly() << "\n";);
|
||||
m_stats.m_simplified++;
|
||||
pdd t = source.poly();
|
||||
pdd r = target.poly().reduce(t);
|
||||
if (r == target.poly() || is_too_complex(r)) {
|
||||
bool grobner::simplify_source_target(equation const& src, equation& dst, bool& changed_leading_term) {
|
||||
if (&src == &dst) {
|
||||
return false;
|
||||
}
|
||||
changed_leading_term = target.is_processed() && m.different_leading_term(r, target.poly());
|
||||
target = r;
|
||||
target = m_dep_manager.mk_join(target.dep(), source.dep());
|
||||
update_stats_max_degree_and_size(target);
|
||||
TRACE("grobner", tout << "simplified " << target.poly() << "\n";);
|
||||
m_stats.m_simplified++;
|
||||
pdd t = src.poly();
|
||||
pdd r = dst.poly().reduce(t);
|
||||
if (r == dst.poly() || is_too_complex(r)) {
|
||||
return false;
|
||||
}
|
||||
TRACE("grobner",
|
||||
tout << "reduce: " << dst.poly() << "\n";
|
||||
tout << "using: " << t << "\n";
|
||||
tout << "to: " << r << "\n";);
|
||||
changed_leading_term = dst.state() == processed && m.different_leading_term(r, dst.poly());
|
||||
dst = r;
|
||||
dst = m_dep_manager.mk_join(dst.dep(), src.dep());
|
||||
update_stats_max_degree_and_size(dst);
|
||||
return true;
|
||||
}
|
||||
|
||||
void grobner::simplify_using(equation & dst, equation const& src, bool& changed_leading_term) {
|
||||
if (&src == &dst) return;
|
||||
m_stats.m_simplified++;
|
||||
pdd t = src.poly();
|
||||
pdd r = dst.poly().reduce(t);
|
||||
changed_leading_term = dst.state() == processed && m.different_leading_term(r, dst.poly());
|
||||
TRACE("grobner",
|
||||
tout << "reduce: " << dst.poly() << "\n";
|
||||
tout << "using: " << t << "\n";
|
||||
tout << "to: " << r << "\n";);
|
||||
|
||||
if (r == dst.poly()) return;
|
||||
dst = r;
|
||||
dst = m_dep_manager.mk_join(dst.dep(), src.dep());
|
||||
update_stats_max_degree_and_size(dst);
|
||||
}
|
||||
|
||||
/*
|
||||
let eq1: ab+q=0, and eq2: ac+e=0, then qc - eb = 0
|
||||
*/
|
||||
|
@ -347,10 +498,10 @@ namespace dd {
|
|||
scoped_detach sd(*this, e);
|
||||
equation& eq = *e;
|
||||
SASSERT(!m_watch[eq.poly().var()].contains(e));
|
||||
SASSERT(!eq.is_processed());
|
||||
SASSERT(eq.state() == to_simplify);
|
||||
if (!simplify_using(eq, m_processed)) return false;
|
||||
if (is_trivial(eq)) { sd.e = nullptr; retire(e); return true; }
|
||||
if (check_conflict(eq)) return false;
|
||||
if (check_conflict(eq)) { sd.e = nullptr; return false; }
|
||||
if (!simplify_using(m_processed, eq)) return false;
|
||||
TRACE("grobner", display(tout << "eq = ", eq););
|
||||
superpose(eq);
|
||||
|
@ -372,7 +523,7 @@ namespace dd {
|
|||
}
|
||||
|
||||
void grobner::add_to_watch(equation& eq) {
|
||||
SASSERT(!eq.is_processed());
|
||||
SASSERT(eq.state() == to_simplify);
|
||||
SASSERT(is_tuned());
|
||||
pdd const& p = eq.poly();
|
||||
if (!p.is_val()) {
|
||||
|
@ -386,7 +537,7 @@ namespace dd {
|
|||
unsigned j = 0;
|
||||
for (equation* _target : watch) {
|
||||
equation& target = *_target;
|
||||
SASSERT(!target.is_processed());
|
||||
SASSERT(target.state() == to_simplify);
|
||||
SASSERT(target.poly().var() == v);
|
||||
bool changed_leading_term = false;
|
||||
if (!done()) simplify_source_target(eq, target, changed_leading_term);
|
||||
|
@ -394,8 +545,9 @@ namespace dd {
|
|||
retire(&target);
|
||||
}
|
||||
else if (check_conflict(target)) {
|
||||
// remove from watch
|
||||
} else if (target.poly().var() != v) {
|
||||
// pushed to solved
|
||||
}
|
||||
else if (target.poly().var() != v) {
|
||||
// move to other watch list
|
||||
m_watch[target.poly().var()].push_back(_target);
|
||||
}
|
||||
|
@ -415,13 +567,13 @@ namespace dd {
|
|||
equation* eq = nullptr;
|
||||
for (equation* curr : watch) {
|
||||
pdd const& p = curr->poly();
|
||||
if (!curr->is_processed() && !p.is_val() && p.var() == v) {
|
||||
if (curr->state() == to_simplify && !p.is_val() && p.var() == v) {
|
||||
if (!eq || is_simpler(*curr, *eq))
|
||||
eq = curr;
|
||||
}
|
||||
}
|
||||
if (eq) {
|
||||
pop_equation(eq, m_to_simplify);
|
||||
pop_equation(eq);
|
||||
m_watch[eq->poly().var()].erase(eq);
|
||||
return eq;
|
||||
}
|
||||
|
@ -432,14 +584,17 @@ namespace dd {
|
|||
|
||||
grobner::equation_vector const& grobner::equations() {
|
||||
m_all_eqs.reset();
|
||||
for (equation* eq : m_solved) m_all_eqs.push_back(eq);
|
||||
for (equation* eq : m_to_simplify) m_all_eqs.push_back(eq);
|
||||
for (equation* eq : m_processed) m_all_eqs.push_back(eq);
|
||||
return m_all_eqs;
|
||||
}
|
||||
|
||||
void grobner::reset() {
|
||||
for (equation* e : m_solved) dealloc(e);
|
||||
for (equation* e : m_to_simplify) dealloc(e);
|
||||
for (equation* e : m_processed) dealloc(e);
|
||||
m_solved.reset();
|
||||
m_processed.reset();
|
||||
m_to_simplify.reset();
|
||||
m_stats.reset();
|
||||
|
@ -448,9 +603,13 @@ namespace dd {
|
|||
|
||||
void grobner::add(pdd const& p, u_dependency * dep) {
|
||||
if (p.is_zero()) return;
|
||||
equation * eq = alloc(equation, p, dep, m_to_simplify.size());
|
||||
m_to_simplify.push_back(eq);
|
||||
if (!check_conflict(*eq) && is_tuned()) {
|
||||
equation * eq = alloc(equation, p, dep);
|
||||
if (check_conflict(*eq)) {
|
||||
return;
|
||||
}
|
||||
push_equation(to_simplify, eq);
|
||||
|
||||
if (is_tuned()) {
|
||||
m_levelp1 = std::max(m_var2level[p.var()]+1, m_levelp1);
|
||||
}
|
||||
update_stats_max_degree_and_size(*eq);
|
||||
|
@ -467,12 +626,23 @@ namespace dd {
|
|||
m_conflict != nullptr;
|
||||
}
|
||||
|
||||
grobner::equation_vector& grobner::get_queue(equation const& eq) {
|
||||
switch (eq.state()) {
|
||||
case processed: return m_processed;
|
||||
case to_simplify: return m_to_simplify;
|
||||
case solved: return m_solved;
|
||||
}
|
||||
UNREACHABLE();
|
||||
return m_to_simplify;
|
||||
}
|
||||
|
||||
void grobner::del_equation(equation& eq) {
|
||||
pop_equation(eq, eq.is_processed() ? m_processed : m_to_simplify);
|
||||
pop_equation(eq);
|
||||
retire(&eq);
|
||||
}
|
||||
|
||||
void grobner::pop_equation(equation& eq, equation_vector& v) {
|
||||
void grobner::pop_equation(equation& eq) {
|
||||
equation_vector& v = get_queue(eq);
|
||||
unsigned idx = eq.idx();
|
||||
if (idx != v.size() - 1) {
|
||||
equation* eq2 = v.back();
|
||||
|
@ -482,7 +652,9 @@ namespace dd {
|
|||
v.pop_back();
|
||||
}
|
||||
|
||||
void grobner::push_equation(equation& eq, equation_vector& v) {
|
||||
void grobner::push_equation(eq_state st, equation& eq) {
|
||||
eq.set_state(st);
|
||||
equation_vector& v = get_queue(eq);
|
||||
eq.set_index(v.size());
|
||||
v.push_back(&eq);
|
||||
}
|
||||
|
@ -507,6 +679,7 @@ namespace dd {
|
|||
}
|
||||
|
||||
std::ostream& grobner::display(std::ostream& out) const {
|
||||
out << "solved\n"; for (auto e : m_solved) display(out, *e);
|
||||
out << "processed\n"; for (auto e : m_processed) display(out, *e);
|
||||
out << "to_simplify\n"; for (auto e : m_to_simplify) display(out, *e);
|
||||
statistics st;
|
||||
|
@ -520,17 +693,27 @@ namespace dd {
|
|||
// they are labled as processed
|
||||
unsigned i = 0;
|
||||
for (auto* e : m_processed) {
|
||||
VERIFY(e->is_processed());
|
||||
VERIFY(e->state() == processed);
|
||||
VERIFY(e->idx() == i);
|
||||
VERIFY(!e->poly().is_val());
|
||||
++i;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for (auto* e : m_solved) {
|
||||
VERIFY(e->state() == solved);
|
||||
VERIFY(e->idx() == i);
|
||||
++i;
|
||||
}
|
||||
|
||||
// equations in to_simplify have correct indices
|
||||
// they are labeled as non-processed
|
||||
// their top-most variable is watched
|
||||
i = 0;
|
||||
for (auto* e : m_to_simplify) {
|
||||
VERIFY(!e->is_processed());
|
||||
VERIFY(e->idx() == i);
|
||||
VERIFY(e->state() == to_simplify);
|
||||
VERIFY(!e->poly().is_val());
|
||||
if (is_tuned()) {
|
||||
pdd const& p = e->poly();
|
||||
VERIFY(p.is_val() || m_watch[p.var()].contains(e));
|
||||
|
@ -544,7 +727,7 @@ namespace dd {
|
|||
for (equation* e : w) {
|
||||
VERIFY(!e->poly().is_val());
|
||||
VERIFY(e->poly().var() == i);
|
||||
VERIFY(!e->is_processed());
|
||||
VERIFY(e->state() == to_simplify);
|
||||
VERIFY(m_to_simplify.contains(e));
|
||||
}
|
||||
++i;
|
||||
|
|
|
@ -51,15 +51,21 @@ public:
|
|||
{}
|
||||
};
|
||||
|
||||
enum eq_state {
|
||||
solved,
|
||||
processed,
|
||||
to_simplify
|
||||
};
|
||||
|
||||
class equation {
|
||||
bool m_processed; //!< state
|
||||
eq_state m_state;
|
||||
unsigned m_idx; //!< unique index
|
||||
pdd m_poly; //!< polynomial in pdd form
|
||||
u_dependency * m_dep; //!< justification for the equality
|
||||
public:
|
||||
equation(pdd const& p, u_dependency* d, unsigned idx):
|
||||
m_processed(false),
|
||||
m_idx(idx),
|
||||
equation(pdd const& p, u_dependency* d):
|
||||
m_state(to_simplify),
|
||||
m_idx(0),
|
||||
m_poly(p),
|
||||
m_dep(d)
|
||||
{}
|
||||
|
@ -69,8 +75,8 @@ public:
|
|||
unsigned idx() const { return m_idx; }
|
||||
void operator=(pdd& p) { m_poly = p; }
|
||||
void operator=(u_dependency* d) { m_dep = d; }
|
||||
bool is_processed() const { return m_processed; }
|
||||
void set_processed(bool p) { m_processed = p; }
|
||||
eq_state state() const { return m_state; }
|
||||
void set_state(eq_state st) { m_state = st; }
|
||||
void set_index(unsigned idx) { m_idx = idx; }
|
||||
};
|
||||
private:
|
||||
|
@ -83,11 +89,12 @@ private:
|
|||
stats m_stats;
|
||||
config m_config;
|
||||
print_dep_t m_print_dep;
|
||||
equation_vector m_solved; // equations with solved variables, triangular
|
||||
equation_vector m_processed;
|
||||
equation_vector m_to_simplify;
|
||||
mutable u_dependency_manager m_dep_manager;
|
||||
equation_vector m_all_eqs;
|
||||
equation const* m_conflict;
|
||||
equation* m_conflict;
|
||||
public:
|
||||
grobner(reslimit& lim, pdd_manager& m);
|
||||
~grobner();
|
||||
|
@ -99,7 +106,7 @@ public:
|
|||
void add(pdd const& p) { add(p, nullptr); }
|
||||
void add(pdd const& p, u_dependency * dep);
|
||||
|
||||
void simplify_linear();
|
||||
void simplify();
|
||||
void saturate();
|
||||
|
||||
equation_vector const& equations();
|
||||
|
@ -120,14 +127,15 @@ private:
|
|||
void superpose(equation const& eq1, equation const& eq2);
|
||||
void superpose(equation const& eq);
|
||||
bool simplify_source_target(equation const& source, equation& target, bool& changed_leading_term);
|
||||
bool simplify_using(equation_vector& set, equation const& eq);
|
||||
bool simplify_using(equation& eq, equation_vector const& eqs);
|
||||
bool simplify_using(equation_vector& set, equation const& eq);
|
||||
void simplify_using(equation & dst, equation const& src, bool& changed_leading_term);
|
||||
|
||||
bool eliminate(equation& eq) { return is_trivial(eq) && (del_equation(eq), true); }
|
||||
bool is_trivial(equation const& eq) const { return eq.poly().is_zero(); }
|
||||
bool is_simpler(equation const& eq1, equation const& eq2) { return eq1.poly() < eq2.poly(); }
|
||||
bool check_conflict(equation const& eq) { return eq.poly().is_val() && !is_trivial(eq) && (set_conflict(eq), true); }
|
||||
void set_conflict(equation const& eq) { m_conflict = &eq; }
|
||||
bool check_conflict(equation& eq) { return eq.poly().is_val() && !is_trivial(eq) && (set_conflict(eq), true); }
|
||||
void set_conflict(equation& eq) { m_conflict = &eq; push_equation(solved, eq); }
|
||||
bool is_too_complex(const equation& eq) const { return is_too_complex(eq.poly()); }
|
||||
bool is_too_complex(const pdd& p) const { return p.tree_size() > m_config.m_expr_size_limit; }
|
||||
|
||||
|
@ -144,16 +152,22 @@ private:
|
|||
void add_to_watch(equation& eq);
|
||||
|
||||
void del_equation(equation& eq);
|
||||
equation_vector& get_queue(equation const& eq);
|
||||
void retire(equation* eq) { dealloc(eq); }
|
||||
void pop_equation(equation& eq, equation_vector& v);
|
||||
void pop_equation(equation* eq, equation_vector& v) { pop_equation(*eq, v); }
|
||||
void push_equation(equation& eq, equation_vector& v);
|
||||
void push_equation(equation* eq, equation_vector& v) { push_equation(*eq, v); }
|
||||
void pop_equation(equation& eq);
|
||||
void pop_equation(equation* eq) { pop_equation(*eq); }
|
||||
void push_equation(eq_state st, equation& eq);
|
||||
void push_equation(eq_state st, equation* eq) { push_equation(st, *eq); }
|
||||
|
||||
struct compare_top_var;
|
||||
bool simplify_linear_step();
|
||||
void add_to_use(equation* e, vector<equation_vector>& use_list);
|
||||
typedef vector<equation_vector> use_list_t;
|
||||
use_list_t get_use_list();
|
||||
void add_to_use(equation* e, use_list_t& use_list);
|
||||
void remove_from_use(equation* e, use_list_t& use_list);
|
||||
|
||||
bool simplify_cc_step();
|
||||
bool simplify_elim_step();
|
||||
|
||||
void invariant() const;
|
||||
struct scoped_detach {
|
||||
|
@ -162,9 +176,7 @@ private:
|
|||
scoped_detach(grobner& g, equation* e): g(g), e(e) {}
|
||||
~scoped_detach() {
|
||||
if (e) {
|
||||
e->set_processed(true);
|
||||
e->set_index(g.m_processed.size());
|
||||
g.m_processed.push_back(e);
|
||||
g.push_equation(processed, *e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "ast/bv_decl_plugin.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "ast/ast_ll_pp.h"
|
||||
#include "ast/reg_decl_plugins.h"
|
||||
#include "tactic/goal.h"
|
||||
#include "tactic/tactic.h"
|
||||
|
@ -76,31 +77,33 @@ namespace dd {
|
|||
void add_def(unsigned_vector const& id2var, app* e, ast_manager& m, pdd_manager& p, grobner& g) {
|
||||
expr* a, *b;
|
||||
pdd v1 = p.mk_var(id2var[e->get_id()]);
|
||||
pdd q(p);
|
||||
if (m.is_and(e)) {
|
||||
pdd r = p.one();
|
||||
for (expr* arg : *e) r *= p.mk_var(id2var[arg->get_id()]);
|
||||
g.add(v1 + r + 1);
|
||||
q = v1 + r;
|
||||
}
|
||||
else if (m.is_or(e)) {
|
||||
pdd r = p.zero();
|
||||
for (expr* arg : *e) r |= p.mk_var(id2var[arg->get_id()]);
|
||||
g.add(v1 + r + 1);
|
||||
q = v1 + r;
|
||||
}
|
||||
else if (m.is_not(e, a)) {
|
||||
pdd v2 = p.mk_var(id2var[a->get_id()]);
|
||||
g.add(v1 + v2 + 1);
|
||||
q = v1 + v2 + 1;
|
||||
}
|
||||
else if (m.is_eq(e, a, b)) {
|
||||
pdd v2 = p.mk_var(id2var[a->get_id()]);
|
||||
pdd v3 = p.mk_var(id2var[b->get_id()]);
|
||||
g.add(v1 + v2 + v3 + 1);
|
||||
q = v1 + v2 + v3 + 1;
|
||||
}
|
||||
else if (is_uninterp_const(e)) {
|
||||
// pass
|
||||
return;
|
||||
}
|
||||
else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
g.add(q);
|
||||
}
|
||||
|
||||
void collect_id2var(unsigned_vector& id2var, expr_ref_vector const& fmls) {
|
||||
|
@ -133,7 +136,10 @@ namespace dd {
|
|||
for (expr* e : fmls) {
|
||||
g.add(p.mk_var(id2var[e->get_id()]) + 1);
|
||||
}
|
||||
g.simplify_linear();
|
||||
g.display(std::cout);
|
||||
g.simplify();
|
||||
g.display(std::cout);
|
||||
g.saturate();
|
||||
g.display(std::cout);
|
||||
}
|
||||
|
||||
|
@ -141,8 +147,8 @@ namespace dd {
|
|||
ast_manager m;
|
||||
reg_decl_plugins(m);
|
||||
bv_util bv(m);
|
||||
expr_ref x(m.mk_const("x", bv.mk_sort(4)), m);
|
||||
expr_ref y(m.mk_const("y", bv.mk_sort(4)), m);
|
||||
expr_ref x(m.mk_const("x", bv.mk_sort(3)), m);
|
||||
expr_ref y(m.mk_const("y", bv.mk_sort(3)), m);
|
||||
expr_ref xy(bv.mk_bv_mul(x, y), m);
|
||||
expr_ref yx(bv.mk_bv_mul(y, x), m);
|
||||
expr_ref eq(m.mk_not(m.mk_eq(xy,yx)), m);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue