3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-08 10:25:18 +00:00
z3/lib/unifier.cpp
Leonardo de Moura e9eab22e5c Z3 sources
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
2012-10-02 11:35:25 -07:00

184 lines
5 KiB
C++

/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
unifier.cpp
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-01-28.
Revision History:
--*/
#include"unifier.h"
#include"ast_pp.h"
void unifier::reset(unsigned num_offsets) {
m_todo.reset();
m_find.reset();
m_size.reset();
}
/**
\brief Find with path compression.
*/
expr_offset unifier::find(expr_offset p) {
buffer<expr_offset> path;
expr_offset next;
while (m_find.find(p, next)) {
path.push_back(p);
p = next;
}
buffer<expr_offset>::iterator it = path.begin();
buffer<expr_offset>::iterator end = path.end();
for (; it != end; ++it) {
expr_offset & prev = *it;
m_find.insert(prev, p);
}
return p;
}
void unifier::save_var(expr_offset const & p, expr_offset const & t) {
expr * n = p.get_expr();
if (is_var(n)) {
unsigned off = p.get_offset();
m_subst->insert(to_var(n)->get_idx(), off, t);
}
}
/**
\brief Merge the equivalence classes of n1 and n2. n2 will be the
root of the resultant equivalence class.
*/
void unifier::union1(expr_offset const & n1, expr_offset const & n2) {
DEBUG_CODE({
expr_offset f;
SASSERT(!m_find.find(n1, f));
SASSERT(!m_find.find(n2, f));
});
unsigned sz1 = 1;
unsigned sz2 = 1;
m_size.find(n1, sz1);
m_size.find(n2, sz2);
m_find.insert(n1, n2);
m_size.insert(n2, sz1 + sz2);
save_var(n1, n2);
}
/**
\brief Merge the equivalence classes of n1 and n2. The root of the
resultant equivalence class is the one with more elements.
*/
void unifier::union2(expr_offset n1, expr_offset n2) {
DEBUG_CODE({
expr_offset f;
SASSERT(!m_find.find(n1, f));
SASSERT(!m_find.find(n2, f));
});
unsigned sz1 = 1;
unsigned sz2 = 1;
m_size.find(n1, sz1);
m_size.find(n2, sz2);
if (sz1 > sz2)
std::swap(n1, n2);
m_find.insert(n1, n2);
m_size.insert(n2, sz1 + sz2);
save_var(n1, n2);
}
bool unifier::unify_core(expr_offset p1, expr_offset p2) {
entry e(p1, p2);
m_todo.push_back(e);
while (!m_todo.empty()) {
entry const & e = m_todo.back();
p1 = find(e.first);
p2 = find(e.second);
m_todo.pop_back();
if (p1 != p2) {
expr * n1 = p1.get_expr();
expr * n2 = p2.get_expr();
SASSERT(!is_quantifier(n1));
SASSERT(!is_quantifier(n2));
bool v1 = is_var(n1);
bool v2 = is_var(n2);
if (v1 && v2) {
union2(p1, p2);
}
else if (v1) {
union1(p1, p2);
}
else if (v2) {
union1(p2, p1);
}
else {
app * a1 = to_app(n1);
app * a2 = to_app(n2);
unsigned off1 = p1.get_offset();
unsigned off2 = p2.get_offset();
if (a1->get_decl() != a2->get_decl() || a1->get_num_args() != a2->get_num_args())
return false;
union2(p1, p2);
unsigned j = a1->get_num_args();
while (j > 0) {
--j;
entry new_e(expr_offset(a1->get_arg(j), off1),
expr_offset(a2->get_arg(j), off2));
m_todo.push_back(new_e);
}
}
}
}
return true;
}
bool unifier::operator()(unsigned num_exprs, expr ** es, substitution & s, bool use_offsets) {
SASSERT(num_exprs > 0);
unsigned num_offsets = use_offsets ? num_exprs : 1;
reset(num_offsets);
m_subst = &s;
#if 1
TRACE("unifier", for (unsigned i = 0; i < num_exprs; ++i) tout << mk_pp(es[i], m_manager) << "\n";);
for (unsigned i = s.get_num_bindings(); i > 0; ) {
--i;
std::pair<unsigned,unsigned> bound;
expr_offset root, child;
s.get_binding(i, bound, root);
TRACE("unifier", tout << bound.first << " |-> " << mk_pp(root.get_expr(), m_manager) << "\n";);
if (is_var(root.get_expr())) {
var* v = m_manager.mk_var(bound.first,to_var(root.get_expr())->get_sort());
child = expr_offset(v, bound.second);
unsigned sz1 = 1;
unsigned sz2 = 1;
m_size.find(child, sz1);
m_size.find(root, sz2);
m_find.insert(child, root);
m_size.insert(root, sz1 + sz2);
}
}
#endif
for (unsigned i = 0; i < num_exprs - 1; i++) {
if (!unify_core(expr_offset(es[i], use_offsets ? i : 0),
expr_offset(es[i+1], use_offsets ? i + 1 : 0))) {
m_last_call_succeeded = false;
return m_last_call_succeeded;
}
}
m_last_call_succeeded = m_subst->acyclic();
return m_last_call_succeeded;
}
bool unifier::operator()(expr * e1, expr * e2, substitution & s, bool use_offsets) {
expr * es[2] = { e1, e2 };
return operator()(2, es, s, use_offsets);
}