3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-08-11 13:40:52 +00:00

Reorganizing the code

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2012-10-20 22:03:58 -07:00
parent 2b8fb6c718
commit 492484c5aa
125 changed files with 632 additions and 390 deletions

467
src/rewriter/der.cpp Normal file
View file

@ -0,0 +1,467 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
der.cpp
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-01-27.
Revision History:
Christoph Wintersteiger, 2010-03-30: Added Destr. Multi-Equality Resolution
--*/
#include"der.h"
#include"occurs.h"
#include"for_each_expr.h"
#include"rewriter_def.h"
#include"ast_pp.h"
#include"ast_ll_pp.h"
#include"ast_smt2_pp.h"
static bool is_var(expr * e, unsigned num_decls) {
return is_var(e) && to_var(e)->get_idx() < num_decls;
}
static bool is_neg_var(ast_manager & m, expr * e, unsigned num_decls) {
return m.is_not(e) && is_var(to_app(e)->get_arg(0)) && to_var(to_app(e)->get_arg(0))->get_idx() < num_decls;
}
/**
\brief Return true if \c e is of the form (not (= VAR t)) or (not (iff VAR t)) or (iff VAR t) or (iff (not VAR) t) or (VAR IDX) or (not (VAR IDX)).
The last case can be viewed
*/
bool der::is_var_diseq(expr * e, unsigned num_decls, var * & v, expr_ref & t) {
// (not (= VAR t)) and (not (iff VAR t)) cases
if (m_manager.is_not(e) && (m_manager.is_eq(to_app(e)->get_arg(0)) || m_manager.is_iff(to_app(e)->get_arg(0)))) {
app * eq = to_app(to_app(e)->get_arg(0));
SASSERT(m_manager.is_eq(eq) || m_manager.is_iff(eq));
expr * lhs = eq->get_arg(0);
expr * rhs = eq->get_arg(1);
if (!is_var(lhs, num_decls) && !is_var(rhs, num_decls))
return false;
if (!is_var(lhs, num_decls))
std::swap(lhs, rhs);
SASSERT(is_var(lhs, num_decls));
// Remark: Occurs check is not necessary here... the top-sort procedure will check for cycles...
// if (occurs(lhs, rhs)) {
// return false;
// }
v = to_var(lhs);
t = rhs;
TRACE("der", tout << mk_pp(e, m_manager) << "\n";);
return true;
}
// (iff VAR t) and (iff (not VAR) t) cases
else if (m_manager.is_iff(e)) {
expr * lhs = to_app(e)->get_arg(0);
expr * rhs = to_app(e)->get_arg(1);
// (iff VAR t) case
if (is_var(lhs, num_decls) || is_var(rhs, num_decls)) {
if (!is_var(lhs, num_decls))
std::swap(lhs, rhs);
SASSERT(is_var(lhs, num_decls));
// Remark: Occurs check is not necessary here... the top-sort procedure will check for cycles...
// if (occurs(lhs, rhs)) {
// return false;
// }
v = to_var(lhs);
t = m_manager.mk_not(rhs);
m_new_exprs.push_back(t);
TRACE("der", tout << mk_pp(e, m_manager) << "\n";);
return true;
}
// (iff (not VAR) t) case
else if (is_neg_var(m_manager, lhs, num_decls) || is_neg_var(m_manager, rhs, num_decls)) {
if (!is_neg_var(m_manager, lhs, num_decls))
std::swap(lhs, rhs);
SASSERT(is_neg_var(m_manager, lhs, num_decls));
expr * lhs_var = to_app(lhs)->get_arg(0);
// Remark: Occurs check is not necessary here... the top-sort procedure will check for cycles...
// if (occurs(lhs_var, rhs)) {
// return false;
// }
v = to_var(lhs_var);
t = rhs;
TRACE("der", tout << mk_pp(e, m_manager) << "\n";);
return true;
}
else {
return false;
}
}
// VAR != false case
else if (is_var(e, num_decls)) {
t = m_manager.mk_false();
v = to_var(e);
TRACE("der", tout << mk_pp(e, m_manager) << "\n";);
return true;
}
// VAR != true case
else if (is_neg_var(m_manager, e, num_decls)) {
t = m_manager.mk_true();
v = to_var(to_app(e)->get_arg(0));
TRACE("der", tout << mk_pp(e, m_manager) << "\n";);
return true;
}
else {
return false;
}
}
void der::operator()(quantifier * q, expr_ref & r, proof_ref & pr) {
bool reduced = false;
pr = 0;
r = q;
TRACE("der", tout << mk_pp(q, m_manager) << "\n";);
// Keep applying it until r doesn't change anymore
do {
proof_ref curr_pr(m_manager);
q = to_quantifier(r);
reduce1(q, r, curr_pr);
if (q != r)
reduced = true;
if (m_manager.proofs_enabled()) {
pr = m_manager.mk_transitivity(pr, curr_pr);
}
} while (q != r && is_quantifier(r));
// Eliminate variables that have become unused
if (reduced && is_forall(r)) {
quantifier * q = to_quantifier(r);
elim_unused_vars(m_manager, q, r);
if (m_manager.proofs_enabled()) {
proof * p1 = m_manager.mk_elim_unused_vars(q, r);
pr = m_manager.mk_transitivity(pr, p1);
}
}
m_new_exprs.reset();
}
void der::reduce1(quantifier * q, expr_ref & r, proof_ref & pr) {
if (!is_forall(q)) {
pr = 0;
r = q;
return;
}
expr * e = q->get_expr();
unsigned num_decls = q->get_num_decls();
var * v = 0;
expr_ref t(m_manager);
if (m_manager.is_or(e)) {
unsigned num_args = to_app(e)->get_num_args();
unsigned i = 0;
unsigned diseq_count = 0;
unsigned largest_vinx = 0;
m_map.reset();
m_pos2var.reset();
m_inx2var.reset();
m_pos2var.reserve(num_args, -1);
// Find all disequalities
for (; i < num_args; i++) {
if (is_var_diseq(to_app(e)->get_arg(i), num_decls, v, t)) {
unsigned idx = v->get_idx();
if(m_map.get(idx, 0) == 0) {
m_map.reserve(idx + 1, 0);
m_inx2var.reserve(idx + 1, 0);
m_map[idx] = t;
m_inx2var[idx] = v;
m_pos2var[i] = idx;
diseq_count++;
largest_vinx = (idx>largest_vinx) ? idx : largest_vinx;
}
}
}
if (diseq_count > 0) {
get_elimination_order();
SASSERT(m_order.size() <= diseq_count); // some might be missing because of cycles
if (!m_order.empty()) {
create_substitution(largest_vinx + 1);
apply_substitution(q, r);
}
}
else {
TRACE("der_bug", tout << "Did not find any diseq\n" << mk_pp(q, m_manager) << "\n";);
r = q;
}
}
// Remark: get_elimination_order/top-sort checks for cycles, but it is not invoked for unit clauses.
// So, we must perform a occurs check here.
else if (is_var_diseq(e, num_decls, v, t) && !occurs(v, t)) {
r = m_manager.mk_false();
}
else
r = q;
if (m_manager.proofs_enabled()) {
pr = r == q ? 0 : m_manager.mk_der(q, r);
}
}
void der_sort_vars(ptr_vector<var> & vars, ptr_vector<expr> & definitions, unsigned_vector & order) {
order.reset();
// eliminate self loops, and definitions containing quantifiers.
bool found = false;
for (unsigned i = 0; i < definitions.size(); i++) {
var * v = vars[i];
expr * t = definitions[i];
if (t == 0 || has_quantifiers(t) || occurs(v, t))
definitions[i] = 0;
else
found = true; // found at least one candidate
}
if (!found)
return;
typedef std::pair<expr *, unsigned> frame;
svector<frame> todo;
expr_fast_mark1 visiting;
expr_fast_mark2 done;
unsigned vidx, num;
for (unsigned i = 0; i < definitions.size(); i++) {
if (definitions[i] == 0)
continue;
var * v = vars[i];
SASSERT(v->get_idx() == i);
SASSERT(todo.empty());
todo.push_back(frame(v, 0));
while (!todo.empty()) {
start:
frame & fr = todo.back();
expr * t = fr.first;
if (t->get_ref_count() > 1 && done.is_marked(t)) {
todo.pop_back();
continue;
}
switch (t->get_kind()) {
case AST_VAR:
vidx = to_var(t)->get_idx();
if (fr.second == 0) {
CTRACE("der_bug", vidx >= definitions.size(), tout << "vidx: " << vidx << "\n";);
// Remark: The size of definitions may be smaller than the number of variables occuring in the quantified formula.
if (definitions.get(vidx, 0) != 0) {
if (visiting.is_marked(t)) {
// cycle detected: remove t
visiting.reset_mark(t);
definitions[vidx] = 0;
}
else {
visiting.mark(t);
fr.second = 1;
todo.push_back(frame(definitions[vidx], 0));
goto start;
}
}
}
else {
SASSERT(fr.second == 1);
if (definitions.get(vidx, 0) != 0) {
visiting.reset_mark(t);
order.push_back(vidx);
}
else {
// var was removed from the list of candidate vars to elim cycle
// do nothing
}
}
if (t->get_ref_count() > 1)
done.mark(t);
todo.pop_back();
break;
case AST_QUANTIFIER:
UNREACHABLE();
todo.pop_back();
break;
case AST_APP:
num = to_app(t)->get_num_args();
while (fr.second < num) {
expr * arg = to_app(t)->get_arg(fr.second);
fr.second++;
if (arg->get_ref_count() > 1 && done.is_marked(arg))
continue;
todo.push_back(frame(arg, 0));
goto start;
}
if (t->get_ref_count() > 1)
done.mark(t);
todo.pop_back();
break;
default:
UNREACHABLE();
todo.pop_back();
break;
}
}
}
}
void der::get_elimination_order() {
m_order.reset();
TRACE("top_sort",
tout << "DEFINITIONS: " << std::endl;
for(unsigned i = 0; i < m_map.size(); i++)
if(m_map[i]) tout << "VAR " << i << " = " << mk_pp(m_map[i], m_manager) << std::endl;
);
// der::top_sort ts(m_manager);
der_sort_vars(m_inx2var, m_map, m_order);
TRACE("der",
tout << "Elimination m_order:" << std::endl;
for(unsigned i=0; i<m_order.size(); i++)
{
if (i != 0) tout << ",";
tout << m_order[i];
}
tout << std::endl;
);
}
void der::create_substitution(unsigned sz) {
m_subst_map.reset();
m_subst_map.resize(sz, 0);
for(unsigned i = 0; i < m_order.size(); i++) {
expr_ref cur(m_map[m_order[i]], m_manager);
// do all the previous substitutions before inserting
expr_ref r(m_manager);
m_subst(cur, m_subst_map.size(), m_subst_map.c_ptr(), r);
unsigned inx = sz - m_order[i]- 1;
SASSERT(m_subst_map[inx]==0);
m_subst_map[inx] = r;
}
}
void der::apply_substitution(quantifier * q, expr_ref & r) {
expr * e = q->get_expr();
unsigned num_args=to_app(e)->get_num_args();
// get a new expression
m_new_args.reset();
for(unsigned i = 0; i < num_args; i++) {
int x = m_pos2var[i];
if (x != -1 && m_map[x] != 0)
continue; // this is a disequality with definition (vanishes)
m_new_args.push_back(to_app(e)->get_arg(i));
}
unsigned sz = m_new_args.size();
expr_ref t(m_manager);
t = (sz == 1) ? m_new_args[0] : m_manager.mk_or(sz, m_new_args.c_ptr());
expr_ref new_e(m_manager);
m_subst(t, m_subst_map.size(), m_subst_map.c_ptr(), new_e);
// don't forget to update the quantifier patterns
expr_ref_buffer new_patterns(m_manager);
expr_ref_buffer new_no_patterns(m_manager);
for (unsigned j = 0; j < q->get_num_patterns(); j++) {
expr_ref new_pat(m_manager);
m_subst(q->get_pattern(j), m_subst_map.size(), m_subst_map.c_ptr(), new_pat);
new_patterns.push_back(new_pat);
}
for (unsigned j = 0; j < q->get_num_no_patterns(); j++) {
expr_ref new_nopat(m_manager);
m_subst(q->get_no_pattern(j), m_subst_map.size(), m_subst_map.c_ptr(), new_nopat);
new_no_patterns.push_back(new_nopat);
}
r = m_manager.update_quantifier(q, new_patterns.size(), new_patterns.c_ptr(),
new_no_patterns.size(), new_no_patterns.c_ptr(), new_e);
}
struct der_rewriter_cfg : public default_rewriter_cfg {
der m_der;
der_rewriter_cfg(ast_manager & m):m_der(m) {}
ast_manager & m() const { return m_der.m(); }
bool reduce_quantifier(quantifier * old_q,
expr * new_body,
expr * const * new_patterns,
expr * const * new_no_patterns,
expr_ref & result,
proof_ref & result_pr) {
quantifier_ref q1(m());
q1 = m().update_quantifier(old_q, old_q->get_num_patterns(), new_patterns, old_q->get_num_no_patterns(), new_no_patterns, new_body);
m_der(q1, result, result_pr);
return true;
}
};
template class rewriter_tpl<der_rewriter_cfg>;
struct der_rewriter::imp : public rewriter_tpl<der_rewriter_cfg> {
der_rewriter_cfg m_cfg;
imp(ast_manager & m):
rewriter_tpl<der_rewriter_cfg>(m, m.proofs_enabled(), m_cfg),
m_cfg(m) {
}
};
der_rewriter::der_rewriter(ast_manager & m) {
m_imp = alloc(imp, m);
}
der_rewriter::~der_rewriter() {
dealloc(m_imp);
}
ast_manager & der_rewriter::m() const {
return m_imp->m();
}
void der_rewriter::operator()(expr * t, expr_ref & result, proof_ref & result_pr) {
m_imp->operator()(t, result, result_pr);
}
void der_rewriter::set_cancel(bool f) {
#pragma omp critical (der_rewriter)
{
m_imp->set_cancel(f);
}
}
void der_rewriter::cleanup() {
ast_manager & m = m_imp->m();
#pragma omp critical (th_rewriter)
{
dealloc(m_imp);
m_imp = alloc(imp, m);
}
}
void der_rewriter::reset() {
m_imp->reset();
}

187
src/rewriter/der.h Normal file
View file

@ -0,0 +1,187 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
der.h
Abstract:
Destructive equality resolution.
Author:
Leonardo de Moura (leonardo) 2008-01-27.
Revision History:
Christoph Wintersteiger, 2010-03-30: Added Destr. Multi-Equality Resolution
--*/
#ifndef _DER_H_
#define _DER_H_
#include"ast.h"
#include"var_subst.h"
/*
New DER: the class DER (above) eliminates variables one by one.
This is inefficient, and we should implement a new version that
can handle efficiently examples with hundreds of variables.
Suppose the target of the simplification is the quantifier
(FORALL (x1 T1) (x2 T2) ... (xn Tn) (or ....))
So, the variables x1 ... xn are the candidates for elimination.
First, we build a mapping of candidate substitutions
Since variables x1 ... xn have ids 0 ... n-1, we can
use an array m_map to implement this mapping.
The idea is to traverse the children of the (or ...) looking
for diseqs. The method is_var_diseq can be used for doing that.
Given a child c, if is_var_diseq(c, num_decls, v, t) returns true,
and m_map[v] is null, then we store t at m_map[v].
For performance reasons, we also store a mapping from child position (in the OR) to variable ID.
Thus, m_pos2var[pos] contains the variable that is defined by the diseq at position pos.
m_pos2var[pos] = -1, if this position does not contain a diseq.
After doing that, m_map contains the variables that can
be potentially eliminated using DER.
We say m_map[v] is the definition of variable v.
The next step is to perform a topological sort on these
variables. The result is an array (m_order) of integers (variable ids)
such that i < j implies that m_map[m_order[i]] does not depend on variable m_order[j].
For example, consider the case where m_map contains the following values
m_map[0] = (+ (VAR 2) 0)
m_map[1] = null
m_map[2] = (+ (VAR 3) 0)
m_map[3] = (+ (VAR 1) 1)
m_map[4] = (* (VAR 5) 2)
m_map[5] = null
In this example, variable 0 depends on the definition of variable 2, which
depends on the definition of variable 3, which depends on the definition of variable 0 (cycle).
On the other hand, no cycle is found when starting at variable 4.
Cycles can be broken by erasing entries from m_map. For example, the cycle above
can be removed by setting m_map[0] = null.
m_map[0] = null
m_map[1] = null
m_map[2] = (+ (VAR 3) 0)
m_map[3] = (+ (VAR 1) 1)
m_map[4] = (* (VAR 5) 2)
m_map[5] = null
The file asserted_formulas.cpp has a class top_sort for performing topological sort.
This class cannot be used here, since it is meant for eliminating constants (instead of variables).
We need to implement a new top_sort here, we do not need a separate class for doing that.
Moreover, it is much simpler, since m_map is just an array.
In the example above (after setting m_map[0] to null), top_sort will produce the following order
m_order = [3, 2, 4]
The next step is to use var_subst to update the definitions in var_subst.
The idea is to process the variables in the order specified by m_order.
When processing m_map[m_order[i]] we use the definitions of all variables in m_order[0 ... i-1].
For example:
The first variable is 3, since it is at m_order[0], nothing needs to be done.
Next we have variable 2, we use m_map[3] since 3 is before 2 in m_order. So, the new
definition for 2 is (+ (+ (VAR 1) 1) 0). That is, we update m_map[2] with (+ (+ (VAR 1) 1) 0)
Next we have variable 4, we use m_map[3] and m_map[2] since 3 and 2 are before 4 in m_order.
In this case, var_subst will not do anything since m_map[4] does not contain variables 3 or 2.
So, the new m_map is:
m_map[0] = null
m_map[1] = null
m_map[2] = (+ (+ (VAR 1) 1) 0)
m_map[3] = (+ (VAR 1) 1)
m_map[4] = (* (VAR 5) 2)
m_map[5] = null
Now, we update the body of the quantifier using var_subst and the mapping above.
The idea is to create a new set of children for the OR.
For each child at position i, we do
if m_map[m_pos2var[i]] != -1
skip this child, it is a diseq used during DER
else
apply var_subst using m_map to this child, and store the result in a new children array
Create a new OR (new body of the quantifier) using the new children
Then, we create a new quantifier using this new body, and use the function elim_unused_vars to
eliminate the ununsed variables.
Remark: let us implement the new version inside the class der.
Use #if 0 ... #endif to comment the old version.
Remark: after you are done, we can eliminate the call to occurs in is_var_diseq, since
top_sort is already performing cycle detection.
*/
/**
\brief Functor for applying Destructive Multi-Equality Resolution.
(forall (X Y) (or X /= s C[X])) --> (forall (Y) C[Y])
*/
class der {
ast_manager & m_manager;
var_subst m_subst;
expr_ref_buffer m_new_exprs;
ptr_vector<expr> m_map;
int_vector m_pos2var;
ptr_vector<var> m_inx2var;
unsigned_vector m_order;
expr_ref_vector m_subst_map;
expr_ref_buffer m_new_args;
/**
\brief Return true if e can be viewed as a variable disequality.
Store the variable id in v and the definition in t.
For example:
if e is (not (= (VAR 1) T)), then v assigned to 1, and t to T.
if e is (iff (VAR 2) T), then v is assigned to 2, and t to (not T).
(not T) is used because this formula is equivalent to (not (iff (VAR 2) (not T))),
and can be viewed as a disequality.
*/
bool is_var_diseq(expr * e, unsigned num_decls, var *& v, expr_ref & t);
void get_elimination_order();
void create_substitution(unsigned sz);
void apply_substitution(quantifier * q, expr_ref & r);
void reduce1(quantifier * q, expr_ref & r, proof_ref & pr);
public:
der(ast_manager & m):m_manager(m),m_subst(m),m_new_exprs(m),m_subst_map(m),m_new_args(m) {}
ast_manager & m() const { return m_manager; }
void operator()(quantifier * q, expr_ref & r, proof_ref & pr);
};
/**
\brief Functor for applying Destructive Multi-Equality Resolution in all
universal quantifiers in an expression.
*/
class der_rewriter {
protected:
struct imp;
imp * m_imp;
public:
der_rewriter(ast_manager & m);
~der_rewriter();
ast_manager & m () const;
void operator()(expr * t, expr_ref & result, proof_ref & result_pr);
void cancel() { set_cancel(true); }
void reset_cancel() { set_cancel(false); }
void set_cancel(bool f);
void cleanup();
void reset();
};
typedef der_rewriter der_star;
#endif /* _DER_H_ */

View file

@ -0,0 +1,156 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
expr_replacer.cpp
Abstract:
Abstract (functor) for replacing constants with expressions.
Author:
Leonardo (leonardo) 2011-04-29
Notes:
--*/
#include"expr_replacer.h"
#include"rewriter_def.h"
#include"th_rewriter.h"
#include"cooperate.h"
void expr_replacer::operator()(expr * t, expr_ref & result, proof_ref & result_pr) {
expr_dependency_ref result_dep(m());
operator()(t, result, result_pr, result_dep);
}
void expr_replacer::operator()(expr * t, expr_ref & result) {
proof_ref pr(m());
operator()(t, result, pr);
}
struct expr_replacer::scoped_set_subst {
expr_replacer & m_r;
scoped_set_subst(expr_replacer & r, expr_substitution & s):m_r(r) { m_r.set_substitution(&s); }
~scoped_set_subst() { m_r.set_substitution(0); }
};
void expr_replacer::apply_substitution(expr * s, expr * def, proof * def_pr, expr_ref & t) {
expr_substitution sub(m());
sub.insert(s, def, def_pr);
scoped_set_subst set(*this, sub);
(*this)(t);
}
void expr_replacer::apply_substitution(expr * s, expr * def, expr_ref & t) {
expr_substitution sub(m());
sub.insert(s, def);
scoped_set_subst set(*this, sub);
(*this)(t);
}
struct default_expr_replacer_cfg : public default_rewriter_cfg {
ast_manager & m;
expr_substitution * m_subst;
expr_dependency_ref m_used_dependencies;
default_expr_replacer_cfg(ast_manager & _m):
m(_m),
m_subst(0),
m_used_dependencies(_m) {
}
bool get_subst(expr * s, expr * & t, proof * & pr) {
if (m_subst == 0)
return false;
expr_dependency * d = 0;
if (m_subst->find(s, t, pr, d)) {
m_used_dependencies = m.mk_join(m_used_dependencies, d);
return true;
}
return false;
}
bool max_steps_exceeded(unsigned num_steps) const {
cooperate("simplifier");
return false;
}
};
template class rewriter_tpl<default_expr_replacer_cfg>;
class default_expr_replacer : public expr_replacer {
default_expr_replacer_cfg m_cfg;
rewriter_tpl<default_expr_replacer_cfg> m_replacer;
public:
default_expr_replacer(ast_manager & m):
m_cfg(m),
m_replacer(m, m.proofs_enabled(), m_cfg) {
}
virtual ast_manager & m() const { return m_replacer.m(); }
virtual void set_substitution(expr_substitution * s) {
m_replacer.cleanup();
m_replacer.cfg().m_subst = s;
}
virtual void operator()(expr * t, expr_ref & result, proof_ref & result_pr, expr_dependency_ref & result_dep) {
result_dep = 0;
m_replacer.operator()(t, result, result_pr);
if (m_cfg.m_used_dependencies != 0) {
result_dep = m_cfg.m_used_dependencies;
m_replacer.reset(); // reset cache
m_cfg.m_used_dependencies = 0;
}
}
virtual void set_cancel(bool f) {
m_replacer.set_cancel(f);
}
virtual unsigned get_num_steps() const {
return m_replacer.get_num_steps();
}
};
expr_replacer * mk_default_expr_replacer(ast_manager & m) {
return alloc(default_expr_replacer, m);
}
/**
\brief Adapter for using th_rewriter as an expr_replacer.
*/
class th_rewriter2expr_replacer : public expr_replacer {
th_rewriter m_r;
public:
th_rewriter2expr_replacer(ast_manager & m, params_ref const & p):
m_r(m, p) {
}
virtual ~th_rewriter2expr_replacer() {}
virtual ast_manager & m() const { return m_r.m(); }
virtual void set_substitution(expr_substitution * s) { m_r.set_substitution(s); }
virtual void operator()(expr * t, expr_ref & result, proof_ref & result_pr, expr_dependency_ref & result_dep) {
m_r(t, result, result_pr);
result_dep = m_r.get_used_dependencies();
m_r.reset_used_dependencies();
}
virtual void set_cancel(bool f) {
m_r.set_cancel(f);
}
virtual unsigned get_num_steps() const {
return m_r.get_num_steps();
}
};
expr_replacer * mk_expr_simp_replacer(ast_manager & m, params_ref const & p) {
return alloc(th_rewriter2expr_replacer, m, p);
}

View file

@ -0,0 +1,62 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
expr_replacer.h
Abstract:
Abstract (functor) for replacing expressions.
Author:
Leonardo (leonardo) 2011-04-29
Notes:
--*/
#ifndef _EXPR_REPLACER_H_
#define _EXPR_REPLACER_H_
#include"ast.h"
#include"expr_substitution.h"
#include"params.h"
/**
\brief Abstract interface for functors that replace constants with expressions.
*/
class expr_replacer {
struct scoped_set_subst;
public:
virtual ~expr_replacer() {}
virtual ast_manager & m() const = 0;
virtual void set_substitution(expr_substitution * s) = 0;
virtual void operator()(expr * t, expr_ref & result, proof_ref & result_pr, expr_dependency_ref & deps) = 0;
virtual void operator()(expr * t, expr_ref & result, proof_ref & result_pr);
virtual void operator()(expr * t, expr_ref & result);
virtual void operator()(expr_ref & t) { expr_ref s(t, m()); (*this)(s, t); }
void cancel() { set_cancel(true); }
void reset_cancel() { set_cancel(false); }
virtual void set_cancel(bool f) = 0;
virtual unsigned get_num_steps() const { return 0; }
void apply_substitution(expr * s, expr * def, proof * def_pr, expr_ref & t);
void apply_substitution(expr * s, expr * def, expr_ref & t);
};
/**
\brief Create a vanilla replacer. It just applies the substitution.
*/
expr_replacer * mk_default_expr_replacer(ast_manager & m);
/**
\brief Apply substitution and simplify.
*/
expr_replacer * mk_expr_simp_replacer(ast_manager & m, params_ref const & p = params_ref());
#endif