z3-z3-4.13.0.src.smt.smt_enode.cpp Maven / Gradle / Ivy
The newest version!
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
smt_enode.cpp
Abstract:
Author:
Leonardo de Moura (leonardo) 2008-02-19.
Revision History:
--*/
#include "ast/ast_pp.h"
#include "smt/smt_context.h"
#include "smt/smt_enode.h"
namespace smt {
/**
\brief Initialize an enode in the given memory position.
*/
enode * enode::init(ast_manager & m, void * mem, app2enode_t const & app2enode, app * owner,
unsigned generation, bool suppress_args, bool merge_tf, unsigned iscope_lvl,
bool cgc_enabled, bool update_children_parent) {
SASSERT(m.is_bool(owner) || !merge_tf);
enode * n = new (mem) enode();
n->m_owner = owner;
n->m_root = n;
n->m_next = n;
n->m_cg = nullptr;
n->m_class_size = 1;
n->m_generation = generation;
n->m_func_decl_id = UINT_MAX;
n->m_mark = false;
n->m_mark2 = false;
n->m_interpreted = false;
n->m_suppress_args = suppress_args;
n->m_eq = m.is_eq(owner);
n->m_commutative = n->get_num_args() == 2 && owner->get_decl()->is_commutative();
n->m_bool = m.is_bool(owner);
n->m_merge_tf = merge_tf;
n->m_cgc_enabled = cgc_enabled;
n->m_iscope_lvl = iscope_lvl;
n->m_lbl_hash = -1;
n->m_proof_is_logged = false;
n->m_is_shared = 2;
unsigned num_args = n->get_num_args();
for (unsigned i = 0; i < num_args; i++) {
enode * arg = app2enode[owner->get_arg(i)->get_id()];
n->m_args[i] = arg;
arg->get_root()->m_is_shared = 2;
SASSERT(n->get_arg(i) == arg);
if (update_children_parent)
arg->get_root()->m_parents.push_back(n);
}
TRACE("mk_enode_detail", tout << "new enode suppress_args: " << n->m_suppress_args << "\n";);
SASSERT(n->m_suppress_args == suppress_args);
return n;
}
enode * enode::mk(ast_manager & m, region & r, app2enode_t const & app2enode, app * owner,
unsigned generation, bool suppress_args, bool merge_tf, unsigned iscope_lvl,
bool cgc_enabled, bool update_children_parent) {
SASSERT(m.is_bool(owner) || !merge_tf);
unsigned sz = get_enode_size(suppress_args ? 0 : owner->get_num_args());
void * mem = r.allocate(sz);
return init(m, mem, app2enode, owner, generation, suppress_args, merge_tf, iscope_lvl, cgc_enabled, update_children_parent);
}
enode * enode::mk_dummy(ast_manager & m, app2enode_t const & app2enode, app * owner) {
unsigned sz = get_enode_size(owner->get_num_args());
void * mem = alloc_svect(char, sz);
return init(m, mem, app2enode, owner, 0, false, false, 0, true, false);
}
void enode::del_eh(ast_manager & m, bool update_children_parent) {
SASSERT(m_class_size == 1);
SASSERT(m_root == this);
SASSERT(m_next == this);
unsigned num_args = get_num_args();
for (unsigned i = 0; i < num_args; i++) {
enode * arg = get_arg(i);
if (update_children_parent) {
SASSERT(arg->get_root()->m_parents.back() == this);
arg->get_root()->m_parents.pop_back();
}
}
this->~enode();
}
unsigned enode::get_num_th_vars() const {
return m_th_var_list.size();
}
/**
\brief Return the theory var (in theory th_id) associated with
the enode.
Return null_theory_var if the enode is not associated
with a variable of theory th_id
*/
theory_var enode::get_th_var(theory_id th_id) const {
return m_th_var_list.find(th_id);
}
/**
\brief Add the entry (v, id) to the list of theory variables.
*/
void enode::add_th_var(theory_var v, theory_id id, region & r) {
m_th_var_list.add_var(v, id, r);
}
/**
\brief Replace the entry (v', id) with the entry (v, id).
The enode must have an entry (v', id)
*/
void enode::replace_th_var(theory_var v, theory_id id) {
m_th_var_list.replace(v, id);
}
/**
\brief Delete theory variable. It assumes the
enode is associated with a variable of the given theory.
*/
void enode::del_th_var(theory_id id) {
m_th_var_list.del_var(id);
}
/**
\brief Push old value of generation on the context trail stack
and update the generation.
*/
void enode::set_generation(context & ctx, unsigned generation) {
if (m_generation == generation)
return;
ctx.push_trail(value_trail(m_generation));
m_generation = generation;
}
void enode::set_lbl_hash(context & ctx) {
SASSERT(m_lbl_hash == -1);
// m_lbl_hash should be different from -1, if and only if,
// there is a pattern that contains the enode. So,
// I use a trail to restore the value of m_lbl_hash to -1.
ctx.push_trail(value_trail(m_lbl_hash));
unsigned h = hash_u(get_owner_id());
m_lbl_hash = h & (APPROX_SET_CAPACITY - 1);
// propagate modification to the root m_lbls set.
approx_set & r_lbls = m_root->m_lbls;
if (!r_lbls.may_contain(m_lbl_hash)) {
ctx.push_trail(value_trail(r_lbls));
r_lbls.insert(m_lbl_hash);
}
}
enode * enode::get_eq_enode_with_min_gen() {
if (m_generation == 0)
return this;
enode * r = this;
enode * curr = this;
do {
if (curr->m_generation < r->m_generation) {
r = curr;
if (r->m_generation == 0)
return r;
}
curr = curr->m_next;
}
while (curr != this);
return r;
}
#ifdef Z3DEBUG
bool enode::check_invariant() const {
unsigned class_size = 0;
bool found_root = false;
bool found_this = false;
bool has_interpreted = false;
// "Equivalence" class structure.
enode const * curr = this;
do {
SASSERT(curr->m_root == m_root);
class_size++;
if (curr == m_root)
found_root = true;
if (curr == this)
found_this = true;
if (curr->is_interpreted())
has_interpreted = true;
curr = curr->m_next;
}
while (curr != this);
SASSERT(found_root);
SASSERT(found_this);
SASSERT(this != m_root || class_size == m_class_size);
SASSERT(!has_interpreted || m_root->is_interpreted());
// Parent use-list
if (this == m_root) {
for (enode* parent : m_parents) {
unsigned i = 0;
unsigned num_args = parent->get_num_args();
SASSERT(num_args > 0);
for (; i < num_args; i++) {
enode * arg = parent->get_arg(i);
if (arg->get_root() == m_root)
break;
}
SASSERT(i < num_args);
}
}
// Proof tree
// m_root is reachable from "this" by following the transitivity proof
SASSERT(trans_reaches(m_root));
SASSERT(check_parent_invariant());
return true;
}
/**
\brief Return true if the node is n or n is reached following the
m_proof.m_target pointers
*/
bool enode::trans_reaches(enode * n) const {
const enode * curr = this;
while (curr != 0) {
if (curr == n) {
return true;
}
curr = curr->m_trans.m_target;
}
return false;
}
bool enode::check_parent_invariant() const {
if (this != m_root)
return true;
enode const * curr = m_root;
do {
if (curr != m_root) {
for (enode * p : curr->m_parents) {
if (!p->is_true_eq() && !m_root->contains_parent_congruent_to(p)) {
UNREACHABLE();
}
}
}
curr = curr->m_next;
}
while (curr != m_root);
return true;
}
bool enode::contains_parent_congruent_to(enode * p) const {
for (enode* curr : m_parents) {
if (congruent(curr, p))
return true;
}
return false;
}
#endif
void enode::display_lbls(std::ostream & out) const {
out << "#" << get_owner_id() << " -> #" << get_root()->get_owner_id() << ", lbls: " << get_lbls() << ", plbls: " << get_plbls()
<< ", root->lbls: " << get_root()->get_lbls() << ", root->plbls: " << get_root()->get_plbls();
if (has_lbl_hash())
out << ", lbl-hash: " << static_cast(get_lbl_hash());
out << "\n";
}
bool congruent(enode * n1, enode * n2, bool & comm) {
comm = false;
if (n1->get_expr()->get_decl() != n2->get_expr()->get_decl())
return false;
unsigned num_args = n1->get_num_args();
if (num_args != n2->get_num_args())
return false;
if (n1->is_commutative()) {
enode * c1_1 = n1->get_arg(0)->get_root();
enode * c1_2 = n1->get_arg(1)->get_root();
enode * c2_1 = n2->get_arg(0)->get_root();
enode * c2_2 = n2->get_arg(1)->get_root();
if (c1_1 == c2_1 && c1_2 == c2_2) {
return true;
}
if (c1_1 == c2_2 && c1_2 == c2_1) {
comm = true;
return true;
}
return false;
}
else {
for (unsigned i = 0; i < num_args; i++)
if (n1->get_arg(i)->get_root() != n2->get_arg(i)->get_root())
return false;
return true;
}
}
unsigned get_max_generation(unsigned num_enodes, enode * const * enodes) {
unsigned max = 0;
for (unsigned i = 0; i < num_enodes; i++) {
unsigned curr = enodes[i]->get_generation();
if (curr > max)
max = curr;
}
return max;
}
void unmark_enodes(unsigned num_enodes, enode * const * enodes) {
for (unsigned i = 0; i < num_enodes; i++)
enodes[i]->unset_mark();
}
void unmark_enodes2(unsigned num_enodes, enode * const * enodes) {
for (unsigned i = 0; i < num_enodes; i++)
enodes[i]->unset_mark2();
}
tmp_enode::tmp_enode():
m_app(0),
m_capacity(0),
m_enode_data(nullptr) {
SASSERT(m_app.get_app()->get_decl() == 0);
set_capacity(5);
}
tmp_enode::~tmp_enode() {
dealloc_svect(m_enode_data);
}
void tmp_enode::set_capacity(unsigned new_capacity) {
SASSERT(new_capacity > m_capacity);
if (m_enode_data)
dealloc_svect(m_enode_data);
m_capacity = new_capacity;
unsigned sz = sizeof(enode) + m_capacity * sizeof(enode*);
m_enode_data = alloc_svect(char, sz);
memset(m_enode_data, 0, sz);
enode * n = get_enode();
n->m_owner = m_app.get_app();
n->m_root = n;
n->m_next = n;
n->m_class_size = 1;
n->m_cgc_enabled = true;
n->m_func_decl_id = UINT_MAX;
}
enode * tmp_enode::set(func_decl * f, unsigned num_args, enode * const * args) {
if (num_args > m_capacity)
set_capacity(num_args * 2);
enode * r = get_enode();
if (m_app.get_app()->get_decl() != f) {
r->m_func_decl_id = UINT_MAX;
}
m_app.set_decl(f);
m_app.set_num_args(num_args);
r->m_commutative = num_args == 2 && f->is_commutative();
memcpy(get_enode()->m_args, args, sizeof(enode*)*num_args);
return r;
}
void tmp_enode::reset() {
get_enode()->m_func_decl_id = UINT_MAX;
}
};