mirror of
https://github.com/Z3Prover/z3
synced 2025-08-13 22:41:15 +00:00
using a consistent naming convention for naming tactic subfolders
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
67f5ed46c1
commit
0990a2e045
140 changed files with 14 additions and 12 deletions
907
src/tactic/ufbv/ufbv_rewriter.cpp
Normal file
907
src/tactic/ufbv/ufbv_rewriter.cpp
Normal file
|
@ -0,0 +1,907 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
demodulator.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2010-04-12.
|
||||
|
||||
Revision History:
|
||||
|
||||
Christoph M. Wintersteiger (cwinter) 2010-04-21: Implementation
|
||||
Christoph M. Wintersteiger (cwinter) 2012-10-24: Moved from demodulator.h to ufbv_rewriter.h
|
||||
|
||||
--*/
|
||||
|
||||
#include"ast_pp.h"
|
||||
#include"ufbv_rewriter.h"
|
||||
#include"for_each_expr.h"
|
||||
#include"var_subst.h"
|
||||
#include"uint_set.h"
|
||||
|
||||
ufbv_rewriter::ufbv_rewriter(ast_manager & m, basic_simplifier_plugin & p):
|
||||
m_manager(m),
|
||||
m_match_subst(m),
|
||||
m_bsimp(p),
|
||||
m_todo(m),
|
||||
m_rewrite_todo(m),
|
||||
m_rewrite_cache(m),
|
||||
m_new_exprs(m) {
|
||||
}
|
||||
|
||||
ufbv_rewriter::~ufbv_rewriter() {
|
||||
reset_dealloc_values(m_fwd_idx);
|
||||
reset_dealloc_values(m_back_idx);
|
||||
for (demodulator2lhs_rhs::iterator it = m_demodulator2lhs_rhs.begin(); it != m_demodulator2lhs_rhs.end(); it++) {
|
||||
m_manager.dec_ref(it->m_key);
|
||||
m_manager.dec_ref(it->m_value.first);
|
||||
m_manager.dec_ref(it->m_value.second);
|
||||
}
|
||||
}
|
||||
|
||||
bool ufbv_rewriter::is_demodulator(expr * e, expr_ref & large, expr_ref & small) const {
|
||||
if (e->get_kind() == AST_QUANTIFIER) {
|
||||
quantifier * q = to_quantifier(e);
|
||||
if (q->is_forall()) {
|
||||
expr * qe = q->get_expr();
|
||||
if ((m_manager.is_eq(qe) || m_manager.is_iff(qe))) {
|
||||
app * eq = to_app(q->get_expr());
|
||||
expr * lhs = eq->get_arg(0);
|
||||
expr * rhs = eq->get_arg(1);
|
||||
int subset = is_subset(lhs, rhs);
|
||||
int smaller = is_smaller(lhs, rhs);
|
||||
TRACE("demodulator", tout << "testing is_demodulator:\n"
|
||||
<< mk_pp(lhs, m_manager) << "\n"
|
||||
<< mk_pp(rhs, m_manager) << "\n"
|
||||
<< "subset: " << subset << ", smaller: " << smaller << "\n";);
|
||||
// We only track uninterpreted functions, everything else is likely too expensive.
|
||||
if ((subset == +1 || subset == +2) && smaller == +1) {
|
||||
if (is_uninterp(rhs)) {
|
||||
large = rhs;
|
||||
small = lhs;
|
||||
return true;
|
||||
}
|
||||
#if 1
|
||||
// lhs = (not rhs) --> (not lhs) = rhs
|
||||
expr * not_rhs;
|
||||
if (m_manager.is_not(rhs, not_rhs) && is_uninterp(not_rhs)) {
|
||||
large = not_rhs;
|
||||
small = m_manager.mk_not(lhs);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if ((subset == -1 || subset == +2) && smaller == -1) {
|
||||
if (is_uninterp(lhs)) {
|
||||
large = lhs;
|
||||
small = rhs;
|
||||
return true;
|
||||
}
|
||||
#if 1
|
||||
// (not lhs) = rhs --> lhs = (not rhs)
|
||||
expr * not_lhs;
|
||||
if (m_manager.is_not(lhs, not_lhs) && is_uninterp(not_lhs)) {
|
||||
large = not_lhs;
|
||||
small = m_manager.mk_not(rhs);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} else if (m_manager.is_not(qe) && is_uninterp(to_app(qe)->get_arg(0))) {
|
||||
// this is like (not (f ... )) --> (= (f ...) false)
|
||||
large = to_app(qe)->get_arg(0);
|
||||
small = m_manager.mk_false();
|
||||
return true;
|
||||
} else if (is_uninterp(qe)) {
|
||||
// this is like (f ... ) --> (= (f ...) true)
|
||||
large = to_app(qe);
|
||||
small = m_manager.mk_true();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
class var_set_proc {
|
||||
uint_set & m_set;
|
||||
public:
|
||||
var_set_proc(uint_set &s):m_set(s) {}
|
||||
void operator()(var * n) { m_set.insert(n->get_idx()); }
|
||||
void operator()(quantifier * n) {}
|
||||
void operator()(app * n) {}
|
||||
};
|
||||
|
||||
int ufbv_rewriter::is_subset(expr * e1, expr * e2) const {
|
||||
uint_set ev1, ev2;
|
||||
|
||||
if (m_manager.is_value(e1))
|
||||
return 1; // values are always a subset!
|
||||
|
||||
var_set_proc proc1(ev1);
|
||||
for_each_expr(proc1, e1);
|
||||
var_set_proc proc2(ev2);
|
||||
for_each_expr(proc2, e2);
|
||||
|
||||
return (ev1==ev2 ) ? +2 : // We return +2 if the sets are equal.
|
||||
(ev1.subset_of(ev2)) ? +1 :
|
||||
(ev2.subset_of(ev1)) ? -1 :
|
||||
0 ;
|
||||
}
|
||||
|
||||
int ufbv_rewriter::is_smaller(expr * e1, expr * e2) const {
|
||||
unsigned sz1 = 0, sz2 = 0;
|
||||
|
||||
// values are always smaller!
|
||||
if (m_manager.is_value(e1))
|
||||
return +1;
|
||||
else if (m_manager.is_value(e2))
|
||||
return -1;
|
||||
|
||||
// interpreted stuff is always better than uninterpreted.
|
||||
if (!is_uninterp(e1) && is_uninterp(e2))
|
||||
return +1;
|
||||
else if (is_uninterp(e1) && !is_uninterp(e2))
|
||||
return -1;
|
||||
|
||||
// two uninterpreted functions are ordered first by the number of
|
||||
// arguments, then by their id.
|
||||
if (is_uninterp(e1) && is_uninterp(e2)) {
|
||||
if (to_app(e1)->get_num_args() < to_app(e2)->get_num_args())
|
||||
return +1;
|
||||
else if (to_app(e1)->get_num_args() > to_app(e2)->get_num_args())
|
||||
return -1;
|
||||
else {
|
||||
unsigned a = to_app(e1)->get_decl()->get_id();
|
||||
unsigned b = to_app(e2)->get_decl()->get_id();
|
||||
if (a < b)
|
||||
return +1;
|
||||
else if (a > b)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
switch (e1->get_kind()) {
|
||||
case AST_VAR: sz1 = 1; break;
|
||||
case AST_QUANTIFIER: sz1 = to_quantifier(e1)->get_depth(); break;
|
||||
case AST_APP: sz1 = to_app(e1)->get_depth(); break;
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
|
||||
switch (e2->get_kind()) {
|
||||
case AST_VAR: sz2 = 1; break;
|
||||
case AST_QUANTIFIER: sz2 = to_quantifier(e2)->get_depth(); break;
|
||||
case AST_APP: sz2 = to_app(e2)->get_depth(); break;
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
|
||||
return (sz1 == sz2) ? 0 :
|
||||
(sz1 < sz2) ? +1 :
|
||||
-1 ;
|
||||
}
|
||||
|
||||
class max_var_id_proc {
|
||||
unsigned m_max_var_id;
|
||||
public:
|
||||
max_var_id_proc(void):m_max_var_id(0) {}
|
||||
void operator()(var * n) {
|
||||
if(n->get_idx() > m_max_var_id)
|
||||
m_max_var_id = n->get_idx();
|
||||
}
|
||||
void operator()(quantifier * n) {}
|
||||
void operator()(app * n) {}
|
||||
unsigned get_max(void) { return m_max_var_id; }
|
||||
};
|
||||
|
||||
unsigned ufbv_rewriter::max_var_id(expr * e)
|
||||
{
|
||||
max_var_id_proc proc;
|
||||
for_each_expr(proc, e);
|
||||
return proc.get_max();
|
||||
}
|
||||
|
||||
void ufbv_rewriter::insert_fwd_idx(expr * large, expr * small, quantifier * demodulator) {
|
||||
SASSERT(large->get_kind() == AST_APP);
|
||||
SASSERT(demodulator);
|
||||
SASSERT(large && small);
|
||||
TRACE("demodulator_fwd", tout << "INSERT: " << mk_pp(demodulator, m_manager) << std::endl; );
|
||||
|
||||
func_decl * fd = to_app(large)->get_decl();
|
||||
|
||||
fwd_idx_map::iterator it = m_fwd_idx.find_iterator(fd);
|
||||
if (it == m_fwd_idx.end()) {
|
||||
quantifier_set * qs = alloc(quantifier_set, 1);
|
||||
m_fwd_idx.insert(fd, qs);
|
||||
it = m_fwd_idx.find_iterator(fd);
|
||||
}
|
||||
|
||||
SASSERT(it->m_value);
|
||||
it->m_value->insert(demodulator);
|
||||
|
||||
m_manager.inc_ref(demodulator);
|
||||
m_manager.inc_ref(large);
|
||||
m_manager.inc_ref(small);
|
||||
m_demodulator2lhs_rhs.insert(demodulator, expr_pair(large, small));
|
||||
}
|
||||
|
||||
void ufbv_rewriter::remove_fwd_idx(func_decl * f, quantifier * demodulator) {
|
||||
TRACE("demodulator_fwd", tout << "REMOVE: " << std::hex << (size_t)demodulator << std::endl; );
|
||||
|
||||
fwd_idx_map::iterator it = m_fwd_idx.find_iterator(f);
|
||||
if (it != m_fwd_idx.end()) {
|
||||
demodulator2lhs_rhs::iterator fit = m_demodulator2lhs_rhs.find_iterator(demodulator);
|
||||
m_manager.dec_ref(fit->m_value.first);
|
||||
m_manager.dec_ref(fit->m_value.second);
|
||||
m_manager.dec_ref(demodulator);
|
||||
m_demodulator2lhs_rhs.erase(demodulator);
|
||||
it->m_value->erase(demodulator);
|
||||
} else {
|
||||
SASSERT(m_demodulator2lhs_rhs.contains(demodulator));
|
||||
}
|
||||
}
|
||||
|
||||
bool ufbv_rewriter::check_fwd_idx_consistency(void) {
|
||||
for (fwd_idx_map::iterator it = m_fwd_idx.begin(); it != m_fwd_idx.end() ; it++ ) {
|
||||
quantifier_set * set = it->m_value;
|
||||
SASSERT(set);
|
||||
|
||||
for (quantifier_set::iterator sit = set->begin(); sit != set->end(); sit++) {
|
||||
if (!m_demodulator2lhs_rhs.contains(*sit)) return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ufbv_rewriter::show_fwd_idx(std::ostream & out) {
|
||||
for (fwd_idx_map::iterator it = m_fwd_idx.begin(); it != m_fwd_idx.end() ; it++ ) {
|
||||
quantifier_set * set = it->m_value;
|
||||
SASSERT(!set);
|
||||
|
||||
out << it->m_key->get_name() << ": " << std::endl;
|
||||
|
||||
for (quantifier_set::iterator sit = set->begin(); sit != set->end(); sit++) {
|
||||
out << std::hex << (size_t)*sit << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
out << "D2LR: " << std::endl;
|
||||
for (demodulator2lhs_rhs::iterator it = m_demodulator2lhs_rhs.begin(); it != m_demodulator2lhs_rhs.end() ; it++) {
|
||||
out << (size_t) it->m_key << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
bool ufbv_rewriter::rewrite1(func_decl * f, ptr_vector<expr> & m_new_args, expr_ref & np) {
|
||||
fwd_idx_map::iterator it = m_fwd_idx.find_iterator(f);
|
||||
if (it != m_fwd_idx.end()) {
|
||||
TRACE("demodulator_bug", tout << "trying to rewrite: " << f->get_name() << " args:\n";
|
||||
for (unsigned i = 0; i < m_new_args.size(); i++) { tout << mk_pp(m_new_args[i], m_manager) << "\n"; });
|
||||
quantifier_set::iterator dit = it->m_value->begin();
|
||||
quantifier_set::iterator dend = it->m_value->end();
|
||||
for ( ; dit != dend ; dit++ ) {
|
||||
quantifier * d = *dit;
|
||||
|
||||
SASSERT(m_demodulator2lhs_rhs.contains(d));
|
||||
expr_pair l_s;
|
||||
m_demodulator2lhs_rhs.find(d, l_s);
|
||||
app * large = to_app(l_s.first);
|
||||
|
||||
if (large->get_num_args() != m_new_args.size())
|
||||
continue;
|
||||
|
||||
TRACE("demodulator_bug", tout << "Matching with demodulator: " << mk_pp(d, m_manager) << std::endl; );
|
||||
|
||||
SASSERT(large->get_decl() == f);
|
||||
|
||||
if (m_match_subst(large, l_s.second, m_new_args.c_ptr(), np)) {
|
||||
TRACE("demodulator_bug", tout << "succeeded...\n" << mk_pp(l_s.second, m_manager) << "\n===>\n" << mk_pp(np, m_manager) << "\n";);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ufbv_rewriter::rewrite_visit_children(app * a) {
|
||||
bool res=true;
|
||||
unsigned j = a->get_num_args();
|
||||
while (j > 0) {
|
||||
expr * e = a->get_arg(--j);
|
||||
if (!m_rewrite_cache.contains(e) || !m_rewrite_cache.get(e).second) {
|
||||
m_rewrite_todo.push_back(e);
|
||||
res = false;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void ufbv_rewriter::rewrite_cache(expr * e, expr * new_e, bool done) {
|
||||
m_rewrite_cache.insert(e, expr_bool_pair(new_e, done));
|
||||
}
|
||||
|
||||
expr * ufbv_rewriter::rewrite(expr * n) {
|
||||
if (m_fwd_idx.empty())
|
||||
return n;
|
||||
|
||||
TRACE("demodulator", tout << "rewrite: " << mk_pp(n, m_manager) << std::endl; );
|
||||
app * a;
|
||||
|
||||
SASSERT(m_rewrite_todo.empty());
|
||||
m_rewrite_cache.reset();
|
||||
|
||||
m_rewrite_todo.push_back(n);
|
||||
while (!m_rewrite_todo.empty()) {
|
||||
TRACE("demodulator_stack", tout << "STACK: " << std::endl;
|
||||
for ( unsigned i = 0; i<m_rewrite_todo.size(); i++)
|
||||
tout << std::dec << i << ": " << std::hex << (size_t)m_rewrite_todo[i] << std::endl;
|
||||
);
|
||||
|
||||
expr * e = m_rewrite_todo.back();
|
||||
expr * actual = e;
|
||||
|
||||
if (m_rewrite_cache.contains(e)) {
|
||||
const expr_bool_pair &ebp = m_rewrite_cache.get(e);
|
||||
if (ebp.second) {
|
||||
m_rewrite_todo.pop_back();
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
actual = ebp.first;
|
||||
}
|
||||
}
|
||||
|
||||
switch (actual->get_kind()) {
|
||||
case AST_VAR:
|
||||
rewrite_cache(e, actual, true);
|
||||
m_rewrite_todo.pop_back();
|
||||
break;
|
||||
case AST_APP:
|
||||
a = to_app(actual);
|
||||
if (rewrite_visit_children(a)) {
|
||||
func_decl * f = a->get_decl();
|
||||
m_new_args.reset();
|
||||
unsigned num_args = a->get_num_args();
|
||||
bool all_untouched=true;
|
||||
for (unsigned i = 0 ; i < num_args ; i++ ) {
|
||||
expr * o_child = a->get_arg(i);
|
||||
expr * n_child;
|
||||
SASSERT(m_rewrite_cache.contains(o_child) && m_rewrite_cache.get(o_child).second);
|
||||
expr_bool_pair const & ebp = m_rewrite_cache.get(o_child);
|
||||
n_child = ebp.first;
|
||||
if (n_child != o_child)
|
||||
all_untouched = false;
|
||||
m_new_args.push_back(n_child);
|
||||
}
|
||||
expr_ref np(m_manager);
|
||||
if (rewrite1(f, m_new_args, np)) {
|
||||
rewrite_cache(e, np, false);
|
||||
// No pop.
|
||||
} else {
|
||||
if(all_untouched) {
|
||||
rewrite_cache(e, actual, true);
|
||||
}
|
||||
else {
|
||||
expr_ref na(m_manager);
|
||||
if (f->get_family_id() != m_manager.get_basic_family_id())
|
||||
na = m_manager.mk_app(f, m_new_args.size(), m_new_args.c_ptr());
|
||||
else
|
||||
m_bsimp.reduce(f, m_new_args.size(), m_new_args.c_ptr(), na);
|
||||
TRACE("demodulator_bug", tout << "e:\n" << mk_pp(e, m_manager) << "\nnew_args: \n";
|
||||
for (unsigned i = 0; i < m_new_args.size(); i++) { tout << mk_pp(m_new_args[i], m_manager) << "\n"; }
|
||||
tout << "=====>\n";
|
||||
tout << "na:\n " << mk_pp(na, m_manager) << "\n";);
|
||||
rewrite_cache(e, na, true);
|
||||
}
|
||||
m_rewrite_todo.pop_back();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AST_QUANTIFIER: {
|
||||
expr * body = to_quantifier(actual)->get_expr();
|
||||
if (m_rewrite_cache.contains(body)) {
|
||||
const expr_bool_pair ebp = m_rewrite_cache.get(body);
|
||||
SASSERT(ebp.second);
|
||||
expr * new_body = ebp.first;
|
||||
quantifier_ref q(m_manager);
|
||||
q = m_manager.update_quantifier(to_quantifier(actual), new_body);
|
||||
m_new_exprs.push_back(q);
|
||||
expr_ref new_q(m_manager);
|
||||
elim_unused_vars(m_manager, q, new_q);
|
||||
m_new_exprs.push_back(new_q);
|
||||
rewrite_cache(e, new_q, true);
|
||||
m_rewrite_todo.pop_back();
|
||||
} else {
|
||||
m_rewrite_todo.push_back(body);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
SASSERT(m_rewrite_cache.contains(n));
|
||||
const expr_bool_pair & ebp = m_rewrite_cache.get(n);
|
||||
SASSERT(ebp.second);
|
||||
expr * r = ebp.first;
|
||||
|
||||
TRACE("demodulator", tout << "rewrite result: " << mk_pp(r, m_manager) << std::endl; );
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
class ufbv_rewriter::add_back_idx_proc {
|
||||
ast_manager & m_manager;
|
||||
back_idx_map & m_back_idx;
|
||||
expr * m_expr;
|
||||
public:
|
||||
add_back_idx_proc(ast_manager & m, back_idx_map & bi, expr * e):m_manager(m),m_back_idx(bi),m_expr(e) {}
|
||||
void operator()(var * n) {}
|
||||
void operator()(quantifier * n) {}
|
||||
void operator()(app * n) {
|
||||
// We track only uninterpreted and constant functions.
|
||||
if (n->get_num_args()==0) return;
|
||||
SASSERT(m_expr && m_expr != (expr*) 0x00000003);
|
||||
func_decl * d=n->get_decl();
|
||||
if (d->get_family_id() == null_family_id) {
|
||||
back_idx_map::iterator it = m_back_idx.find_iterator(d);
|
||||
if (it != m_back_idx.end()) {
|
||||
SASSERT(it->m_value);
|
||||
it->m_value->insert(m_expr);
|
||||
} else {
|
||||
expr_set * e = alloc(expr_set);
|
||||
e->insert(m_expr);
|
||||
m_back_idx.insert(d, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class ufbv_rewriter::remove_back_idx_proc {
|
||||
ast_manager & m_manager;
|
||||
back_idx_map & m_back_idx;
|
||||
expr * m_expr;
|
||||
public:
|
||||
remove_back_idx_proc(ast_manager & m, back_idx_map & bi, expr * e):m_manager(m),m_back_idx(bi),m_expr(e) {}
|
||||
void operator()(var * n) {}
|
||||
void operator()(quantifier * n) {}
|
||||
void operator()(app * n) {
|
||||
// We track only uninterpreted and constant functions.
|
||||
if (n->get_num_args()==0) return;
|
||||
func_decl * d=n->get_decl();
|
||||
if (d->get_family_id() == null_family_id) {
|
||||
back_idx_map::iterator it = m_back_idx.find_iterator(d);
|
||||
if (it != m_back_idx.end()) {
|
||||
SASSERT(it->m_value);
|
||||
it->m_value->remove(m_expr);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void ufbv_rewriter::reschedule_processed(func_decl * f) {
|
||||
//use m_back_idx to find all formulas p in m_processed that contains f {
|
||||
back_idx_map::iterator it = m_back_idx.find_iterator(f);
|
||||
if (it != m_back_idx.end()) {
|
||||
SASSERT(it->m_value);
|
||||
expr_set temp;
|
||||
|
||||
expr_set::iterator sit = it->m_value->begin();
|
||||
expr_set::iterator send = it->m_value->end();
|
||||
for ( ; sit != send ; sit++ ) {
|
||||
expr * p = *sit;
|
||||
if (m_processed.contains(p))
|
||||
temp.insert(p);
|
||||
}
|
||||
|
||||
sit = temp.begin();
|
||||
send = temp.end();
|
||||
for ( ; sit != send; sit++) {
|
||||
expr * p = *sit;
|
||||
// remove p from m_processed and m_back_idx
|
||||
m_processed.remove(p);
|
||||
remove_back_idx_proc proc(m_manager, m_back_idx, p); // this could change it->m_value, thus we need the `temp' set.
|
||||
for_each_expr(proc, p);
|
||||
// insert p into m_todo
|
||||
m_todo.push_back(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ufbv_rewriter::can_rewrite(expr * n, expr * lhs) {
|
||||
// this is a quick check, we just traverse d and check if there is an expression in d that is an instance of lhs of n'.
|
||||
// we cannot use the trick used for m_processed, since the main loop would not terminate.
|
||||
|
||||
ptr_vector<expr> stack;
|
||||
expr * curr;
|
||||
expr_mark visited;
|
||||
|
||||
stack.push_back(n);
|
||||
|
||||
while (!stack.empty()) {
|
||||
curr = stack.back();
|
||||
|
||||
if (visited.is_marked(curr)) {
|
||||
stack.pop_back();
|
||||
continue;
|
||||
}
|
||||
|
||||
switch(curr->get_kind()) {
|
||||
case AST_VAR:
|
||||
visited.mark(curr, true);
|
||||
stack.pop_back();
|
||||
break;
|
||||
|
||||
case AST_APP:
|
||||
if (for_each_expr_args(stack, visited, to_app(curr)->get_num_args(), to_app(curr)->get_args())) {
|
||||
if (m_match_subst(lhs, curr))
|
||||
return true;
|
||||
visited.mark(curr, true);
|
||||
stack.pop_back();
|
||||
}
|
||||
break;
|
||||
|
||||
case AST_QUANTIFIER:
|
||||
if (!for_each_expr_args(stack, visited, to_quantifier(curr)->get_num_patterns(),
|
||||
to_quantifier(curr)->get_patterns())) {
|
||||
break;
|
||||
}
|
||||
if (!for_each_expr_args(stack, visited, to_quantifier(curr)->get_num_no_patterns(),
|
||||
to_quantifier(curr)->get_no_patterns())) {
|
||||
break;
|
||||
}
|
||||
if (!visited.is_marked(to_quantifier(curr)->get_expr())) {
|
||||
stack.push_back(to_quantifier(curr)->get_expr());
|
||||
break;
|
||||
}
|
||||
|
||||
stack.pop_back();
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ufbv_rewriter::reschedule_demodulators(func_decl * f, expr * lhs) {
|
||||
// use m_back_idx to find all demodulators d in m_fwd_idx that contains f {
|
||||
|
||||
//ptr_vector<expr> to_remove;
|
||||
|
||||
back_idx_map::iterator it = m_back_idx.find_iterator(f);
|
||||
if (it != m_back_idx.end()) {
|
||||
SASSERT(it->m_value);
|
||||
expr_set all_occurrences;
|
||||
expr_ref l(m_manager);
|
||||
|
||||
expr_set::iterator esit = it->m_value->begin();
|
||||
expr_set::iterator esend = it->m_value->end();
|
||||
for ( ; esit != esend ; esit++)
|
||||
all_occurrences.insert(*esit);
|
||||
|
||||
// Run over all f-demodulators
|
||||
esit = all_occurrences.begin();
|
||||
esend = all_occurrences.end();
|
||||
for ( ; esit != esend ; esit++ ) {
|
||||
expr * occ = *esit;
|
||||
|
||||
if (!is_quantifier(occ))
|
||||
continue;
|
||||
|
||||
// Use the fwd idx to find out whether this is a demodulator.
|
||||
demodulator2lhs_rhs::iterator d2lr_it = m_demodulator2lhs_rhs.find_iterator(to_quantifier(occ));
|
||||
if (d2lr_it != m_demodulator2lhs_rhs.end()) {
|
||||
l = d2lr_it->m_value.first;
|
||||
quantifier_ref d(m_manager);
|
||||
func_decl_ref df(m_manager);
|
||||
d = to_quantifier(occ);
|
||||
df = to_app(l)->get_decl();
|
||||
|
||||
// Now we know there is an occurrence of f in d
|
||||
// if n' can rewrite d {
|
||||
if (can_rewrite(d, lhs)) {
|
||||
TRACE("demodulator", tout << "Rescheduling: " << std::endl << mk_pp(d, m_manager) << std::endl; );
|
||||
// remove d from m_fwd_idx
|
||||
remove_fwd_idx(df, d);
|
||||
// remove d from m_back_idx
|
||||
// just remember it here, because otherwise it and/or esit might become invalid?
|
||||
// to_remove.insert(d);
|
||||
remove_back_idx_proc proc(m_manager, m_back_idx, d);
|
||||
for_each_expr(proc, d);
|
||||
// insert d into m_todo
|
||||
m_todo.push_back(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//for (ptr_vector<expr>::iterator it = to_remove.begin(); it != to_remove.end(); it++) {
|
||||
// expr * d = *it;
|
||||
// remove_back_idx_proc proc(m_manager, m_back_idx, d);
|
||||
// for_each_expr(proc, d);
|
||||
//}
|
||||
}
|
||||
|
||||
void ufbv_rewriter::operator()(unsigned n, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs) {
|
||||
if (m_manager.proofs_enabled()) {
|
||||
// Let us not waste time with proof production
|
||||
warning_msg("PRE_DEMODULATOR=true is not supported when proofs are enabled.");
|
||||
new_exprs.append(n, exprs);
|
||||
new_prs.append(n, prs);
|
||||
return;
|
||||
}
|
||||
|
||||
TRACE("demodulator", tout << "before demodulator:\n";
|
||||
for ( unsigned i = 0 ; i < n ; i++ )
|
||||
tout << mk_pp(exprs[i], m_manager) << std::endl; );
|
||||
|
||||
// Initially, m_todo contains all formulas. That is, it contains the argument exprs. m_fwd_idx, m_processed, m_back_idx are empty.
|
||||
unsigned max_vid = 0;
|
||||
for ( unsigned i = 0 ; i < n ; i++ ) {
|
||||
m_todo.push_back(exprs[i]);
|
||||
max_vid = std::max(max_vid, max_var_id(exprs[i]));
|
||||
}
|
||||
|
||||
m_match_subst.reserve(max_vid);
|
||||
|
||||
while (!m_todo.empty()) {
|
||||
// let n be the next formula in m_todo.
|
||||
expr_ref cur(m_manager);
|
||||
cur = m_todo.back();
|
||||
m_todo.pop_back();
|
||||
|
||||
// rewrite cur using m_fwd_idx, and let n' be the result.
|
||||
expr * np = rewrite(cur);
|
||||
// at this point, it should be the case that there is no demodulator in m_fwd_idx that can rewrite n'.
|
||||
SASSERT(rewrite(np)==np);
|
||||
|
||||
// if (n' is not a demodulator) {
|
||||
expr_ref large(m_manager), small(m_manager);
|
||||
if (!is_demodulator(np, large, small)) {
|
||||
// insert n' into m_processed
|
||||
m_processed.insert(np);
|
||||
// update m_back_idx (traverse n' and for each uninterpreted function declaration f in n' add the entry f->n' to m_back_idx)
|
||||
add_back_idx_proc proc(m_manager, m_back_idx, np);
|
||||
for_each_expr(proc, np);
|
||||
} else {
|
||||
// np is a demodulator that allows us to replace 'large' with 'small'.
|
||||
TRACE("demodulator", tout << "Found demodulator: " << std::endl;
|
||||
tout << mk_pp(large.get(), m_manager) << std::endl << " ---> " <<
|
||||
std::endl << mk_pp(small.get(), m_manager) << std::endl; );
|
||||
|
||||
TRACE("demodulator_s", tout << "Found demodulator: " << std::endl;
|
||||
tout << to_app(large)->get_decl()->get_name() <<
|
||||
"[" << to_app(large)->get_depth() << "]" << " ---> ";
|
||||
if (is_app(small))
|
||||
tout << to_app(small)->get_decl()->get_name() <<
|
||||
"[" << to_app(small)->get_depth() << "]" << std::endl;
|
||||
else
|
||||
tout << mk_pp(small.get(), m_manager) << std::endl; );
|
||||
|
||||
// let f be the top symbol of n'
|
||||
SASSERT(is_app(large));
|
||||
func_decl * f = to_app(large)->get_decl();
|
||||
|
||||
reschedule_processed(f);
|
||||
reschedule_demodulators(f, large);
|
||||
|
||||
// insert n' into m_fwd_idx
|
||||
insert_fwd_idx(large, small, to_quantifier(np));
|
||||
|
||||
// update m_back_idx
|
||||
add_back_idx_proc proc(m_manager, m_back_idx, np);
|
||||
for_each_expr(proc, np);
|
||||
}
|
||||
}
|
||||
|
||||
// the result is the contents of m_processed + all demodulators in m_fwd_idx.
|
||||
obj_hashtable<expr>::iterator pit = m_processed.begin();
|
||||
obj_hashtable<expr>::iterator pend = m_processed.end();
|
||||
for ( ; pit != pend ; pit++ ) {
|
||||
new_exprs.push_back(*pit);
|
||||
TRACE("demodulator", tout << mk_pp(*pit, m_manager) << std::endl; );
|
||||
}
|
||||
|
||||
fwd_idx_map::iterator fit = m_fwd_idx.begin();
|
||||
fwd_idx_map::iterator fend = m_fwd_idx.end();
|
||||
for ( ; fit != fend ; fit++ ) {
|
||||
if (fit->m_value) {
|
||||
quantifier_set::iterator dit = fit->m_value->begin();
|
||||
quantifier_set::iterator dend = fit->m_value->end();
|
||||
for ( ; dit != dend ; dit++ ) {
|
||||
expr * e = *dit;
|
||||
new_exprs.push_back(e);
|
||||
TRACE("demodulator", tout << mk_pp(*dit, m_manager) << std::endl; );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TRACE("demodulator", tout << "after demodulator:\n";
|
||||
for ( unsigned i = 0 ; i < new_exprs.size() ; i++ )
|
||||
tout << mk_pp(new_exprs[i].get(), m_manager) << std::endl; );
|
||||
}
|
||||
|
||||
|
||||
ufbv_rewriter::match_subst::match_subst(ast_manager & m):
|
||||
m_manager(m),
|
||||
m_subst(m) {
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Auxiliary functor used to implement optimization in match_args. See comment there.
|
||||
*/
|
||||
struct match_args_aux_proc {
|
||||
substitution & m_subst;
|
||||
struct no_match {};
|
||||
|
||||
match_args_aux_proc(substitution & s):m_subst(s) {}
|
||||
|
||||
void operator()(var * n) {
|
||||
expr_offset r;
|
||||
if (m_subst.find(n, 0, r)) {
|
||||
if (r.get_expr() != n) {
|
||||
SASSERT(r.get_offset() == 1);
|
||||
throw no_match();
|
||||
}
|
||||
else {
|
||||
m_subst.insert(n, 0, expr_offset(n, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
void operator()(quantifier * n) { throw no_match(); }
|
||||
void operator()(app * n) {}
|
||||
};
|
||||
|
||||
bool ufbv_rewriter::match_subst::match_args(app * lhs, expr * const * args) {
|
||||
m_cache.reset();
|
||||
m_todo.reset();
|
||||
|
||||
// fill todo-list, and perform quick success/failure tests
|
||||
m_all_args_eq = true;
|
||||
unsigned num_args = lhs->get_num_args();
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
expr * t_arg = lhs->get_arg(i);
|
||||
expr * i_arg = args[i];
|
||||
if (t_arg != i_arg)
|
||||
m_all_args_eq = false;
|
||||
if (is_app(t_arg) && is_app(i_arg) && to_app(t_arg)->get_decl() != to_app(i_arg)->get_decl()) {
|
||||
// quick failure...
|
||||
return false;
|
||||
}
|
||||
m_todo.push_back(expr_pair(t_arg, i_arg));
|
||||
}
|
||||
|
||||
if (m_all_args_eq) {
|
||||
// quick success worked...
|
||||
return true;
|
||||
}
|
||||
|
||||
m_subst.reset();
|
||||
|
||||
while (!m_todo.empty()) {
|
||||
expr_pair const & p = m_todo.back();
|
||||
|
||||
if (is_var(p.first)) {
|
||||
expr_offset r;
|
||||
if (m_subst.find(to_var(p.first), 0, r)) {
|
||||
if (r.get_expr() != p.second)
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
m_subst.insert(to_var(p.first), 0, expr_offset(p.second, 1));
|
||||
}
|
||||
m_todo.pop_back();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_var(p.second))
|
||||
return false;
|
||||
|
||||
// we may have nested quantifiers.
|
||||
if (is_quantifier(p.first) || is_quantifier(p.second))
|
||||
return false;
|
||||
|
||||
SASSERT(is_app(p.first) && is_app(p.second));
|
||||
|
||||
if (to_app(p.first)->is_ground() && !to_app(p.second)->is_ground())
|
||||
return false;
|
||||
|
||||
if (p.first == p.second && to_app(p.first)->is_ground()) {
|
||||
SASSERT(to_app(p.second)->is_ground());
|
||||
m_todo.pop_back();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_cache.contains(p)) {
|
||||
m_todo.pop_back();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (p.first == p.second) {
|
||||
// p.first and p.second is not ground...
|
||||
|
||||
// Traverse p.first and check whether every variable X:0 in p.first
|
||||
// 1) is unbounded (then we bind X:0 -> X:1)
|
||||
// 2) or, is already bounded to X:1
|
||||
// If that is, the case, we execute:
|
||||
// m_todo.pop_back();
|
||||
// m_cache.insert(p);
|
||||
// continue;
|
||||
// Otherwise
|
||||
// return false;
|
||||
match_args_aux_proc proc(m_subst);
|
||||
try {
|
||||
for_each_expr(proc, p.first);
|
||||
// succeeded
|
||||
m_todo.pop_back();
|
||||
m_cache.insert(p);
|
||||
continue;
|
||||
}
|
||||
catch (match_args_aux_proc::no_match) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
app * n1 = to_app(p.first);
|
||||
app * n2 = to_app(p.second);
|
||||
|
||||
if (n1->get_decl() != n2->get_decl())
|
||||
return false;
|
||||
|
||||
unsigned num_args1 = n1->get_num_args();
|
||||
if (num_args1 != n2->get_num_args())
|
||||
return false;
|
||||
|
||||
m_todo.pop_back();
|
||||
|
||||
if (num_args1 == 0)
|
||||
continue;
|
||||
|
||||
m_cache.insert(p);
|
||||
unsigned j = num_args1;
|
||||
while (j > 0) {
|
||||
--j;
|
||||
m_todo.push_back(expr_pair(n1->get_arg(j), n2->get_arg(j)));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool ufbv_rewriter::match_subst::operator()(app * lhs, expr * rhs, expr * const * args, expr_ref & new_rhs) {
|
||||
if (match_args(lhs, args)) {
|
||||
if (m_all_args_eq) {
|
||||
// quick success...
|
||||
new_rhs = rhs;
|
||||
return true;
|
||||
}
|
||||
unsigned deltas[2] = { 0, 0 };
|
||||
m_subst.apply(2, deltas, expr_offset(rhs, 0), new_rhs);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ufbv_rewriter::match_subst::operator()(expr * t, expr * i) {
|
||||
m_cache.reset();
|
||||
m_todo.reset();
|
||||
if (is_var(t))
|
||||
return true;
|
||||
if (is_app(t) && is_app(i) && to_app(t)->get_decl() == to_app(i)->get_decl() && to_app(t)->get_num_args() == to_app(i)->get_num_args()) {
|
||||
return match_args(to_app(t), to_app(i)->get_args());
|
||||
}
|
||||
return false;
|
||||
}
|
267
src/tactic/ufbv/ufbv_rewriter.h
Normal file
267
src/tactic/ufbv/ufbv_rewriter.h
Normal file
|
@ -0,0 +1,267 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
demodulator.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2010-04-12.
|
||||
|
||||
Revision History:
|
||||
|
||||
Christoph M. Wintersteiger (cwinter) 2012-10-24: Moved from demodulator.h to ufbv_rewriter.h
|
||||
|
||||
--*/
|
||||
#ifndef _UFBV_REWRITER_H_
|
||||
#define _UFBV_REWRITER_H_
|
||||
|
||||
#include"ast.h"
|
||||
#include"substitution.h"
|
||||
#include"obj_hashtable.h"
|
||||
#include"obj_pair_hashtable.h"
|
||||
#include"array_map.h"
|
||||
#include"basic_simplifier_plugin.h"
|
||||
|
||||
/**
|
||||
\brief Apply demodulators as a preprocessing technique.
|
||||
|
||||
In first-order theorem proving (FOTP), a demodulator is a universally quantified formula of the form:
|
||||
|
||||
Forall X1, ..., Xn. L[X1, ..., Xn] = R[X1, ..., Xn]
|
||||
Where L[X1, ..., Xn] contains all variables in R[X1, ..., Xn], and
|
||||
L[X1, ..., Xn] is "bigger" than R[X1, ...,Xn].
|
||||
|
||||
The idea is to replace something big L[X1, ..., Xn] with something smaller R[X1, ..., Xn].
|
||||
In FOTP, they use term orderings to decide what does it mean to be smaller.
|
||||
We are using demodulators in a different context (pre-processing).
|
||||
So, I suggest we have a virtual method is_smaller for comparing expressions.
|
||||
The default implementation just compares the size of the expressions.
|
||||
|
||||
Similarly, in our context, formulas using iff are also demodulators.
|
||||
Forall X1, ..., Xn. L[X1, ..., Xn] iff R[X1, ..., Xn]
|
||||
|
||||
After selecting the demodulators, we traverse the rest of the formula looking for instances of L[X1, ..., Xn].
|
||||
Whenever we find an instance, we replace it with the associated instance of R[X1, ..., Xn].
|
||||
|
||||
For example, suppose we have
|
||||
|
||||
Forall x, y. f(x+y, y) = y
|
||||
and
|
||||
f(g(b) + h(c), h(c)) <= 0
|
||||
|
||||
The term f(g(b) + h(c), h(c)) is an instance of f(x+y, y) if we replace x <- g(b) and y <- h(c).
|
||||
So, we can replace it with "y" which is bound to h(c) in this example. So, the result of the transformation is:
|
||||
|
||||
Forall x, y. f(x+y, y) = y
|
||||
and
|
||||
h(c) <= 0
|
||||
|
||||
In the first implementation, let us ignore theory matching. That is,
|
||||
for us the term f(a+1) is not an instance of f(1+x), because the
|
||||
matcher doesn't know + is commutative. Observe the demodulator is
|
||||
*not* copied to the macro manager in this case.
|
||||
|
||||
Another complication is when we are looking for instances inside other universally quantified formulas.
|
||||
The problem is that both formulas (demodular) and target are reusing variables names (ids).
|
||||
To avoid renaming, we use offsets. The idea is to represent renames implicitly. In this case,
|
||||
each offset is a different "variable bank". A pair (expr, offset) is essentially an expression
|
||||
where every variable in expr is assumed to be from the "bank" offset.
|
||||
|
||||
The class substitution (in substitution.h) manages offsets for us.
|
||||
The class matcher (in matcher.h) can be use to test whether an expression is an instance of another one.
|
||||
|
||||
Finally, there is the problem when we have N demodulators (where N is big), and a big formula, and we want
|
||||
to traverse the formula only once looking for opportunities for applying these N demodulators.
|
||||
We want to efficiently find the applicable demodulars.
|
||||
We can start with a simple optimization that given a func_decl it returns the set of demodulators that start with this declaration.
|
||||
For example, suppose we have the demodulators.
|
||||
forall x, f(x, g(0)) = 10
|
||||
forall x, f(g(h(x)), g(1)) = 20
|
||||
Then, in our "index" f would map to these two demodulators.
|
||||
|
||||
As a final optimization, we should adapt the code to use substitution-trees.
|
||||
The current implementation in Z3 is not efficient, and I think it is buggy.
|
||||
So, it would be great to replace it with a new one.
|
||||
The code in spc_rewriter.* does something like that. We cannot reuse this code directly since it is meant
|
||||
for the superposion engine in Z3, but we can adapt it for our needs in the preprocessor.
|
||||
|
||||
*/
|
||||
class ufbv_rewriter {
|
||||
class rewrite_proc;
|
||||
class add_back_idx_proc;
|
||||
class remove_back_idx_proc;
|
||||
class can_rewrite_proc;
|
||||
|
||||
typedef std::pair<expr *, bool> expr_bool_pair;
|
||||
|
||||
class plugin {
|
||||
ast_manager& m_manager;
|
||||
public:
|
||||
plugin(ast_manager& m): m_manager(m) { }
|
||||
void ins_eh(expr* k, expr_bool_pair v) { m_manager.inc_ref(k); m_manager.inc_ref(v.first); }
|
||||
void del_eh(expr* k, expr_bool_pair v) { m_manager.dec_ref(k); m_manager.dec_ref(v.first); }
|
||||
static unsigned to_int(expr const * k) { return k->get_id(); }
|
||||
};
|
||||
typedef array_map<expr*, expr_bool_pair, plugin> expr_map;
|
||||
|
||||
typedef std::pair<expr *, expr *> expr_pair;
|
||||
typedef obj_hashtable<expr> expr_set;
|
||||
typedef obj_map<func_decl, expr_set *> back_idx_map;
|
||||
typedef obj_hashtable<quantifier> quantifier_set;
|
||||
typedef obj_map<func_decl, quantifier_set *> fwd_idx_map;
|
||||
typedef obj_map<quantifier, expr_pair> demodulator2lhs_rhs;
|
||||
typedef expr_map rewrite_cache_map;
|
||||
|
||||
/**
|
||||
\brief Custom matcher & substitution application
|
||||
*/
|
||||
class match_subst {
|
||||
typedef std::pair<expr *, expr *> expr_pair;
|
||||
typedef obj_pair_hashtable<expr, expr> cache;
|
||||
|
||||
void reset();
|
||||
|
||||
ast_manager & m_manager;
|
||||
substitution m_subst;
|
||||
cache m_cache;
|
||||
svector<expr_pair> m_todo;
|
||||
bool m_all_args_eq;
|
||||
|
||||
bool match_args(app * t, expr * const * args);
|
||||
|
||||
public:
|
||||
match_subst(ast_manager & m);
|
||||
void reserve(unsigned max_vid) { m_subst.reserve(2, max_vid+1); }
|
||||
/**
|
||||
\brief Let f be the top symbol of lhs. If (f args) is an
|
||||
instance of lhs, that is, there is a substitution s
|
||||
s.t. s[lhs] = (f args), then return true and store s[rhs]
|
||||
into new_rhs. Where s[t] represents the application of the
|
||||
substitution s into t.
|
||||
|
||||
Assumptions, the variables in lhs and (f args) are assumed to be distinct.
|
||||
So, (f x y) matches (f y x).
|
||||
Moreover, the result should be in terms of the variables in (f args).
|
||||
*/
|
||||
bool operator()(app * lhs, expr * rhs, expr * const * args, expr_ref & new_rhs);
|
||||
|
||||
/**
|
||||
\brief Return true if \c i is an instance of \c t.
|
||||
*/
|
||||
bool operator()(expr * t, expr * i);
|
||||
};
|
||||
|
||||
ast_manager & m_manager;
|
||||
match_subst m_match_subst;
|
||||
basic_simplifier_plugin & m_bsimp;
|
||||
fwd_idx_map m_fwd_idx;
|
||||
back_idx_map m_back_idx;
|
||||
demodulator2lhs_rhs m_demodulator2lhs_rhs;
|
||||
expr_ref_buffer m_todo;
|
||||
obj_hashtable<expr> m_processed;
|
||||
ptr_vector<expr> m_new_args;
|
||||
|
||||
expr_ref_buffer m_rewrite_todo;
|
||||
rewrite_cache_map m_rewrite_cache;
|
||||
expr_ref_buffer m_new_exprs;
|
||||
|
||||
void insert_fwd_idx(expr * large, expr * small, quantifier * demodulator);
|
||||
void remove_fwd_idx(func_decl * f, quantifier * demodulator);
|
||||
bool check_fwd_idx_consistency(void);
|
||||
void show_fwd_idx(std::ostream & out);
|
||||
bool is_demodulator(expr * e, expr_ref & large, expr_ref & small) const;
|
||||
bool can_rewrite(expr * n, expr * lhs);
|
||||
|
||||
expr * rewrite(expr * n);
|
||||
bool rewrite1(func_decl * f, ptr_vector<expr> & m_new_args, expr_ref & np);
|
||||
bool rewrite_visit_children(app * a);
|
||||
void rewrite_cache(expr * e, expr * new_e, bool done);
|
||||
void reschedule_processed(func_decl * f);
|
||||
void reschedule_demodulators(func_decl * f, expr * np);
|
||||
unsigned max_var_id(expr * e);
|
||||
|
||||
protected:
|
||||
// is_smaller returns -1 for e1<e2, 0 for e1==e2 and +1 for e1>e2.
|
||||
virtual int is_smaller(expr * e1, expr * e2) const;
|
||||
|
||||
// is_subset returns -1 for e1 subset e2, +1 for e2 subset e1, 0 else.
|
||||
virtual int is_subset(expr * e1, expr * e2) const;
|
||||
|
||||
public:
|
||||
ufbv_rewriter(ast_manager & m, basic_simplifier_plugin & p);
|
||||
virtual ~ufbv_rewriter();
|
||||
|
||||
void operator()(unsigned n, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs);
|
||||
|
||||
/**
|
||||
Given a demodulator (aka rewrite rule) of the form
|
||||
Forall X. L[X] = R[X]
|
||||
We say the top symbol is the first symbol in L.
|
||||
For example: f is the top symbol in
|
||||
Forall x, f(h(x)) = x + 1
|
||||
|
||||
The rewrite engine main loop is based on the DISCOUNT loop used in first-order theorem provers.
|
||||
|
||||
Main structures:
|
||||
- m_todo: The todo-stack of formulas to be processed.
|
||||
- m_fwd_idx: "Forward index" for finding efficiently which demodulators can be used to rewrite an expression.
|
||||
We organize this set as a mapping from func_decl to a set of demodulators which start with the same top symbol.
|
||||
- m_processed: The set of already processed formulas. We can represent it using a hashtable.
|
||||
- m_back_idx: "Backward index" we use it to find efficiently which already processed expressions and demodulators may be rewritten
|
||||
by a new demodulator. Again, we use a very simple index, for each uninterpreted function symbol (ignore constants)
|
||||
f, store the expressions in m_processed and the demodulators that contain f.
|
||||
If you prefer, you may use two m_back_idxs (one for formulas in m_processed and another for demodulators in m_fwd_idx).
|
||||
|
||||
Initially, m_todo contains all formulas. That is, it contains the argument exprs. m_fwd_idx, m_processed, m_back_idx are empty.
|
||||
|
||||
while (m_todo is not empty) {
|
||||
let n be the next formula in m_todo.
|
||||
rewrite n using m_fwd_idx, and let n' be the result.
|
||||
// at this point, it should be the case that there is no demodulator in m_fwd_idx that can rewrite n'.
|
||||
if (n' is not a demodulator) {
|
||||
insert n' into m_processed
|
||||
update m_back_idx (traverse n' and for each uninterpreted function declaration f in n' add the entry f->n' to m_back_idx)
|
||||
}
|
||||
else {
|
||||
let f be the top symbol of n'
|
||||
use m_back_idx to find all formulas p in m_processed that contains f {
|
||||
remove p from m_processed
|
||||
remove p from m_back_idx
|
||||
insert p into m_todo
|
||||
}
|
||||
use m_back_idx to find all demodulators d in m_fwd_idx that contains f {
|
||||
if n' can rewrite d {
|
||||
// this is a quick check, we just traverse d and check if there is an expression in d that is an instance of lhs of n'.
|
||||
// we cannot use the trick used for m_processed, since the main loop would not terminate.
|
||||
remove d from m_fwd_idx
|
||||
remode d from m_back_idx
|
||||
insert p into m_todo
|
||||
}
|
||||
}
|
||||
insert n' into m_fwd_idx
|
||||
update m_back_idx
|
||||
}
|
||||
}
|
||||
the result is the contents of m_processed + all demodulators in m_fwd_idx.
|
||||
|
||||
Note: to remove p from m_back_idx, we need to traverse p, and for every function declartion f in p, we should remove the entry f->p from m_back_idx.
|
||||
|
||||
Note: we can implement m_back_idx for formulas as:
|
||||
typedef obj_hashtable<expr> expr_set;
|
||||
obj_map<func_decl, expr_set *> m_back_idx;
|
||||
we should represent the sets as hashtables because we want to be able to efficiently remove elements from these sets.
|
||||
ptr_vector<expr_set> m_expr_set_to_delete; // same trick we used in macro_manager.
|
||||
we can use a similar structure for m_back_idx and m_fwd_idx for demodulators.
|
||||
|
||||
Note: m_processed should be obj_hashtable<expr> since we want to remove elements from there efficiently.
|
||||
*/
|
||||
};
|
||||
|
||||
#endif /* _UFBV_REWRITER_H_ */
|
||||
|
498
src/tactic/ufbv/ufbv_tactic.cpp
Normal file
498
src/tactic/ufbv/ufbv_tactic.cpp
Normal file
|
@ -0,0 +1,498 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
ufbv_tactic.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
General purpose tactic for UFBV benchmarks.
|
||||
|
||||
Author:
|
||||
|
||||
Christoph (cwinter) 2012-10-24
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include"tactical.h"
|
||||
#include"simplify_tactic.h"
|
||||
#include"propagate_values_tactic.h"
|
||||
#include"solve_eqs_tactic.h"
|
||||
#include"simplifier.h"
|
||||
#include"basic_simplifier_plugin.h"
|
||||
#include"arith_simplifier_plugin.h"
|
||||
#include"bv_simplifier_plugin.h"
|
||||
#include"macro_manager.h"
|
||||
#include"macro_finder.h"
|
||||
#include"quasi_macros.h"
|
||||
#include"ufbv_rewriter.h"
|
||||
#include"extension_model_converter.h"
|
||||
#include"distribute_forall_tactic.h"
|
||||
#include"der_tactic.h"
|
||||
#include"reduce_args_tactic.h"
|
||||
#include"smt_tactic.h"
|
||||
#include"ufbv_tactic.h"
|
||||
#include"nnf_tactic.h"
|
||||
|
||||
class macro_finder_tactic : public tactic {
|
||||
|
||||
struct imp {
|
||||
ast_manager & m_manager;
|
||||
bool m_cancel;
|
||||
bool m_elim_and;
|
||||
|
||||
imp(ast_manager & m, params_ref const & p) : m_manager(m),m_elim_and(false),m_cancel(false) {
|
||||
updt_params(p);
|
||||
}
|
||||
|
||||
ast_manager & m() const { return m_manager; }
|
||||
|
||||
void set_cancel(bool f) {
|
||||
m_cancel = f;
|
||||
}
|
||||
|
||||
void operator()(goal_ref const & g,
|
||||
goal_ref_buffer & result,
|
||||
model_converter_ref & mc,
|
||||
proof_converter_ref & pc,
|
||||
expr_dependency_ref & core) {
|
||||
SASSERT(g->is_well_sorted());
|
||||
mc = 0; pc = 0; core = 0;
|
||||
tactic_report report("macro-finder", *g);
|
||||
fail_if_unsat_core_generation("macro-finder", g);
|
||||
|
||||
bool produce_proofs = g->proofs_enabled();
|
||||
bool produce_models = g->models_enabled();
|
||||
|
||||
simplifier simp(m_manager);
|
||||
basic_simplifier_plugin * bsimp = alloc(basic_simplifier_plugin, m_manager);
|
||||
bsimp->set_eliminate_and(m_elim_and);
|
||||
simp.register_plugin(bsimp);
|
||||
arith_simplifier_params a_params;
|
||||
arith_simplifier_plugin * asimp = alloc(arith_simplifier_plugin, m_manager, *bsimp, a_params);
|
||||
simp.register_plugin(asimp);
|
||||
bv_simplifier_params bv_params;
|
||||
bv_simplifier_plugin * bvsimp = alloc(bv_simplifier_plugin, m_manager, *bsimp, bv_params);
|
||||
simp.register_plugin(bvsimp);
|
||||
|
||||
macro_manager mm(m_manager, simp);
|
||||
macro_finder mf(m_manager, mm);
|
||||
|
||||
expr_ref_vector forms(m_manager), new_forms(m_manager);
|
||||
proof_ref_vector proofs(m_manager), new_proofs(m_manager);
|
||||
unsigned size = g->size();
|
||||
for (unsigned idx = 0; idx < size; idx++) {
|
||||
forms.push_back(g->form(idx));
|
||||
proofs.push_back(g->pr(idx));
|
||||
}
|
||||
|
||||
mf(forms.size(), forms.c_ptr(), proofs.c_ptr(), new_forms, new_proofs);
|
||||
|
||||
unsigned i = 0;
|
||||
for (; i < g->size(); i++)
|
||||
g->update(i, new_forms.get(i), produce_proofs ? new_proofs.get(i) : 0, 0);
|
||||
|
||||
for (; i < new_forms.size(); i++)
|
||||
g->assert_expr(new_forms.get(i), new_proofs.get(i), 0);
|
||||
|
||||
extension_model_converter * evmc = alloc(extension_model_converter, mm.get_manager());
|
||||
unsigned num = mm.get_num_macros();
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
expr_ref f_interp(mm.get_manager());
|
||||
func_decl * f = mm.get_macro_interpretation(i, f_interp);
|
||||
evmc->insert(f, f_interp);
|
||||
}
|
||||
mc = evmc;
|
||||
|
||||
g->inc_depth();
|
||||
result.push_back(g.get());
|
||||
TRACE("macro-finder", g->display(tout););
|
||||
SASSERT(g->is_well_sorted());
|
||||
}
|
||||
|
||||
void updt_params(params_ref const & p) {
|
||||
m_elim_and = p.get_bool(":elim-and", false);
|
||||
}
|
||||
};
|
||||
|
||||
imp * m_imp;
|
||||
params_ref m_params;
|
||||
public:
|
||||
macro_finder_tactic(ast_manager & m, params_ref const & p):
|
||||
m_params(p) {
|
||||
m_imp = alloc(imp, m, p);
|
||||
}
|
||||
|
||||
virtual tactic * translate(ast_manager & m) {
|
||||
return alloc(macro_finder_tactic, m, m_params);
|
||||
}
|
||||
|
||||
virtual ~macro_finder_tactic() {
|
||||
dealloc(m_imp);
|
||||
}
|
||||
|
||||
virtual void updt_params(params_ref const & p) {
|
||||
m_params = p;
|
||||
m_imp->updt_params(p);
|
||||
}
|
||||
|
||||
virtual void collect_param_descrs(param_descrs & r) {
|
||||
insert_max_memory(r);
|
||||
insert_produce_models(r);
|
||||
insert_produce_proofs(r);
|
||||
r.insert(":elim-and", CPK_BOOL, "(default: false) eliminate conjunctions during (internal) calls to the simplifier.");
|
||||
}
|
||||
|
||||
virtual void operator()(goal_ref const & in,
|
||||
goal_ref_buffer & result,
|
||||
model_converter_ref & mc,
|
||||
proof_converter_ref & pc,
|
||||
expr_dependency_ref & core) {
|
||||
(*m_imp)(in, result, mc, pc, core);
|
||||
}
|
||||
|
||||
virtual void cleanup() {
|
||||
ast_manager & m = m_imp->m();
|
||||
imp * d = m_imp;
|
||||
#pragma omp critical (tactic_cancel)
|
||||
{
|
||||
m_imp = 0;
|
||||
}
|
||||
dealloc(d);
|
||||
d = alloc(imp, m, m_params);
|
||||
#pragma omp critical (tactic_cancel)
|
||||
{
|
||||
m_imp = d;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void set_cancel(bool f) {
|
||||
if (m_imp)
|
||||
m_imp->set_cancel(f);
|
||||
}
|
||||
};
|
||||
|
||||
tactic * mk_macro_finder_tactic(ast_manager & m, params_ref const & p) {
|
||||
return alloc(macro_finder_tactic, m, p);
|
||||
}
|
||||
|
||||
class ufbv_rewriter_tactic : public tactic {
|
||||
|
||||
struct imp {
|
||||
ast_manager & m_manager;
|
||||
bool m_cancel;
|
||||
|
||||
imp(ast_manager & m, params_ref const & p) : m_manager(m),m_cancel(false) {
|
||||
updt_params(p);
|
||||
}
|
||||
|
||||
ast_manager & m() const { return m_manager; }
|
||||
|
||||
void set_cancel(bool f) {
|
||||
m_cancel = f;
|
||||
}
|
||||
|
||||
void operator()(goal_ref const & g,
|
||||
goal_ref_buffer & result,
|
||||
model_converter_ref & mc,
|
||||
proof_converter_ref & pc,
|
||||
expr_dependency_ref & core) {
|
||||
SASSERT(g->is_well_sorted());
|
||||
mc = 0; pc = 0; core = 0;
|
||||
tactic_report report("ufbv-rewriter", *g);
|
||||
fail_if_unsat_core_generation("ufbv-rewriter", g);
|
||||
|
||||
bool produce_proofs = g->proofs_enabled();
|
||||
bool produce_models = g->models_enabled();
|
||||
|
||||
basic_simplifier_plugin bsimp(m_manager);
|
||||
bsimp.set_eliminate_and(true);
|
||||
ufbv_rewriter dem(m_manager, bsimp);
|
||||
|
||||
expr_ref_vector forms(m_manager), new_forms(m_manager);
|
||||
proof_ref_vector proofs(m_manager), new_proofs(m_manager);
|
||||
|
||||
unsigned size = g->size();
|
||||
for (unsigned i = 0; i < size; i++) {
|
||||
forms.push_back(g->form(i));
|
||||
proofs.push_back(g->pr(i));
|
||||
}
|
||||
|
||||
dem(forms.size(), forms.c_ptr(), proofs.c_ptr(), new_forms, new_proofs);
|
||||
|
||||
unsigned i = 0;
|
||||
for (; i < g->size(); i++)
|
||||
g->update(i, new_forms.get(i), produce_proofs ? new_proofs.get(i) : 0, g->dep(i));
|
||||
|
||||
for (; i < new_forms.size(); i++)
|
||||
g->assert_expr(new_forms.get(i), new_proofs.get(i), 0);
|
||||
|
||||
mc = 0; // CMW: Remark: The demodulator could potentially remove all references to a variable.
|
||||
|
||||
g->inc_depth();
|
||||
result.push_back(g.get());
|
||||
TRACE("ufbv-rewriter", g->display(tout););
|
||||
SASSERT(g->is_well_sorted());
|
||||
}
|
||||
|
||||
void updt_params(params_ref const & p) {
|
||||
}
|
||||
};
|
||||
|
||||
imp * m_imp;
|
||||
params_ref m_params;
|
||||
|
||||
public:
|
||||
ufbv_rewriter_tactic(ast_manager & m, params_ref const & p):
|
||||
m_params(p) {
|
||||
m_imp = alloc(imp, m, p);
|
||||
}
|
||||
|
||||
virtual tactic * translate(ast_manager & m) {
|
||||
return alloc(ufbv_rewriter_tactic, m, m_params);
|
||||
}
|
||||
|
||||
virtual ~ufbv_rewriter_tactic() {
|
||||
dealloc(m_imp);
|
||||
}
|
||||
|
||||
virtual void updt_params(params_ref const & p) {
|
||||
m_params = p;
|
||||
m_imp->updt_params(p);
|
||||
}
|
||||
|
||||
virtual void collect_param_descrs(param_descrs & r) {
|
||||
insert_max_memory(r);
|
||||
insert_produce_models(r);
|
||||
insert_produce_proofs(r);
|
||||
}
|
||||
|
||||
virtual void operator()(goal_ref const & in,
|
||||
goal_ref_buffer & result,
|
||||
model_converter_ref & mc,
|
||||
proof_converter_ref & pc,
|
||||
expr_dependency_ref & core) {
|
||||
(*m_imp)(in, result, mc, pc, core);
|
||||
}
|
||||
|
||||
virtual void cleanup() {
|
||||
ast_manager & m = m_imp->m();
|
||||
imp * d = m_imp;
|
||||
#pragma omp critical (tactic_cancel)
|
||||
{
|
||||
m_imp = 0;
|
||||
}
|
||||
dealloc(d);
|
||||
d = alloc(imp, m, m_params);
|
||||
#pragma omp critical (tactic_cancel)
|
||||
{
|
||||
m_imp = d;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void set_cancel(bool f) {
|
||||
if (m_imp)
|
||||
m_imp->set_cancel(f);
|
||||
}
|
||||
};
|
||||
|
||||
tactic * mk_ufbv_rewriter_tactic(ast_manager & m, params_ref const & p) {
|
||||
return alloc(ufbv_rewriter_tactic, m, p);
|
||||
}
|
||||
|
||||
tactic * mk_der_fp_tactic(ast_manager & m, params_ref const & p) {
|
||||
return repeat(and_then(mk_der_tactic(m), mk_simplify_tactic(m, p)));
|
||||
}
|
||||
|
||||
class quasi_macros_tactic : public tactic {
|
||||
|
||||
struct imp {
|
||||
ast_manager & m_manager;
|
||||
bool m_cancel;
|
||||
|
||||
imp(ast_manager & m, params_ref const & p) : m_manager(m),m_cancel(false) {
|
||||
updt_params(p);
|
||||
}
|
||||
|
||||
ast_manager & m() const { return m_manager; }
|
||||
|
||||
void set_cancel(bool f) {
|
||||
m_cancel = f;
|
||||
}
|
||||
|
||||
void operator()(goal_ref const & g,
|
||||
goal_ref_buffer & result,
|
||||
model_converter_ref & mc,
|
||||
proof_converter_ref & pc,
|
||||
expr_dependency_ref & core) {
|
||||
SASSERT(g->is_well_sorted());
|
||||
mc = 0; pc = 0; core = 0;
|
||||
tactic_report report("quasi-macros", *g);
|
||||
fail_if_unsat_core_generation("quasi-macros", g);
|
||||
|
||||
bool produce_proofs = g->proofs_enabled();
|
||||
bool produce_models = g->models_enabled();
|
||||
|
||||
simplifier simp(m_manager);
|
||||
basic_simplifier_plugin * bsimp = alloc(basic_simplifier_plugin, m_manager);
|
||||
bsimp->set_eliminate_and(true);
|
||||
simp.register_plugin(bsimp);
|
||||
arith_simplifier_params a_params;
|
||||
arith_simplifier_plugin * asimp = alloc(arith_simplifier_plugin, m_manager, *bsimp, a_params);
|
||||
simp.register_plugin(asimp);
|
||||
bv_simplifier_params bv_params;
|
||||
bv_simplifier_plugin * bvsimp = alloc(bv_simplifier_plugin, m_manager, *bsimp, bv_params);
|
||||
simp.register_plugin(bvsimp);
|
||||
|
||||
macro_manager mm(m_manager, simp);
|
||||
quasi_macros qm(m_manager, mm, *bsimp, simp);
|
||||
bool more = true;
|
||||
|
||||
expr_ref_vector forms(m_manager), new_forms(m_manager);
|
||||
proof_ref_vector proofs(m_manager), new_proofs(m_manager);
|
||||
|
||||
unsigned size = g->size();
|
||||
for (unsigned i = 0; i < size; i++) {
|
||||
forms.push_back(g->form(i));
|
||||
proofs.push_back(g->pr(i));
|
||||
}
|
||||
|
||||
while (more) { // CMW: use repeat(...) ?
|
||||
if (m_cancel)
|
||||
throw tactic_exception(TACTIC_CANCELED_MSG);
|
||||
|
||||
new_forms.reset();
|
||||
new_proofs.reset();
|
||||
more = qm(forms.size(), forms.c_ptr(), proofs.c_ptr(), new_forms, new_proofs);
|
||||
forms.swap(new_forms);
|
||||
proofs.swap(new_proofs);
|
||||
}
|
||||
|
||||
unsigned i = 0;
|
||||
for (; i < g->size(); i++)
|
||||
g->update(i, new_forms.get(i), produce_proofs ? new_proofs.get(i) : 0, 0);
|
||||
|
||||
for (; i < new_forms.size(); i++)
|
||||
g->assert_expr(new_forms.get(i), new_proofs.get(i), 0);
|
||||
|
||||
extension_model_converter * evmc = alloc(extension_model_converter, mm.get_manager());
|
||||
unsigned num = mm.get_num_macros();
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
expr_ref f_interp(mm.get_manager());
|
||||
func_decl * f = mm.get_macro_interpretation(i, f_interp);
|
||||
evmc->insert(f, f_interp);
|
||||
}
|
||||
mc = evmc;
|
||||
|
||||
g->inc_depth();
|
||||
result.push_back(g.get());
|
||||
TRACE("quasi-macros", g->display(tout););
|
||||
SASSERT(g->is_well_sorted());
|
||||
}
|
||||
|
||||
void updt_params(params_ref const & p) {
|
||||
}
|
||||
};
|
||||
|
||||
imp * m_imp;
|
||||
params_ref m_params;
|
||||
|
||||
public:
|
||||
quasi_macros_tactic(ast_manager & m, params_ref const & p):
|
||||
m_params(p) {
|
||||
m_imp = alloc(imp, m, p);
|
||||
}
|
||||
|
||||
virtual tactic * translate(ast_manager & m) {
|
||||
return alloc(quasi_macros_tactic, m, m_params);
|
||||
}
|
||||
|
||||
virtual ~quasi_macros_tactic() {
|
||||
dealloc(m_imp);
|
||||
}
|
||||
|
||||
virtual void updt_params(params_ref const & p) {
|
||||
m_params = p;
|
||||
m_imp->updt_params(p);
|
||||
}
|
||||
|
||||
virtual void collect_param_descrs(param_descrs & r) {
|
||||
insert_max_memory(r);
|
||||
insert_produce_models(r);
|
||||
insert_produce_proofs(r);
|
||||
}
|
||||
|
||||
virtual void operator()(goal_ref const & in,
|
||||
goal_ref_buffer & result,
|
||||
model_converter_ref & mc,
|
||||
proof_converter_ref & pc,
|
||||
expr_dependency_ref & core) {
|
||||
(*m_imp)(in, result, mc, pc, core);
|
||||
}
|
||||
|
||||
virtual void cleanup() {
|
||||
ast_manager & m = m_imp->m();
|
||||
imp * d = m_imp;
|
||||
#pragma omp critical (tactic_cancel)
|
||||
{
|
||||
m_imp = 0;
|
||||
}
|
||||
dealloc(d);
|
||||
d = alloc(imp, m, m_params);
|
||||
#pragma omp critical (tactic_cancel)
|
||||
{
|
||||
m_imp = d;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void set_cancel(bool f) {
|
||||
if (m_imp)
|
||||
m_imp->set_cancel(f);
|
||||
}
|
||||
};
|
||||
|
||||
tactic * mk_quasi_macros_tactic(ast_manager & m, params_ref const & p) {
|
||||
return alloc(quasi_macros_tactic, m, p);
|
||||
}
|
||||
|
||||
tactic * mk_ufbv_preprocessor_tactic(ast_manager & m, params_ref const & p) {
|
||||
params_ref elim_and_p;
|
||||
elim_and_p.set_bool(":elim-and", true);
|
||||
|
||||
return and_then(
|
||||
and_then(mk_simplify_tactic(m, p),
|
||||
mk_propagate_values_tactic(m, p),
|
||||
and_then(mk_macro_finder_tactic(m, elim_and_p),
|
||||
mk_macro_finder_tactic(m, p), mk_simplify_tactic(m, p)),
|
||||
and_then(mk_snf_tactic(m, p), mk_simplify_tactic(m, p)),
|
||||
mk_simplify_tactic(m, elim_and_p),
|
||||
mk_solve_eqs_tactic(m, p),
|
||||
and_then(mk_der_fp_tactic(m, p), mk_simplify_tactic(m, p)),
|
||||
and_then(mk_distribute_forall_tactic(m, p), mk_simplify_tactic(m, p))),
|
||||
and_then( and_then(mk_reduce_args_tactic(m, p), mk_simplify_tactic(m, p)),
|
||||
and_then(mk_macro_finder_tactic(m, elim_and_p), mk_simplify_tactic(m, p)),
|
||||
and_then(mk_ufbv_rewriter_tactic(m, p), mk_simplify_tactic(m, p)),
|
||||
and_then(mk_quasi_macros_tactic(m, p), mk_simplify_tactic(m, p)),
|
||||
and_then(mk_der_fp_tactic(m, p), mk_simplify_tactic(m, p)),
|
||||
mk_simplify_tactic(m, p)));
|
||||
}
|
||||
|
||||
tactic * mk_ufbv_tactic(ast_manager & m, params_ref const & p) {
|
||||
params_ref main_p(p);
|
||||
main_p.set_bool(":mbqi", true);
|
||||
main_p.set_uint(":mbqi-max-iterations", -1);
|
||||
main_p.set_bool(":elim-and", true);
|
||||
main_p.set_bool(":solver", true);
|
||||
|
||||
params_ref smt_p(p);
|
||||
smt_p.set_bool(":auto-config", false);
|
||||
|
||||
tactic * t = and_then(repeat(mk_ufbv_preprocessor_tactic(m, main_p), 2),
|
||||
using_params(mk_smt_tactic(smt_p), main_p));
|
||||
|
||||
t->updt_params(p);
|
||||
|
||||
return t;
|
||||
}
|
30
src/tactic/ufbv/ufbv_tactic.h
Normal file
30
src/tactic/ufbv/ufbv_tactic.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
ufbv_tactic.h
|
||||
|
||||
Abstract:
|
||||
|
||||
General purpose tactic for UFBV benchmarks.
|
||||
|
||||
Author:
|
||||
|
||||
Christoph (cwinter) 2012-10-24
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _UFBV_TACTIC_H_
|
||||
#define _UFBV_TACTIC_H_
|
||||
|
||||
#include"params.h"
|
||||
class ast_manager;
|
||||
class tactic;
|
||||
|
||||
tactic * mk_macro_finder_tactic(ast_manager & m, params_ref const & p);
|
||||
|
||||
tactic * mk_ufbv_tactic(ast_manager & m, params_ref const & p);
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue