mirror of
https://github.com/Z3Prover/z3
synced 2025-05-03 22:05:45 +00:00
Z3 sources
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
3f9edad676
commit
e9eab22e5c
1186 changed files with 381859 additions and 0 deletions
183
lib/unifier.cpp
Normal file
183
lib/unifier.cpp
Normal file
|
@ -0,0 +1,183 @@
|
|||
/*++
|
||||
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);
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue