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:
parent
2b8fb6c718
commit
492484c5aa
125 changed files with 632 additions and 390 deletions
467
src/rewriter/der.cpp
Normal file
467
src/rewriter/der.cpp
Normal 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
187
src/rewriter/der.h
Normal 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_ */
|
||||
|
156
src/rewriter/expr_replacer.cpp
Normal file
156
src/rewriter/expr_replacer.cpp
Normal 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);
|
||||
}
|
62
src/rewriter/expr_replacer.h
Normal file
62
src/rewriter/expr_replacer.h
Normal 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
|
Loading…
Add table
Add a link
Reference in a new issue