mirror of
https://github.com/Z3Prover/z3
synced 2025-07-27 22:47:55 +00:00
Reorganizing the code
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
8b70f0b833
commit
d8cd3fc3ab
36 changed files with 261 additions and 429 deletions
94
src/ast/expr_map.cpp
Normal file
94
src/ast/expr_map.cpp
Normal file
|
@ -0,0 +1,94 @@
|
|||
/*++
|
||||
Copyright (c) 2007 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
expr_map.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Mapping from expressions to expressions + proofs. This mapping
|
||||
is used to cache simplification results.
|
||||
For every entry [e1->(e2, p)] we have that p is a proof that (= e1 e2).
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2008-01-03
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include"expr_map.h"
|
||||
#include"dec_ref_util.h"
|
||||
|
||||
expr_map::expr_map(ast_manager & m):
|
||||
m_manager(m),
|
||||
m_store_proofs(m.proofs_enabled()) {
|
||||
}
|
||||
|
||||
expr_map::expr_map(ast_manager & m, bool store_proofs):
|
||||
m_manager(m),
|
||||
m_store_proofs(store_proofs) {
|
||||
}
|
||||
|
||||
expr_map::~expr_map() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void expr_map::insert(expr * k, expr * d, proof * p) {
|
||||
m_manager.inc_ref(d);
|
||||
obj_map<expr, expr*>::obj_map_entry * entry = m_expr2expr.find_core(k);
|
||||
if (entry != 0) {
|
||||
m_manager.dec_ref(entry->get_data().m_value);
|
||||
entry->get_data().m_value = d;
|
||||
if (m_store_proofs) {
|
||||
m_manager.inc_ref(p);
|
||||
obj_map<expr, proof*>::obj_map_entry * entry_pr = m_expr2pr.find_core(k);
|
||||
SASSERT(entry_pr != 0);
|
||||
m_manager.dec_ref(entry_pr->get_data().m_value);
|
||||
entry_pr->get_data().m_value = p;
|
||||
}
|
||||
}
|
||||
else {
|
||||
m_manager.inc_ref(k);
|
||||
m_expr2expr.insert(k, d);
|
||||
if (m_store_proofs) {
|
||||
m_manager.inc_ref(p);
|
||||
m_expr2pr.insert(k, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void expr_map::get(expr * k, expr * & d, proof * & p) const {
|
||||
if (m_expr2expr.find(k, d)) {
|
||||
p = 0;
|
||||
if (m_store_proofs)
|
||||
m_expr2pr.find(k, p);
|
||||
}
|
||||
}
|
||||
|
||||
void expr_map::erase(expr * k) {
|
||||
expr * v;
|
||||
if (m_expr2expr.find(k, v)) {
|
||||
m_expr2expr.erase(k);
|
||||
m_manager.dec_ref(v);
|
||||
if (m_store_proofs) {
|
||||
proof * pr = 0;
|
||||
m_expr2pr.find(k, pr);
|
||||
m_expr2pr.erase(k);
|
||||
m_manager.dec_ref(pr);
|
||||
}
|
||||
m_manager.dec_ref(k);
|
||||
}
|
||||
}
|
||||
|
||||
void expr_map::reset() {
|
||||
dec_ref_values(m_manager, m_expr2pr);
|
||||
dec_ref_key_values(m_manager, m_expr2expr);
|
||||
}
|
||||
|
||||
void expr_map::flush() {
|
||||
reset();
|
||||
m_expr2expr.finalize();
|
||||
m_expr2pr.finalize();
|
||||
}
|
49
src/ast/expr_map.h
Normal file
49
src/ast/expr_map.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*++
|
||||
Copyright (c) 2007 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
expr_map.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Mapping from expressions to expressions + proofs. This mapping
|
||||
is used to cache simplification results.
|
||||
For every entry [e1->(e2, p)] we have that p is a proof that (= e1 e2).
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2008-01-03
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _EXPR_MAP_H_
|
||||
#define _EXPR_MAP_H_
|
||||
|
||||
#include"ast.h"
|
||||
#include"obj_hashtable.h"
|
||||
|
||||
/**
|
||||
\brief Map from expressions to expressions+proofs.
|
||||
|
||||
When proof production is disabled, no extra space is used.
|
||||
*/
|
||||
class expr_map {
|
||||
ast_manager & m_manager;
|
||||
bool m_store_proofs;
|
||||
obj_map<expr, expr*> m_expr2expr;
|
||||
obj_map<expr, proof*> m_expr2pr;
|
||||
public:
|
||||
expr_map(ast_manager & m);
|
||||
expr_map(ast_manager & m, bool store_proofs);
|
||||
~expr_map();
|
||||
void insert(expr * k, expr * d, proof * p);
|
||||
bool contains(expr * k) const { return m_expr2expr.contains(k); }
|
||||
void get(expr * k, expr * & d, proof * & p) const;
|
||||
void erase(expr * k);
|
||||
void reset();
|
||||
void flush();
|
||||
};
|
||||
|
||||
#endif
|
225
src/ast/func_decl_dependencies.cpp
Normal file
225
src/ast/func_decl_dependencies.cpp
Normal file
|
@ -0,0 +1,225 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
func_decl_dependencies.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2010-12-15.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"func_decl_dependencies.h"
|
||||
#include"for_each_expr.h"
|
||||
#include"ast_util.h"
|
||||
|
||||
struct collect_dependencies_proc {
|
||||
ast_manager & m_manager;
|
||||
func_decl_set & m_set;
|
||||
bool m_ng_only; // collect only declarations in non ground expressions
|
||||
|
||||
collect_dependencies_proc(ast_manager & m, func_decl_set & s, bool ng_only):
|
||||
m_manager(m),
|
||||
m_set(s),
|
||||
m_ng_only(ng_only) {}
|
||||
|
||||
void operator()(var * n) {}
|
||||
|
||||
void operator()(quantifier * n) {}
|
||||
|
||||
void operator()(app * n) {
|
||||
// We do not need to track dependencies on constants ...
|
||||
if (n->get_num_args()==0)
|
||||
return;
|
||||
if (m_ng_only && is_ground(n))
|
||||
return;
|
||||
// ... and interpreted function symbols
|
||||
func_decl * d = n->get_decl();
|
||||
if (d->get_family_id() == null_family_id) {
|
||||
m_set.insert(d);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void collect_func_decls(ast_manager & m, expr * n, func_decl_set & r, bool ng_only) {
|
||||
collect_dependencies_proc proc(m, r, ng_only);
|
||||
for_each_expr(proc, n);
|
||||
}
|
||||
|
||||
void func_decl_dependencies::reset() {
|
||||
dependency_graph::iterator it = m_deps.begin();
|
||||
dependency_graph::iterator end = m_deps.end();
|
||||
for (; it != end; ++it) {
|
||||
func_decl * f = (*it).m_key;
|
||||
func_decl_set * s = (*it).m_value;
|
||||
m_manager.dec_ref(f);
|
||||
dec_ref(m_manager, *s);
|
||||
dealloc(s);
|
||||
}
|
||||
m_deps.reset();
|
||||
}
|
||||
|
||||
void func_decl_dependencies::collect_func_decls(expr * n, func_decl_set * s) {
|
||||
::collect_func_decls(m_manager, n, *s, false);
|
||||
}
|
||||
|
||||
void func_decl_dependencies::collect_ng_func_decls(expr * n, func_decl_set * s) {
|
||||
::collect_func_decls(m_manager, n, *s, true);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Functor for finding cycles in macro definitions
|
||||
*/
|
||||
class func_decl_dependencies::top_sort {
|
||||
enum color { OPEN, IN_PROGRESS, CLOSED };
|
||||
ast_manager & m_manager;
|
||||
dependency_graph & m_deps;
|
||||
|
||||
typedef obj_map<func_decl, color> color_map;
|
||||
color_map m_colors;
|
||||
ptr_vector<func_decl> m_todo;
|
||||
|
||||
func_decl_set * definition(func_decl * f) const {
|
||||
func_decl_set * r = 0;
|
||||
m_deps.find(f, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
color get_color(func_decl * f) const {
|
||||
if (!f)
|
||||
return CLOSED;
|
||||
color_map::iterator it = m_colors.find_iterator(f);
|
||||
if (it != m_colors.end())
|
||||
return it->m_value;
|
||||
return OPEN;
|
||||
}
|
||||
|
||||
void set_color(func_decl * f, color c) {
|
||||
m_colors.insert(f, c);
|
||||
}
|
||||
|
||||
void visit(func_decl * f, bool & visited) {
|
||||
if (get_color(f) != CLOSED) {
|
||||
m_todo.push_back(f);
|
||||
visited = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool visit_children(func_decl * f) {
|
||||
func_decl_set * def = definition(f);
|
||||
if (!def)
|
||||
return true;
|
||||
bool visited = true;
|
||||
func_decl_set::iterator it = def->begin();
|
||||
func_decl_set::iterator end = def->end();
|
||||
for (; it != end; ++it) {
|
||||
visit(*it, visited);
|
||||
}
|
||||
return visited;
|
||||
}
|
||||
|
||||
bool all_children_closed(func_decl * f) const {
|
||||
func_decl_set * def = definition(f);
|
||||
if (!def)
|
||||
return true;
|
||||
func_decl_set::iterator it = def->begin();
|
||||
func_decl_set::iterator end = def->end();
|
||||
for (; it != end; ++it) {
|
||||
if (get_color(*it) != CLOSED)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return \c true if a cycle is detected.
|
||||
*/
|
||||
bool main_loop(func_decl * f) {
|
||||
if (get_color(f) == CLOSED)
|
||||
return false;
|
||||
m_todo.push_back(f);
|
||||
while (!m_todo.empty()) {
|
||||
func_decl * f = m_todo.back();
|
||||
|
||||
switch (get_color(f)) {
|
||||
case CLOSED:
|
||||
m_todo.pop_back();
|
||||
break;
|
||||
case OPEN:
|
||||
set_color(f, IN_PROGRESS);
|
||||
if (visit_children(f)) {
|
||||
SASSERT(m_todo.back() == f);
|
||||
m_todo.pop_back();
|
||||
set_color(f, CLOSED);
|
||||
}
|
||||
break;
|
||||
case IN_PROGRESS:
|
||||
if (all_children_closed(f)) {
|
||||
SASSERT(m_todo.back() == f);
|
||||
set_color(f, CLOSED);
|
||||
} else {
|
||||
m_todo.reset();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
top_sort(ast_manager & m, dependency_graph & deps):m_manager(m), m_deps(deps) {}
|
||||
|
||||
bool operator()(func_decl * new_decl) {
|
||||
|
||||
// [Leo]: It is not trivial to reuse m_colors between different calls since we are update the graph.
|
||||
// To implement this optimization, we need an incremental topological sort algorithm.
|
||||
// The trick of saving the dependencies will save a lot of time. So, I don't think we really
|
||||
// need a incremental top-sort algo.
|
||||
m_colors.reset();
|
||||
return main_loop(new_decl);
|
||||
}
|
||||
};
|
||||
|
||||
bool func_decl_dependencies::insert(func_decl * f, func_decl_set * s) {
|
||||
if (m_deps.contains(f)) {
|
||||
dealloc(s);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_deps.insert(f, s);
|
||||
|
||||
top_sort cycle_detector(m_manager, m_deps);
|
||||
if (cycle_detector(f)) {
|
||||
m_deps.erase(f);
|
||||
dealloc(s);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_manager.inc_ref(f);
|
||||
inc_ref(m_manager, *s);
|
||||
return true;
|
||||
}
|
||||
|
||||
void func_decl_dependencies::erase(func_decl * f) {
|
||||
func_decl_set * s = 0;
|
||||
if (m_deps.find(f, s)) {
|
||||
m_manager.dec_ref(f);
|
||||
dec_ref(m_manager, *s);
|
||||
m_deps.erase(f);
|
||||
dealloc(s);
|
||||
}
|
||||
}
|
||||
|
||||
void func_decl_dependencies::display(std::ostream & out) {
|
||||
// TODO
|
||||
}
|
110
src/ast/func_decl_dependencies.h
Normal file
110
src/ast/func_decl_dependencies.h
Normal file
|
@ -0,0 +1,110 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
func_decl_dependencies.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2010-12-15.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _FUNC_DECL_DEPENDENCIES_H_
|
||||
#define _FUNC_DECL_DEPENDENCIES_H_
|
||||
|
||||
#include"ast.h"
|
||||
#include"obj_hashtable.h"
|
||||
|
||||
// Set of dependencies
|
||||
typedef obj_hashtable<func_decl> func_decl_set;
|
||||
|
||||
/**
|
||||
\brief Collect uninterpreted function declarations (with arity > 0) occurring in \c n.
|
||||
*/
|
||||
void collect_func_decls(ast_manager & m, expr * n, func_decl_set & r, bool ng_only = false);
|
||||
|
||||
/**
|
||||
\brief Auxiliary data-structure used for tracking dependencies between function declarations.
|
||||
|
||||
The following pattern of use is expected:
|
||||
|
||||
func_decl_dependencies & dm;
|
||||
func_decl_set * S = dm.mk_func_decl_set();
|
||||
dm.collect_func_decls(t_1, S);
|
||||
...
|
||||
dm.collect_func_decls(t_n, S);
|
||||
dm.insert(f, S);
|
||||
*/
|
||||
class func_decl_dependencies {
|
||||
typedef obj_map<func_decl, func_decl_set *> dependency_graph;
|
||||
ast_manager & m_manager;
|
||||
dependency_graph m_deps;
|
||||
|
||||
class top_sort;
|
||||
|
||||
public:
|
||||
func_decl_dependencies(ast_manager & m):m_manager(m) {}
|
||||
~func_decl_dependencies() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void reset();
|
||||
|
||||
/**
|
||||
\brief Create a dependecy set.
|
||||
This set should be populated using #collect_func_decls.
|
||||
After populating the set, it must be used as an argument for the #insert method.
|
||||
|
||||
\remark The manager owns the set.
|
||||
|
||||
\warning Failure to call #insert will produce a memory leak.
|
||||
*/
|
||||
func_decl_set * mk_func_decl_set() { return alloc(func_decl_set); }
|
||||
|
||||
/**
|
||||
\brief Store the uninterpreted function declarations used in \c n into \c s.
|
||||
*/
|
||||
void collect_func_decls(expr * n, func_decl_set * s);
|
||||
|
||||
/**
|
||||
\brief Store the uninterpreted function declarations (in non ground terms) used in \c n into \c s.
|
||||
*/
|
||||
void collect_ng_func_decls(expr * n, func_decl_set * s);
|
||||
|
||||
/**
|
||||
\brief Insert \c f in the manager with the given set of dependencies.
|
||||
The insertion succeeds iff
|
||||
1- no cycle is created between the new entry and
|
||||
the already existing dependencies.
|
||||
2- \c f was not already inserted into the manager.
|
||||
|
||||
Return false in case of failure.
|
||||
|
||||
\remark The manager is the owner of the dependency sets.
|
||||
*/
|
||||
bool insert(func_decl * f, func_decl_set * s);
|
||||
|
||||
/**
|
||||
\brief Return true if \c f is registered in this manager.
|
||||
*/
|
||||
bool contains(func_decl * f) const { return m_deps.contains(f); }
|
||||
|
||||
func_decl_set * get_dependencies(func_decl * f) const { func_decl_set * r = 0; m_deps.find(f, r); return r; }
|
||||
|
||||
/**
|
||||
\brief Erase \c f (and its dependencies) from the manager.
|
||||
*/
|
||||
void erase(func_decl * f);
|
||||
|
||||
void display(std::ostream & out);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
105
src/ast/used_symbols.h
Normal file
105
src/ast/used_symbols.h
Normal file
|
@ -0,0 +1,105 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
used_symbols.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Collect the symbols used in an expression.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2011-01-11.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _USED_SYMBOLS_H_
|
||||
#define _USED_SYMBOLS_H_
|
||||
|
||||
#include"ast.h"
|
||||
#include"hashtable.h"
|
||||
#include"obj_hashtable.h"
|
||||
|
||||
struct do_nothing_rename_proc {
|
||||
symbol operator()(symbol const & s) const { return s; }
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Functor for collecting the symbols used in an expression.
|
||||
*/
|
||||
template<typename RENAME_PROC=do_nothing_rename_proc>
|
||||
class used_symbols : public RENAME_PROC {
|
||||
typedef hashtable<symbol, symbol_hash_proc, symbol_eq_proc> symbol_set;
|
||||
|
||||
symbol_set m_used;
|
||||
obj_hashtable<expr> m_visited;
|
||||
ptr_vector<expr> m_todo;
|
||||
|
||||
void found(symbol const & s) { m_used.insert(RENAME_PROC::operator()(s)); }
|
||||
|
||||
void visit(expr * n) {
|
||||
if (!m_visited.contains(n)) {
|
||||
m_visited.insert(n);
|
||||
m_todo.push_back(n);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
used_symbols(RENAME_PROC const & p = RENAME_PROC()):
|
||||
RENAME_PROC(p) {
|
||||
}
|
||||
|
||||
void operator()(expr * n, bool ignore_quantifiers = false) {
|
||||
m_visited.reset();
|
||||
m_used.reset();
|
||||
m_todo.reset();
|
||||
visit(n);
|
||||
while (!m_todo.empty()) {
|
||||
n = m_todo.back();
|
||||
m_todo.pop_back();
|
||||
unsigned j;
|
||||
switch (n->get_kind()) {
|
||||
case AST_APP:
|
||||
found(to_app(n)->get_decl()->get_name());
|
||||
j = to_app(n)->get_num_args();
|
||||
while (j > 0) {
|
||||
--j;
|
||||
visit(to_app(n)->get_arg(j));
|
||||
}
|
||||
break;
|
||||
case AST_QUANTIFIER:
|
||||
if (!ignore_quantifiers) {
|
||||
found(to_quantifier(n)->get_qid());
|
||||
unsigned num_decls = to_quantifier(n)->get_num_decls();
|
||||
for (unsigned i = 0; i < num_decls; i++)
|
||||
found(to_quantifier(n)->get_decl_name(i));
|
||||
unsigned num_pats = to_quantifier(n)->get_num_patterns();
|
||||
for (unsigned i = 0; i < num_pats; i++)
|
||||
visit(to_quantifier(n)->get_pattern(i));
|
||||
unsigned num_no_pats = to_quantifier(n)->get_num_no_patterns();
|
||||
for (unsigned i = 0; i < num_no_pats; i++)
|
||||
visit(to_quantifier(n)->get_no_pattern(i));
|
||||
visit(to_quantifier(n)->get_expr());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool contains(symbol const & s) const { return m_used.contains(RENAME_PROC::operator()(s)); }
|
||||
|
||||
bool contains_core(symbol const & s) const { return m_used.contains(s); }
|
||||
|
||||
void insert(symbol const & s) { m_used.insert(RENAME_PROC::operator()(s)); }
|
||||
|
||||
void insert_core(symbol const & s) { m_used.insert(s); }
|
||||
|
||||
void erase_core(symbol const & s) { m_used.erase(s); }
|
||||
};
|
||||
|
||||
#endif /* _USED_SYMBOLS_H_ */
|
Loading…
Add table
Add a link
Reference in a new issue