3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-22 16:45:31 +00:00

Reorganizing code base

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2012-10-20 16:33:01 -07:00
parent 9a84cba6c9
commit ded42feeb6
62 changed files with 4 additions and 115 deletions

View file

@ -1,224 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
act_cache.cpp
Abstract:
expr -> expr activity cache
It maintains at most N unused entries
Author:
Leonardo (leonardo) 2011-04-12
Notes:
--*/
#include"act_cache.h"
#define MIN_MAX_UNUSED 1024
#define INITIAL_CAPACITY 128
/*
This cache is a mapping from expr -> tagged expressions
A tagged expression is essentially a pair (expr, flag)
Thus, an entry
t -> (s, 0)
maps the key t to value s, and says that key t was never accessed.
That is, client code never executed find(t)
Similarly, an entry
t -> (s, 1)
also maps the key t to value s, but signs that key t was already accessed
by client code.
When a new key/value pair is inserted the flag is 0.
The flag is set to 1 after the key is accessed.
The number of unused entries (m_unused) is equal to the number of entries
of the form
t -> (s, 0)
That is, it is the number of keys that were never accessed by cliend code.
The cache maintains at most m_max_unused entries.
When the maximum number of unused entries exceeds m_max_unused, then
the cache will delete the oldest unused entry.
*/
/**
m_queue stores the recently added keys.
The queue is implemented as pair: m_queue (vector), m_qhead (unsigned).
The "active" part of m_queue is the range [m_qhead, m_queue.size())
The "inactive" part [0, m_qhead) contains keys that were already used by client code.
This procedure, deletes the inactive part, and makes m_qhead == 0.
*/
void act_cache::compress_queue() {
SASSERT(m_qhead > 0);
unsigned sz = m_queue.size();
unsigned j = 0;
for (unsigned i = m_qhead; i < sz; i++, j++) {
m_queue[j] = m_queue[i];
}
m_queue.shrink(j);
m_qhead = 0;
}
void act_cache::init() {
if (m_max_unused < MIN_MAX_UNUSED)
m_max_unused = MIN_MAX_UNUSED;
m_unused = 0;
m_qhead = 0;
}
void act_cache::dec_refs() {
map::iterator it = m_table.begin();
map::iterator end = m_table.end();
for (; it != end; ++it) {
m_manager.dec_ref((*it).m_key);
m_manager.dec_ref(UNTAG(expr*, (*it).m_value));
}
}
act_cache::act_cache(ast_manager & m):
m_manager(m),
m_max_unused(m.get_num_asts()) {
init();
}
act_cache::act_cache(ast_manager & m, unsigned max_unused):
m_manager(m),
m_max_unused(max_unused) {
init();
}
act_cache::~act_cache() {
dec_refs();
}
/**
\brief Search m_queue from [m_qhead, m_queue.size()) until it finds
an unused key. That is a key associated with an entry
key -> (value, 0)
*/
void act_cache::del_unused() {
unsigned sz = m_queue.size();
while (m_qhead < sz) {
expr * k = m_queue[m_qhead];
m_qhead++;
SASSERT(m_table.contains(k));
map::key_value * entry = m_table.find_core(k);
SASSERT(entry);
if (GET_TAG(entry->m_value) == 0) {
// Key k was never accessed by client code.
// That is, find(k) was never executed by client code.
m_unused--;
expr * v = entry->m_value;
m_table.erase(k);
m_manager.dec_ref(k);
m_manager.dec_ref(v);
break;
}
}
if (m_qhead == sz) {
// The "active" part of the queue is empty.
// So, we perform a "cheap" compress.
m_queue.reset();
m_qhead = 0;
}
else if (m_qhead > m_max_unused) {
compress_queue();
}
}
/**
\brief Insert a new entry k -> v into the cache.
*/
void act_cache::insert(expr * k, expr * v) {
SASSERT(k);
if (m_unused >= m_max_unused)
del_unused();
expr * dummy = reinterpret_cast<expr*>(1);
map::key_value & entry = m_table.insert_if_not_there(k, dummy);
#if 0
unsigned static counter = 0;
counter++;
if (counter % 100000 == 0)
verbose_stream() << "[act-cache] counter: " << counter << " used_slots: " << m_table.used_slots() << " capacity: " << m_table.capacity() << " size: " << m_table.size() << " collisions: " << m_table.collisions() << "\n";
#endif
#ifdef Z3DEBUG
unsigned expected_tag;
#endif
if (entry.m_value == dummy) {
// new entry;
m_manager.inc_ref(k);
m_manager.inc_ref(v);
entry.m_value = v;
m_queue.push_back(k);
m_unused++;
DEBUG_CODE(expected_tag = 0;); // new entry
}
else if (UNTAG(expr*, entry.m_value) == v) {
// already there
DEBUG_CODE(expected_tag = GET_TAG(entry.m_value););
}
else {
// replacing old entry
m_manager.inc_ref(v);
m_manager.dec_ref(UNTAG(expr*, entry.m_value));
entry.m_value = v;
SASSERT(GET_TAG(entry.m_value) == 0);
// replaced old entry, and reset the tag.
DEBUG_CODE(expected_tag = 0;);
}
DEBUG_CODE({
expr * v2;
SASSERT(m_table.find(k, v2));
SASSERT(v == UNTAG(expr*, v2));
SASSERT(expected_tag == GET_TAG(v2));
});
}
/**
\brief Search for key k in the cache.
If entry k -> (v, tag) is found, we set tag to 1.
*/
expr * act_cache::find(expr * k) {
map::key_value * entry = m_table.find_core(k);
if (entry == 0)
return 0;
if (GET_TAG(entry->m_value) == 0) {
entry->m_value = TAG(expr*, entry->m_value, 1);
SASSERT(GET_TAG(entry->m_value) == 1);
SASSERT(m_unused > 0);
m_unused--;
DEBUG_CODE({
expr * v;
SASSERT(m_table.find(k, v));
SASSERT(GET_TAG(v) == 1);
});
}
return UNTAG(expr*, entry->m_value);
}
void act_cache::reset() {
dec_refs();
m_table.reset();
m_queue.reset();
m_unused = 0;
m_qhead = 0;
}
void act_cache::cleanup() {
dec_refs();
m_table.finalize();
m_queue.finalize();
m_unused = 0;
m_qhead = 0;
}
bool act_cache::check_invariant() const {
return true;
}

View file

@ -1,56 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
act_cache.h
Abstract:
expr -> expr activity cache
It maintains at most N unused entries
Author:
Leonardo (leonardo) 2011-04-12
Notes:
--*/
#ifndef _ACT_CACHE_H_
#define _ACT_CACHE_H_
#include"ast.h"
#include"obj_hashtable.h"
#include"chashtable.h"
class act_cache {
ast_manager & m_manager;
typedef cmap<expr*, expr*, obj_ptr_hash<expr>, default_eq<expr*> > map;
map m_table;
ptr_vector<expr> m_queue; // recently created queue
unsigned m_qhead;
unsigned m_unused;
unsigned m_max_unused;
void compress_queue();
void init();
void dec_refs();
void del_unused();
public:
act_cache(ast_manager & m);
act_cache(ast_manager & m, unsigned max_unused);
~act_cache();
void insert(expr * k, expr * v);
expr * find(expr * k);
void reset();
void cleanup();
unsigned size() const { return m_table.size(); }
unsigned capacity() const { return m_table.capacity(); }
bool empty() const { return m_table.empty(); }
bool check_invariant() const;
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,183 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
arith_rewriter.h
Abstract:
Basic rewriting rules for arithmetic
Author:
Leonardo (leonardo) 2011-04-10
Notes:
--*/
#ifndef _ARITH_REWRITER_H_
#define _ARITH_REWRITER_H_
#include"poly_rewriter.h"
#include"arith_decl_plugin.h"
class arith_rewriter_core {
protected:
typedef rational numeral;
arith_util m_util;
bool m_expand_power;
bool m_mul2power;
bool m_expand_tan;
ast_manager & m() const { return m_util.get_manager(); }
family_id get_fid() const { return m_util.get_family_id(); }
bool is_numeral(expr * n) const { return m_util.is_numeral(n); }
bool is_numeral(expr * n, numeral & r) const { return m_util.is_numeral(n, r); }
bool is_zero(expr * n) const { return m_util.is_zero(n); }
bool is_minus_one(expr * n) const { return m_util.is_minus_one(n); }
void normalize(numeral & c, sort * s) {}
app * mk_numeral(numeral const & r, sort * s) { return m_util.mk_numeral(r, s); }
decl_kind add_decl_kind() const { return OP_ADD; }
decl_kind mul_decl_kind() const { return OP_MUL; }
bool use_power() const { return m_mul2power && !m_expand_power; }
decl_kind power_decl_kind() const { return OP_POWER; }
public:
arith_rewriter_core(ast_manager & m):m_util(m) {}
};
class arith_rewriter : public poly_rewriter<arith_rewriter_core> {
bool m_arith_lhs;
bool m_gcd_rounding;
bool m_eq2ineq;
bool m_elim_to_real;
bool m_push_to_real;
bool m_anum_simp;
bool m_elim_rem;
unsigned m_max_degree;
void get_coeffs_gcd(expr * t, numeral & g, bool & first, unsigned & num_consts);
enum const_treatment { CT_FLOOR, CT_CEIL, CT_FALSE };
bool div_polynomial(expr * t, numeral const & g, const_treatment ct, expr_ref & result);
enum op_kind { LE, GE, EQ };
static op_kind inv(op_kind k) { return k == LE ? GE : (k == GE ? LE : EQ); }
bool is_bound(expr * arg1, expr * arg2, op_kind kind, expr_ref & result);
br_status mk_le_ge_eq_core(expr * arg1, expr * arg2, op_kind kind, expr_ref & result);
bool elim_to_real_var(expr * var, expr_ref & new_var);
bool elim_to_real_mon(expr * monomial, expr_ref & new_monomial);
bool elim_to_real_pol(expr * p, expr_ref & new_p);
bool elim_to_real(expr * arg1, expr * arg2, expr_ref & new_arg1, expr_ref & new_arg2);
void updt_local_params(params_ref const & p);
bool is_anum_simp_target(unsigned num_args, expr * const * args);
br_status mk_div_irrat_rat(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_div_rat_irrat(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_div_irrat_irrat(expr * arg1, expr * arg2, expr_ref & result);
bool is_reduce_power_target(expr * arg, bool is_eq);
expr * reduce_power(expr * arg, bool is_eq);
br_status reduce_power(expr * arg1, expr * arg2, op_kind kind, expr_ref & result);
bool is_pi_multiple(expr * t, rational & k);
bool is_pi_offset(expr * t, rational & k, expr * & m);
bool is_2_pi_integer(expr * t);
bool is_2_pi_integer_offset(expr * t, expr * & m);
bool is_pi_integer(expr * t);
bool is_pi_integer_offset(expr * t, expr * & m);
expr * mk_sin_value(rational const & k);
app * mk_sqrt(rational const & k);
public:
arith_rewriter(ast_manager & m, params_ref const & p = params_ref()):
poly_rewriter<arith_rewriter_core>(m, p) {
updt_local_params(p);
}
void updt_params(params_ref const & p);
static void get_param_descrs(param_descrs & r);
br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
void mk_app(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
if (mk_app_core(f, num_args, args, result) == BR_FAILED)
result = m().mk_app(f, num_args, args);
}
br_status mk_eq_core(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_le_core(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_lt_core(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_ge_core(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_gt_core(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_add_core(unsigned num_args, expr * const * args, expr_ref & result);
br_status mk_mul_core(unsigned num_args, expr * const * args, expr_ref & result);
void mk_eq(expr * arg1, expr * arg2, expr_ref & result) {
if (mk_eq_core(arg1, arg2, result) == BR_FAILED)
result = m_util.mk_le(arg1, arg2);
}
void mk_le(expr * arg1, expr * arg2, expr_ref & result) {
if (mk_le_core(arg1, arg2, result) == BR_FAILED)
result = m_util.mk_le(arg1, arg2);
}
void mk_lt(expr * arg1, expr * arg2, expr_ref & result) { mk_lt_core(arg1, arg2, result); }
void mk_ge(expr * arg1, expr * arg2, expr_ref & result) {
if (mk_ge_core(arg1, arg2, result) == BR_FAILED)
result = m_util.mk_ge(arg1, arg2);
}
void mk_gt(expr * arg1, expr * arg2, expr_ref & result) { mk_gt_core(arg1, arg2, result); }
br_status mk_div_core(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_idiv_core(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_mod_core(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_rem_core(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_power_core(expr* arg1, expr* arg2, expr_ref & result);
void mk_div(expr * arg1, expr * arg2, expr_ref & result) {
if (mk_div_core(arg1, arg2, result) == BR_FAILED)
result = m().mk_app(get_fid(), OP_DIV, arg1, arg2);
}
void mk_idiv(expr * arg1, expr * arg2, expr_ref & result) {
if (mk_idiv_core(arg1, arg2, result) == BR_FAILED)
result = m().mk_app(get_fid(), OP_IDIV, arg1, arg2);
}
void mk_mod(expr * arg1, expr * arg2, expr_ref & result) {
if (mk_mod_core(arg1, arg2, result) == BR_FAILED)
result = m().mk_app(get_fid(), OP_MOD, arg1, arg2);
}
void mk_rem(expr * arg1, expr * arg2, expr_ref & result) {
if (mk_rem_core(arg1, arg2, result) == BR_FAILED)
result = m().mk_app(get_fid(), OP_REM, arg1, arg2);
}
br_status mk_to_int_core(expr * arg, expr_ref & result);
br_status mk_to_real_core(expr * arg, expr_ref & result);
void mk_to_int(expr * arg, expr_ref & result) {
if (mk_to_int_core(arg, result) == BR_FAILED)
result = m().mk_app(get_fid(), OP_TO_INT, 1, &arg);
}
void mk_to_real(expr * arg, expr_ref & result) {
if (mk_to_real_core(arg, result) == BR_FAILED)
result = m().mk_app(get_fid(), OP_TO_REAL, 1, &arg);
}
br_status mk_is_int(expr * arg, expr_ref & result);
void set_cancel(bool f);
br_status mk_sin_core(expr * arg, expr_ref & result);
br_status mk_cos_core(expr * arg, expr_ref & result);
br_status mk_tan_core(expr * arg, expr_ref & result);
br_status mk_asin_core(expr * arg, expr_ref & result);
br_status mk_acos_core(expr * arg, expr_ref & result);
br_status mk_atan_core(expr * arg, expr_ref & result);
br_status mk_sinh_core(expr * arg, expr_ref & result);
br_status mk_cosh_core(expr * arg, expr_ref & result);
br_status mk_tanh_core(expr * arg, expr_ref & result);
};
#endif

View file

@ -1,359 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
array_rewriter.cpp
Abstract:
Basic rewriting rules for Arrays.
Author:
Leonardo (leonardo) 2011-04-06
Notes:
--*/
#include"array_rewriter.h"
#include"ast_lt.h"
#include"ast_pp.h"
void array_rewriter::updt_params(params_ref const & p) {
m_sort_store = p.get_bool(":sort-store", false);
m_expand_select_store = p.get_bool(":expand-select-store", false);
}
void array_rewriter::get_param_descrs(param_descrs & r) {
r.insert(":expand-select-store", CPK_BOOL, "(default: false) replace a (select (store ...) ...) term by an if-then-else term.");
r.insert(":sort-store", CPK_BOOL, "(default: false) sort nested stores when the indices are known to be different.");
}
br_status array_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(f->get_family_id() == get_fid());
TRACE("array_rewriter", tout << mk_pp(f, m()) << "\n";
for (unsigned i = 0; i < num_args; ++i) {
tout << mk_pp(args[i], m()) << "\n";
});
switch (f->get_decl_kind()) {
case OP_SELECT:
return mk_select_core(num_args, args, result);
case OP_STORE:
return mk_store_core(num_args, args, result);
case OP_ARRAY_MAP:
SASSERT(f->get_num_parameters() == 1);
SASSERT(f->get_parameter(0).is_ast());
SASSERT(is_func_decl(f->get_parameter(0).get_ast()));
return mk_map_core(to_func_decl(f->get_parameter(0).get_ast()), num_args, args, result);
case OP_SET_UNION:
return mk_set_union(num_args, args, result);
case OP_SET_INTERSECT:
return mk_set_intersect(num_args, args, result);
case OP_SET_SUBSET:
SASSERT(num_args == 2);
return mk_set_subset(args[0], args[1], result);
case OP_SET_COMPLEMENT:
SASSERT(num_args == 1);
return mk_set_complement(args[0], result);
case OP_SET_DIFFERENCE:
SASSERT(num_args == 2);
return mk_set_difference(args[0], args[1], result);
default:
return BR_FAILED;
}
}
// l_true -- all equal
// l_false -- at least one disequal
// l_undef -- don't know
template<bool CHECK_DISEQ>
lbool array_rewriter::compare_args(unsigned num_args, expr * const * args1, expr * const * args2) {
for (unsigned i = 0; i < num_args; i++) {
if (args1[i] == args2[i])
continue;
if (CHECK_DISEQ && m().are_distinct(args1[i], args2[i]))
return l_false;
return l_undef;
}
return l_true;
}
br_status array_rewriter::mk_store_core(unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(num_args >= 3);
if (m_util.is_store(args[0])) {
lbool r = m_sort_store ?
compare_args<true>(num_args - 2, args + 1, to_app(args[0])->get_args() + 1) :
compare_args<false>(num_args - 2, args + 1, to_app(args[0])->get_args() + 1);
switch (r) {
case l_true: {
//
// store(store(a,i,v),i,w) --> store(a,i,w)
//
ptr_buffer<expr> new_args;
new_args.push_back(to_app(args[0])->get_arg(0));
new_args.append(num_args-1, args+1);
SASSERT(new_args.size() == num_args);
result = m().mk_app(get_fid(), OP_STORE, num_args, new_args.c_ptr());
return BR_DONE;
}
case l_false:
SASSERT(m_sort_store);
//
// store(store(a,i,v),j,w) -> store(store(a,j,w),i,v)
// if i, j are different, lt(i,j)
//
if (lex_lt(num_args-2, args+1, to_app(args[0])->get_args() + 1)) {
ptr_buffer<expr> new_args;
new_args.push_back(to_app(args[0])->get_arg(0));
new_args.append(num_args-1, args+1);
expr * nested_store = m().mk_app(get_fid(), OP_STORE, num_args, new_args.c_ptr());
new_args.reset();
new_args.push_back(nested_store);
new_args.append(num_args - 1, to_app(args[0])->get_args() + 1);
result = m().mk_app(get_fid(), OP_STORE, num_args, new_args.c_ptr());
return BR_REWRITE2;
}
break;
case l_undef:
break;
}
}
//
// store(const(v),i,v) --> const(v)
//
if (m_util.is_const(args[0]) &&
to_app(args[0])->get_arg(0) == args[num_args-1]) {
result = args[0];
return BR_DONE;
}
expr * v = args[num_args-1];
//
// store(a, i, select(a, i)) --> a
//
if (m_util.is_select(v) &&
compare_args<false>(num_args-1, args, to_app(v)->get_args())) {
result = args[0];
return BR_DONE;
}
return BR_FAILED;
}
br_status array_rewriter::mk_select_core(unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(num_args >= 2);
if (m_util.is_store(args[0])) {
SASSERT(to_app(args[0])->get_num_args() == num_args+1);
switch (compare_args<true>(num_args - 1, args+1, to_app(args[0])->get_args()+1)) {
case l_true:
// select(store(a, I, v), I) --> v
result = to_app(args[0])->get_arg(num_args);
return BR_DONE;
case l_false: {
// select(store(a, I, v), J) --> select(a, J) if I != J
ptr_buffer<expr> new_args;
new_args.push_back(to_app(args[0])->get_arg(0));
new_args.append(num_args-1, args+1);
result = m().mk_app(get_fid(), OP_SELECT, num_args, new_args.c_ptr());
return BR_REWRITE1;
}
default:
if (m_expand_select_store) {
// select(store(a, I, v), J) --> ite(I=J, v, select(a, J))
ptr_buffer<expr> new_args;
new_args.push_back(to_app(args[0])->get_arg(0));
new_args.append(num_args-1, args+1);
expr * sel_a_j = m().mk_app(get_fid(), OP_SELECT, num_args, new_args.c_ptr());
expr * v = to_app(args[0])->get_arg(num_args);
ptr_buffer<expr> eqs;
unsigned num_indices = num_args-1;
for (unsigned i = 0; i < num_indices; i++) {
eqs.push_back(m().mk_eq(to_app(args[0])->get_arg(i+1), args[i+1]));
}
if (num_indices == 1) {
result = m().mk_ite(eqs[0], v, sel_a_j);
return BR_REWRITE2;
}
else {
result = m().mk_ite(m().mk_and(eqs.size(), eqs.c_ptr()), v, sel_a_j);
return BR_REWRITE3;
}
}
return BR_FAILED;
}
}
if (m_util.is_const(args[0])) {
// select(const(v), I) --> v
result = to_app(args[0])->get_arg(0);
return BR_DONE;
}
if (m_util.is_as_array(args[0])) {
// select(as-array[f], I) --> f(I)
func_decl * f = m_util.get_as_array_func_decl(to_app(args[0]));
result = m().mk_app(f, num_args - 1, args + 1);
return BR_REWRITE1;
}
return BR_FAILED;
}
br_status array_rewriter::mk_map_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(num_args >= 0);
bool is_store0 = m_util.is_store(args[0]);
bool is_const0 = m_util.is_const(args[0]);
if (num_args == 1) {
//
// map_f (store a j v) = (store (map_f a) j (f v))
//
if (is_store0) {
app * store_expr = to_app(args[0]);
unsigned num_args = store_expr->get_num_args();
SASSERT(num_args >= 3);
expr * a = store_expr->get_arg(0);
expr * v = store_expr->get_arg(num_args-1);
ptr_buffer<expr> new_args;
new_args.push_back(m_util.mk_map(f, 1, &a)); // (map_f a)
new_args.append(num_args - 2, store_expr->get_args() + 1); // j
new_args.push_back(m().mk_app(f, v)); // (f v)
result = m().mk_app(get_fid(), OP_STORE, new_args.size(), new_args.c_ptr());
return BR_REWRITE2;
}
//
// map_f (const v) = (const (f v))
//
if (is_const0) {
expr * fv = m().mk_app(f, to_app(args[0])->get_arg(0));
result = m_util.mk_const_array(m().get_sort(args[0]), fv);
return BR_REWRITE2;
}
return BR_FAILED;
}
SASSERT(num_args > 1);
if (is_store0) {
unsigned num_indices = to_app(args[0])->get_num_args() - 2;
unsigned i;
for (i = 1; i < num_args; i++) {
if (!m_util.is_store(args[i]))
break;
unsigned j;
for (j = 1; j < num_indices+1; j++) {
if (to_app(args[0])->get_arg(j) != to_app(args[i])->get_arg(j))
break;
}
if (j < num_indices+1)
break;
}
//
// map_f (store a_1 j v_1) ... (store a_n j v_n) --> (store (map_f a_1 ... a_n) j (f v_1 ... v_n))
//
if (i == num_args) {
ptr_buffer<expr> arrays;
ptr_buffer<expr> values;
for (unsigned i = 0; i < num_args; i++) {
arrays.push_back(to_app(args[i])->get_arg(0));
values.push_back(to_app(args[i])->get_arg(num_indices+1));
}
ptr_buffer<expr> new_args;
new_args.push_back(m_util.mk_map(f, arrays.size(), arrays.c_ptr()));
new_args.append(num_indices, to_app(args[0])->get_args() + 1);
new_args.push_back(m().mk_app(f, values.size(), values.c_ptr()));
result = m().mk_app(get_fid(), OP_STORE, new_args.size(), new_args.c_ptr());
return BR_REWRITE2;
}
return BR_FAILED;
}
if (is_const0) {
unsigned i;
for (i = 1; i < num_args; i++) {
if (!m_util.is_const(args[i]))
break;
}
if (i == num_args) {
//
// map_f (const v_1) ... (const v_n) = (const (f v_1 ... v_n))
//
ptr_buffer<expr> values;
for (unsigned i = 0; i < num_args; i++) {
values.push_back(to_app(args[i])->get_arg(0));
}
expr * fv = m().mk_app(f, values.size(), values.c_ptr());
parameter p(m().get_sort(args[0]));
result = m().mk_app(get_fid(), OP_CONST_ARRAY, 1, &p, 1, &fv);
return BR_REWRITE2;
}
return BR_FAILED;
}
return BR_FAILED;
}
void array_rewriter::mk_store(unsigned num_args, expr * const * args, expr_ref & result) {
if (mk_store_core(num_args, args, result) == BR_FAILED)
result = m().mk_app(get_fid(), OP_STORE, num_args, args);
}
void array_rewriter::mk_select(unsigned num_args, expr * const * args, expr_ref & result) {
if (mk_select_core(num_args, args, result) == BR_FAILED)
result = m().mk_app(get_fid(), OP_SELECT, num_args, args);
}
void array_rewriter::mk_map(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
if (mk_map_core(f, num_args, args, result) == BR_FAILED)
result = m_util.mk_map(f, num_args, args);
}
br_status array_rewriter::mk_set_union(unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(num_args > 0);
if (num_args == 1) {
result = args[0];
return BR_DONE;
}
SASSERT(num_args >= 2);
br_status r = unsigned2br_status(num_args - 2);
result = m_util.mk_map(m().mk_or_decl(), num_args, args);
return r;
}
br_status array_rewriter::mk_set_intersect(unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(num_args > 0);
if (num_args == 1) {
result = args[0];
return BR_DONE;
}
SASSERT(num_args >= 2);
br_status r = unsigned2br_status(num_args - 2);
result = m_util.mk_map(m().mk_and_decl(), num_args, args);
return r;
}
br_status array_rewriter::mk_set_complement(expr * arg, expr_ref & result) {
return mk_map_core(m().mk_not_decl(), 1, &arg, result);
}
br_status array_rewriter::mk_set_difference(expr * arg1, expr * arg2, expr_ref & result) {
expr * args[2] = { arg1, m_util.mk_map(m().mk_not_decl(), 1, &arg2) };
result = m_util.mk_map(m().mk_and_decl(), 2, args);
return BR_REWRITE2;
}
br_status array_rewriter::mk_set_subset(expr * arg1, expr * arg2, expr_ref & result) {
mk_set_difference(arg1, arg2, result);
result = m().mk_eq(result.get(), m_util.mk_empty_set(m().get_sort(arg1)));
return BR_REWRITE3;
}

View file

@ -1,65 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
array_rewriter.h
Abstract:
Basic rewriting rules for Arrays.
Author:
Leonardo (leonardo) 2011-04-06
Notes:
--*/
#ifndef _ARRAY_REWRITER_H_
#define _ARRAY_REWRITER_H_
#include"array_decl_plugin.h"
#include"rewriter_types.h"
#include"lbool.h"
#include"params.h"
/**
\brief Cheap rewrite rules for Arrays
*/
class array_rewriter {
array_util m_util;
bool m_sort_store;
bool m_expand_select_store;
template<bool CHECK_DISEQ>
lbool compare_args(unsigned num_args, expr * const * args1, expr * const * args2);
public:
array_rewriter(ast_manager & m, params_ref const & p = params_ref()):
m_util(m) {
updt_params(p);
}
ast_manager & m() const { return m_util.get_manager(); }
family_id get_fid() const { return m_util.get_family_id(); }
void updt_params(params_ref const & p);
static void get_param_descrs(param_descrs & r);
br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
br_status mk_store_core(unsigned num_args, expr * const * args, expr_ref & result);
br_status mk_select_core(unsigned num_args, expr * const * args, expr_ref & result);
br_status mk_map_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
void mk_store(unsigned num_args, expr * const * args, expr_ref & result);
void mk_select(unsigned num_args, expr * const * args, expr_ref & result);
void mk_map(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
// The following methods never return BR_FAILED
br_status mk_set_union(unsigned num_args, expr * const * args, expr_ref & result);
br_status mk_set_intersect(unsigned num_args, expr * const * args, expr_ref & result);
br_status mk_set_complement(expr * arg, expr_ref & result);
br_status mk_set_difference(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_set_subset(expr * arg1, expr * arg2, expr_ref & result);
};
#endif

View file

@ -1,353 +0,0 @@
/*++
Copyright (c) 2007 Microsoft Corporation
Module Name:
ast_dag_pp.cpp
Abstract:
AST low level pretty printer.
Author:
Leonardo de Moura (leonardo) 2006-10-19.
Nikolaj Bjorner (nbjorner) 2007-07-17
Revision History:
--*/
#include<iostream>
#include"for_each_ast.h"
#include"arith_decl_plugin.h"
#include"bv_decl_plugin.h"
#include"ast_pp.h"
class dag_printer {
ast_manager& m_manager;
std::ostream & m_out;
ast_mark& m_mark;
bool m_initialized;
svector<symbol> m_names;
family_id m_basic_fid;
family_id m_bv_fid;
family_id m_arith_fid;
family_id m_array_fid;
arith_util m_arith;
bv_util m_bv;
bool m_enable_shortcut;
void process_ast(ast* a) {
for_each_ast(*this, m_mark, a);
}
void process_info(decl_info* info) {
if (!info) {
return;
}
unsigned num_params = info->get_num_parameters();
for (unsigned i = 0; i < num_params; ++i) {
parameter const& p = info->get_parameter(i);
if (p.is_ast() && !m_mark.is_marked(p.get_ast())) {
process_ast(p.get_ast());
}
}
}
template<typename T>
void display_children(unsigned num_children, T * const * children) {
for (unsigned i = 0; i < num_children; i++) {
display_node_id(children[i]);
}
}
void display_node_id(ast* n) {
unsigned id = n->get_id();
switch(n->get_kind()) {
case AST_FUNC_DECL:
case AST_SORT:
m_out << "$d" << (id - (1 << 31)) << " ";
break;
default:
m_out << "$" << id << " ";
break;
}
}
void display_parameter(parameter const& p)
{
if (p.is_int()) {
m_out << p.get_int() << " ";
}
else if (p.is_ast()) {
SASSERT(p.is_ast());
display_node_id(p.get_ast());
}
else if (p.is_rational()) {
m_out << p.get_rational() << " ";
}
else if (p.is_symbol()) {
display_symbol(p.get_symbol());
}
else {
UNREACHABLE();
}
}
// Display:
// App name [ parameters] arguments
//
void display_builtin(app* n) {
func_decl* d = n->get_decl();
unsigned num_params = d->get_num_parameters();
m_out << "App ";
display_node_id(n);
display_symbol(d->get_name());
if (num_params > 0) {
m_out << "[ ";
for (unsigned i = 0; i < num_params; ++i) {
display_parameter(d->get_parameter(i));
}
m_out << "] ";
}
display_children(n->get_num_args(), n->get_args());
m_out << "\n";
}
void display_info(func_decl_info* info) {
if (!info) {
return;
}
m_out << "BUILTIN " << get_family_name(info->get_family_id()) << " " << info->get_decl_kind() << " ";
if (info->is_associative()) {
m_out << ":assoc ";
}
if (info->is_commutative()) {
m_out << ":comm ";
}
if (info->is_injective()) {
m_out << ":inj ";
}
for (unsigned i = 0; i < info->get_num_parameters(); ++i) {
display_parameter(info->get_parameter(i));
}
}
void display_info(sort_info* info) {
if (!info) {
return;
}
m_out << "BUILTIN " << get_family_name(info->get_family_id()) << " " << info->get_decl_kind() << " ";
// TODO: remove this if... it doesn't make sense...
if (!info->is_infinite() && !info->is_very_big()) {
m_out << "Size " << info->get_num_elements().size() << " ";
}
for (unsigned i = 0; i < info->get_num_parameters(); ++i) {
display_parameter(info->get_parameter(i));
}
}
symbol get_family_name(family_id id) {
if (id == null_family_id) {
return symbol("null");
}
if (!m_initialized) {
svector<symbol> names;
svector<family_id> range;
m_manager.get_dom(names);
m_manager.get_range(range);
m_names.resize(range.size());
for (unsigned i = 0; i < range.size(); ++i) {
SASSERT(range[i] < static_cast<family_id>(range.size()));
m_names[range[i]] = names[i];
}
m_initialized = true;
}
SASSERT(id < static_cast<family_id>(m_names.size()));
return m_names[id];
}
bool has_special_char(char const* s) {
while (s && *s) {
if (*s == ' ') {
return true;
}
++s;
}
return false;
}
void display_symbol(symbol const& s) {
if (s.is_numerical()) {
m_out << s << " ";
}
else if (!(s.bare_str()[0])) {
m_out << "\"null\" ";
}
else if (!has_special_char(s.bare_str())) {
m_out << s << " ";
}
else {
char const* r = s.bare_str();
m_out << "\"";
while (*r) {
if (*r == ' ' || *r == '\n' ||
*r == '\t' || *r == '\r') {
m_out << "\\" << ((unsigned)(*r));
}
else {
m_out << *r;
}
++r;
}
m_out << "\" ";
}
}
public:
dag_printer(ast_manager& mgr, std::ostream & out, ast_mark& mark):
m_manager(mgr),
m_out(out),
m_mark(mark),
m_initialized(false),
m_basic_fid(mgr.get_basic_family_id()),
m_bv_fid(mgr.get_family_id("bv")),
m_arith_fid(mgr.get_family_id("arith")),
m_array_fid(mgr.get_family_id("array")),
m_arith(mgr),
m_bv(mgr),
m_enable_shortcut(true)
{
}
void operator()(sort * n) {
process_info(n->get_info());
m_out << "Ty ";
display_node_id(n);
display_symbol(n->get_name());
display_info(n->get_info());
m_out << "\n";
}
void pp_num(app* n, rational const& r) {
m_out << "Num ";
display_node_id(n);
m_out << r << " ";
display_node_id(m_manager.get_sort(n));
m_out << "\n";
}
void operator()(var * n) {
process_ast(n->get_sort());
m_out << "Var ";
display_node_id(n);
m_out << n->get_idx() << " ";
display_node_id(n->get_sort());
m_out << "\n";
}
void operator()(func_decl * n) {
process_info(n->get_info());
family_id fid = n->get_family_id();
if (m_arith_fid == fid &&
n->get_info()->get_decl_kind() == OP_NUM) {
return;
}
if (m_bv_fid == fid &&
n->get_info()->get_decl_kind() == OP_BV_NUM) {
return;
}
m_out << "Dec ";
display_node_id(n);
display_symbol(n->get_name());
unsigned dom_size = n->get_arity();
for (unsigned i = 0; i < dom_size; ++i) {
display_node_id(n->get_domain(i));
}
display_node_id(n->get_range());
display_info(n->get_info());
m_out << "\n";
}
void operator()(app * n) {
process_ast(n->get_decl());
family_id fid = n->get_family_id();
unsigned bv_size;
rational val;
if (m_arith.is_numeral(n, val)) {
pp_num(n, val);
}
else if (m_bv.is_numeral(n, val, bv_size)) {
pp_num(n, val);
}
else if (m_enable_shortcut &&
fid != null_family_id &&
(fid == m_basic_fid || fid == m_bv_fid || fid == m_array_fid || fid == m_arith_fid)) {
display_builtin(n);
}
else if (n->get_num_args() == 0 && fid == null_family_id) {
func_decl* d = n->get_decl();
m_out << "Const ";
display_node_id(n);
display_symbol(d->get_name());
display_node_id(d->get_range());
m_out << "\n";
}
else {
m_out << "Fun ";
display_node_id(n);
display_node_id(n->get_decl());
display_children(n->get_num_args(), n->get_args());
m_out << "\n";
}
}
void operator()(quantifier * n) {
m_out << "Qua ";
display_node_id(n);
m_out << (n->is_forall() ? "FORALL" : "EXISTS") << " ";
m_out << n->get_weight() << " ";
if (symbol::null != n->get_skid()) {
m_out << "\"" << n->get_skid() << "\" ";
}
else {
m_out << "\"null\" ";
}
if (symbol::null != n->get_qid()) {
m_out << "\"" << n->get_qid() << "\" ";
}
else {
m_out << "\"null\" ";
}
unsigned num_decls = n->get_num_decls();
m_out << num_decls << " ";
for (unsigned i = 0; i < num_decls; i++) {
m_out << n->get_decl_name(i) << " ";
display_node_id(n->get_decl_sort(i));
}
m_out << n->get_num_patterns() << " ";
display_children(n->get_num_patterns(), n->get_patterns());
display_node_id(n->get_expr());
m_out << "\n";
}
};
void ast_dag_pp(std::ostream & out, ast_manager& mgr, ast_mark& mark, ast * n) {
dag_printer p(mgr, out, mark);
for_each_ast(p, mark, n, true);
}
void ast_dag_pp(std::ostream & out, ast_manager& mgr, ast * n) {
ast_mark mark;
ast_dag_pp(out, mgr, mark, n);
}

View file

@ -1,31 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
ast_dag_pp.h
Abstract:
AST low level pretty printer.
Author:
Leonardo de Moura (leonardo) 2006-10-19.
Revision History:
--*/
#ifndef _AST_DAG_PP_H_
#define _AST_DAG_PP_H_
#include<iostream>
class ast;
void ast_dag_pp(std::ostream & out, ast_manager& mgr, ast * n);
void ast_dag_pp(std::ostream & out, ast_manager& mgr, ast_mark& mark, ast * n);
#endif /* _AST_DAG_PP_H_ */

View file

@ -1,144 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
ast_lt.cpp
Abstract:
Total order on ASTs that does not depend on the internal ids.
Author:
Leonardo de Moura (leonardo) 2011-04-08
Revision History:
--*/
#include"ast.h"
#define check_symbol(S1,S2) if (S1 != S2) return lt(S1,S2)
#define check_value(V1,V2) if (V1 != V2) return V1 < V2
#define check_bool(B1,B2) if (B1 != B2) return !B1 && B2
#define check_ptr(P1,P2) if (!P1 && P2) return true; if (P1 && !P2) return false
#define check_ast(T1,T2) if (T1 != T2) { n1 = T1; n2 = T2; goto start; }
#define check_parameter(p1, p2) { \
check_value(p1.get_kind(), p2.get_kind()); \
switch (p1.get_kind()) { \
case parameter::PARAM_INT: \
check_value(p1.get_int(), p2.get_int()); \
break; \
case parameter::PARAM_AST: \
check_ast(p1.get_ast(), p2.get_ast()); \
break; \
case parameter::PARAM_SYMBOL: \
check_symbol(p1.get_symbol(), p2.get_symbol()); \
break; \
case parameter::PARAM_RATIONAL: \
check_value(p1.get_rational(), p2.get_rational()); \
break; \
case parameter::PARAM_DOUBLE: \
check_value(p1.get_double(), p2.get_double()); \
break; \
case parameter::PARAM_EXTERNAL: \
check_value(p1.get_ext_id(), p2.get_ext_id()); \
break; \
default: \
UNREACHABLE(); \
break; \
} \
}
bool lt(ast * n1, ast * n2) {
unsigned num;
start:
if (n1 == n2)
return false;
check_value(n1->get_kind(), n2->get_kind());
switch(n1->get_kind()) {
case AST_SORT:
check_symbol(to_sort(n1)->get_name(), to_sort(n2)->get_name());
check_value(to_sort(n1)->get_num_parameters(), to_sort(n2)->get_num_parameters());
num = to_sort(n1)->get_num_parameters();
SASSERT(num > 0);
for (unsigned i = 0; i < num; i++) {
parameter p1 = to_sort(n1)->get_parameter(i);
parameter p2 = to_sort(n2)->get_parameter(i);
check_parameter(p1, p2);
}
UNREACHABLE();
return false;
case AST_FUNC_DECL:
check_symbol(to_func_decl(n1)->get_name(), to_func_decl(n2)->get_name());
check_value(to_func_decl(n1)->get_arity(), to_func_decl(n2)->get_arity());
check_value(to_func_decl(n1)->get_num_parameters(), to_func_decl(n2)->get_num_parameters());
num = to_func_decl(n1)->get_num_parameters();
for (unsigned i = 0; i < num; i++) {
parameter p1 = to_func_decl(n1)->get_parameter(i);
parameter p2 = to_func_decl(n2)->get_parameter(i);
check_parameter(p1, p2);
}
num = to_func_decl(n1)->get_arity();
for (unsigned i = 0; i < num; i++) {
ast * d1 = to_func_decl(n1)->get_domain(i);
ast * d2 = to_func_decl(n2)->get_domain(i);
check_ast(d1, d2);
}
n1 = to_func_decl(n1)->get_range();
n2 = to_func_decl(n2)->get_range();
goto start;
case AST_APP:
check_value(to_app(n1)->get_num_args(), to_app(n2)->get_num_args());
check_value(to_app(n1)->get_depth(), to_app(n2)->get_depth());
check_ast(to_app(n1)->get_decl(), to_app(n2)->get_decl());
num = to_app(n1)->get_num_args();
for (unsigned i = 0; i < num; i++) {
expr * arg1 = to_app(n1)->get_arg(i);
expr * arg2 = to_app(n2)->get_arg(i);
check_ast(arg1, arg2);
}
UNREACHABLE();
return false;
case AST_QUANTIFIER:
check_bool(to_quantifier(n1)->is_forall(), to_quantifier(n2)->is_forall());
check_value(to_quantifier(n1)->get_num_decls(), to_quantifier(n2)->get_num_decls());
check_value(to_quantifier(n1)->get_num_patterns(), to_quantifier(n2)->get_num_patterns());
check_value(to_quantifier(n1)->get_num_no_patterns(), to_quantifier(n2)->get_num_no_patterns());
check_value(to_quantifier(n1)->get_weight(), to_quantifier(n2)->get_weight());
num = to_quantifier(n1)->get_num_decls();
for (unsigned i = 0; i < num; i++) {
check_symbol(to_quantifier(n1)->get_decl_name(i), to_quantifier(n2)->get_decl_name(i));
check_ast(to_quantifier(n1)->get_decl_sort(i), to_quantifier(n2)->get_decl_sort(i));
}
num = to_quantifier(n1)->get_num_patterns();
for (unsigned i = 0; i < num; i++) {
check_ast(to_quantifier(n1)->get_pattern(i), to_quantifier(n2)->get_pattern(i));
}
num = to_quantifier(n1)->get_num_no_patterns();
for (unsigned i = 0; i < num; i++) {
check_ast(to_quantifier(n1)->get_no_pattern(i), to_quantifier(n2)->get_no_pattern(i));
}
n1 = to_quantifier(n1)->get_expr();
n2 = to_quantifier(n2)->get_expr();
goto start;
case AST_VAR:
check_value(to_var(n1)->get_idx(), to_var(n2)->get_idx());
n1 = to_var(n1)->get_sort();
n2 = to_var(n2)->get_sort();
goto start;
default:
UNREACHABLE();
return false;
}
}
bool lex_lt(unsigned num, ast * const * n1, ast * const * n2) {
for (unsigned i = 0; i < num; i ++) {
if (n1[i] == n2[i])
continue;
return lt(n1[i], n2[i]);
}
return false;
}

View file

@ -1,35 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
ast_lt.h
Abstract:
Total order on ASTs that does not depend on the internal ids.
Author:
Leonardo de Moura (leonardo) 2011-04-08
Revision History:
--*/
#ifndef _AST_LT_H_
#define _AST_LT_H_
class ast;
bool lt(ast * n1, ast * n2);
struct ast_to_lt {
bool operator()(ast * n1, ast * n2) const { return lt(n1, n2); }
};
bool lex_lt(unsigned num, ast * const * n1, ast * const * n2);
inline bool lex_lt(unsigned num, expr * const * n1, expr * const * n2) {
return lex_lt(num, reinterpret_cast<ast*const*>(n1), reinterpret_cast<ast*const*>(n2));
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,103 +0,0 @@
/*++
Copyright (c) 2008 Microsoft Corporation
Module Name:
ast_smt_pp.h
Abstract:
Pretty printer of AST formulas as SMT benchmarks.
Author:
Nikolaj Bjorner 2008-04-09.
Revision History:
--*/
#ifndef _AST_SMT_PP_H_
#define _AST_SMT_PP_H_
#include"ast.h"
#include<string>
#include"map.h"
class smt_renaming {
typedef map<symbol, symbol, symbol_hash_proc, symbol_eq_proc> symbol2symbol;
symbol2symbol m_translate;
symbol2symbol m_rev_translate;
symbol fix_symbol(symbol s, int k);
bool is_legal(char c);
bool is_special(char const* s);
bool is_numerical(char const* s);
bool all_is_legal(char const* s);
public:
smt_renaming();
symbol get_symbol(symbol s0);
symbol operator()(symbol const & s) { return get_symbol(s); }
};
class ast_smt_pp {
public:
class is_declared {
public:
virtual bool operator()(func_decl* d) const { return false; }
virtual bool operator()(sort* s) const { return false; }
};
private:
ast_manager& m_manager;
expr_ref_vector m_assumptions;
expr_ref_vector m_assumptions_star;
symbol m_benchmark_name;
symbol m_source_info;
symbol m_status;
symbol m_category;
symbol m_logic;
std::string m_attributes;
family_id m_dt_fid;
is_declared m_is_declared_default;
is_declared* m_is_declared;
bool m_simplify_implies;
public:
ast_smt_pp(ast_manager& m);
void set_benchmark_name(const char* bn) { if (bn) m_benchmark_name = bn; }
void set_source_info(const char* si) { if (si) m_source_info = si; }
void set_status(const char* s) { if (s) m_status = s; }
void set_category(const char* c) { if (c) m_category = c; }
void set_logic(const char* l) { if (l) m_logic = l; }
void add_attributes(const char* s) { if (s) m_attributes += s; }
void add_assumption(expr* n) { m_assumptions.push_back(n); }
void add_assumption_star(expr* n) { m_assumptions_star.push_back(n); }
void set_simplify_implies(bool f) { m_simplify_implies = f; }
void set_is_declared(is_declared* id) { m_is_declared = id; }
void display(std::ostream& strm, expr* n);
void display_smt2(std::ostream& strm, expr* n);
void display_expr(std::ostream& strm, expr* n);
void display_expr_smt2(std::ostream& strm, expr* n, unsigned indent = 0, unsigned num_var_names = 0, char const* const* var_names = 0);
};
struct mk_smt_pp {
expr * m_expr;
ast_manager& m_manager;
unsigned m_indent;
unsigned m_num_var_names;
char const* const* m_var_names;
mk_smt_pp(expr* e, ast_manager & m, unsigned indent = 0, unsigned num_var_names = 0, char const* const* var_names = 0) :
m_expr(e), m_manager(m), m_indent(indent), m_num_var_names(num_var_names), m_var_names(var_names) {}
};
inline std::ostream& operator<<(std::ostream& out, const mk_smt_pp & p) {
ast_smt_pp pp(p.m_manager);
pp.display_expr_smt2(out, p.m_expr, p.m_indent, p.m_num_var_names, p.m_var_names);
return out;
}
#endif

View file

@ -1,331 +0,0 @@
/*++
Copyright (c) 2008 Microsoft Corporation
Module Name:
ast_translation.cpp
Abstract:
AST translation functions
Author:
Christoph Wintersteiger (t-cwinte) 2008-11-20
Revision History:
--*/
#include "arith_decl_plugin.h"
#include "bv_decl_plugin.h"
#include "datatype_decl_plugin.h"
#include "array_decl_plugin.h"
#include "format.h"
#include "ast_translation.h"
#include "ast_ll_pp.h"
ast_translation::~ast_translation() {
reset_cache();
}
void ast_translation::cleanup() {
reset_cache();
m_cache.finalize();
m_result_stack.finalize();
m_frame_stack.finalize();
m_extra_children_stack.finalize();
}
void ast_translation::reset_cache() {
obj_map<ast, ast*>::iterator it = m_cache.begin();
obj_map<ast, ast*>::iterator end = m_cache.end();
for (; it != end; ++it) {
m_from_manager.dec_ref(it->m_key);
m_to_manager.dec_ref(it->m_value);
}
m_cache.reset();
}
void ast_translation::cache(ast * s, ast * t) {
SASSERT(!m_cache.contains(s));
if (s->get_ref_count() > 1) {
m_cache.insert(s, t);
m_from_manager.inc_ref(s);
m_to_manager.inc_ref(t);
}
}
void ast_translation::collect_decl_extra_children(decl * d) {
unsigned num_params = d->get_num_parameters();
for (unsigned i = 0; i < num_params; i++) {
parameter const & p = d->get_parameter(i);
if (p.is_ast())
m_extra_children_stack.push_back(p.get_ast());
}
}
void ast_translation::push_frame(ast * n) {
m_frame_stack.push_back(frame(n, 0, m_extra_children_stack.size(), m_result_stack.size()));
switch (n->get_kind()) {
case AST_SORT:
case AST_FUNC_DECL:
collect_decl_extra_children(to_decl(n));
break;
default:
break;
}
}
bool ast_translation::visit(ast * n) {
ast * r;
if (n->get_ref_count() > 1 && m_cache.find(n, r)) {
m_result_stack.push_back(r);
return true;
}
push_frame(n);
return false;
}
void ast_translation::copy_params(decl * d, unsigned rpos, buffer<parameter> & ps) {
unsigned num = d->get_num_parameters();
unsigned j = rpos;
for (unsigned i = 0; i < num; i++) {
parameter const & p = d->get_parameter(i);
if (p.is_ast()) {
ps.push_back(parameter(m_result_stack[j]));
j++;
}
else if (p.is_external()) {
SASSERT(d->get_family_id() != null_family_id);
decl_plugin & from_plugin = *(m_from_manager.get_plugin(d->get_family_id()));
decl_plugin & to_plugin = *(m_to_manager.get_plugin(d->get_family_id()));
ps.push_back(from_plugin.translate(p, to_plugin));
}
else {
ps.push_back(p);
}
}
}
void ast_translation::mk_sort(sort * s, frame & fr) {
sort_info * si = s->get_info();
sort * new_s;
if (si == 0) {
new_s = m_to_manager.mk_sort(s->get_name());
SASSERT(m_result_stack.size() == fr.m_rpos);
}
else {
buffer<parameter> ps;
copy_params(s, fr.m_rpos, ps);
new_s = m_to_manager.mk_sort(s->get_name(), sort_info(si->get_family_id(),
si->get_decl_kind(),
si->get_num_elements(),
si->get_num_parameters(),
ps.c_ptr(),
s->private_parameters()));
}
m_result_stack.shrink(fr.m_rpos);
m_result_stack.push_back(new_s);
m_extra_children_stack.shrink(fr.m_cpos);
cache(s, new_s);
m_frame_stack.pop_back();
}
void ast_translation::mk_func_decl(func_decl * f, frame & fr) {
func_decl_info * fi = f->get_info();
SASSERT(fr.m_cpos <= m_extra_children_stack.size());
unsigned num_extra = m_extra_children_stack.size() - fr.m_cpos;
sort ** new_domain = reinterpret_cast<sort**>(m_result_stack.c_ptr() + fr.m_rpos + num_extra);
sort * new_range = static_cast<sort*>(m_result_stack.back());
func_decl * new_f;
if (fi == 0) {
new_f = m_to_manager.mk_func_decl(f->get_name(),
f->get_arity(),
new_domain,
new_range);
}
else {
buffer<parameter> ps;
copy_params(f, fr.m_rpos, ps);
func_decl_info new_fi(fi->get_family_id(),
fi->get_decl_kind(),
fi->get_num_parameters(),
ps.c_ptr());
new_fi.set_left_associative(fi->is_left_associative());
new_fi.set_right_associative(fi->is_right_associative());
new_fi.set_flat_associative(fi->is_flat_associative());
new_fi.set_commutative(fi->is_commutative());
new_fi.set_chainable(fi->is_chainable());
new_fi.set_pairwise(fi->is_pairwise());
new_fi.set_injective(fi->is_injective());
new_fi.set_skolem(fi->is_skolem());
new_fi.set_idempotent(fi->is_idempotent());
new_f = m_to_manager.mk_func_decl(f->get_name(),
f->get_arity(),
new_domain,
new_range,
new_fi);
}
TRACE("ast_translation",
tout << f->get_name() << " "; if (fi) tout << *fi; tout << "\n";
tout << "---->\n";
tout << new_f->get_name() << " "; if (new_f->get_info()) tout << *(new_f->get_info()); tout << "\n";);
m_result_stack.shrink(fr.m_rpos);
m_result_stack.push_back(new_f);
m_extra_children_stack.shrink(fr.m_cpos);
cache(f, new_f);
m_frame_stack.pop_back();
}
ast * ast_translation::process(ast const * _n) {
SASSERT(m_result_stack.empty());
SASSERT(m_frame_stack.empty());
SASSERT(m_extra_children_stack.empty());
if (!visit(const_cast<ast*>(_n))) {
while (!m_frame_stack.empty()) {
loop:
frame & fr = m_frame_stack.back();
ast * n = fr.m_n;
ast * r;
TRACE("ast_translation", tout << mk_ll_pp(n, m_from_manager, false) << "\n";);
if (fr.m_idx == 0 && n->get_ref_count() > 1 && m_cache.find(n, r)) {
SASSERT(m_result_stack.size() == fr.m_rpos);
m_result_stack.push_back(r);
m_extra_children_stack.shrink(fr.m_cpos);
m_frame_stack.pop_back();
TRACE("ast_translation", tout << "hit\n";);
continue;
}
switch (n->get_kind()) {
case AST_VAR: {
if (fr.m_idx == 0) {
fr.m_idx = 1;
if (!visit(to_var(n)->get_sort()))
goto loop;
}
sort * new_s = to_sort(m_result_stack.back());
var * new_var = m_to_manager.mk_var(to_var(n)->get_idx(), new_s);
m_result_stack.pop_back();
m_result_stack.push_back(new_var);
cache(n, new_var);
m_frame_stack.pop_back();
break;
}
case AST_APP: {
if (fr.m_idx == 0) {
fr.m_idx = 1;
if (!visit(to_app(n)->get_decl()))
goto loop;
}
unsigned num = to_app(n)->get_num_args();
while (fr.m_idx <= num) {
expr * arg = to_app(n)->get_arg(fr.m_idx - 1);
fr.m_idx++;
if (!visit(arg))
goto loop;
}
func_decl * new_f = to_func_decl(m_result_stack[fr.m_rpos]);
expr ** new_args = reinterpret_cast<expr **>(m_result_stack.c_ptr() + fr.m_rpos + 1);
expr * new_app = m_to_manager.mk_app(new_f, num, new_args);
m_result_stack.shrink(fr.m_rpos);
m_result_stack.push_back(new_app);
cache(n, new_app);
m_frame_stack.pop_back();
break;
}
case AST_QUANTIFIER: {
unsigned num_decls = to_quantifier(n)->get_num_decls();
unsigned num = num_decls + to_quantifier(n)->get_num_children();
while (fr.m_idx < num) {
ast * child;
if (fr.m_idx < num_decls)
child = to_quantifier(n)->get_decl_sort(fr.m_idx);
else
child = to_quantifier(n)->get_child(fr.m_idx - num_decls);
fr.m_idx++;
if (!visit(child))
goto loop;
}
symbol const * dnames = to_quantifier(n)->get_decl_names();
sort ** dsorts = reinterpret_cast<sort**>(m_result_stack.c_ptr() + fr.m_rpos);
expr * body = static_cast<expr*>(m_result_stack[fr.m_rpos + num_decls]);
unsigned num_pats = to_quantifier(n)->get_num_patterns();
expr ** pats = reinterpret_cast<expr**>(m_result_stack.c_ptr() + fr.m_rpos + num_decls + 1);
unsigned num_no_pats = to_quantifier(n)->get_num_no_patterns();
expr ** no_pats = pats + num_pats;
quantifier * new_q = m_to_manager.mk_quantifier(to_quantifier(n)->is_forall(),
num_decls,
dsorts,
dnames,
body,
to_quantifier(n)->get_weight(),
to_quantifier(n)->get_qid(),
to_quantifier(n)->get_skid(),
num_pats, pats,
num_no_pats, no_pats);
m_result_stack.shrink(fr.m_rpos);
m_result_stack.push_back(new_q);
cache(n, new_q);
m_frame_stack.pop_back();
break;
}
case AST_SORT: {
SASSERT(fr.m_cpos <= m_extra_children_stack.size());
unsigned num = m_extra_children_stack.size() - fr.m_cpos;
while (fr.m_idx < num) {
ast * c = m_extra_children_stack[fr.m_cpos + fr.m_idx];
fr.m_idx++;
if (!visit(c))
goto loop;
}
mk_sort(to_sort(n), fr);
break;
}
case AST_FUNC_DECL: {
SASSERT(fr.m_cpos <= m_extra_children_stack.size());
unsigned num_extra = m_extra_children_stack.size() - fr.m_cpos;
unsigned arity = to_func_decl(n)->get_arity();
unsigned num = num_extra + arity + 1;
while (fr.m_idx < num) {
ast * c;
if (fr.m_idx < num_extra)
c = m_extra_children_stack[fr.m_cpos + fr.m_idx];
else if (fr.m_idx < num_extra + arity)
c = to_func_decl(n)->get_domain(fr.m_idx - num_extra);
else
c = to_func_decl(n)->get_range();
fr.m_idx++;
if (!visit(c))
goto loop;
}
mk_func_decl(to_func_decl(n), fr);
break;
}
default:
UNREACHABLE();
break;
}
}
}
SASSERT(m_result_stack.size() == 1);
ast * r = m_result_stack.back();
m_result_stack.reset();
return r;
}
expr_dependency * expr_dependency_translation::operator()(expr_dependency * d) {
if (d == 0)
return d;
m_buffer.reset();
m_translation.from().linearize(d, m_buffer);
unsigned sz = m_buffer.size();
SASSERT(sz >= 1);
for (unsigned i = 0; i < sz; i++) {
m_buffer[i] = m_translation(m_buffer[i]);
}
return m_translation.to().mk_join(sz, m_buffer.c_ptr());
}

View file

@ -1,97 +0,0 @@
/*++
Copyright (c) 2008 Microsoft Corporation
Module Name:
ast_translation.h
Abstract:
AST translation functions
Author:
Christoph Wintersteiger (t-cwinte) 2008-11-20
Revision History:
2011-05-26: New local translation class.
--*/
#ifndef _AST_TRANSLATION_H_
#define _AST_TRANSLATION_H_
#include"ast.h"
class ast_translation {
struct frame {
ast * m_n;
unsigned m_idx;
unsigned m_cpos;
unsigned m_rpos;
frame(ast * n, unsigned idx, unsigned cpos, unsigned rpos):m_n(n), m_idx(idx), m_cpos(cpos), m_rpos(rpos) {}
};
ast_manager & m_from_manager;
ast_manager & m_to_manager;
svector<frame> m_frame_stack;
ptr_vector<ast> m_extra_children_stack; // for sort and func_decl, since they have nested AST in their parameters
ptr_vector<ast> m_result_stack;
obj_map<ast, ast*> m_cache;
void cache(ast * s, ast * t);
void collect_decl_extra_children(decl * d);
void push_frame(ast * n);
bool visit(ast * n);
void copy_params(decl * d, unsigned rpos, buffer<parameter> & ps);
void mk_sort(sort * s, frame & fr);
void mk_func_decl(func_decl * f, frame & fr);
ast * process(ast const * n);
public:
ast_translation(ast_manager & from, ast_manager & to, bool copy_plugins = true) : m_from_manager(from), m_to_manager(to) {
if (copy_plugins)
m_to_manager.copy_families_plugins(m_from_manager);
}
~ast_translation();
template<typename T>
T * operator()(T const * n) {
SASSERT(from().contains(const_cast<T*>(n)));
ast * r = process(n);
SASSERT(to().contains(const_cast<ast*>(r)));
return static_cast<T*>(r);
}
ast_manager & from() const { return m_from_manager; }
ast_manager & to() const { return m_to_manager; }
void reset_cache();
void cleanup();
};
// Translation with non-persistent cache.
inline ast * translate(ast const * a, ast_manager & from, ast_manager & to) {
return ast_translation(from, to)(a);
}
inline expr * translate(expr const * e, ast_manager & from, ast_manager & to) {
return ast_translation(from, to)(e);
}
class expr_dependency_translation {
ast_translation & m_translation;
ptr_vector<expr> m_buffer;
public:
expr_dependency_translation(ast_translation & t):m_translation(t) {}
expr_dependency * operator()(expr_dependency * d);
};
inline expr_dependency * translate(expr_dependency * d, ast_manager & from, ast_manager & to) {
ast_translation t(from, to);
expr_dependency_translation td(t);
return td(d);
}
#endif

View file

@ -1,989 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
bool_rewriter.h
Abstract:
Basic rewrites for Boolean operators.
Author:
Leonardo (leonardo) 2011-04-04
Notes:
--*/
#include"bool_rewriter.h"
#include"rewriter_def.h"
void bool_rewriter::updt_params(params_ref const & p) {
m_flat = p.get_bool(":flat", true);
m_elim_and = p.get_bool(":elim-and", false);
m_local_ctx = p.get_bool(":local-ctx", false);
m_local_ctx_limit = p.get_uint(":local-ctx-limit", UINT_MAX);
m_blast_distinct = p.get_bool(":blast-distinct", false);
m_ite_extra_rules = p.get_bool(":ite-extra-rules", false);
}
void bool_rewriter::get_param_descrs(param_descrs & r) {
r.insert(":ite-extra-rules", CPK_BOOL, "(default: false) extra ite simplifications, these additional simplifications may reduce size locally but increase globally.");
r.insert(":flat", CPK_BOOL, "(default: true) create nary applications for and,or,+,*,bvadd,bvmul,bvand,bvor,bvxor.");
r.insert(":elim-and", CPK_BOOL, "(default: false) conjunctions are rewritten using negation and disjunctions.");
r.insert(":local-ctx", CPK_BOOL, "(default: false) perform local (i.e., cheap) context simplifications.");
r.insert(":local-ctx-limit", CPK_UINT, "(default: inf) limit for applying local context simplifier.");
r.insert(":blast-distinct", CPK_BOOL, "(default: false) expand a distinct predicate into a quadratic number of disequalities.");
}
br_status bool_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(f->get_family_id() == m().get_basic_family_id());
switch (f->get_decl_kind()) {
case OP_EQ:
case OP_IFF:
SASSERT(num_args == 2);
return mk_eq_core(args[0], args[1], result);
case OP_DISTINCT:
return mk_distinct_core(num_args, args, result);
case OP_AND:
return mk_and_core(num_args, args, result);
case OP_OR:
return mk_or_core(num_args, args, result);
case OP_NOT:
SASSERT(num_args == 1);
return mk_not_core(args[0], result);
case OP_ITE:
SASSERT(num_args == 3);
return mk_ite_core(args[0], args[1], args[2], result);
case OP_IMPLIES:
SASSERT(num_args == 2);
mk_implies(args[0], args[1], result);
return BR_DONE;
case OP_XOR:
SASSERT(num_args == 2);
mk_xor(args[0], args[1], result);
return BR_DONE;
default:
return BR_FAILED;
}
}
void bool_rewriter::mk_and_as_or(unsigned num_args, expr * const * args, expr_ref & result) {
expr_ref_buffer new_args(m());
for (unsigned i = 0; i < num_args; i++) {
expr_ref tmp(m());
mk_not(args[i], tmp);
new_args.push_back(tmp);
}
expr_ref tmp(m());
mk_or(new_args.size(), new_args.c_ptr(), tmp);
mk_not(tmp, result);
}
br_status bool_rewriter::mk_nflat_and_core(unsigned num_args, expr * const * args, expr_ref & result) {
bool s = false;
ptr_buffer<expr> buffer;
expr_fast_mark1 neg_lits;
expr_fast_mark2 pos_lits;
for (unsigned i = 0; i < num_args; i++) {
expr * arg = args[i];
if (m().is_true(arg)) {
s = true;
continue;
}
if (m().is_false(arg)) {
result = m().mk_false();
return BR_DONE;
}
if (m().is_not(arg)) {
expr * atom = to_app(arg)->get_arg(0);
if (neg_lits.is_marked(atom)) {
s = true;
continue;
}
if (pos_lits.is_marked(atom)) {
result = m().mk_false();
return BR_DONE;
}
neg_lits.mark(atom);
}
else {
if (pos_lits.is_marked(arg)) {
s = true;
continue;
}
if (neg_lits.is_marked(arg)) {
result = m().mk_false();
return BR_DONE;
}
pos_lits.mark(arg);
}
buffer.push_back(arg);
}
unsigned sz = buffer.size();
switch(sz) {
case 0:
result = m().mk_true();
return BR_DONE;
case 1:
result = buffer.back();
return BR_DONE;
default:
if (s) {
result = m().mk_and(sz, buffer.c_ptr());
return BR_DONE;
}
return BR_FAILED;
}
}
br_status bool_rewriter::mk_flat_and_core(unsigned num_args, expr * const * args, expr_ref & result) {
unsigned i;
for (i = 0; i < num_args; i++) {
if (m().is_and(args[i]))
break;
}
if (i < num_args) {
// has nested ANDs
ptr_buffer<expr> flat_args;
flat_args.append(i, args);
for (; i < num_args; i++) {
expr * arg = args[i];
// Remark: all rewrites are depth 1.
if (m().is_and(arg)) {
unsigned num = to_app(arg)->get_num_args();
for (unsigned j = 0; j < num; j++)
flat_args.push_back(to_app(arg)->get_arg(j));
}
else {
flat_args.push_back(arg);
}
}
if (mk_nflat_and_core(flat_args.size(), flat_args.c_ptr(), result) == BR_FAILED)
result = m().mk_and(flat_args.size(), flat_args.c_ptr());
return BR_DONE;
}
return mk_nflat_and_core(num_args, args, result);
}
br_status bool_rewriter::mk_nflat_or_core(unsigned num_args, expr * const * args, expr_ref & result) {
bool s = false;
ptr_buffer<expr> buffer;
expr_fast_mark1 neg_lits;
expr_fast_mark2 pos_lits;
for (unsigned i = 0; i < num_args; i++) {
expr * arg = args[i];
if (m().is_true(arg)) {
result = m().mk_true();
return BR_DONE;
}
if (m().is_false(arg)) {
s = true;
continue;
}
if (m().is_not(arg)) {
expr * atom = to_app(arg)->get_arg(0);
if (neg_lits.is_marked(atom)) {
s = true;
continue;
}
if (pos_lits.is_marked(atom)) {
result = m().mk_true();
return BR_DONE;
}
neg_lits.mark(atom);
}
else {
if (pos_lits.is_marked(arg)) {
s = true;
continue;
}
if (neg_lits.is_marked(arg)) {
result = m().mk_true();
return BR_DONE;
}
pos_lits.mark(arg);
}
buffer.push_back(arg);
}
unsigned sz = buffer.size();
switch(sz) {
case 0:
result = m().mk_false();
return BR_DONE;
case 1:
result = buffer.back();
return BR_DONE;
default:
if (m_local_ctx && m_local_ctx_cost <= m_local_ctx_limit) {
neg_lits.reset();
pos_lits.reset();
if (local_ctx_simp(sz, buffer.c_ptr(), result))
return BR_DONE;
}
if (s) {
result = m().mk_or(sz, buffer.c_ptr());
return BR_DONE;
}
return BR_FAILED;
}
}
br_status bool_rewriter::mk_flat_or_core(unsigned num_args, expr * const * args, expr_ref & result) {
unsigned i;
for (i = 0; i < num_args; i++) {
if (m().is_or(args[i]))
break;
}
if (i < num_args) {
// has nested ORs
ptr_buffer<expr> flat_args;
flat_args.append(i, args);
for (; i < num_args; i++) {
expr * arg = args[i];
// Remark: all rewrites are depth 1.
if (m().is_or(arg)) {
unsigned num = to_app(arg)->get_num_args();
for (unsigned j = 0; j < num; j++)
flat_args.push_back(to_app(arg)->get_arg(j));
}
else {
flat_args.push_back(arg);
}
}
if (mk_nflat_or_core(flat_args.size(), flat_args.c_ptr(), result) == BR_FAILED)
result = m().mk_or(flat_args.size(), flat_args.c_ptr());
return BR_DONE;
}
return mk_nflat_or_core(num_args, args, result);
}
expr * bool_rewriter::mk_or_app(unsigned num_args, expr * const * args) {
switch(num_args) {
case 0: return m().mk_false();
case 1: return args[0];
default: return m().mk_or(num_args, args);
}
}
/**
\brief Auxiliary method for local_ctx_simp.
Replace args[i] by true if marked in neg_lits.
Replace args[i] by false if marked in pos_lits.
*/
bool bool_rewriter::simp_nested_not_or(unsigned num_args, expr * const * args,
expr_fast_mark1 & neg_lits, expr_fast_mark2 & pos_lits, expr_ref & result) {
ptr_buffer<expr> new_args;
bool simp = false;
m_local_ctx_cost += num_args;
for (unsigned i = 0; i < num_args; i++) {
expr * arg = args[i];
if (neg_lits.is_marked(arg)) {
result = m().mk_false();
return true;
}
if (pos_lits.is_marked(arg)) {
simp = true;
continue;
}
if (m().is_not(arg)) {
expr * atom = to_app(arg)->get_arg(0);
if (neg_lits.is_marked(atom)) {
simp = true;
continue;
}
if (pos_lits.is_marked(atom)) {
result = m().mk_false();
return true;
}
}
new_args.push_back(arg);
}
if (simp) {
switch(new_args.size()) {
case 0:
result = m().mk_true();
return true;
case 1:
mk_not(new_args[0], result);
return true;
default:
result = m().mk_not(m().mk_or(new_args.size(), new_args.c_ptr()));
return true;
}
}
return false;
}
expr * bool_rewriter::simp_arg(expr * arg, expr_fast_mark1 & neg_lits, expr_fast_mark2 & pos_lits, bool & modified) {
if (m().is_not(arg)) {
expr * atom = to_app(arg)->get_arg(0);
if (neg_lits.is_marked(atom)) {
modified = true;
return m().mk_false();
}
if (pos_lits.is_marked(atom)) {
modified = true;
return m().mk_true();
}
return arg;
}
else {
if (neg_lits.is_marked(arg)) {
modified = true;
return m().mk_true();
}
if (pos_lits.is_marked(arg)) {
modified = true;
return m().mk_false();
}
return arg;
}
}
/**
\brief Simpler version of mk_ite, that will not invoke mk_or/mk_and.
It is used byt local_ctx_simp to prevent a recursive call to local_ctx_simp.
See comment at simp_nested_eq_ite.
*/
void bool_rewriter::mk_nested_ite(expr * c, expr * t, expr * e, expr_ref & result) {
if (m().is_true(c)) {
result = t;
return;
}
if (m().is_false(c)) {
result = e;
return;
}
if (t == e) {
result = t;
return;
}
if (m().is_bool(t)) {
if (m().is_true(t)) {
if (m().is_false(e)) {
result = c;
return;
}
result = m().mk_or(c, e);
return;
}
if (m().is_false(t)) {
if (m().is_true(e)) {
mk_not(c, result);
return;
}
expr_ref tmp(m());
mk_not(e, tmp);
result = m().mk_not(m().mk_or(c, tmp));
return;
}
if (m().is_true(e)) {
expr_ref tmp(m());
mk_not(c, tmp);
result = m().mk_or(tmp, t);
return;
}
if (m().is_false(e) || c == e) {
expr_ref tmp1(m());
expr_ref tmp2(m());
mk_not(c, tmp1);
mk_not(t, tmp2);
result = m().mk_not(m().mk_or(tmp1, tmp2));
return;
}
if (c == t) {
result = m().mk_or(c, e);
return;
}
if (m().is_complement_core(t, e)) { // t = not(e)
mk_eq(c, t, result);
return;
}
if (m().is_complement_core(e, t)) { // e = not(t)
mk_eq(c, t, result);
return;
}
}
result = m().mk_ite(c, t, e);
}
bool bool_rewriter::simp_nested_eq_ite(expr * t, expr_fast_mark1 & neg_lits, expr_fast_mark2 & pos_lits, expr_ref & result) {
bool neg = false;
m_local_ctx_cost += 3;
if (m().is_not(t)) {
neg = true;
t = to_app(t)->get_arg(0);
}
if (m().is_iff(t) || m().is_eq(t)) {
bool modified = false;
expr * new_lhs = simp_arg(to_app(t)->get_arg(0), neg_lits, pos_lits, modified);
expr * new_rhs = simp_arg(to_app(t)->get_arg(1), neg_lits, pos_lits, modified);
if (!modified)
return false;
mk_eq(new_lhs, new_rhs, result);
if (neg)
mk_not(result, result);
return true;
}
if (m().is_ite(t)) {
bool modified = false;
expr * new_c = simp_arg(to_app(t)->get_arg(0), neg_lits, pos_lits, modified);
expr * new_t = simp_arg(to_app(t)->get_arg(1), neg_lits, pos_lits, modified);
expr * new_e = simp_arg(to_app(t)->get_arg(2), neg_lits, pos_lits, modified);
if (!modified)
return false;
// It is not safe to invoke mk_ite here, since it can recursively call
// local_ctx_simp by
// - transforming the ITE into an OR
// - and invoked mk_or, that will invoke local_ctx_simp
// mk_ite(new_c, new_t, new_e, result);
mk_nested_ite(new_c, new_t, new_e, result);
if (neg)
mk_not(result, result);
return true;
}
return false;
}
/**
\brief Apply local context simplification at (OR args[0] ... args[num_args-1])
Basic idea:
- Replace args[i] by false in the other arguments
- If args[i] is of the form (not t), then replace t by true in the other arguments.
To make sure the simplification is efficient we bound the depth.
*/
bool bool_rewriter::local_ctx_simp(unsigned num_args, expr * const * args, expr_ref & result) {
expr_ref_vector old_args(m());
expr_ref_vector new_args(m());
expr_ref new_arg(m());
expr_fast_mark1 neg_lits;
expr_fast_mark2 pos_lits;
bool simp = false;
bool modified = false;
bool forward = true;
unsigned rounds = 0;
while (true) {
rounds++;
#if 0
if (rounds > 10)
verbose_stream() << "rounds: " << rounds << "\n";
#endif
#define PUSH_NEW_ARG(ARG) { \
new_args.push_back(ARG); \
if (m().is_not(ARG)) \
neg_lits.mark(to_app(ARG)->get_arg(0)); \
else \
pos_lits.mark(ARG); \
}
#define PROCESS_ARG() \
{ \
expr * arg = args[i]; \
if (m().is_not(arg) && m().is_or(to_app(arg)->get_arg(0)) && \
simp_nested_not_or(to_app(to_app(arg)->get_arg(0))->get_num_args(), \
to_app(to_app(arg)->get_arg(0))->get_args(), \
neg_lits, \
pos_lits, \
new_arg)) { \
modified = true; simp = true; \
arg = new_arg; \
} \
if (simp_nested_eq_ite(arg, neg_lits, pos_lits, new_arg)) { \
modified = true; simp = true; \
arg = new_arg; \
} \
if (m().is_false(arg)) \
continue; \
if (m().is_true(arg)) { \
result = arg; \
return true; \
} \
if (m_flat && m().is_or(arg)) { \
unsigned sz = to_app(arg)->get_num_args(); \
for (unsigned j = 0; j < sz; j++) { \
expr * arg_arg = to_app(arg)->get_arg(j); \
PUSH_NEW_ARG(arg_arg); \
} \
} \
else { \
PUSH_NEW_ARG(arg); \
} \
}
m_local_ctx_cost += 2*num_args;
#if 0
static unsigned counter = 0;
counter++;
if (counter % 10000 == 0)
verbose_stream() << "local-ctx-cost: " << m_local_ctx_cost << "\n";
#endif
if (forward) {
for (unsigned i = 0; i < num_args; i++) {
PROCESS_ARG();
}
forward = false;
}
else {
unsigned i = num_args;
while (i > 0) {
--i;
PROCESS_ARG();
}
if (!modified) {
if (simp) {
result = mk_or_app(num_args, args);
return true;
}
return false; // didn't simplify
}
// preserve the original order...
std::reverse(new_args.c_ptr(), new_args.c_ptr() + new_args.size());
modified = false;
forward = true;
}
pos_lits.reset();
neg_lits.reset();
old_args.reset();
old_args.swap(new_args);
SASSERT(new_args.empty());
args = old_args.c_ptr();
num_args = old_args.size();
}
}
/**
\brief Apply simplification if ite is an if-then-else tree where every leaf is a value.
This is an efficient way to
*/
br_status bool_rewriter::try_ite_value(app * ite, app * val, expr_ref & result) {
SASSERT(m().is_ite(ite));
SASSERT(m().is_value(val));
expr * t = ite->get_arg(1);
expr * e = ite->get_arg(2);
if (!m().is_value(t) || !m().is_value(e))
return BR_FAILED;
if (t != val && e != val) {
TRACE("try_ite_value", tout << mk_ismt2_pp(t, m()) << " " << mk_ismt2_pp(e, m()) << " " << mk_ismt2_pp(val, m()) << "\n";
tout << t << " " << e << " " << val << "\n";);
result = m().mk_false();
return BR_DONE;
}
if (t == val && e == val) {
result = m().mk_true();
return BR_DONE;
}
if (t == val) {
result = ite->get_arg(0);
return BR_DONE;
}
SASSERT(e == val);
mk_not(ite->get_arg(0), result);
return BR_DONE;
}
#if 0
// Return true if ite is an if-then-else tree where the leaves are values,
// and they are all different from val
static bool is_ite_value_tree_neq_value(ast_manager & m, app * ite, app * val) {
SASSERT(m.is_ite(ite));
SASSERT(m.is_value(val));
expr_fast_mark1 visited;
ptr_buffer<app> todo;
todo.push_back(ite);
#define VISIT(ARG) { \
if (m.is_value(ARG)) { \
if (ARG == val) \
return false; \
} \
else if (m.is_ite(ARG)) { \
if (!visited.is_marked(ARG)) { \
visited.mark(ARG); \
todo.push_back(to_app(ARG)); \
} \
} \
else { \
return false; \
} \
}
while (!todo.empty()) {
app * ite = todo.back();
todo.pop_back();
SASSERT(m.is_ite(ite));
expr * t = ite->get_arg(1);
expr * e = ite->get_arg(2);
VISIT(t);
VISIT(e);
}
return true;
}
#endif
br_status bool_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) {
if (lhs == rhs) {
result = m().mk_true();
return BR_DONE;
}
if (m().are_distinct(lhs, rhs)) {
result = m().mk_false();
return BR_DONE;
}
br_status r = BR_FAILED;
if (m().is_ite(lhs) && m().is_value(rhs)) {
// if (is_ite_value_tree_neq_value(m(), to_app(lhs), to_app(rhs))) {
// result = m().mk_false();
// return BR_DONE;
// }
r = try_ite_value(to_app(lhs), to_app(rhs), result);
CTRACE("try_ite_value", r != BR_FAILED,
tout << mk_ismt2_pp(lhs, m()) << "\n" << mk_ismt2_pp(rhs, m()) << "\n--->\n" << mk_ismt2_pp(result, m()) << "\n";);
}
else if (m().is_ite(rhs) && m().is_value(lhs)) {
// if (is_ite_value_tree_neq_value(m(), to_app(rhs), to_app(lhs))) {
// result = m().mk_false();
// return BR_DONE;
// }
r = try_ite_value(to_app(rhs), to_app(lhs), result);
CTRACE("try_ite_value", r != BR_FAILED,
tout << mk_ismt2_pp(lhs, m()) << "\n" << mk_ismt2_pp(rhs, m()) << "\n--->\n" << mk_ismt2_pp(result, m()) << "\n";);
}
if (r != BR_FAILED)
return r;
if (m().is_bool(lhs)) {
bool unfolded = false;
if (m().is_not(lhs) && m().is_not(rhs)) {
lhs = to_app(lhs)->get_arg(0);
rhs = to_app(rhs)->get_arg(0);
unfolded = true;
}
if (m().is_true(lhs)) {
result = rhs;
return BR_DONE;
}
if (m().is_false(lhs)) {
mk_not(rhs, result);
return BR_DONE;
}
if (m().is_true(rhs)) {
result = lhs;
return BR_DONE;
}
if (m().is_false(rhs)) {
mk_not(lhs, result);
return BR_DONE;
}
if (m().is_complement(lhs, rhs)) {
result = m().mk_false();
return BR_DONE;
}
if (unfolded) {
result = m().mk_eq(lhs, rhs);
return BR_DONE;
}
}
return BR_FAILED;
}
br_status bool_rewriter::mk_distinct_core(unsigned num_args, expr * const * args, expr_ref & result) {
if (num_args <= 1) {
result = m().mk_true();
return BR_DONE;
}
if (num_args == 2) {
expr_ref tmp(m());
result = m().mk_not(m().mk_eq(args[0], args[1]));
return BR_REWRITE2; // mk_eq may be dispatched to other rewriters.
}
expr_fast_mark1 visited;
bool all_value = true;
for (unsigned i = 0; i < num_args; i++) {
expr * arg = args[i];
if (visited.is_marked(arg)) {
result = m().mk_false();
return BR_DONE;
}
visited.mark(arg);
if (!m().is_value(arg))
all_value = false;
}
if (all_value) {
result = m().mk_true();
return BR_DONE;
}
SASSERT(num_args > 2);
if (m().is_bool(args[0])) {
result = m().mk_false();
return BR_DONE;
}
if (m_blast_distinct) {
ptr_buffer<expr> new_diseqs;
for (unsigned i = 0; i < num_args; i++) {
for (unsigned j = i + 1; j < num_args; j++)
new_diseqs.push_back(m().mk_not(m().mk_eq(args[i], args[j])));
}
result = m().mk_and(new_diseqs.size(), new_diseqs.c_ptr());
return BR_REWRITE3;
}
return BR_FAILED;
}
br_status bool_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & result) {
bool s = false;
// (ite (not c) a b) ==> (ite c b a)
if (m().is_not(c)) {
c = to_app(c)->get_arg(0);
std::swap(t, e);
s = true;
}
// (ite c (ite c t1 t2) t3) ==> (ite c t1 t3)
if (m().is_ite(t) && to_app(t)->get_arg(0) == c) {
// Remark: (ite c (ite (not c) t1 t2) t3) ==> (ite c t2 t3) does not happen if applying rewrites bottom up
t = to_app(t)->get_arg(1);
s = true;
}
// (ite c t1 (ite c t2 t3)) ==> (ite c t1 t3)
if (m().is_ite(e) && to_app(e)->get_arg(0) == c) {
// Remark: (ite c t1 (ite (not c) t2 t3)) ==> (ite c t1 t2) does not happen if applying rewrites bottom up
e = to_app(e)->get_arg(2);
s = true;
}
if (m().is_true(c)) {
result = t;
return BR_DONE;
}
if (m().is_false(c)) {
result = e;
return BR_DONE;
}
if (t == e) {
result = t;
return BR_DONE;
}
if (m().is_bool(t)) {
if (m().is_true(t)) {
if (m().is_false(e)) {
result = c;
return BR_DONE;
}
mk_or(c, e, result);
return BR_DONE;
}
if (m().is_false(t)) {
if (m().is_true(e)) {
mk_not(c, result);
return BR_DONE;
}
expr_ref tmp(m());
mk_not(c, tmp);
mk_and(tmp, e, result);
return BR_DONE;
}
if (m().is_true(e)) {
expr_ref tmp(m());
mk_not(c, tmp);
mk_or(tmp, t, result);
return BR_DONE;
}
if (m().is_false(e)) {
mk_and(c, t, result);
return BR_DONE;
}
if (c == e) {
mk_and(c, t, result);
return BR_DONE;
}
if (c == t) {
mk_or(c, e, result);
return BR_DONE;
}
if (m().is_complement_core(t, e)) { // t = not(e)
mk_eq(c, t, result);
return BR_DONE;
}
if (m().is_complement_core(e, t)) { // e = not(t)
mk_eq(c, t, result);
return BR_DONE;
}
}
if (m().is_ite(t) && m_ite_extra_rules) {
// (ite c1 (ite c2 t1 t2) t1) ==> (ite (and c1 (not c2)) t2 t1)
if (e == to_app(t)->get_arg(1)) {
expr_ref not_c2(m());
mk_not(to_app(t)->get_arg(0), not_c2);
expr_ref new_c(m());
mk_and(c, not_c2, new_c);
result = m().mk_ite(new_c, to_app(t)->get_arg(2), e);
return BR_REWRITE1;
}
// (ite c1 (ite c2 t1 t2) t2) ==> (ite (and c1 c2) t1 t2)
if (e == to_app(t)->get_arg(2)) {
expr_ref new_c(m());
mk_and(c, to_app(t)->get_arg(0), new_c);
result = m().mk_ite(new_c, to_app(t)->get_arg(1), e);
return BR_REWRITE1;
}
if (m().is_ite(e)) {
// (ite c1 (ite c2 t1 t2) (ite c3 t1 t2)) ==> (ite (or (and c1 c2) (and (not c1) c3)) t1 t2)
if (to_app(t)->get_arg(1) == to_app(e)->get_arg(1) &&
to_app(t)->get_arg(2) == to_app(e)->get_arg(2)) {
expr_ref and1(m());
expr_ref and2(m());
expr_ref notc(m());
mk_and(c, to_app(t)->get_arg(0), and1);
mk_not(c, notc);
mk_and(notc, to_app(e)->get_arg(0), and2);
expr_ref new_c(m());
mk_or(and1, and2, new_c);
result = m().mk_ite(new_c, to_app(t)->get_arg(1), to_app(t)->get_arg(2));
return BR_REWRITE1;
}
// (ite c1 (ite c2 t1 t2) (ite c3 t2 t1)) ==> (ite (or (and c1 c2) (and (not c1) (not c3))) t1 t2)
if (to_app(t)->get_arg(1) == to_app(e)->get_arg(2) &&
to_app(t)->get_arg(2) == to_app(e)->get_arg(1)) {
expr_ref and1(m());
expr_ref and2(m());
expr_ref notc(m());
mk_and(c, to_app(t)->get_arg(0), and1);
mk_not(c, notc);
expr_ref notc3(m());
mk_not(to_app(e)->get_arg(0), notc3);
mk_and(notc, notc3, and2);
expr_ref new_c(m());
mk_or(and1, and2, new_c);
result = m().mk_ite(new_c, to_app(t)->get_arg(1), to_app(t)->get_arg(2));
return BR_REWRITE1;
}
}
}
if (m().is_ite(e) && m_ite_extra_rules) {
// (ite c1 t1 (ite c2 t1 t2)) ==> (ite (or c1 c2) t1 t2)
if (t == to_app(e)->get_arg(1)) {
expr_ref new_c(m());
mk_or(c, to_app(e)->get_arg(0), new_c);
result = m().mk_ite(new_c, t, to_app(e)->get_arg(2));
return BR_REWRITE1;
}
// (ite c1 t1 (ite c2 t2 t1)) ==> (ite (or c1 (not c2)) t1 t2)
if (t == to_app(e)->get_arg(2)) {
expr_ref not_c2(m());
mk_not(to_app(e)->get_arg(0), not_c2);
expr_ref new_c(m());
mk_or(c, not_c2, new_c);
result = m().mk_ite(new_c, t, to_app(e)->get_arg(1));
return BR_REWRITE1;
}
}
if (s) {
result = m().mk_ite(c, t, e);
return BR_DONE;
}
return BR_FAILED;
}
br_status bool_rewriter::mk_not_core(expr * t, expr_ref & result) {
if (m().is_not(t)) {
result = to_app(t)->get_arg(0);
return BR_DONE;
}
if (m().is_true(t)) {
result = m().mk_false();
return BR_DONE;
}
if (m().is_false(t)) {
result = m().mk_true();
return BR_DONE;
}
if (is_eq(t) && m().is_bool(to_app(t)->get_arg(0))) {
expr_ref tmp(m());
mk_not(to_app(t)->get_arg(0), tmp);
mk_eq(tmp, to_app(t)->get_arg(1), result);
return BR_DONE;
}
return BR_FAILED;
}
void bool_rewriter::mk_xor(expr * lhs, expr * rhs, expr_ref & result) {
expr_ref tmp(m());
mk_not(lhs, tmp);
mk_eq(tmp, rhs, result);
}
void bool_rewriter::mk_implies(expr * lhs, expr * rhs, expr_ref & result) {
expr_ref tmp(m());
mk_not(lhs, tmp);
mk_or(tmp, rhs, result);
}
void bool_rewriter::mk_nand(unsigned num_args, expr * const * args, expr_ref & result) {
expr_ref tmp(m_manager);
mk_and(num_args, args, tmp);
mk_not(tmp, result);
}
void bool_rewriter::mk_nor(unsigned num_args, expr * const * args, expr_ref & result) {
expr_ref tmp(m_manager);
mk_or(num_args, args, tmp);
mk_not(tmp, result);
}
void bool_rewriter::mk_nand(expr * arg1, expr * arg2, expr_ref & result) {
expr_ref tmp(m_manager);
mk_and(arg1, arg2, tmp);
mk_not(tmp, result);
}
void bool_rewriter::mk_nor(expr * arg1, expr * arg2, expr_ref & result) {
expr_ref tmp(m_manager);
mk_or(arg1, arg2, tmp);
mk_not(tmp, result);
}
template class rewriter_tpl<bool_rewriter_cfg>;

View file

@ -1,199 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
bool_rewriter.h
Abstract:
Basic rewriting rules for Boolean operators.
Author:
Leonardo (leonardo) 2011-04-04
Notes:
--*/
#ifndef _BOOL_REWRITER_H_
#define _BOOL_REWRITER_H_
#include"ast.h"
#include"rewriter.h"
#include"params.h"
/**
\brief Apply basic Boolean rewriting operations.
Only depth 1 simplifications are performed.
Note: there are no recursive calls.
Note: arguments of AC operators are not sorted.
Note: arguments of = and xor are also not sorted.
Note: By default, (AND A B) is not rewritten as (NOT (OR (NOT A) (NOT B)))
Note: AND OR operators are flattened only if mk_flat_app, mk_flat_or, mk_flat_and are used.
The following operators are expanded:
- => (implies)
- xor
- nand
- nor
- iff
All methods run in time almost linear on the number of arguments.
Actually, this is not true when flattening is enabled.
A better approximation is O(Sum_{t \in args} size1(t)).
Where size1(t) = max{t->get_num_args(), 1}.
*/
class bool_rewriter {
ast_manager & m_manager;
bool m_flat;
bool m_local_ctx;
bool m_elim_and;
bool m_blast_distinct;
bool m_ite_extra_rules;
unsigned m_local_ctx_limit;
unsigned m_local_ctx_cost;
br_status mk_flat_and_core(unsigned num_args, expr * const * args, expr_ref & result);
br_status mk_flat_or_core(unsigned num_args, expr * const * args, expr_ref & result);
br_status mk_nflat_and_core(unsigned num_args, expr * const * args, expr_ref & result);
br_status mk_nflat_or_core(unsigned num_args, expr * const * args, expr_ref & result);
void mk_and_as_or(unsigned num_args, expr * const * args, expr_ref & result);
expr * mk_or_app(unsigned num_args, expr * const * args);
bool simp_nested_not_or(unsigned num_args, expr * const * args, expr_fast_mark1 & neg_lits, expr_fast_mark2 & pos_lits, expr_ref & result);
expr * simp_arg(expr * arg, expr_fast_mark1 & neg_lits, expr_fast_mark2 & pos_lits, bool & modified);
void mk_nested_ite(expr * new_c, expr * new_t, expr * new_e, expr_ref & result);
bool simp_nested_eq_ite(expr * t, expr_fast_mark1 & neg_lits, expr_fast_mark2 & pos_lits, expr_ref & result);
bool local_ctx_simp(unsigned num_args, expr * const * args, expr_ref & result);
br_status try_ite_value(app * ite, app * val, expr_ref & result);
public:
bool_rewriter(ast_manager & m, params_ref const & p = params_ref()):m_manager(m), m_local_ctx_cost(0) { updt_params(p); }
ast_manager & m() const { return m_manager; }
family_id get_fid() const { return m().get_basic_family_id(); }
bool is_eq(expr * t) const { return m().is_eq(t) || m().is_iff(t); }
bool flat() const { return m_flat; }
void set_flat(bool f) { m_flat = f; }
bool elim_and() const { return m_elim_and; }
void set_elim_and(bool f) { m_elim_and = f; }
void reset_local_ctx_cost() { m_local_ctx_cost = 0; }
void updt_params(params_ref const & p);
static void get_param_descrs(param_descrs & r);
// The core methods return true if a rewrite-step/simplification was applied
// to the arguments, and the result is stored in 'result'. Otherwise, they return false
// and result.get == 0.
br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
void mk_app(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
if (mk_app_core(f, num_args, args, result) == BR_FAILED)
result = m().mk_app(f, num_args, args);
}
br_status mk_eq_core(expr * lhs, expr * rhs, expr_ref & result);
br_status mk_distinct_core(unsigned num_args, expr * const * args, expr_ref & result);
br_status mk_iff_core(expr * lhs, expr * rhs, expr_ref & result) { return mk_eq_core(lhs, rhs, result); }
br_status mk_and_core(unsigned num_args, expr * const * args, expr_ref & result) {
if (m_elim_and) {
mk_and_as_or(num_args, args, result);
return BR_DONE;
}
else if (m_flat) {
return mk_flat_and_core(num_args, args, result);
}
else {
return mk_nflat_and_core(num_args, args, result);
}
}
br_status mk_or_core(unsigned num_args, expr * const * args, expr_ref & result) {
return m_flat ?
mk_flat_or_core(num_args, args, result) :
mk_nflat_or_core(num_args, args, result);
}
br_status mk_ite_core(expr * c, expr * t, expr * e, expr_ref & result);
br_status mk_not_core(expr * t, expr_ref & result);
void mk_eq(expr * lhs, expr * rhs, expr_ref & result) {
if (mk_eq_core(lhs, rhs, result) == BR_FAILED)
result = m().mk_eq(lhs, rhs);
}
void mk_iff(expr * lhs, expr * rhs, expr_ref & result) { mk_eq(lhs, rhs, result); }
void mk_xor(expr * lhs, expr * rhs, expr_ref & result);
void mk_and(unsigned num_args, expr * const * args, expr_ref & result) {
if (mk_and_core(num_args, args, result) == BR_FAILED) {
SASSERT(!m_elim_and);
result = m().mk_and(num_args, args);
}
}
void mk_or(unsigned num_args, expr * const * args, expr_ref & result) {
if (mk_or_core(num_args, args, result) == BR_FAILED)
result = m().mk_or(num_args, args);
}
void mk_and(expr * arg1, expr * arg2, expr_ref & result) {
expr * args[2] = {arg1, arg2};
mk_and(2, args, result);
}
void mk_or(expr * arg1, expr * arg2, expr_ref & result) {
expr * args[2] = {arg1, arg2};
mk_or(2, args, result);
}
void mk_and(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) {
expr * args[3] = {arg1, arg2, arg3};
mk_and(3, args, result);
}
void mk_or(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) {
expr * args[3] = {arg1, arg2, arg3};
mk_or(3, args, result);
}
void mk_implies(expr * lhs, expr * rhs, expr_ref & result);
void mk_ite(expr * c, expr * t, expr * e, expr_ref & result) {
if (mk_ite_core(c, t, e, result) == BR_FAILED)
result = m().mk_ite(c, t, e);
}
void mk_distinct(unsigned num_args, expr * const * args, expr_ref & result) {
if (mk_distinct_core(num_args, args, result) == BR_FAILED)
result = m().mk_distinct(num_args, args);
}
void mk_not(expr * t, expr_ref & result) {
if (mk_not_core(t, result) == BR_FAILED)
result = m().mk_not(t);
}
void mk_nand(unsigned num_args, expr * const * args, expr_ref & result);
void mk_nor(unsigned num_args, expr * const * args, expr_ref & result);
void mk_nand(expr * arg1, expr * arg2, expr_ref & result);
void mk_nor(expr * arg1, expr * arg2, expr_ref & result);
};
struct bool_rewriter_cfg : public default_rewriter_cfg {
bool_rewriter m_r;
bool flat_assoc(func_decl * f) const { return m_r.flat() && (m_r.m().is_and(f) || m_r.m().is_or(f)); }
bool rewrite_patterns() const { return false; }
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
result_pr = 0;
if (f->get_family_id() != m_r.get_fid())
return BR_FAILED;
return m_r.mk_app_core(f, num, args, result);
}
bool_rewriter_cfg(ast_manager & m, params_ref const & p):m_r(m, p) {}
};
class bool_rewriter_star : public rewriter_tpl<bool_rewriter_cfg> {
bool_rewriter_cfg m_cfg;
public:
bool_rewriter_star(ast_manager & m, params_ref const & p):
rewriter_tpl<bool_rewriter_cfg>(m, false, m_cfg),
m_cfg(m, p) {}
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,171 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
bv_rewriter.h
Abstract:
Basic rewriting rules for bit-vectors
Author:
Leonardo (leonardo) 2011-04-14
Notes:
--*/
#ifndef _BV_REWRITER_H_
#define _BV_REWRITER_H_
#include"poly_rewriter.h"
#include"bv_decl_plugin.h"
#include"arith_decl_plugin.h"
class mk_extract_proc {
bv_util & m_util;
unsigned m_high;
unsigned m_low;
sort * m_domain;
func_decl * m_f_cached;
public:
mk_extract_proc(bv_util & u);
~mk_extract_proc();
app * operator()(unsigned high, unsigned low, expr * arg);
};
class bv_rewriter_core {
protected:
typedef rational numeral;
bv_util m_util;
ast_manager & m() const { return m_util.get_manager(); }
family_id get_fid() const { return m_util.get_family_id(); }
bool is_numeral(expr * n) const { return m_util.is_numeral(n); }
bool is_numeral(expr * n, numeral & r) const { unsigned sz; return m_util.is_numeral(n, r, sz); }
bool is_zero(expr * n) const { return m_util.is_zero(n); }
bool is_minus_one(expr * n) const { return m_util.is_allone(n); }
void normalize(numeral & c, sort * s) { unsigned bv_size = m_util.get_bv_size(s); c = m_util.norm(c, bv_size); }
app * mk_numeral(numeral const & r, sort * s) { return m_util.mk_numeral(r, s); }
decl_kind add_decl_kind() const { return OP_BADD; }
decl_kind mul_decl_kind() const { return OP_BMUL; }
bool use_power() const { return false; }
decl_kind power_decl_kind() const { UNREACHABLE(); return static_cast<decl_kind>(UINT_MAX); }
public:
bv_rewriter_core(ast_manager & m):m_util(m) {}
};
class bv_rewriter : public poly_rewriter<bv_rewriter_core> {
mk_extract_proc m_mk_extract;
arith_util m_autil;
bool m_hi_div0;
bool m_elim_sign_ext;
bool m_mul2concat;
bool m_bit2bool;
bool m_blast_eq_value;
bool m_mkbv2num;
bool m_split_concat_eq;
bool m_udiv2mul;
bool is_zero_bit(expr * x, unsigned idx);
br_status mk_ule(expr * a, expr * b, expr_ref & result);
br_status mk_uge(expr * a, expr * b, expr_ref & result);
br_status mk_ult(expr * a, expr * b, expr_ref & result);
br_status mk_sle(expr * a, expr * b, expr_ref & result);
br_status mk_sge(expr * a, expr * b, expr_ref & result);
br_status mk_slt(expr * a, expr * b, expr_ref & result);
br_status mk_leq_core(bool is_signed, expr * a, expr * b, expr_ref & result);
br_status mk_concat(unsigned num_args, expr * const * args, expr_ref & result);
br_status mk_extract(unsigned high, unsigned low, expr * arg, expr_ref & result);
br_status mk_repeat(unsigned n, expr * arg, expr_ref & result);
br_status mk_zero_extend(unsigned n, expr * arg, expr_ref & result);
br_status mk_sign_extend(unsigned n, expr * arg, expr_ref & result);
br_status mk_bv_not(expr * arg, expr_ref & result);
br_status mk_bv_or(unsigned num, expr * const * args, expr_ref & result);
br_status mk_bv_xor(unsigned num, expr * const * args, expr_ref & result);
br_status mk_bv_and(unsigned num, expr * const * args, expr_ref & result);
br_status mk_bv_nand(unsigned num, expr * const * args, expr_ref & result);
br_status mk_bv_nor(unsigned num, expr * const * args, expr_ref & result);
br_status mk_bv_xnor(unsigned num_args, expr * const * args, expr_ref & result);
br_status mk_bv_rotate_left(unsigned n, expr * arg, expr_ref & result);
br_status mk_bv_rotate_right(unsigned n, expr * arg, expr_ref & result);
br_status mk_bv_ext_rotate_left(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_bv_ext_rotate_right(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_bv_add(unsigned num_args, expr * const * args, expr_ref & result);
br_status mk_bv_add(expr * arg1, expr * arg2, expr_ref & result) {
expr * args[2] = { arg1, arg2 };
return mk_bv_add(2, args, result);
}
br_status mk_bv_mul(unsigned num_args, expr * const * args, expr_ref & result);
br_status mk_bv_shl(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_bv_lshr(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_bv_ashr(expr * arg1, expr * arg2, expr_ref & result);
bool is_minus_one_core(expr * arg) const;
bool is_x_minus_one(expr * arg, expr * & x);
br_status mk_bv_sdiv_core(expr * arg1, expr * arg2, bool hi_div0, expr_ref & result);
br_status mk_bv_udiv_core(expr * arg1, expr * arg2, bool hi_div0, expr_ref & result);
br_status mk_bv_srem_core(expr * arg1, expr * arg2, bool hi_div0, expr_ref & result);
br_status mk_bv_urem_core(expr * arg1, expr * arg2, bool hi_div0, expr_ref & result);
br_status mk_bv_smod_core(expr * arg1, expr * arg2, bool hi_div0, expr_ref & result);
br_status mk_bv_sdiv(expr * arg1, expr * arg2, expr_ref & result) { return mk_bv_sdiv_core(arg1, arg2, m_hi_div0, result); }
br_status mk_bv_udiv(expr * arg1, expr * arg2, expr_ref & result) { return mk_bv_udiv_core(arg1, arg2, m_hi_div0, result); }
br_status mk_bv_srem(expr * arg1, expr * arg2, expr_ref & result) { return mk_bv_srem_core(arg1, arg2, m_hi_div0, result); }
br_status mk_bv_urem(expr * arg1, expr * arg2, expr_ref & result) { return mk_bv_urem_core(arg1, arg2, m_hi_div0, result); }
br_status mk_bv_smod(expr * arg1, expr * arg2, expr_ref & result) { return mk_bv_smod_core(arg1, arg2, m_hi_div0, result); }
br_status mk_bv_sdiv_i(expr * arg1, expr * arg2, expr_ref & result) { return mk_bv_sdiv_core(arg1, arg2, true, result); }
br_status mk_bv_udiv_i(expr * arg1, expr * arg2, expr_ref & result) { return mk_bv_udiv_core(arg1, arg2, true, result); }
br_status mk_bv_srem_i(expr * arg1, expr * arg2, expr_ref & result) { return mk_bv_srem_core(arg1, arg2, true, result); }
br_status mk_bv_urem_i(expr * arg1, expr * arg2, expr_ref & result) { return mk_bv_urem_core(arg1, arg2, true, result); }
br_status mk_bv_smod_i(expr * arg1, expr * arg2, expr_ref & result) { return mk_bv_smod_core(arg1, arg2, true, result); }
br_status mk_int2bv(unsigned bv_size, expr * arg, expr_ref & result);
br_status mk_bv2int(expr * arg, expr_ref & result);
br_status mk_bv_redor(expr * arg, expr_ref & result);
br_status mk_bv_redand(expr * arg, expr_ref & result);
br_status mk_bv_comp(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_bit2bool(expr * lhs, expr * rhs, expr_ref & result);
br_status mk_blast_eq_value(expr * lhs, expr * rhs, expr_ref & result);
br_status mk_eq_concat(expr * lhs, expr * rhs, expr_ref & result);
br_status mk_mkbv(unsigned num, expr * const * args, expr_ref & result);
bool is_minus_one_times_t(expr * arg);
void mk_t1_add_t2_eq_c(expr * t1, expr * t2, expr * c, expr_ref & result);
bool is_concat_split_target(expr * t) const;
br_status mk_mul_eq(expr * lhs, expr * rhs, expr_ref & result);
void updt_local_params(params_ref const & p);
public:
bv_rewriter(ast_manager & m, params_ref const & p = params_ref()):
poly_rewriter<bv_rewriter_core>(m, p),
m_mk_extract(m_util),
m_autil(m) {
updt_local_params(p);
}
void updt_params(params_ref const & p);
static void get_param_descrs(param_descrs & r);
void set_mkbv2num(bool f) { m_mkbv2num = f; }
unsigned get_bv_size(expr * t) const {return m_util.get_bv_size(t); }
bool is_numeral(expr * t) const { return m_util.is_numeral(t); }
bool is_numeral(expr * t, numeral & r, unsigned & sz) const { return m_util.is_numeral(t, r, sz); }
bool is_bv(expr * t) const { return m_util.is_bv(t); }
expr * mk_numeral(numeral const & v, unsigned sz) { return m_util.mk_numeral(v, sz); }
expr * mk_numeral(unsigned v, unsigned sz) { return m_util.mk_numeral(numeral(v), sz); }
br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
void mk_app(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
if (mk_app_core(f, num_args, args, result) == BR_FAILED)
result = m().mk_app(f, num_args, args);
}
br_status mk_eq_core(expr * lhs, expr * rhs, expr_ref & result);
};
#endif

View file

@ -1,111 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
datatype_rewriter.cpp
Abstract:
Basic rewriting rules for Datatypes.
Author:
Leonardo (leonardo) 2011-04-06
Notes:
--*/
#include"datatype_rewriter.h"
br_status datatype_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(f->get_family_id() == get_fid());
switch(f->get_decl_kind()) {
case OP_DT_CONSTRUCTOR: return BR_FAILED;
case OP_DT_RECOGNISER:
//
// simplify is_cons(cons(x,y)) -> true
// simplify is_cons(nil) -> false
//
SASSERT(num_args == 1);
if (!is_app(args[0]) || !m_util.is_constructor(to_app(args[0])))
return BR_FAILED;
if (to_app(args[0])->get_decl() == m_util.get_recognizer_constructor(f))
result = m().mk_true();
else
result = m().mk_false();
return BR_DONE;
case OP_DT_ACCESSOR: {
//
// simplify head(cons(x,y)) -> x
//
SASSERT(num_args == 1);
if (!is_app(args[0]) || !m_util.is_constructor(to_app(args[0])))
return BR_FAILED;
app * a = to_app(args[0]);
func_decl * c_decl = a->get_decl();
if (c_decl != m_util.get_accessor_constructor(f))
return BR_FAILED;
ptr_vector<func_decl> const * acc = m_util.get_constructor_accessors(c_decl);
SASSERT(acc && acc->size() == a->get_num_args());
unsigned num = acc->size();
for (unsigned i = 0; i < num; ++i) {
if (f == (*acc)[i]) {
// found it.
result = a->get_arg(i);
return BR_DONE;
}
}
UNREACHABLE();
break;
}
default:
UNREACHABLE();
}
return BR_FAILED;
}
br_status datatype_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) {
if (!is_app(lhs) || !is_app(rhs) || !m_util.is_constructor(to_app(lhs)) || !m_util.is_constructor(to_app(rhs)))
return BR_FAILED;
if (to_app(lhs)->get_decl() != to_app(rhs)->get_decl()) {
result = m().mk_false();
return BR_DONE;
}
// Remark: In datatype_simplifier_plugin, we used
// m_basic_simplifier to create '=' and 'and' applications in the
// following code. This trick not guarantee that the final expression
// will be fully simplified.
//
// Example:
// The assertion
// (assert (= (cons a1 (cons a2 (cons a3 (cons (+ a4 1) (cons (+ a5 c5) (cons a6 nil))))))
// (cons b1 (cons b2 (cons b3 (cons b4 (cons b5 (cons b6 nil))))))))
//
// After applying asserted_formulas::reduce(), the following formula was generated.
//
// (= a1 b1)
// (= a2 b2)
// (= a3 b3)
// (= (+ a4 (* (- 1) b4)) (- 1))
// (= (+ c5 a5) b5) <<< NOT SIMPLIFIED WITH RESPECT TO ARITHMETIC
// (= (cons a6 nil) (cons b6 nil))) <<< NOT SIMPLIFIED WITH RESPECT TO DATATYPE theory
//
// Note that asserted_formulas::reduce() applied the simplier many times.
// After the first simplification step we had:
// (= a1 b1)
// (= (cons a2 (cons a3 (cons (+ a4 1) (cons (+ a5 c5) (cons a6 nil))))))
// (cons b2 (cons b3 (cons b4 (cons b5 (cons b6 nil))))))
ptr_buffer<expr> eqs;
unsigned num = to_app(lhs)->get_num_args();
SASSERT(num == to_app(rhs)->get_num_args());
for (unsigned i = 0; i < num; ++i) {
eqs.push_back(m().mk_eq(to_app(lhs)->get_arg(i), to_app(rhs)->get_arg(i)));
}
result = m().mk_and(eqs.size(), eqs.c_ptr());
return BR_REWRITE2;
}

View file

@ -1,35 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
datatype_rewriter.h
Abstract:
Basic rewriting rules for Datatypes.
Author:
Leonardo (leonardo) 2011-04-06
Notes:
--*/
#ifndef _DATATYPE_REWRITER_H_
#define _DATATYPE_REWRITER_H_
#include"datatype_decl_plugin.h"
#include"rewriter_types.h"
class datatype_rewriter {
datatype_util m_util;
public:
datatype_rewriter(ast_manager & m):m_util(m) {}
ast_manager & m() const { return m_util.get_manager(); }
family_id get_fid() const { return m_util.get_family_id(); }
br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
br_status mk_eq_core(expr * lhs, expr * rhs, expr_ref & result);
};
#endif

View file

@ -1,102 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
smt_decl_collector.cpp
Abstract:
Collect uninterpreted func_delcs and sorts.
This class was originally in ast_smt_pp.h
Author:
Leonardo (leonardo) 2011-10-04
Revision History:
--*/
#include"decl_collector.h"
void decl_collector::visit_sort(sort * n) {
family_id fid = n->get_family_id();
if (m().is_uninterp(n))
m_sorts.push_back(n);
if (fid == m_dt_fid)
m_sorts.push_back(n);
}
bool decl_collector::is_bool(sort * s) {
return m().is_bool(s);
}
void decl_collector::visit_func(func_decl * n) {
family_id fid = n->get_family_id();
if (fid == null_family_id) {
if (m_sep_preds && is_bool(n->get_range()))
m_preds.push_back(n);
else
m_decls.push_back(n);
}
}
decl_collector::decl_collector(ast_manager & m, bool preds):
m_manager(m),
m_sep_preds(preds) {
m_basic_fid = m_manager.get_basic_family_id();
m_dt_fid = m_manager.get_family_id("datatype");
}
void decl_collector::visit(ast* n) {
ptr_vector<ast> todo;
todo.push_back(n);
while (!todo.empty()) {
n = todo.back();
todo.pop_back();
if (!m_visited.is_marked(n)) {
m_visited.mark(n, true);
switch(n->get_kind()) {
case AST_APP: {
app * a = to_app(n);
for (unsigned i = 0; i < a->get_num_args(); ++i) {
todo.push_back(a->get_arg(i));
}
todo.push_back(a->get_decl());
break;
}
case AST_QUANTIFIER: {
quantifier * q = to_quantifier(n);
unsigned num_decls = q->get_num_decls();
for (unsigned i = 0; i < num_decls; ++i) {
todo.push_back(q->get_decl_sort(i));
}
todo.push_back(q->get_expr());
for (unsigned i = 0; i < q->get_num_patterns(); ++i) {
todo.push_back(q->get_pattern(i));
}
break;
}
case AST_SORT:
visit_sort(to_sort(n));
break;
case AST_FUNC_DECL: {
func_decl * d = to_func_decl(n);
for (unsigned i = 0; i < d->get_arity(); ++i) {
todo.push_back(d->get_domain(i));
}
todo.push_back(d->get_range());
visit_func(d);
break;
}
case AST_VAR:
break;
default:
UNREACHABLE();
}
}
}
}

View file

@ -1,55 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
decl_collector.h
Abstract:
Collect uninterpreted func_delcs and sorts.
This class was originally in ast_smt_pp.h
Author:
Leonardo (leonardo) 2011-10-04
Revision History:
--*/
#ifndef _SMT_DECL_COLLECTOR_H_
#define _SMT_DECL_COLLECTOR_H_
#include"ast.h"
class decl_collector {
ast_manager & m_manager;
bool m_sep_preds;
ptr_vector<sort> m_sorts;
ptr_vector<func_decl> m_decls;
ptr_vector<func_decl> m_preds;
ast_mark m_visited;
family_id m_basic_fid;
family_id m_dt_fid;
void visit_sort(sort* n);
bool is_bool(sort* s);
void visit_func(func_decl* n);
public:
// if preds == true, then predicates are stored in a separate collection.
decl_collector(ast_manager & m, bool preds=true);
ast_manager & m() { return m_manager; }
void visit(ast * n);
unsigned get_num_sorts() const { return m_sorts.size(); }
unsigned get_num_decls() const { return m_decls.size(); }
unsigned get_num_preds() const { return m_preds.size(); }
sort * const * get_sorts() const { return m_sorts.c_ptr(); }
func_decl * const * get_func_decls() const { return m_decls.c_ptr(); }
func_decl * const * get_pred_decls() const { return m_preds.c_ptr(); }
};
#endif

View file

@ -1,57 +0,0 @@
/*++
Copyright (c) 2010 Microsoft Corporation
Module Name:
dl_rewriter.cpp
Abstract:
<abstract>
Author:
Nikolaj Bjorner (nbjorner) 2010-08-10
Revision History:
--*/
#include"dl_rewriter.h"
br_status dl_rewriter::mk_app_core(
func_decl * f, unsigned num_args, expr* const* args, expr_ref& result) {
ast_manager& m = result.get_manager();
uint64 v1, v2;
switch(f->get_decl_kind()) {
case datalog::OP_DL_LT:
if (m_util.is_numeral_ext(args[0], v1) &&
m_util.is_numeral_ext(args[1], v2)) {
result = (v1 < v2)?m.mk_true():m.mk_false();
return BR_DONE;
}
// x < x <=> false
if (args[0] == args[1]) {
result = m.mk_false();
return BR_DONE;
}
// x < 0 <=> false
if (m_util.is_numeral_ext(args[1], v2) && v2 == 0) {
result = m.mk_false();
return BR_DONE;
}
// 0 < x <=> 0 != x
if (m_util.is_numeral_ext(args[1], v1) && v1 == 0) {
result = m.mk_not(m.mk_eq(args[0], args[1]));
return BR_DONE;
}
break;
default:
break;
}
return BR_FAILED;
}

View file

@ -1,33 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
dl_rewriter.h
Abstract:
Basic rewriting rules for atalog finite domains.
Author:
Nikolaj Bjorner (nbjorner) 2012-03-09
Notes:
--*/
#ifndef _DL_REWRITER_H_
#define _DL_REWRITER_H_
#include"dl_decl_plugin.h"
#include"rewriter_types.h"
class dl_rewriter {
datalog::dl_decl_util m_util;
public:
dl_rewriter(ast_manager & m):m_util(m) {}
family_id get_fid() const { return m_util.get_family_id(); }
br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
};
#endif

View file

@ -1,36 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
expr_delta_pair.h
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-01-14.
Revision History:
--*/
#ifndef _EXPR_DELTA_PAIR_H_
#define _EXPR_DELTA_PAIR_H_
/**
\brief Auxiliary structure used to cache the intermediate results of the variable substitution procedure.
*/
struct expr_delta_pair {
expr * m_node;
unsigned m_delta;
expr_delta_pair():m_node(0), m_delta(0) {}
expr_delta_pair(expr * n, unsigned d):m_node(n), m_delta(d) {}
unsigned hash() const { return hash_u_u(m_node->hash(), m_delta); }
bool operator==(const expr_delta_pair & e) const { return m_node == e.m_node && m_delta == e.m_delta; }
};
#endif /* _EXPR_DELTA_PAIR_H_ */

View file

@ -1,157 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
expr_substitution.cpp
Abstract:
expr -> expr substitution
Author:
Leonardo (leonardo) 2011-04-29
Notes:
--*/
#include"expr_substitution.h"
#include"ref_util.h"
typedef obj_map<expr, proof*> expr2proof;
typedef obj_map<expr, expr_dependency*> expr2expr_dependency;
void expr_substitution::init() {
if (proofs_enabled())
m_subst_pr = alloc(expr2proof);
if (unsat_core_enabled())
m_subst_dep = alloc(expr2expr_dependency);
}
expr_substitution::expr_substitution(ast_manager & m):
m_manager(m),
m_cores_enabled(false),
m_proofs_enabled(m.proofs_enabled()) {
init();
}
expr_substitution::expr_substitution(ast_manager & m, bool core_enabled):
m_manager(m),
m_cores_enabled(core_enabled),
m_proofs_enabled(m.proofs_enabled()) {
init();
}
expr_substitution::expr_substitution(ast_manager & m, bool core_enabled, bool proofs_enabled):
m_manager(m),
m_cores_enabled(core_enabled),
m_proofs_enabled(proofs_enabled) {
SASSERT(!proofs_enabled || m.proofs_enabled());
init();
}
expr_substitution::~expr_substitution() {
reset();
}
void expr_substitution::insert(expr * c, expr * def, proof * def_pr, expr_dependency * def_dep) {
obj_map<expr, expr*>::obj_map_entry * entry = m_subst.insert_if_not_there2(c, 0);
if (entry->get_data().m_value == 0) {
// new entry
m_manager.inc_ref(c);
m_manager.inc_ref(def);
entry->get_data().m_value = def;
if (proofs_enabled()) {
SASSERT(!m_subst_pr->contains(c));
m_subst_pr->insert(c, def_pr);
m_manager.inc_ref(def_pr);
}
if (unsat_core_enabled()) {
SASSERT(!m_subst_dep->contains(c));
m_subst_dep->insert(c, def_dep);
m_manager.inc_ref(def_dep);
}
}
else {
// replacing entry
m_manager.inc_ref(def);
m_manager.dec_ref(entry->get_data().m_value);
entry->get_data().m_value = def;
if (proofs_enabled()) {
obj_map<expr, proof*>::obj_map_entry * entry_pr = m_subst_pr->find_core(c);
SASSERT(entry_pr != 0);
m_manager.inc_ref(def_pr);
m_manager.dec_ref(entry_pr->get_data().m_value);
entry_pr->get_data().m_value = def_pr;
}
if (unsat_core_enabled()) {
obj_map<expr, expr_dependency*>::obj_map_entry * entry_dep = m_subst_dep->find_core(c);
SASSERT(entry_dep != 0);
m_manager.inc_ref(def_dep);
m_manager.dec_ref(entry_dep->get_data().m_value);
entry_dep->get_data().m_value = def_dep;
}
}
}
void expr_substitution::erase(expr * c) {
if (proofs_enabled()) {
proof * pr = 0;
if (m_subst_pr->find(c, pr)) {
m_manager.dec_ref(pr);
m_subst_pr->erase(c);
}
}
if (unsat_core_enabled()) {
expr_dependency * dep = 0;
if (m_subst_dep->find(c, dep)) {
m_manager.dec_ref(dep);
m_subst_dep->erase(c);
}
}
expr * def = 0;
if (m_subst.find(c, def)) {
m_manager.dec_ref(c);
m_manager.dec_ref(def);
m_subst.erase(c);
}
}
bool expr_substitution::find(expr * c, expr * & def, proof * & def_pr) {
if (m_subst.find(c, def)) {
if (proofs_enabled())
m_subst_pr->find(c, def_pr);
return true;
}
return false;
}
bool expr_substitution::find(expr * c, expr * & def, proof * & def_pr, expr_dependency * & def_dep) {
if (m_subst.find(c, def)) {
if (proofs_enabled())
m_subst_pr->find(c, def_pr);
if (unsat_core_enabled())
m_subst_dep->find(c, def_dep);
return true;
}
return false;
}
void expr_substitution::reset() {
dec_ref_map_key_values(m_manager, m_subst);
if (proofs_enabled())
dec_ref_map_values(m_manager, *m_subst_pr);
if (unsat_core_enabled())
dec_ref_map_values(m_manager, *m_subst_dep);
}
void expr_substitution::cleanup() {
reset();
m_subst.finalize();
if (proofs_enabled())
m_subst_pr->finalize();
if (unsat_core_enabled())
m_subst_dep->finalize();
}

View file

@ -1,54 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
expr_substitution.h
Abstract:
expr -> expr substitution
Author:
Leonardo (leonardo) 2011-04-29
Notes:
--*/
#ifndef _EXPR_SUBSTITUTION_H_
#define _EXPR_SUBSTITUTION_H_
#include"ast.h"
class expr_substitution {
ast_manager & m_manager;
obj_map<expr, expr*> m_subst;
scoped_ptr<obj_map<expr, proof*> > m_subst_pr;
scoped_ptr<obj_map<expr, expr_dependency*> > m_subst_dep;
unsigned m_cores_enabled:1;
unsigned m_proofs_enabled:1;
void init();
public:
expr_substitution(ast_manager & m);
expr_substitution(ast_manager & m, bool cores_enabled);
expr_substitution(ast_manager & m, bool cores_enabled, bool proofs_enabled);
~expr_substitution();
ast_manager & m() const { return m_manager; }
bool proofs_enabled() const { return m_proofs_enabled; }
bool unsat_core_enabled() const { return m_cores_enabled; }
bool empty() const { return m_subst.empty(); }
void insert(expr * s, expr * def, proof * def_pr = 0, expr_dependency * def_dep = 0);
void erase(expr * s);
bool find(expr * s, expr * & def, proof * & def_pr);
bool find(expr * s, expr * & def, proof * & def_pr, expr_dependency * & def_dep);
void reset();
void cleanup();
};
#endif

View file

@ -1,441 +0,0 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
float_rewriter.cpp
Abstract:
Basic rewriting rules for floating point numbers.
Author:
Leonardo (leonardo) 2012-02-02
Notes:
--*/
#include"float_rewriter.h"
float_rewriter::float_rewriter(ast_manager & m, params_ref const & p):
m_util(m) {
updt_params(p);
}
float_rewriter::~float_rewriter() {
}
void float_rewriter::updt_params(params_ref const & p) {
}
void float_rewriter::get_param_descrs(param_descrs & r) {
}
br_status float_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
br_status st = BR_FAILED;
SASSERT(f->get_family_id() == get_fid());
switch (f->get_decl_kind()) {
case OP_TO_FLOAT: st = mk_to_float(f, num_args, args, result); break;
case OP_FLOAT_ADD: SASSERT(num_args == 3); st = mk_add(args[0], args[1], args[2], result); break;
case OP_FLOAT_SUB: SASSERT(num_args == 3); st = mk_sub(args[0], args[1], args[2], result); break;
case OP_FLOAT_UMINUS: SASSERT(num_args == 1); st = mk_uminus(args[0], result); break;
case OP_FLOAT_MUL: SASSERT(num_args == 3); st = mk_mul(args[0], args[1], args[2], result); break;
case OP_FLOAT_DIV: SASSERT(num_args == 3); st = mk_div(args[0], args[1], args[2], result); break;
case OP_FLOAT_REM: SASSERT(num_args == 2); st = mk_rem(args[0], args[1], result); break;
case OP_FLOAT_ABS: SASSERT(num_args == 1); st = mk_abs(args[0], result); break;
case OP_FLOAT_MIN: SASSERT(num_args == 2); st = mk_min(args[0], args[1], result); break;
case OP_FLOAT_MAX: SASSERT(num_args == 2); st = mk_max(args[0], args[1], result); break;
case OP_FLOAT_FUSED_MA: SASSERT(num_args == 4); st = mk_fused_ma(args[0], args[1], args[2], args[3], result); break;
case OP_FLOAT_SQRT: SASSERT(num_args == 2); st = mk_sqrt(args[0], args[1], result); break;
case OP_FLOAT_ROUND_TO_INTEGRAL: SASSERT(num_args == 2); st = mk_round(args[0], args[1], result); break;
case OP_FLOAT_EQ: SASSERT(num_args == 2); st = mk_float_eq(args[0], args[1], result); break;
case OP_FLOAT_LT: SASSERT(num_args == 2); st = mk_lt(args[0], args[1], result); break;
case OP_FLOAT_GT: SASSERT(num_args == 2); st = mk_gt(args[0], args[1], result); break;
case OP_FLOAT_LE: SASSERT(num_args == 2); st = mk_le(args[0], args[1], result); break;
case OP_FLOAT_GE: SASSERT(num_args == 2); st = mk_ge(args[0], args[1], result); break;
case OP_FLOAT_IS_ZERO: SASSERT(num_args == 1); st = mk_is_zero(args[0], result); break;
case OP_FLOAT_IS_NZERO: SASSERT(num_args == 1); st = mk_is_nzero(args[0], result); break;
case OP_FLOAT_IS_PZERO: SASSERT(num_args == 1); st = mk_is_pzero(args[0], result); break;
case OP_FLOAT_IS_SIGN_MINUS: SASSERT(num_args == 1); st = mk_is_sign_minus(args[0], result); break;
}
return st;
}
br_status float_rewriter::mk_to_float(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(f->get_num_parameters() == 2);
SASSERT(f->get_parameter(0).is_int());
SASSERT(f->get_parameter(1).is_int());
unsigned ebits = f->get_parameter(0).get_int();
unsigned sbits = f->get_parameter(1).get_int();
if (num_args == 2) {
mpf_rounding_mode rm;
if (!m_util.is_rm(args[0], rm))
return BR_FAILED;
rational q;
if (!m_util.au().is_numeral(args[1], q))
return BR_FAILED;
mpf v;
m_util.fm().set(v, ebits, sbits, rm, q.to_mpq());
result = m_util.mk_value(v);
m_util.fm().del(v);
return BR_DONE;
}
else if (num_args == 3 &&
m_util.is_rm(m().get_sort(args[0])) &&
m_util.au().is_real(args[1]) &&
m_util.au().is_int(args[2])) {
mpf_rounding_mode rm;
if (!m_util.is_rm(args[0], rm))
return BR_FAILED;
rational q;
if (!m_util.au().is_numeral(args[1], q))
return BR_FAILED;
rational e;
if (!m_util.au().is_numeral(args[2], e))
return BR_FAILED;
TRACE("fp_rewriter", tout << "q: " << q << ", e: " << e << "\n";);
mpf v;
m_util.fm().set(v, ebits, sbits, rm, q.to_mpq(), e.to_mpq().numerator());
result = m_util.mk_value(v);
m_util.fm().del(v);
return BR_DONE;
}
else {
return BR_FAILED;
}
}
br_status float_rewriter::mk_add(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) {
mpf_rounding_mode rm;
if (m_util.is_rm(arg1, rm)) {
scoped_mpf v2(m_util.fm()), v3(m_util.fm());
if (m_util.is_value(arg2, v2) && m_util.is_value(arg3, v3)) {
scoped_mpf t(m_util.fm());
m_util.fm().add(rm, v2, v3, t);
result = m_util.mk_value(t);
return BR_DONE;
}
}
return BR_FAILED;
}
br_status float_rewriter::mk_sub(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) {
// a - b = a + (-b)
result = m_util.mk_add(arg1, arg2, m_util.mk_uminus(arg3));
return BR_REWRITE2;
}
br_status float_rewriter::mk_mul(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) {
mpf_rounding_mode rm;
if (m_util.is_rm(arg1, rm)) {
scoped_mpf v2(m_util.fm()), v3(m_util.fm());
if (m_util.is_value(arg2, v2) && m_util.is_value(arg3, v3)) {
scoped_mpf t(m_util.fm());
m_util.fm().mul(rm, v2, v3, t);
result = m_util.mk_value(t);
return BR_DONE;
}
}
return BR_FAILED;
}
br_status float_rewriter::mk_div(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) {
mpf_rounding_mode rm;
if (m_util.is_rm(arg1, rm)) {
scoped_mpf v2(m_util.fm()), v3(m_util.fm());
if (m_util.is_value(arg2, v2) && m_util.is_value(arg3, v3)) {
scoped_mpf t(m_util.fm());
m_util.fm().div(rm, v2, v3, t);
result = m_util.mk_value(t);
return BR_DONE;
}
}
return BR_FAILED;
}
br_status float_rewriter::mk_uminus(expr * arg1, expr_ref & result) {
if (m_util.is_nan(arg1)) {
// -nan --> nan
result = arg1;
return BR_DONE;
}
if (m_util.is_plus_inf(arg1)) {
// - +oo --> -oo
result = m_util.mk_minus_inf(m().get_sort(arg1));
return BR_DONE;
}
if (m_util.is_minus_inf(arg1)) {
// - -oo -> +oo
result = m_util.mk_plus_inf(m().get_sort(arg1));
return BR_DONE;
}
if (m_util.is_uminus(arg1)) {
// - - a --> a
result = to_app(arg1)->get_arg(0);
return BR_DONE;
}
scoped_mpf v1(m_util.fm());
if (m_util.is_value(arg1, v1)) {
m_util.fm().neg(v1);
result = m_util.mk_value(v1);
return BR_DONE;
}
// TODO: more simplifications
return BR_FAILED;
}
br_status float_rewriter::mk_rem(expr * arg1, expr * arg2, expr_ref & result) {
scoped_mpf v1(m_util.fm()), v2(m_util.fm());
if (m_util.is_value(arg1, v1) && m_util.is_value(arg2, v2)) {
scoped_mpf t(m_util.fm());
m_util.fm().rem(v1, v2, t);
result = m_util.mk_value(t);
return BR_DONE;
}
return BR_FAILED;
}
br_status float_rewriter::mk_abs(expr * arg1, expr_ref & result) {
if (m_util.is_nan(arg1)) {
result = arg1;
return BR_DONE;
}
sort * s = m().get_sort(arg1);
result = m().mk_ite(m_util.mk_lt(arg1, m_util.mk_pzero(s)),
m_util.mk_uminus(arg1),
arg1);
return BR_REWRITE2;
}
br_status float_rewriter::mk_min(expr * arg1, expr * arg2, expr_ref & result) {
if (m_util.is_nan(arg1)) {
result = arg2;
return BR_DONE;
}
if (m_util.is_nan(arg2)) {
result = arg1;
return BR_DONE;
}
// expand as using ite's
result = m().mk_ite(mk_eq_nan(arg1),
arg2,
m().mk_ite(mk_eq_nan(arg2),
arg1,
m().mk_ite(m_util.mk_lt(arg1, arg2),
arg1,
arg2)));
return BR_REWRITE_FULL;
}
br_status float_rewriter::mk_max(expr * arg1, expr * arg2, expr_ref & result) {
if (m_util.is_nan(arg1)) {
result = arg2;
return BR_DONE;
}
if (m_util.is_nan(arg2)) {
result = arg1;
return BR_DONE;
}
// expand as using ite's
result = m().mk_ite(mk_eq_nan(arg1),
arg2,
m().mk_ite(mk_eq_nan(arg2),
arg1,
m().mk_ite(m_util.mk_gt(arg1, arg2),
arg1,
arg2)));
return BR_REWRITE_FULL;
}
br_status float_rewriter::mk_fused_ma(expr * arg1, expr * arg2, expr * arg3, expr * arg4, expr_ref & result) {
mpf_rounding_mode rm;
if (m_util.is_rm(arg1, rm)) {
scoped_mpf v2(m_util.fm()), v3(m_util.fm()), v4(m_util.fm());
if (m_util.is_value(arg2, v2) && m_util.is_value(arg3, v3) && m_util.is_value(arg4, v4)) {
scoped_mpf t(m_util.fm());
m_util.fm().fused_mul_add(rm, v2, v3, v4, t);
result = m_util.mk_value(t);
return BR_DONE;
}
}
return BR_FAILED;
}
br_status float_rewriter::mk_sqrt(expr * arg1, expr * arg2, expr_ref & result) {
mpf_rounding_mode rm;
if (m_util.is_rm(arg1, rm)) {
scoped_mpf v2(m_util.fm());
if (m_util.is_value(arg2, v2)) {
scoped_mpf t(m_util.fm());
m_util.fm().sqrt(rm, v2, t);
result = m_util.mk_value(t);
return BR_DONE;
}
}
return BR_FAILED;
}
br_status float_rewriter::mk_round(expr * arg1, expr * arg2, expr_ref & result) {
mpf_rounding_mode rm;
if (m_util.is_rm(arg1, rm)) {
scoped_mpf v2(m_util.fm());
if (m_util.is_value(arg2, v2)) {
scoped_mpf t(m_util.fm());
m_util.fm().round_to_integral(rm, v2, t);
result = m_util.mk_value(t);
return BR_DONE;
}
}
return BR_FAILED;
}
// This the floating point theory ==
br_status float_rewriter::mk_float_eq(expr * arg1, expr * arg2, expr_ref & result) {
scoped_mpf v1(m_util.fm()), v2(m_util.fm());
if (m_util.is_value(arg1, v1) && m_util.is_value(arg2, v2)) {
result = (m_util.fm().eq(v1, v2)) ? m().mk_true() : m().mk_false();
return BR_DONE;
}
return BR_FAILED;
}
// Return (= arg NaN)
app * float_rewriter::mk_eq_nan(expr * arg) {
return m().mk_eq(arg, m_util.mk_nan(m().get_sort(arg)));
}
// Return (not (= arg NaN))
app * float_rewriter::mk_neq_nan(expr * arg) {
return m().mk_not(mk_eq_nan(arg));
}
br_status float_rewriter::mk_lt(expr * arg1, expr * arg2, expr_ref & result) {
if (m_util.is_nan(arg1) || m_util.is_nan(arg2)) {
result = m().mk_false();
return BR_DONE;
}
if (m_util.is_minus_inf(arg1)) {
// -oo < arg2 --> not(arg2 = -oo) and not(arg2 = NaN)
result = m().mk_and(m().mk_not(m().mk_eq(arg2, arg1)), mk_neq_nan(arg2));
return BR_REWRITE2;
}
if (m_util.is_minus_inf(arg2)) {
// arg1 < -oo --> false
result = m().mk_false();
return BR_DONE;
}
if (m_util.is_plus_inf(arg1)) {
// +oo < arg2 --> false
result = m().mk_false();
return BR_DONE;
}
if (m_util.is_plus_inf(arg2)) {
// arg1 < +oo --> not(arg1 = +oo) and not(arg1 = NaN)
result = m().mk_and(m().mk_not(m().mk_eq(arg1, arg2)), mk_neq_nan(arg1));
return BR_REWRITE2;
}
scoped_mpf v1(m_util.fm()), v2(m_util.fm());
if (m_util.is_value(arg1, v1) && m_util.is_value(arg2, v2)) {
result = (m_util.fm().lt(v1, v2)) ? m().mk_true() : m().mk_false();
return BR_DONE;
}
// TODO: more simplifications
return BR_FAILED;
}
br_status float_rewriter::mk_gt(expr * arg1, expr * arg2, expr_ref & result) {
result = m_util.mk_lt(arg2, arg1);
return BR_REWRITE1;
}
br_status float_rewriter::mk_le(expr * arg1, expr * arg2, expr_ref & result) {
if (m_util.is_nan(arg1) || m_util.is_nan(arg2)) {
result = m().mk_false();
return BR_DONE;
}
scoped_mpf v1(m_util.fm()), v2(m_util.fm());
if (m_util.is_value(arg1, v1) && m_util.is_value(arg2, v2)) {
result = (m_util.fm().le(v1, v2)) ? m().mk_true() : m().mk_false();
return BR_DONE;
}
return BR_FAILED;
}
br_status float_rewriter::mk_ge(expr * arg1, expr * arg2, expr_ref & result) {
result = m_util.mk_le(arg2, arg1);
return BR_REWRITE1;
}
br_status float_rewriter::mk_is_zero(expr * arg1, expr_ref & result) {
scoped_mpf v(m_util.fm());
if (m_util.is_value(arg1, v)) {
result = (m_util.fm().is_zero(v)) ? m().mk_true() : m().mk_false();
return BR_DONE;
}
return BR_FAILED;
}
br_status float_rewriter::mk_is_nzero(expr * arg1, expr_ref & result) {
scoped_mpf v(m_util.fm());
if (m_util.is_value(arg1, v)) {
result = (m_util.fm().is_nzero(v)) ? m().mk_true() : m().mk_false();
return BR_DONE;
}
return BR_FAILED;
}
br_status float_rewriter::mk_is_pzero(expr * arg1, expr_ref & result) {
scoped_mpf v(m_util.fm());
if (m_util.is_value(arg1, v)) {
result = (m_util.fm().is_pzero(v)) ? m().mk_true() : m().mk_false();
return BR_DONE;
}
return BR_FAILED;
}
br_status float_rewriter::mk_is_sign_minus(expr * arg1, expr_ref & result) {
scoped_mpf v(m_util.fm());
if (m_util.is_value(arg1, v)) {
result = (m_util.fm().is_neg(v)) ? m().mk_true() : m().mk_false();
return BR_DONE;
}
return BR_FAILED;
}
// This the SMT =
br_status float_rewriter::mk_eq_core(expr * arg1, expr * arg2, expr_ref & result) {
scoped_mpf v1(m_util.fm()), v2(m_util.fm());
if (m_util.is_value(arg1, v1) && m_util.is_value(arg2, v2)) {
result = (v1 == v2) ? m().mk_true() : m().mk_false();
return BR_DONE;
}
return BR_FAILED;
}

View file

@ -1,72 +0,0 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
float_rewriter.h
Abstract:
Basic rewriting rules for floating point numbers.
Author:
Leonardo (leonardo) 2012-02-02
Notes:
--*/
#ifndef _FLOAT_REWRITER_H_
#define _FLOAT_REWRITER_H_
#include"ast.h"
#include"rewriter.h"
#include"params.h"
#include"float_decl_plugin.h"
#include"mpf.h"
class float_rewriter {
float_util m_util;
mpf_manager m_fm;
app * mk_eq_nan(expr * arg);
app * mk_neq_nan(expr * arg);
public:
float_rewriter(ast_manager & m, params_ref const & p = params_ref());
~float_rewriter();
ast_manager & m() const { return m_util.m(); }
family_id get_fid() const { return m_util.get_fid(); }
void updt_params(params_ref const & p);
static void get_param_descrs(param_descrs & r);
br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
br_status mk_eq_core(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_to_float(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
br_status mk_add(expr * arg1, expr * arg2, expr * arg3, expr_ref & result);
br_status mk_sub(expr * arg1, expr * arg2, expr * arg3, expr_ref & result);
br_status mk_mul(expr * arg1, expr * arg2, expr * arg3, expr_ref & result);
br_status mk_div(expr * arg1, expr * arg2, expr * arg3, expr_ref & result);
br_status mk_uminus(expr * arg1, expr_ref & result);
br_status mk_rem(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_abs(expr * arg1, expr_ref & result);
br_status mk_min(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_max(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_fused_ma(expr * arg1, expr * arg2, expr * arg3, expr * arg4, expr_ref & result);
br_status mk_sqrt(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_round(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_float_eq(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_lt(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_gt(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_le(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_ge(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_is_zero(expr * arg1, expr_ref & result);
br_status mk_is_nzero(expr * arg1, expr_ref & result);
br_status mk_is_pzero(expr * arg1, expr_ref & result);
br_status mk_is_sign_minus(expr * arg1, expr_ref & result);
};
#endif

View file

@ -1,630 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
goal.cpp
Abstract:
Proof / Model finding Goals
Author:
Leonardo de Moura (leonardo) 2011-10-12
Revision History:
--*/
#include"goal.h"
#include"cmd_context.h"
#include"ast_ll_pp.h"
#include"ast_smt2_pp.h"
#include"for_each_expr.h"
#include"well_sorted.h"
std::ostream & operator<<(std::ostream & out, goal::precision p) {
switch (p) {
case goal::PRECISE: out << "precise"; break;
case goal::UNDER: out << "under"; break;
case goal::OVER: out << "over"; break;
case goal::UNDER_OVER: out << "under-over"; break;
}
return out;
}
void goal::copy_to(goal & target) const {
SASSERT(&m_manager == &(target.m_manager));
if (this == &target)
return;
m().copy(m_forms, target.m_forms);
m().copy(m_proofs, target.m_proofs);
m().copy(m_dependencies, target.m_dependencies);
target.m_depth = std::max(m_depth, target.m_depth);
SASSERT(target.m_proofs_enabled == m_proofs_enabled);
SASSERT(target.m_core_enabled == m_core_enabled);
target.m_inconsistent = m_inconsistent;
target.m_precision = mk_union(prec(), target.prec());
}
void goal::push_back(expr * f, proof * pr, expr_dependency * d) {
if (m().is_true(f))
return;
if (m().is_false(f)) {
m().del(m_forms);
m().del(m_proofs);
m().del(m_dependencies);
m_inconsistent = true;
}
else {
SASSERT(!m_inconsistent);
}
m().push_back(m_forms, f);
if (proofs_enabled())
m().push_back(m_proofs, pr);
if (unsat_core_enabled())
m().push_back(m_dependencies, d);
}
void goal::quick_process(bool save_first, expr * & f, expr_dependency * d) {
if (!m().is_and(f) && !(m().is_not(f) && m().is_or(to_app(f)->get_arg(0)))) {
if (!save_first) {
push_back(f, 0, d);
}
return;
}
typedef std::pair<expr *, bool> expr_pol;
sbuffer<expr_pol, 64> todo;
todo.push_back(expr_pol(f, true));
while (!todo.empty()) {
if (m_inconsistent)
return;
expr_pol p = todo.back();
expr * curr = p.first;
bool pol = p.second;
todo.pop_back();
if (pol && m().is_and(curr)) {
app * t = to_app(curr);
unsigned i = t->get_num_args();
while (i > 0) {
--i;
todo.push_back(expr_pol(t->get_arg(i), true));
}
}
else if (!pol && m().is_or(curr)) {
app * t = to_app(curr);
unsigned i = t->get_num_args();
while (i > 0) {
--i;
todo.push_back(expr_pol(t->get_arg(i), false));
}
}
else if (m().is_not(curr)) {
todo.push_back(expr_pol(to_app(curr)->get_arg(0), !pol));
}
else {
if (!pol)
curr = m().mk_not(curr);
if (save_first) {
f = curr;
save_first = false;
}
else {
push_back(curr, 0, d);
}
}
}
}
void goal::process_and(bool save_first, app * f, proof * pr, expr_dependency * d, expr_ref & out_f, proof_ref & out_pr) {
unsigned num = f->get_num_args();
for (unsigned i = 0; i < num; i++) {
if (m_inconsistent)
return;
slow_process(save_first && i == 0, f->get_arg(i), m().mk_and_elim(pr, i), d, out_f, out_pr);
}
}
void goal::process_not_or(bool save_first, app * f, proof * pr, expr_dependency * d, expr_ref & out_f, proof_ref & out_pr) {
unsigned num = f->get_num_args();
for (unsigned i = 0; i < num; i++) {
if (m_inconsistent)
return;
expr * child = f->get_arg(i);
if (m().is_not(child)) {
expr * not_child = to_app(child)->get_arg(0);
slow_process(save_first && i == 0, not_child, m().mk_not_or_elim(pr, i), d, out_f, out_pr);
}
else {
expr_ref not_child(m());
not_child = m().mk_not(child);
slow_process(save_first && i == 0, not_child, m().mk_not_or_elim(pr, i), d, out_f, out_pr);
}
}
}
void goal::slow_process(bool save_first, expr * f, proof * pr, expr_dependency * d, expr_ref & out_f, proof_ref & out_pr) {
if (m().is_and(f))
process_and(save_first, to_app(f), pr, d, out_f, out_pr);
else if (m().is_not(f) && m().is_or(to_app(f)->get_arg(0)))
process_not_or(save_first, to_app(to_app(f)->get_arg(0)), pr, d, out_f, out_pr);
else if (save_first) {
out_f = f;
out_pr = pr;
}
else {
push_back(f, pr, d);
}
}
void goal::slow_process(expr * f, proof * pr, expr_dependency * d) {
expr_ref out_f(m());
proof_ref out_pr(m());
slow_process(false, f, pr, d, out_f, out_pr);
}
void goal::assert_expr(expr * f, proof * pr, expr_dependency * d) {
SASSERT(proofs_enabled() == (pr != 0 && !m().is_undef_proof(pr)));
if (m_inconsistent)
return;
if (proofs_enabled())
slow_process(f, pr, d);
else
quick_process(false, f, d);
}
void goal::get_formulas(ptr_vector<expr> & result) {
unsigned sz = size();
for (unsigned i = 0; i < sz; i++) {
result.push_back(form(i));
}
}
void goal::update(unsigned i, expr * f, proof * pr, expr_dependency * d) {
SASSERT(proofs_enabled() == (pr != 0 && !m().is_undef_proof(pr)));
if (m_inconsistent)
return;
if (proofs_enabled()) {
expr_ref out_f(m());
proof_ref out_pr(m());
slow_process(true, f, pr, d, out_f, out_pr);
if (!m_inconsistent) {
if (m().is_false(out_f)) {
push_back(out_f, out_pr, d);
}
else {
m().set(m_forms, i, out_f);
m().set(m_proofs, i, out_pr);
if (unsat_core_enabled())
m().set(m_dependencies, i, d);
}
}
}
else {
quick_process(true, f, d);
if (!m_inconsistent) {
if (m().is_false(f)) {
push_back(f, 0, d);
}
else {
m().set(m_forms, i, f);
if (unsat_core_enabled())
m().set(m_dependencies, i, d);
}
}
}
}
void goal::reset_core() {
m().del(m_forms);
m().del(m_proofs);
m().del(m_dependencies);
}
void goal::reset_all() {
reset_core();
m_depth = 0;
m_inconsistent = false;
m_precision = PRECISE;
}
void goal::reset() {
reset_core();
m_inconsistent = false;
}
void goal::display(cmd_context & ctx, std::ostream & out) const {
out << "(goal";
unsigned sz = size();
for (unsigned i = 0; i < sz; i++) {
out << "\n ";
ctx.display(out, form(i), 2);
}
out << "\n :precision " << prec() << " :depth " << depth() << ")" << std::endl;
}
void goal::display_with_dependencies(cmd_context & ctx, std::ostream & out) const {
ptr_vector<expr> deps;
obj_hashtable<expr> to_pp;
out << "(goal";
unsigned sz = size();
for (unsigned i = 0; i < sz; i++) {
out << "\n |-";
deps.reset();
m().linearize(dep(i), deps);
ptr_vector<expr>::iterator it = deps.begin();
ptr_vector<expr>::iterator end = deps.end();
for (; it != end; ++it) {
expr * d = *it;
if (is_uninterp_const(d)) {
out << " " << mk_ismt2_pp(d, m());
}
else {
out << " #" << d->get_id();
to_pp.insert(d);
}
}
out << "\n ";
ctx.display(out, form(i), 2);
}
if (!to_pp.empty()) {
out << "\n :dependencies-definitions (";
obj_hashtable<expr>::iterator it = to_pp.begin();
obj_hashtable<expr>::iterator end = to_pp.end();
for (; it != end; ++it) {
expr * d = *it;
out << "\n (#" << d->get_id() << "\n ";
ctx.display(out, d, 2);
out << ")";
}
out << ")";
}
out << "\n :precision " << prec() << " :depth " << depth() << ")" << std::endl;
}
void goal::display_with_dependencies(std::ostream & out) const {
ptr_vector<expr> deps;
out << "(goal";
unsigned sz = size();
for (unsigned i = 0; i < sz; i++) {
out << "\n |-";
deps.reset();
m().linearize(dep(i), deps);
ptr_vector<expr>::iterator it = deps.begin();
ptr_vector<expr>::iterator end = deps.end();
for (; it != end; ++it) {
expr * d = *it;
if (is_uninterp_const(d)) {
out << " " << mk_ismt2_pp(d, m());
}
else {
out << " #" << d->get_id();
}
}
out << "\n " << mk_ismt2_pp(form(i), m(), 2);
}
out << "\n :precision " << prec() << " :depth " << depth() << ")" << std::endl;
}
void goal::display(cmd_context & ctx) const {
display(ctx, ctx.regular_stream());
}
void goal::display_with_dependencies(cmd_context & ctx) const {
display_with_dependencies(ctx, ctx.regular_stream());
}
void goal::display(std::ostream & out) const {
out << "(goal";
unsigned sz = size();
for (unsigned i = 0; i < sz; i++) {
out << "\n ";
out << mk_ismt2_pp(form(i), m(), 2);
}
out << ")" << std::endl;
}
void goal::display_as_and(std::ostream & out) const {
ptr_buffer<expr> args;
unsigned sz = size();
for (unsigned i = 0; i < sz; i++)
args.push_back(form(i));
expr_ref tmp(m());
tmp = m().mk_and(args.size(), args.c_ptr());
out << mk_ismt2_pp(tmp, m()) << "\n";
}
void goal::display_ll(std::ostream & out) const {
unsigned sz = size();
for (unsigned i = 0; i < sz; i++) {
out << mk_ll_pp(form(i), m()) << "\n";
}
}
/**
\brief Assumes that the formula is already in CNF.
*/
void goal::display_dimacs(std::ostream & out) const {
obj_map<expr, unsigned> expr2var;
unsigned num_vars = 0;
unsigned num_cls = size();
for (unsigned i = 0; i < num_cls; i++) {
expr * f = form(i);
unsigned num_lits;
expr * const * lits;
if (m().is_or(f)) {
num_lits = to_app(f)->get_num_args();
lits = to_app(f)->get_args();
}
else {
num_lits = 1;
lits = &f;
}
for (unsigned j = 0; j < num_lits; j++) {
expr * l = lits[j];
if (m().is_not(l))
l = to_app(l)->get_arg(0);
if (expr2var.contains(l))
continue;
num_vars++;
expr2var.insert(l, num_vars);
}
}
out << "p cnf " << num_vars << " " << num_cls << "\n";
for (unsigned i = 0; i < num_cls; i++) {
expr * f = form(i);
unsigned num_lits;
expr * const * lits;
if (m().is_or(f)) {
num_lits = to_app(f)->get_num_args();
lits = to_app(f)->get_args();
}
else {
num_lits = 1;
lits = &f;
}
for (unsigned j = 0; j < num_lits; j++) {
expr * l = lits[j];
if (m().is_not(l)) {
out << "-";
l = to_app(l)->get_arg(0);
}
unsigned id = UINT_MAX;
expr2var.find(l, id);
SASSERT(id != UINT_MAX);
out << id << " ";
}
out << "0\n";
}
}
unsigned goal::num_exprs() const {
expr_fast_mark1 visited;
unsigned sz = size();
unsigned r = 0;
for (unsigned i = 0; i < sz; i++) {
r += get_num_exprs(form(i), visited);
}
return r;
}
void goal::shrink(unsigned j) {
SASSERT(j <= size());
unsigned sz = size();
for (unsigned i = j; i < sz; i++)
m().pop_back(m_forms);
if (proofs_enabled()) {
for (unsigned i = j; i < sz; i++)
m().pop_back(m_proofs);
}
if (unsat_core_enabled()) {
for (unsigned i = j; i < sz; i++)
m().pop_back(m_dependencies);
}
}
/**
\brief Eliminate true formulas.
*/
void goal::elim_true() {
unsigned sz = size();
unsigned j = 0;
for (unsigned i = 0; i < sz; i++) {
expr * f = form(i);
if (m().is_true(f))
continue;
if (i == j) {
j++;
continue;
}
m().set(m_forms, j, f);
if (proofs_enabled())
m().set(m_proofs, j, m().get(m_proofs, i));
if (unsat_core_enabled())
m().set(m_dependencies, j, m().get(m_dependencies, i));
j++;
}
shrink(j);
}
/**
\brief Return the position of formula f in the goal.
Return UINT_MAX if f is not in the goal
*/
unsigned goal::get_idx(expr * f) const {
unsigned sz = size();
for (unsigned j = 0; j < sz; j++) {
if (form(j) == f)
return j;
}
return UINT_MAX;
}
/**
\brief Return the position of formula (not f) in the goal.
Return UINT_MAX if (not f) is not in the goal
*/
unsigned goal::get_not_idx(expr * f) const {
expr * atom;
unsigned sz = size();
for (unsigned j = 0; j < sz; j++) {
if (m().is_not(form(j), atom) && atom == f)
return j;
}
return UINT_MAX;
}
void goal::elim_redundancies() {
if (inconsistent())
return;
expr_ref_fast_mark1 neg_lits(m());
expr_ref_fast_mark2 pos_lits(m());
unsigned sz = size();
unsigned j = 0;
for (unsigned i = 0; i < sz; i++) {
expr * f = form(i);
if (m().is_true(f))
continue;
if (m().is_not(f)) {
expr * atom = to_app(f)->get_arg(0);
if (neg_lits.is_marked(atom))
continue;
if (pos_lits.is_marked(atom)) {
proof * p = 0;
if (proofs_enabled()) {
proof * prs[2] = { pr(get_idx(atom)), pr(i) };
p = m().mk_unit_resolution(2, prs);
}
expr_dependency_ref d(m());
if (unsat_core_enabled())
d = m().mk_join(dep(get_idx(atom)), dep(i));
push_back(m().mk_false(), p, d);
return;
}
neg_lits.mark(atom);
}
else {
if (pos_lits.is_marked(f))
continue;
if (neg_lits.is_marked(f)) {
proof * p = 0;
if (proofs_enabled()) {
proof * prs[2] = { pr(get_not_idx(f)), pr(i) };
p = m().mk_unit_resolution(2, prs);
}
expr_dependency_ref d(m());
if (unsat_core_enabled())
d = m().mk_join(dep(get_not_idx(f)), dep(i));
push_back(m().mk_false(), p, d);
return;
}
pos_lits.mark(f);
}
if (i == j) {
j++;
continue;
}
m().set(m_forms, j, f);
if (proofs_enabled())
m().set(m_proofs, j, pr(i));
if (unsat_core_enabled())
m().set(m_dependencies, j, dep(i));
j++;
}
shrink(j);
}
bool goal::is_well_sorted() const {
unsigned sz = size();
for (unsigned i = 0; i < sz; i++) {
expr * t = form(i);
if (!::is_well_sorted(m(), t))
return false;
}
return true;
}
/**
\brief Assert expressions from ctx into t.
*/
void assert_exprs_from(cmd_context const & ctx, goal & t) {
if (ctx.produce_proofs() && ctx.produce_unsat_cores())
throw cmd_exception("Frontend does not support simultaneous generation of proofs and unsat cores");
ast_manager & m = t.m();
bool proofs_enabled = t.proofs_enabled();
ptr_vector<expr>::const_iterator it = ctx.begin_assertions();
ptr_vector<expr>::const_iterator end = ctx.end_assertions();
for (; it != end; ++it) {
t.assert_expr(*it, proofs_enabled ? m.mk_asserted(*it) : 0, 0);
}
if (ctx.produce_unsat_cores()) {
SASSERT(!ctx.produce_proofs());
it = ctx.begin_assumptions();
end = ctx.end_assumptions();
for (; it != end; ++it) {
t.assert_expr(*it, 0, m.mk_leaf(*it));
}
}
else {
SASSERT(ctx.begin_assumptions() == ctx.end_assumptions());
}
}
/**
\brief Translate the assertion set to a new one that uses a different ast_manager.
*/
goal * goal::translate(ast_translation & translator) const {
expr_dependency_translation dep_translator(translator);
ast_manager & m_to = translator.to();
goal * res = alloc(goal, m_to, m_to.proofs_enabled() && proofs_enabled(), models_enabled(), unsat_core_enabled());
unsigned sz = m().size(m_forms);
for (unsigned i = 0; i < sz; i++) {
res->m().push_back(res->m_forms, translator(m().get(m_forms, i)));
if (res->proofs_enabled())
res->m().push_back(res->m_proofs, translator(m().get(m_proofs, i)));
if (res->unsat_core_enabled())
res->m().push_back(res->m_dependencies, dep_translator(m().get(m_dependencies, i)));
}
res->m_inconsistent = m_inconsistent;
res->m_depth = m_depth;
res->m_precision = m_precision;
return res;
}
bool is_equal(goal const & s1, goal const & s2) {
if (s1.size() != s2.size())
return false;
unsigned num1 = 0; // num unique ASTs in s1
unsigned num2 = 0; // num unique ASTs in s2
expr_fast_mark1 visited1;
expr_fast_mark2 visited2;
unsigned sz = s1.size();
for (unsigned i = 0; i < sz; i++) {
expr * f1 = s1.form(i);
if (visited1.is_marked(f1))
continue;
num1++;
visited1.mark(f1);
}
SASSERT(num1 <= sz);
SASSERT(0 <= num1);
for (unsigned i = 0; i < sz; i++) {
expr * f2 = s2.form(i);
if (visited2.is_marked(f2))
continue;
num2++;
visited2.mark(f2);
if (!visited1.is_marked(f2))
return false;
}
SASSERT(num2 <= sz);
SASSERT(0 <= num2);
SASSERT(num1 >= num2);
return num1 == num2;
}

View file

@ -1,255 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
goal.h
Abstract:
A goal is essentially a set of formulas. Tactics are used to build
proof and model finding procedures for these sets.
Remark: In a previous version of Z3, goals were called assertion_sets.
Here is a summary of the main changes:
- Goals track whether they are the result of applying over/under approximation steps.
This prevent users from creating unsound strategies (e.g., user uses nia2sat, but does not check the sat_preserving flag).
- Goals track dependencies (aka light proofs) for unsat core extraction, and building multi-tier solvers.
This kind of dependency tracking is more powerful than the one used in the current Z3, since
it does not prevent the use of preprocessing steps such as "Gaussian Elimination".
Author:
Leonardo de Moura (leonardo) 2011-10-12
Revision History:
--*/
#ifndef _GOAL_H_
#define _GOAL_H_
#include"ast.h"
#include"ast_translation.h"
#include"for_each_expr.h"
#include"ref.h"
#include"ref_vector.h"
#include"ref_buffer.h"
class cmd_context;
class goal {
public:
enum precision {
PRECISE,
UNDER, // goal is the product of an under-approximation
OVER, // goal is the product of an over-approximation
UNDER_OVER // goal is garbage: the produce of combined under and over approximation steps.
};
static precision mk_union(precision p1, precision p2) {
if (p1 == PRECISE) return p2;
if (p2 == PRECISE) return p1;
if (p1 != p2) return UNDER_OVER;
return p1;
}
protected:
ast_manager & m_manager;
unsigned m_ref_count;
expr_array m_forms;
expr_array m_proofs;
expr_dependency_array m_dependencies;
// attributes
unsigned m_depth:26; // depth of the goal in the goal tree.
unsigned m_models_enabled:1; // model generation is enabled.
unsigned m_proofs_enabled:1; // proof production is enabled. m_manager.proofs_enabled() must be true if m_proofs_enabled == true
unsigned m_core_enabled:1; // unsat core extraction is enabled.
unsigned m_inconsistent:1; // true if the goal is known to be inconsistent.
unsigned m_precision:2; // PRECISE, UNDER, OVER.
void push_back(expr * f, proof * pr, expr_dependency * d);
void quick_process(bool save_first, expr * & f, expr_dependency * d);
void process_and(bool save_first, app * f, proof * pr, expr_dependency * d, expr_ref & out_f, proof_ref & out_pr);
void process_not_or(bool save_first, app * f, proof * pr, expr_dependency * d, expr_ref & out_f, proof_ref & out_pr);
void slow_process(bool save_first, expr * f, proof * pr, expr_dependency * d, expr_ref & out_f, proof_ref & out_pr);
void slow_process(expr * f, proof * pr, expr_dependency * d);
unsigned get_idx(expr * f) const;
unsigned get_not_idx(expr * f) const;
void shrink(unsigned j);
void reset_core();
public:
goal(ast_manager & m, bool models_enabled = true, bool core_enabled = false):
m_manager(m),
m_ref_count(0),
m_depth(0),
m_models_enabled(models_enabled),
m_proofs_enabled(m.proofs_enabled()),
m_core_enabled(core_enabled),
m_inconsistent(false),
m_precision(PRECISE) {
}
goal(ast_manager & m, bool proofs_enabled, bool models_enabled, bool core_enabled):
m_manager(m),
m_ref_count(0),
m_depth(0),
m_models_enabled(models_enabled),
m_proofs_enabled(proofs_enabled),
m_core_enabled(core_enabled),
m_inconsistent(false),
m_precision(PRECISE) {
SASSERT(!proofs_enabled || m.proofs_enabled());
}
goal(goal const & src):
m_manager(src.m()),
m_ref_count(0),
m_depth(0),
m_models_enabled(src.models_enabled()),
m_proofs_enabled(src.proofs_enabled()),
m_core_enabled(src.unsat_core_enabled()),
m_inconsistent(false),
m_precision(PRECISE) {
copy_from(src);
}
// Copy configuration: depth, models/proofs/cores flags, and precision from src.
// The assertions are not copied
goal(goal const & src, bool):
m_manager(src.m()),
m_ref_count(0),
m_depth(src.m_depth),
m_models_enabled(src.models_enabled()),
m_proofs_enabled(src.proofs_enabled()),
m_core_enabled(src.unsat_core_enabled()),
m_inconsistent(false),
m_precision(src.m_precision) {
}
~goal() { reset_core(); }
void inc_ref() { ++m_ref_count; }
void dec_ref() { --m_ref_count; if (m_ref_count == 0) dealloc(this); }
ast_manager & m() const { return m_manager; }
unsigned depth() const { return m_depth; }
bool models_enabled() const { return m_models_enabled; }
bool proofs_enabled() const { return m_proofs_enabled; }
bool unsat_core_enabled() const { return m_core_enabled; }
bool inconsistent() const { return m_inconsistent; }
precision prec() const { return static_cast<precision>(m_precision); }
void set_depth(unsigned d) { m_depth = d; }
void inc_depth() { m_depth++; }
void set_prec(precision d) { m_precision = d; }
void updt_prec(precision d) { m_precision = mk_union(prec(), d); }
void reset_all(); // reset goal and precision and depth attributes.
void reset(); // reset goal but preserve precision and depth attributes.
void copy_to(goal & target) const;
void copy_from(goal const & src) { src.copy_to(*this); }
void assert_expr(expr * f, proof * pr, expr_dependency * d);
void assert_expr(expr * f) {
assert_expr(f, proofs_enabled() ? m().mk_asserted(f) : 0, 0);
}
unsigned size() const { return m().size(m_forms); }
unsigned num_exprs() const;
expr * form(unsigned i) const { return m().get(m_forms, i); }
proof * pr(unsigned i) const { return proofs_enabled() ? static_cast<proof*>(m().get(m_proofs, i)) : 0; }
expr_dependency * dep(unsigned i) const { return unsat_core_enabled() ? m().get(m_dependencies, i) : 0; }
void update(unsigned i, expr * f, proof * pr = 0, expr_dependency * dep = 0);
void get_formulas(ptr_vector<expr> & result);
void elim_true();
void elim_redundancies();
void display(cmd_context & ctx, std::ostream & out) const;
void display(cmd_context & ctx) const;
void display(std::ostream & out) const;
void display_ll(std::ostream & out) const;
void display_as_and(std::ostream & out) const;
void display_dimacs(std::ostream & out) const;
void display_with_dependencies(cmd_context & ctx, std::ostream & out) const;
void display_with_dependencies(cmd_context & ctx) const;
void display_with_dependencies(std::ostream & out) const;
bool sat_preserved() const {
return prec() == PRECISE || prec() == UNDER;
}
bool unsat_preserved() const {
return prec() == PRECISE || prec() == OVER;
}
bool is_decided_sat() const {
return size() == 0 && sat_preserved();
}
bool is_decided_unsat() const {
return inconsistent() && unsat_preserved();
}
bool is_decided() const {
return is_decided_sat() || is_decided_unsat();
}
bool is_well_sorted() const;
goal * translate(ast_translation & translator) const;
};
std::ostream & operator<<(std::ostream & out, goal::precision p);
typedef ref<goal> goal_ref;
typedef sref_vector<goal> goal_ref_vector;
typedef sref_buffer<goal> goal_ref_buffer;
template<typename GoalCollection>
inline bool is_decided(GoalCollection const & c) { return c.size() == 1 && c[0]->is_decided(); }
template<typename GoalCollection>
inline bool is_decided_sat(GoalCollection const & c) { return c.size() == 1 && c[0]->is_decided_sat(); }
template<typename GoalCollection>
inline bool is_decided_unsat(GoalCollection const & c) { return c.size() == 1 && c[0]->is_decided_unsat(); }
void assert_exprs_from(cmd_context const & ctx, goal & t);
template<typename ForEachProc>
void for_each_expr_at(ForEachProc& proc, goal const & s) {
expr_mark visited;
for (unsigned i = 0; i < s.size(); ++i) {
for_each_expr(proc, visited, s.form(i));
}
}
bool is_equal(goal const & g1, goal const & g2);
template<typename Predicate>
bool test(goal const & g, Predicate & proc) {
expr_fast_mark1 visited;
try {
unsigned sz = g.size();
for (unsigned i = 0; i < sz; i++)
quick_for_each_expr(proc, visited, g.form(i));
}
catch (typename Predicate::found) {
return true;
}
return false;
}
template<typename Predicate>
bool test(goal const & g) {
Predicate proc(g.m());
return test(g, proc);
}
#endif

View file

@ -1,115 +0,0 @@
/*++
Copyright (c) 2008 Microsoft Corporation
Module Name:
lockless_queue.h
Abstract:
A queue that doesn't require locking, as long as only
one thread pushes and another thread pops.
Author:
Christoph Wintersteiger (t-cwinte) 2008-12-26
Revision History:
--*/
#ifndef _LOCKLESS_QUEUE_H_
#define _LOCKLESS_QUEUE_H_
#include <new>
#include "debug.h"
template<typename T>
class lockless_queue {
protected:
unsigned m_head;
unsigned m_tail;
unsigned m_size;
T *m_items;
public:
typedef T value_type;
lockless_queue(unsigned size=4096) :
m_head(0),
m_tail(0),
m_size(size),
m_items(0) {
if(m_size>0) {
m_items = alloc_vect<T>(m_size);
SASSERT(m_items!=0);
}
}
lockless_queue(const lockless_queue &other) {
m_items = 0;
m_size = m_head = m_tail = 0;
this->operator=(other);
}
~lockless_queue() {
if(m_items) {
dealloc_vect(m_items, m_size);
m_items=0;
}
}
inline bool push(const T& elem) {
volatile unsigned head = m_head;
if(((head+1)%m_size) == m_tail)
return false; // queue is full.
m_items[head++] = elem;
head %= m_size;
m_head = head;
return true;
}
inline bool pop() {
volatile unsigned tail = m_tail;
if(tail == m_head)
return false; // queue is empty.
tail = (tail+1) % m_size;
m_tail = tail;
return true;
}
inline T& back() const {
SASSERT(!empty());
return m_items[m_tail];
}
inline bool empty() const {
return (m_tail == m_head);
}
inline bool full() const {
return (m_tail == ((m_head+1)%m_size));
}
lockless_queue& operator=(const lockless_queue &other) {
if(m_size!=other.m_size) {
if(m_items) dealloc_vect(m_items, m_size);
m_items = alloc_vect<T>(other.m_size);
m_size = other.m_size;
}
for(size_t cur = other.m_tail; cur!=other.m_head; cur = (cur+1)%m_size)
m_items[cur] = other.m_items[cur];
m_tail = other.m_tail;
m_head = other.m_head;
return *this;
}
};
#endif

View file

@ -1,167 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
poly_rewriter.h
Abstract:
Basic rewriting rules for Polynomials.
Author:
Leonardo (leonardo) 2011-04-08
Notes:
--*/
#ifndef _POLY_REWRITER_H_
#define _POLY_REWRITER_H_
#include"ast.h"
#include"obj_hashtable.h"
#include"rewriter_types.h"
#include"params.h"
template<typename Config>
class poly_rewriter : public Config {
public:
static char const * g_ste_blowup_msg;
protected:
typedef typename Config::numeral numeral;
sort * m_curr_sort;
obj_map<expr, unsigned> m_expr2pos;
bool m_flat;
bool m_som;
unsigned m_som_blowup;
bool m_sort_sums;
bool m_hoist_mul;
bool m_hoist_cmul;
bool is_numeral(expr * n) const { return Config::is_numeral(n); }
bool is_numeral(expr * n, numeral & r) const { return Config::is_numeral(n, r); }
bool is_zero(expr * n) const { return Config::is_zero(n); }
bool is_minus_one(expr * n) const { return Config::is_minus_one(n); }
void normalize(numeral & c) { Config::normalize(c, m_curr_sort); }
app * mk_numeral(numeral const & r) { return Config::mk_numeral(r, m_curr_sort); }
decl_kind add_decl_kind() const { return Config::add_decl_kind(); }
decl_kind mul_decl_kind() const { return Config::mul_decl_kind(); }
bool use_power() const { return Config::use_power(); }
decl_kind power_decl_kind() const { return Config::power_decl_kind(); }
bool is_power(expr * t) const { return is_app_of(t, get_fid(), power_decl_kind()); }
expr * get_power_body(expr * t, rational & k);
struct mon_pw_lt; // functor used to sort monomial elements when use_power() == true
expr * mk_mul_app(unsigned num_args, expr * const * args);
expr * mk_mul_app(numeral const & c, expr * arg);
expr * mk_add_app(unsigned num_args, expr * const * args);
br_status mk_flat_mul_core(unsigned num_args, expr * const * args, expr_ref & result);
br_status mk_nflat_mul_core(unsigned num_args, expr * const * args, expr_ref & result);
expr * get_power_product(expr * t);
expr * get_power_product(expr * t, numeral & a);
br_status mk_flat_add_core(unsigned num_args, expr * const * args, expr_ref & result);
br_status mk_nflat_add_core(unsigned num_args, expr * const * args, expr_ref & result);
void set_curr_sort(sort * s) { m_curr_sort = s; }
expr * const * get_monomials(expr * & t, unsigned & sz) {
if (is_add(t)) {
sz = to_app(t)->get_num_args();
return to_app(t)->get_args();
}
else {
sz = 1;
return &t;
}
}
br_status cancel_monomials(expr * lhs, expr * rhs, bool move, expr_ref & lhs_result, expr_ref & rhs_result);
bool hoist_multiplication(expr_ref& som);
expr* merge_muls(expr* x, expr* y);
struct hoist_cmul_lt;
bool is_mul(expr * t, numeral & c, expr * & pp);
void hoist_cmul(expr_ref_buffer & args);
public:
poly_rewriter(ast_manager & m, params_ref const & p = params_ref()):
Config(m),
m_curr_sort(0),
m_sort_sums(false) {
updt_params(p);
SASSERT(!m_som || m_flat); // som of monomials form requires flattening to be enabled.
SASSERT(!m_som || !m_hoist_mul); // som is mutually exclusive with hoisting multiplication.
updt_params(p);
}
ast_manager & m() const { return Config::m(); }
family_id get_fid() const { return Config::get_fid(); }
void updt_params(params_ref const & p);
static void get_param_descrs(param_descrs & r);
void set_flat(bool f) { m_flat = f; }
void set_sort_sums(bool f) { m_sort_sums = f; }
bool is_add(expr * n) const { return is_app_of(n, get_fid(), add_decl_kind()); }
bool is_mul(expr * n) const { return is_app_of(n, get_fid(), mul_decl_kind()); }
bool is_add(func_decl * f) const { return is_decl_of(f, get_fid(), add_decl_kind()); }
bool is_mul(func_decl * f) const { return is_decl_of(f, get_fid(), mul_decl_kind()); }
br_status mk_mul_core(unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(num_args > 0);
if (num_args == 1) {
result = args[0];
return BR_DONE;
}
set_curr_sort(m().get_sort(args[0]));
return m_flat ?
mk_flat_mul_core(num_args, args, result) :
mk_nflat_mul_core(num_args, args, result);
}
br_status mk_add_core(unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(num_args > 0);
if (num_args == 1) {
result = args[0];
return BR_DONE;
}
set_curr_sort(m().get_sort(args[0]));
return m_flat ?
mk_flat_add_core(num_args, args, result) :
mk_nflat_add_core(num_args, args, result);
}
void mk_add(unsigned num_args, expr * const * args, expr_ref & result) {
if (mk_add_core(num_args, args, result) == BR_FAILED)
result = mk_add_app(num_args, args);
}
void mk_add(expr* a1, expr* a2, expr_ref& result) {
expr* args[2] = { a1, a2 };
mk_add(2, args, result);
}
void mk_mul(unsigned num_args, expr * const * args, expr_ref & result) {
if (mk_mul_core(num_args, args, result) == BR_FAILED)
result = mk_mul_app(num_args, args);
}
void mk_mul(expr* a1, expr* a2, expr_ref& result) {
expr* args[2] = { a1, a2 };
mk_mul(2, args, result);
}
// The result of the following functions is never BR_FAILED
br_status mk_uminus(expr * arg, expr_ref & result);
br_status mk_sub(unsigned num_args, expr * const * args, expr_ref & result);
void mk_sub(expr* a1, expr* a2, expr_ref& result) {
expr* args[2] = { a1, a2 };
mk_sub(2, args, result);
}
};
#endif

View file

@ -1,933 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
poly_rewriter_def.h
Abstract:
Basic rewriting rules for Polynomials.
Author:
Leonardo (leonardo) 2011-04-08
Notes:
--*/
#include"poly_rewriter.h"
#include"ast_lt.h"
#include"ast_ll_pp.h"
#include"ast_smt2_pp.h"
template<typename Config>
char const * poly_rewriter<Config>::g_ste_blowup_msg = "sum of monomials blowup";
template<typename Config>
void poly_rewriter<Config>::updt_params(params_ref const & p) {
m_flat = p.get_bool(":flat", true);
m_som = p.get_bool(":som", false);
m_hoist_mul = p.get_bool(":hoist-mul", false);
m_hoist_cmul = p.get_bool(":hoist-cmul", false);
m_som_blowup = p.get_uint(":som-blowup", UINT_MAX);
}
template<typename Config>
void poly_rewriter<Config>::get_param_descrs(param_descrs & r) {
r.insert(":som", CPK_BOOL, "(default: false) put polynomials in som-of-monomials form.");
r.insert(":som-blowup", CPK_UINT, "(default: infty) maximum number of monomials generated when putting a polynomial in sum-of-monomials normal form");
r.insert(":hoist-mul", CPK_BOOL, "(default: false) hoist multiplication over summation to minimize number of multiplications");
r.insert(":hoist-cmul", CPK_BOOL, "(default: false) hoist constant multiplication over summation to minimize number of multiplications");
}
template<typename Config>
expr * poly_rewriter<Config>::mk_add_app(unsigned num_args, expr * const * args) {
switch (num_args) {
case 0: return mk_numeral(numeral(0));
case 1: return args[0];
default: return m().mk_app(get_fid(), add_decl_kind(), num_args, args);
}
}
// t = (^ x y) --> return x, and set k = y if k is an integer >= 1
// Otherwise return t and set k = 1
template<typename Config>
expr * poly_rewriter<Config>::get_power_body(expr * t, rational & k) {
if (!is_power(t)) {
k = rational(1);
return t;
}
if (is_numeral(to_app(t)->get_arg(1), k) && k.is_int() && k > rational(1)) {
return to_app(t)->get_arg(0);
}
k = rational(1);
return t;
}
template<typename Config>
expr * poly_rewriter<Config>::mk_mul_app(unsigned num_args, expr * const * args) {
switch (num_args) {
case 0:
return mk_numeral(numeral(1));
case 1:
return args[0];
default:
if (use_power()) {
rational k_prev;
expr * prev = get_power_body(args[0], k_prev);
rational k;
ptr_buffer<expr> new_args;
#define PUSH_POWER() { \
if (k_prev.is_one()) { \
new_args.push_back(prev); \
} \
else { \
expr * pargs[2] = { prev, mk_numeral(k_prev) }; \
new_args.push_back(m().mk_app(get_fid(), power_decl_kind(), 2, pargs)); \
} \
}
for (unsigned i = 1; i < num_args; i++) {
expr * arg = get_power_body(args[i], k);
if (arg == prev) {
k_prev += k;
}
else {
PUSH_POWER();
prev = arg;
k_prev = k;
}
}
PUSH_POWER();
SASSERT(new_args.size() > 0);
if (new_args.size() == 1) {
return new_args[0];
}
else {
return m().mk_app(get_fid(), mul_decl_kind(), new_args.size(), new_args.c_ptr());
}
}
else {
return m().mk_app(get_fid(), mul_decl_kind(), num_args, args);
}
}
}
template<typename Config>
expr * poly_rewriter<Config>::mk_mul_app(numeral const & c, expr * arg) {
if (c.is_one()) {
return arg;
}
else {
expr * new_args[2] = { mk_numeral(c), arg };
return mk_mul_app(2, new_args);
}
}
template<typename Config>
br_status poly_rewriter<Config>::mk_flat_mul_core(unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(num_args >= 2);
// only try to apply flattening if it is not already in one of the flat monomial forms
// - (* c x)
// - (* c (* x_1 ... x_n))
if (num_args != 2 || !is_numeral(args[0]) || (is_mul(args[1]) && is_numeral(to_app(args[1])->get_arg(0)))) {
unsigned i;
for (i = 0; i < num_args; i++) {
if (is_mul(args[i]))
break;
}
if (i < num_args) {
// input has nested monomials.
ptr_buffer<expr> flat_args;
// we need the todo buffer to handle: (* (* c (* x_1 ... x_n)) (* d (* y_1 ... y_n)))
ptr_buffer<expr> todo;
flat_args.append(i, args);
for (unsigned j = i; j < num_args; j++) {
if (is_mul(args[j])) {
todo.push_back(args[j]);
while (!todo.empty()) {
expr * curr = todo.back();
todo.pop_back();
if (is_mul(curr)) {
unsigned k = to_app(curr)->get_num_args();
while (k > 0) {
--k;
todo.push_back(to_app(curr)->get_arg(k));
}
}
else {
flat_args.push_back(curr);
}
}
}
else {
flat_args.push_back(args[j]);
}
}
TRACE("poly_rewriter",
tout << "flat mul:\n";
for (unsigned i = 0; i < num_args; i++) tout << mk_bounded_pp(args[i], m()) << "\n";
tout << "---->\n";
for (unsigned i = 0; i < flat_args.size(); i++) tout << mk_bounded_pp(flat_args[i], m()) << "\n";);
br_status st = mk_nflat_mul_core(flat_args.size(), flat_args.c_ptr(), result);
if (st == BR_FAILED) {
result = mk_mul_app(flat_args.size(), flat_args.c_ptr());
return BR_DONE;
}
return st;
}
}
return mk_nflat_mul_core(num_args, args, result);
}
template<typename Config>
struct poly_rewriter<Config>::mon_pw_lt {
poly_rewriter<Config> & m_owner;
mon_pw_lt(poly_rewriter<Config> & o):m_owner(o) {}
bool operator()(expr * n1, expr * n2) const {
rational k;
return lt(m_owner.get_power_body(n1, k),
m_owner.get_power_body(n2, k));
}
};
template<typename Config>
br_status poly_rewriter<Config>::mk_nflat_mul_core(unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(num_args >= 2);
// cheap case
numeral a;
if (num_args == 2 && is_numeral(args[0], a) && !a.is_one() && !a.is_zero() &&
(is_var(args[1]) || to_app(args[1])->get_decl()->get_family_id() != get_fid()))
return BR_FAILED;
numeral c(1);
unsigned num_coeffs = 0;
unsigned num_add = 0;
expr * var = 0;
for (unsigned i = 0; i < num_args; i++) {
expr * arg = args[i];
if (is_numeral(arg, a)) {
num_coeffs++;
c *= a;
}
else {
var = arg;
if (is_add(arg))
num_add++;
}
}
normalize(c);
// (* c_1 ... c_n) --> c_1*...*c_n
if (num_coeffs == num_args) {
result = mk_numeral(c);
return BR_DONE;
}
// (* s ... 0 ... r) --> 0
if (c.is_zero()) {
result = mk_numeral(c);
return BR_DONE;
}
if (num_coeffs == num_args - 1) {
SASSERT(var != 0);
// (* c_1 ... c_n x) --> x if c_1*...*c_n == 1
if (c.is_one()) {
result = var;
return BR_DONE;
}
numeral c_prime;
if (is_mul(var)) {
// apply basic simplification even when flattening is not enabled.
// (* c1 (* c2 x)) --> (* c1*c2 x)
if (to_app(var)->get_num_args() == 2 && is_numeral(to_app(var)->get_arg(0), c_prime)) {
c *= c_prime;
normalize(c);
result = mk_mul_app(c, to_app(var)->get_arg(1));
return BR_REWRITE1;
}
else {
// var is a power-product
return BR_FAILED;
}
}
if (num_add == 0 || m_hoist_cmul) {
SASSERT(!is_add(var) || m_hoist_cmul);
if (num_args == 2 && args[1] == var) {
DEBUG_CODE({
numeral c_prime;
SASSERT(is_numeral(args[0], c_prime) && c == c_prime);
});
// it is already simplified
return BR_FAILED;
}
// (* c_1 ... c_n x) --> (* c_1*...*c_n x)
result = mk_mul_app(c, var);
return BR_DONE;
}
else {
SASSERT(is_add(var));
// (* c_1 ... c_n (+ t_1 ... t_m)) --> (+ (* c_1*...*c_n t_1) ... (* c_1*...*c_n t_m))
ptr_buffer<expr> new_add_args;
unsigned num = to_app(var)->get_num_args();
for (unsigned i = 0; i < num; i++) {
new_add_args.push_back(mk_mul_app(c, to_app(var)->get_arg(i)));
}
result = mk_add_app(new_add_args.size(), new_add_args.c_ptr());
TRACE("mul_bug", tout << "result: " << mk_bounded_pp(result, m(),5) << "\n";);
return BR_REWRITE2;
}
}
SASSERT(num_coeffs <= num_args - 2);
if (!m_som || num_add == 0) {
ptr_buffer<expr> new_args;
expr * prev = 0;
bool ordered = true;
for (unsigned i = 0; i < num_args; i++) {
expr * curr = args[i];
if (is_numeral(curr))
continue;
if (prev != 0 && lt(curr, prev))
ordered = false;
new_args.push_back(curr);
prev = curr;
}
TRACE("poly_rewriter",
for (unsigned i = 0; i < new_args.size(); i++) {
if (i > 0)
tout << (lt(new_args[i-1], new_args[i]) ? " < " : " !< ");
tout << mk_ismt2_pp(new_args[i], m());
}
tout << "\nordered: " << ordered << "\n";);
if (ordered && num_coeffs == 0 && !use_power())
return BR_FAILED;
if (!ordered) {
if (use_power())
std::sort(new_args.begin(), new_args.end(), mon_pw_lt(*this));
else
std::sort(new_args.begin(), new_args.end(), ast_to_lt());
TRACE("poly_rewriter",
tout << "after sorting:\n";
for (unsigned i = 0; i < new_args.size(); i++) {
if (i > 0)
tout << (lt(new_args[i-1], new_args[i]) ? " < " : " !< ");
tout << mk_ismt2_pp(new_args[i], m());
}
tout << "\n";);
}
SASSERT(new_args.size() >= 2);
result = mk_mul_app(new_args.size(), new_args.c_ptr());
result = mk_mul_app(c, result);
TRACE("poly_rewriter", tout << "mk_nflat_mul_core result:\n" << mk_ismt2_pp(result, m()) << "\n";);
return BR_DONE;
}
SASSERT(m_som && num_add > 0);
sbuffer<unsigned> szs;
sbuffer<unsigned> it;
sbuffer<expr **> sums;
for (unsigned i = 0; i < num_args; i ++) {
it.push_back(0);
expr * arg = args[i];
if (is_add(arg)) {
sums.push_back(const_cast<expr**>(to_app(arg)->get_args()));
szs.push_back(to_app(arg)->get_num_args());
}
else {
sums.push_back(const_cast<expr**>(args + i));
szs.push_back(1);
SASSERT(sums.back()[0] == arg);
}
}
expr_ref_buffer sum(m()); // must be ref_buffer because we may throw an exception
ptr_buffer<expr> m_args;
TRACE("som", tout << "starting som...\n";);
do {
TRACE("som", for (unsigned i = 0; i < it.size(); i++) tout << it[i] << " ";
tout << "\n";);
if (sum.size() > m_som_blowup)
throw rewriter_exception(g_ste_blowup_msg);
m_args.reset();
for (unsigned i = 0; i < num_args; i++) {
expr * const * v = sums[i];
expr * arg = v[it[i]];
m_args.push_back(arg);
}
sum.push_back(mk_mul_app(m_args.size(), m_args.c_ptr()));
}
while (product_iterator_next(szs.size(), szs.c_ptr(), it.c_ptr()));
result = mk_add_app(sum.size(), sum.c_ptr());
return BR_REWRITE2;
}
template<typename Config>
br_status poly_rewriter<Config>::mk_flat_add_core(unsigned num_args, expr * const * args, expr_ref & result) {
unsigned i;
for (i = 0; i < num_args; i++) {
if (is_add(args[i]))
break;
}
if (i < num_args) {
// has nested ADDs
ptr_buffer<expr> flat_args;
flat_args.append(i, args);
for (; i < num_args; i++) {
expr * arg = args[i];
// Remark: all rewrites are depth 1.
if (is_add(arg)) {
unsigned num = to_app(arg)->get_num_args();
for (unsigned j = 0; j < num; j++)
flat_args.push_back(to_app(arg)->get_arg(j));
}
else {
flat_args.push_back(arg);
}
}
br_status st = mk_nflat_add_core(flat_args.size(), flat_args.c_ptr(), result);
if (st == BR_FAILED) {
result = mk_add_app(flat_args.size(), flat_args.c_ptr());
return BR_DONE;
}
return st;
}
return mk_nflat_add_core(num_args, args, result);
}
template<typename Config>
inline expr * poly_rewriter<Config>::get_power_product(expr * t) {
if (is_mul(t) && to_app(t)->get_num_args() == 2 && is_numeral(to_app(t)->get_arg(0)))
return to_app(t)->get_arg(1);
return t;
}
template<typename Config>
inline expr * poly_rewriter<Config>::get_power_product(expr * t, numeral & a) {
if (is_mul(t) && to_app(t)->get_num_args() == 2 && is_numeral(to_app(t)->get_arg(0), a))
return to_app(t)->get_arg(1);
a = numeral(1);
return t;
}
template<typename Config>
bool poly_rewriter<Config>::is_mul(expr * t, numeral & c, expr * & pp) {
if (!is_mul(t) || to_app(t)->get_num_args() != 2)
return false;
if (!is_numeral(to_app(t)->get_arg(0), c))
return false;
pp = to_app(t)->get_arg(1);
return true;
}
template<typename Config>
struct poly_rewriter<Config>::hoist_cmul_lt {
poly_rewriter<Config> & m_r;
hoist_cmul_lt(poly_rewriter<Config> & r):m_r(r) {}
bool operator()(expr * t1, expr * t2) const {
expr * pp1, * pp2;
numeral c1, c2;
bool is_mul1 = m_r.is_mul(t1, c1, pp1);
bool is_mul2 = m_r.is_mul(t2, c2, pp2);
if (!is_mul1 && is_mul2)
return true;
if (is_mul1 && !is_mul2)
return false;
if (!is_mul1 && !is_mul2)
return t1->get_id() < t2->get_id();
if (c1 < c2)
return true;
if (c1 > c2)
return false;
return pp1->get_id() < pp2->get_id();
}
};
template<typename Config>
void poly_rewriter<Config>::hoist_cmul(expr_ref_buffer & args) {
unsigned sz = args.size();
std::sort(args.c_ptr(), args.c_ptr() + sz, hoist_cmul_lt(*this));
numeral c, c_prime;
ptr_buffer<expr> pps;
expr * pp, * pp_prime;
unsigned j = 0;
unsigned i = 0;
while (i < sz) {
expr * mon = args[i];
if (is_mul(mon, c, pp) && i < sz - 1) {
expr * mon_prime = args[i+1];
if (is_mul(mon_prime, c_prime, pp_prime) && c == c_prime) {
// found target
pps.reset();
pps.push_back(pp);
pps.push_back(pp_prime);
i += 2;
while (i < sz && is_mul(args[i], c_prime, pp_prime) && c == c_prime) {
pps.push_back(pp_prime);
i++;
}
SASSERT(is_numeral(to_app(mon)->get_arg(0), c_prime) && c == c_prime);
expr * mul_args[2] = { to_app(mon)->get_arg(0), mk_add_app(pps.size(), pps.c_ptr()) };
args.set(j, mk_mul_app(2, mul_args));
j++;
continue;
}
}
args.set(j, mon);
j++;
i++;
}
args.resize(j);
}
template<typename Config>
br_status poly_rewriter<Config>::mk_nflat_add_core(unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(num_args >= 2);
numeral c;
unsigned num_coeffs = 0;
numeral a;
expr_fast_mark1 visited; // visited.is_marked(power_product) if the power_product occurs in args
expr_fast_mark2 multiple; // multiple.is_marked(power_product) if power_product occurs more than once
bool has_multiple = false;
expr * prev = 0;
bool ordered = true;
for (unsigned i = 0; i < num_args; i++) {
expr * arg = args[i];
if (is_numeral(arg, a)) {
num_coeffs++;
c += a;
}
else {
// arg is not a numeral
if (m_sort_sums && ordered) {
if (prev != 0 && lt(arg, prev))
ordered = false;
prev = arg;
}
}
arg = get_power_product(arg);
if (visited.is_marked(arg)) {
multiple.mark(arg);
has_multiple = true;
}
else {
visited.mark(arg);
}
}
normalize(c);
SASSERT(m_sort_sums || ordered);
TRACE("sort_sums",
tout << "ordered: " << ordered << "\n";
for (unsigned i = 0; i < num_args; i++) tout << mk_ismt2_pp(args[i], m()) << "\n";);
if (has_multiple) {
// expensive case
buffer<numeral> coeffs;
m_expr2pos.reset();
// compute the coefficient of power products that occur multiple times.
for (unsigned i = 0; i < num_args; i++) {
expr * arg = args[i];
if (is_numeral(arg))
continue;
expr * pp = get_power_product(arg, a);
if (!multiple.is_marked(pp))
continue;
unsigned pos;
if (m_expr2pos.find(pp, pos)) {
coeffs[pos] += a;
}
else {
m_expr2pos.insert(pp, coeffs.size());
coeffs.push_back(a);
}
}
expr_ref_buffer new_args(m());
if (!c.is_zero()) {
new_args.push_back(mk_numeral(c));
}
// copy power products with non zero coefficients to new_args
visited.reset();
for (unsigned i = 0; i < num_args; i++) {
expr * arg = args[i];
if (is_numeral(arg))
continue;
expr * pp = get_power_product(arg);
if (!multiple.is_marked(pp)) {
new_args.push_back(arg);
}
else if (!visited.is_marked(pp)) {
visited.mark(pp);
unsigned pos = UINT_MAX;
m_expr2pos.find(pp, pos);
SASSERT(pos != UINT_MAX);
a = coeffs[pos];
normalize(a);
if (!a.is_zero())
new_args.push_back(mk_mul_app(a, pp));
}
}
if (m_hoist_cmul) {
hoist_cmul(new_args);
}
else if (m_sort_sums) {
TRACE("sort_sums_bug", tout << "new_args.size(): " << new_args.size() << "\n";);
if (c.is_zero())
std::sort(new_args.c_ptr(), new_args.c_ptr() + new_args.size(), ast_to_lt());
else
std::sort(new_args.c_ptr() + 1, new_args.c_ptr() + new_args.size(), ast_to_lt());
}
result = mk_add_app(new_args.size(), new_args.c_ptr());
if (hoist_multiplication(result)) {
return BR_REWRITE_FULL;
}
return BR_DONE;
}
else {
SASSERT(!has_multiple);
if (ordered && !m_hoist_mul && !m_hoist_cmul) {
if (num_coeffs == 0)
return BR_FAILED;
if (num_coeffs == 1 && is_numeral(args[0], a) && !a.is_zero())
return BR_FAILED;
}
expr_ref_buffer new_args(m());
if (!c.is_zero())
new_args.push_back(mk_numeral(c));
for (unsigned i = 0; i < num_args; i++) {
expr * arg = args[i];
if (is_numeral(arg))
continue;
new_args.push_back(arg);
}
if (m_hoist_cmul) {
hoist_cmul(new_args);
}
else if (!ordered) {
if (c.is_zero())
std::sort(new_args.c_ptr(), new_args.c_ptr() + new_args.size(), ast_to_lt());
else
std::sort(new_args.c_ptr() + 1, new_args.c_ptr() + new_args.size(), ast_to_lt());
}
result = mk_add_app(new_args.size(), new_args.c_ptr());
if (hoist_multiplication(result)) {
return BR_REWRITE_FULL;
}
return BR_DONE;
}
}
template<typename Config>
br_status poly_rewriter<Config>::mk_uminus(expr * arg, expr_ref & result) {
numeral a;
set_curr_sort(m().get_sort(arg));
if (is_numeral(arg, a)) {
a.neg();
normalize(a);
result = mk_numeral(a);
return BR_DONE;
}
else {
result = mk_mul_app(numeral(-1), arg);
return BR_REWRITE1;
}
}
template<typename Config>
br_status poly_rewriter<Config>::mk_sub(unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(num_args > 0);
if (num_args == 1) {
result = args[0];
return BR_DONE;
}
set_curr_sort(m().get_sort(args[0]));
expr * minus_one = mk_numeral(numeral(-1));
ptr_buffer<expr> new_args;
new_args.push_back(args[0]);
for (unsigned i = 1; i < num_args; i++) {
expr * aux_args[2] = { minus_one, args[i] };
new_args.push_back(mk_mul_app(2, aux_args));
}
result = mk_add_app(new_args.size(), new_args.c_ptr());
return BR_REWRITE2;
}
/**
\brief Cancel/Combine monomials that occur is the left and right hand sides.
\remark If move = true, then all non-constant monomials are moved to the left-hand-side.
*/
template<typename Config>
br_status poly_rewriter<Config>::cancel_monomials(expr * lhs, expr * rhs, bool move, expr_ref & lhs_result, expr_ref & rhs_result) {
set_curr_sort(m().get_sort(lhs));
unsigned lhs_sz;
expr * const * lhs_monomials = get_monomials(lhs, lhs_sz);
unsigned rhs_sz;
expr * const * rhs_monomials = get_monomials(rhs, rhs_sz);
expr_fast_mark1 visited; // visited.is_marked(power_product) if the power_product occurs in lhs or rhs
expr_fast_mark2 multiple; // multiple.is_marked(power_product) if power_product occurs more than once
bool has_multiple = false;
numeral c(0);
numeral a;
unsigned num_coeffs = 0;
for (unsigned i = 0; i < lhs_sz; i++) {
expr * arg = lhs_monomials[i];
if (is_numeral(arg, a)) {
c += a;
num_coeffs++;
}
else {
visited.mark(get_power_product(arg));
}
}
if (move && num_coeffs == 0 && is_numeral(rhs))
return BR_FAILED;
for (unsigned i = 0; i < rhs_sz; i++) {
expr * arg = rhs_monomials[i];
if (is_numeral(arg, a)) {
c -= a;
num_coeffs++;
}
else {
expr * pp = get_power_product(arg);
if (visited.is_marked(pp)) {
multiple.mark(pp);
has_multiple = true;
}
}
}
normalize(c);
if (!has_multiple && num_coeffs <= 1) {
if (move) {
if (is_numeral(rhs))
return BR_FAILED;
}
else {
if (num_coeffs == 0 || is_numeral(rhs))
return BR_FAILED;
}
}
buffer<numeral> coeffs;
m_expr2pos.reset();
for (unsigned i = 0; i < lhs_sz; i++) {
expr * arg = lhs_monomials[i];
if (is_numeral(arg))
continue;
expr * pp = get_power_product(arg, a);
if (!multiple.is_marked(pp))
continue;
unsigned pos;
if (m_expr2pos.find(pp, pos)) {
coeffs[pos] += a;
}
else {
m_expr2pos.insert(pp, coeffs.size());
coeffs.push_back(a);
}
}
for (unsigned i = 0; i < rhs_sz; i++) {
expr * arg = rhs_monomials[i];
if (is_numeral(arg))
continue;
expr * pp = get_power_product(arg, a);
if (!multiple.is_marked(pp))
continue;
unsigned pos = UINT_MAX;
m_expr2pos.find(pp, pos);
SASSERT(pos != UINT_MAX);
coeffs[pos] -= a;
}
ptr_buffer<expr> new_lhs_monomials;
new_lhs_monomials.push_back(0); // save space for coefficient if needed
// copy power products with non zero coefficients to new_lhs_monomials
visited.reset();
for (unsigned i = 0; i < lhs_sz; i++) {
expr * arg = lhs_monomials[i];
if (is_numeral(arg))
continue;
expr * pp = get_power_product(arg);
if (!multiple.is_marked(pp)) {
new_lhs_monomials.push_back(arg);
}
else if (!visited.is_marked(pp)) {
visited.mark(pp);
unsigned pos = UINT_MAX;
m_expr2pos.find(pp, pos);
SASSERT(pos != UINT_MAX);
a = coeffs[pos];
if (!a.is_zero())
new_lhs_monomials.push_back(mk_mul_app(a, pp));
}
}
ptr_buffer<expr> new_rhs_monomials;
new_rhs_monomials.push_back(0); // save space for coefficient if needed
for (unsigned i = 0; i < rhs_sz; i++) {
expr * arg = rhs_monomials[i];
if (is_numeral(arg))
continue;
expr * pp = get_power_product(arg, a);
if (!multiple.is_marked(pp)) {
if (move) {
if (!a.is_zero()) {
if (a.is_minus_one()) {
new_lhs_monomials.push_back(pp);
}
else {
a.neg();
SASSERT(!a.is_one());
expr * args[2] = { mk_numeral(a), pp };
new_lhs_monomials.push_back(mk_mul_app(2, args));
}
}
}
else {
new_rhs_monomials.push_back(arg);
}
}
}
bool c_at_rhs = false;
if (move) {
if (m_sort_sums) {
// + 1 to skip coefficient
std::sort(new_lhs_monomials.begin() + 1, new_lhs_monomials.end(), ast_to_lt());
}
c_at_rhs = true;
}
else if (new_rhs_monomials.size() == 1) { // rhs is empty
c_at_rhs = true;
}
else if (new_lhs_monomials.size() > 1) {
c_at_rhs = true;
}
if (c_at_rhs) {
c.neg();
normalize(c);
new_rhs_monomials[0] = mk_numeral(c);
lhs_result = mk_add_app(new_lhs_monomials.size() - 1, new_lhs_monomials.c_ptr() + 1);
rhs_result = mk_add_app(new_rhs_monomials.size(), new_rhs_monomials.c_ptr());
}
else {
new_lhs_monomials[0] = mk_numeral(c);
lhs_result = mk_add_app(new_lhs_monomials.size(), new_lhs_monomials.c_ptr());
rhs_result = mk_add_app(new_rhs_monomials.size() - 1, new_rhs_monomials.c_ptr() + 1);
}
return BR_DONE;
}
#define TO_BUFFER(_tester_, _buffer_, _e_) \
_buffer_.push_back(_e_); \
for (unsigned _i = 0; _i < _buffer_.size(); ) { \
expr* _e = _buffer_[_i]; \
if (_tester_(_e)) { \
app* a = to_app(_e); \
_buffer_[_i] = a->get_arg(0); \
for (unsigned _j = 1; _j < a->get_num_args(); ++_j) { \
_buffer_.push_back(a->get_arg(_j)); \
} \
} \
else { \
++_i; \
} \
} \
template<typename Config>
bool poly_rewriter<Config>::hoist_multiplication(expr_ref& som) {
if (!m_hoist_mul) {
return false;
}
ptr_buffer<expr> adds, muls;
TO_BUFFER(is_add, adds, som);
buffer<bool> valid(adds.size(), true);
obj_map<expr, unsigned> mul_map;
unsigned j;
bool change = false;
for (unsigned k = 0; k < adds.size(); ++k) {
expr* e = adds[k];
muls.reset();
TO_BUFFER(is_mul, muls, e);
for (unsigned i = 0; i < muls.size(); ++i) {
e = muls[i];
if (is_numeral(e)) {
continue;
}
if (mul_map.find(e, j) && valid[j] && j != k) {
m_curr_sort = m().get_sort(adds[k]);
adds[j] = merge_muls(adds[j], adds[k]);
adds[k] = mk_numeral(rational(0));
valid[j] = false;
valid[k] = false;
change = true;
break;
}
else {
mul_map.insert(e, k);
}
}
}
if (!change) {
return false;
}
som = mk_add_app(adds.size(), adds.c_ptr());
return true;
}
template<typename Config>
expr* poly_rewriter<Config>::merge_muls(expr* x, expr* y) {
ptr_buffer<expr> m1, m2;
TO_BUFFER(is_mul, m1, x);
TO_BUFFER(is_mul, m2, y);
unsigned k = 0;
for (unsigned i = 0; i < m1.size(); ++i) {
x = m1[i];
bool found = false;
unsigned j;
for (j = k; j < m2.size(); ++j) {
found = m2[j] == x;
if (found) break;
}
if (found) {
std::swap(m1[i],m1[k]);
std::swap(m2[j],m2[k]);
++k;
}
}
m_curr_sort = m().get_sort(x);
SASSERT(k > 0);
SASSERT(m1.size() >= k);
SASSERT(m2.size() >= k);
expr* args[2] = { mk_mul_app(m1.size()-k, m1.c_ptr()+k),
mk_mul_app(m2.size()-k, m2.c_ptr()+k) };
if (k == m1.size()) {
m1.push_back(0);
}
m1[k] = mk_add_app(2, args);
return mk_mul_app(k+1, m1.c_ptr());
}

View file

@ -1,402 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
rewriter.cpp
Abstract:
Lean and mean rewriter
Author:
Leonardo (leonardo) 2011-03-31
Notes:
--*/
#include"rewriter_def.h"
#include"ast_ll_pp.h"
#include"ast_smt2_pp.h"
void rewriter_core::init_cache_stack() {
SASSERT(m_cache_stack.empty());
m_cache = alloc(cache, m());
m_cache_stack.push_back(m_cache);
if (m_proof_gen) {
SASSERT(m_cache_pr_stack.empty());
m_cache_pr = alloc(cache, m());
m_cache_pr_stack.push_back(m_cache_pr);
}
}
void rewriter_core::del_cache_stack() {
std::for_each(m_cache_stack.begin(), m_cache_stack.end(), delete_proc<cache>());
m_cache_stack.finalize();
m_cache = 0;
if (m_proof_gen) {
std::for_each(m_cache_pr_stack.begin(), m_cache_pr_stack.end(), delete_proc<cache>());
m_cache_pr_stack.finalize();
m_cache_pr = 0;
}
}
void rewriter_core::cache_result(expr * k, expr * v) {
#if 0
// trace for tracking cache usage
verbose_stream() << "1 " << k->get_id() << std::endl;
#endif
SASSERT(!m_proof_gen);
TRACE("rewriter_cache_result", tout << mk_ismt2_pp(k, m()) << "\n--->\n" << mk_ismt2_pp(v, m()) << "\n";);
m_cache->insert(k, v);
#if 0
static unsigned num_cached = 0;
num_cached ++;
if (num_cached % 100000 == 0)
verbose_stream() << "[rewriter] :num-cached " << num_cached << " :capacity " << m_cache->capacity() << " :size " << m_cache->size()
<< " :frame-stack-size " << m_frame_stack.size() << std::endl;
#endif
}
void rewriter_core::cache_result(expr * k, expr * v, proof * pr) {
m_cache->insert(k, v);
SASSERT(m_proof_gen);
m_cache_pr->insert(k, pr);
}
unsigned rewriter_core::get_cache_size() const {
return m_cache->size();
}
void rewriter_core::reset_cache() {
m_cache = m_cache_stack[0];
m_cache->reset();
if (m_proof_gen) {
m_cache_pr = m_cache_pr_stack[0];
m_cache_pr->reset();
}
}
// free memory allocated by the rewriter
void rewriter_core::free_memory() {
del_cache_stack();
m_frame_stack.finalize();
m_result_stack.finalize();
m_scopes.finalize();
}
void rewriter_core::begin_scope() {
m_scopes.push_back(scope(m_root, m_num_qvars));
unsigned lvl = m_scopes.size();
SASSERT(lvl <= m_cache_stack.size());
SASSERT(!m_proof_gen || m_cache_pr_stack.size() == m_cache_stack.size());
if (lvl == m_cache_stack.size()) {
m_cache_stack.push_back(alloc(cache, m()));
if (m_proof_gen)
m_cache_pr_stack.push_back(alloc(cache, m()));
}
m_cache = m_cache_stack[lvl];
m_cache->reset();
SASSERT(m_cache->empty());
if (m_proof_gen) {
m_cache_pr = m_cache_pr_stack[lvl];
m_cache_pr->reset();
SASSERT(m_cache_pr->empty());
}
}
void rewriter_core::end_scope() {
m_cache->reset();
if (m_proof_gen)
m_cache_pr->reset();
scope & s = m_scopes.back();
m_root = s.m_old_root;
m_num_qvars = s.m_old_num_qvars;
m_scopes.pop_back();
unsigned new_lvl = m_scopes.size();
m_cache = m_cache_stack[new_lvl];
if (m_proof_gen)
m_cache_pr = m_cache_pr_stack[new_lvl];
}
bool rewriter_core::is_child_of_top_frame(expr * t) const {
if (m_frame_stack.empty())
return true;
frame const & fr = m_frame_stack.back();
expr * parent = fr.m_curr;
unsigned num;
switch (parent->get_kind()) {
case AST_APP:
num = to_app(parent)->get_num_args();
for (unsigned i = 0; i < num; i++) {
if (to_app(parent)->get_arg(i) == t)
return true;
}
return false;
case AST_QUANTIFIER:
num = to_quantifier(parent)->get_num_children();
for (unsigned i = 0; i < num; i++) {
if (to_quantifier(parent)->get_child(i) == t)
return true;
}
return false;
default:
return false;
}
}
/**
\brief Eliminate (implicit) reflexivity proofs from m_result_pr_stack starting at position spos.
The implicit reflexivity proof is 0.
*/
void rewriter_core::elim_reflex_prs(unsigned spos) {
SASSERT(m_proof_gen);
unsigned sz = m_result_pr_stack.size();
SASSERT(spos <= sz);
unsigned j = spos;
for (unsigned i = spos; i < sz; i++) {
proof * pr = m_result_pr_stack.get(i);
if (pr != 0) {
if (i != j)
m_result_pr_stack.set(j, pr);
j++;
}
}
m_result_pr_stack.shrink(j);
}
rewriter_core::rewriter_core(ast_manager & m, bool proof_gen):
m_manager(m),
m_proof_gen(proof_gen),
m_result_stack(m),
m_result_pr_stack(m),
m_num_qvars(0) {
init_cache_stack();
}
rewriter_core::~rewriter_core() {
del_cache_stack();
}
// reset rewriter (macro definitions are not erased)
void rewriter_core::reset() {
SASSERT(!m_cache_stack.empty());
reset_cache();
m_frame_stack.reset();
m_result_stack.reset();
if (m_proof_gen)
m_result_pr_stack.reset();
m_root = 0;
m_num_qvars = 0;
m_scopes.reset();
}
// free memory & reset (macro definitions are not erased)
void rewriter_core::cleanup() {
free_memory();
init_cache_stack();
m_root = 0;
m_num_qvars = 0;
}
#ifdef _TRACE
void rewriter_core::display_stack(std::ostream & out, unsigned pp_depth) {
svector<frame>::iterator it = m_frame_stack.begin();
svector<frame>::iterator end = m_frame_stack.end();
for (; it != end; ++it) {
out << mk_bounded_pp(it->m_curr, m(), pp_depth) << "\n";
out << "state: " << it->m_state << "\n";
out << "cache: " << it->m_cache_result << ", new_child: " << it->m_new_child << ", max-depth: " << it->m_max_depth << ", i: " << it->m_i << "\n";
out << "------------------\n";
}
}
#endif
bool var_shifter_core::visit(expr * t) {
if (is_ground(t)) {
m_result_stack.push_back(t);
return true;
}
bool c = must_cache(t);
if (c) {
expr * r = get_cached(t);
if (r) {
m_result_stack.push_back(r);
set_new_child_flag(t, r);
return true;
}
}
switch (t->get_kind()) {
case AST_APP:
SASSERT(to_app(t)->get_num_args() > 0);
push_frame(t, c);
return false;
case AST_VAR:
process_var(to_var(t));
return true;
case AST_QUANTIFIER:
push_frame(t, c);
return false;
default:
UNREACHABLE();
return true;
}
}
void var_shifter_core::process_app(app * t, frame & fr) {
unsigned num_args = t->get_num_args();
while (fr.m_i < num_args) {
expr * arg = t->get_arg(fr.m_i);
fr.m_i++;
if (!visit(arg))
return;
}
SASSERT(fr.m_spos + num_args == m_result_stack.size());
expr * new_t;
if (fr.m_new_child) {
expr * const * new_args = m_result_stack.c_ptr() + fr.m_spos;
new_t = m().mk_app(t->get_decl(), num_args, new_args);
}
else {
new_t = t;
}
m_result_stack.shrink(fr.m_spos);
m_result_stack.push_back(new_t);
m_frame_stack.pop_back();
set_new_child_flag(t, new_t);
if (fr.m_cache_result)
cache_result(t, new_t);
}
void var_shifter_core::process_quantifier(quantifier * q, frame & fr) {
if (fr.m_i == 0) {
begin_scope();
m_num_qvars += q->get_num_decls();
m_root = q->get_expr();
}
unsigned num_children = q->get_num_children();
while (fr.m_i < num_children) {
expr * child = q->get_child(fr.m_i);
fr.m_i++;
if (!visit(child))
return;
}
SASSERT(fr.m_spos + num_children == m_result_stack.size());
expr * new_q;
if (fr.m_new_child) {
expr * const * it = m_result_stack.c_ptr() + fr.m_spos;
expr * new_expr = *it;
++it;
expr * const * new_pats = it;
expr * const * new_no_pats = new_pats + q->get_num_patterns();
new_q = m().update_quantifier(q, q->get_num_patterns(), new_pats, q->get_num_no_patterns(), new_no_pats, new_expr);
}
else {
new_q = q;
}
m_result_stack.shrink(fr.m_spos);
m_result_stack.push_back(new_q);
m_frame_stack.pop_back();
set_new_child_flag(q, new_q);
end_scope();
if (fr.m_cache_result)
cache_result(q, new_q);
}
void var_shifter_core::main_loop(expr * t, expr_ref & r) {
SASSERT(m_cache == m_cache_stack[0]);
SASSERT(m_frame_stack.empty());
SASSERT(m_result_stack.empty());
m_root = t;
if (visit(t)) {
r = m_result_stack.back();
m_result_stack.pop_back();
SASSERT(m_result_stack.empty());
return;
}
SASSERT(!m_frame_stack.empty());
while (!m_frame_stack.empty()) {
frame & fr = m_frame_stack.back();
expr * t = fr.m_curr;
if (fr.m_i == 0 && fr.m_cache_result) {
expr * r = get_cached(t);
if (r) {
m_result_stack.push_back(r);
m_frame_stack.pop_back();
set_new_child_flag(t, r);
continue;
}
}
switch (t->get_kind()) {
case AST_APP:
process_app(to_app(t), fr);
break;
case AST_QUANTIFIER:
process_quantifier(to_quantifier(t), fr);
break;
default:
UNREACHABLE();
}
}
r = m_result_stack.back();
m_result_stack.pop_back();
SASSERT(m_result_stack.empty());
}
void var_shifter::operator()(expr * t, unsigned bound, unsigned shift1, unsigned shift2, expr_ref & r) {
if (is_ground(t)) {
r = t;
return;
}
reset_cache();
m_bound = bound;
m_shift1 = shift1;
m_shift2 = shift2;
main_loop(t, r);
}
void var_shifter::process_var(var * v) {
unsigned vidx = v->get_idx();
if (vidx < m_num_qvars) {
m_result_stack.push_back(v);
}
else {
unsigned nvidx = vidx - m_num_qvars;
if (nvidx >= m_bound)
vidx += m_shift1;
else
vidx += m_shift2;
m_result_stack.push_back(m().mk_var(vidx, v->get_sort()));
set_new_child_flag(v);
}
}
void inv_var_shifter::operator()(expr * t, unsigned shift, expr_ref & r) {
if (is_ground(t)) {
r = t;
return;
}
reset_cache();
m_shift = shift;
main_loop(t, r);
}
void inv_var_shifter::process_var(var * v) {
unsigned vidx = v->get_idx();
if (vidx < m_num_qvars) {
m_result_stack.push_back(v);
}
else {
SASSERT(vidx >= m_num_qvars + m_shift);
vidx -= m_shift;
m_result_stack.push_back(m().mk_var(vidx, v->get_sort()));
set_new_child_flag(v);
}
}
template class rewriter_tpl<beta_reducer_cfg>;

View file

@ -1,399 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
rewriter.h
Abstract:
Lean and mean rewriter
Author:
Leonardo (leonardo) 2011-03-31
Notes:
--*/
#ifndef _REWRITER_H_
#define _REWRITER_H_
#include"ast.h"
#include"rewriter_types.h"
#include"act_cache.h"
/**
\brief Common infrastructure for AST rewriters.
*/
class rewriter_core {
protected:
struct frame {
expr * m_curr;
unsigned m_cache_result:1; // true if the result of rewriting m_expr must be cached.
unsigned m_new_child:1;
unsigned m_state:2;
unsigned m_max_depth:2; // bounded rewrite... if m_max_depth == 0, then children are not rewritten.
unsigned m_i:26;
unsigned m_spos; // top of the result stack, when the frame was created.
frame(expr * n, bool cache_res, unsigned st, unsigned max_depth, unsigned spos):
m_curr(n),
m_cache_result(cache_res),
m_new_child(false),
m_state(st),
m_max_depth(max_depth),
m_i(0),
m_spos(spos) {
}
};
ast_manager & m_manager;
bool m_proof_gen;
typedef act_cache cache;
ptr_vector<cache> m_cache_stack;
cache * m_cache; // current cache.
svector<frame> m_frame_stack;
expr_ref_vector m_result_stack;
// proof generation goodness ----
ptr_vector<cache> m_cache_pr_stack;
cache * m_cache_pr;
proof_ref_vector m_result_pr_stack;
// --------------------------
expr * m_root;
unsigned m_num_qvars;
struct scope {
expr * m_old_root;
unsigned m_old_num_qvars;
scope(expr * r, unsigned n):m_old_root(r), m_old_num_qvars(n) {}
};
svector<scope> m_scopes;
// Return true if the rewriting result of the given expression must be cached.
bool must_cache(expr * t) const {
return
t->get_ref_count() > 1 && // t must be a shared expression
t != m_root && // t must not be the root expression
((is_app(t) && to_app(t)->get_num_args() > 0) || is_quantifier(t)); // t is a (non-constant) application or a quantifier.
}
void push_frame_core(expr * t, bool cache_res, unsigned st = 0, unsigned max_depth = RW_UNBOUNDED_DEPTH) {
SASSERT(!m_proof_gen || m_result_stack.size() == m_result_pr_stack.size());
m_frame_stack.push_back(frame(t, cache_res, st, max_depth, m_result_stack.size()));
}
void push_frame(expr * t, unsigned st = 0) {
push_frame_core(t, must_cache(t), st);
}
void init_cache_stack();
void del_cache_stack();
void reset_cache();
void cache_result(expr * k, expr * v);
expr * get_cached(expr * k) const { return m_cache->find(k); }
void cache_result(expr * k, expr * v, proof * pr);
proof * get_cached_pr(expr * k) const { return static_cast<proof*>(m_cache_pr->find(k)); }
void free_memory();
void begin_scope();
void end_scope();
bool is_child_of_top_frame(expr * t) const;
void set_new_child_flag(expr * old_t) {
CTRACE("rewriter_bug", !is_child_of_top_frame(old_t), display_stack(tout, 3););
SASSERT(is_child_of_top_frame(old_t));
if (!m_frame_stack.empty())
m_frame_stack.back().m_new_child = true;
}
void set_new_child_flag(expr * old_t, expr * new_t) { if (old_t != new_t) set_new_child_flag(old_t); }
void elim_reflex_prs(unsigned spos);
public:
rewriter_core(ast_manager & m, bool proof_gen);
~rewriter_core();
ast_manager & m() const { return m_manager; }
void reset();
void cleanup();
#ifdef _TRACE
void display_stack(std::ostream & out, unsigned pp_depth);
#endif
unsigned get_cache_size() const;
};
class var_shifter_core : public rewriter_core {
protected:
bool visit(expr * t);
void process_app(app * t, frame & fr);
virtual void process_var(var * v) = 0;
void process_quantifier(quantifier * q, frame & fr);
void main_loop(expr * t, expr_ref & r);
public:
var_shifter_core(ast_manager & m):rewriter_core(m, false) {}
};
/**
\brief Functor used to shift the free variables of an AST by a given amount.
This functor is used by the var_subst functor.
This functor implements the following functions:
1) shift(n, s) will return a new AST where all free variables (VAR i) in n,
are replaced by (VAR (+ i s)).
2) shift(n, b, s1, s2) is a variant of the previous function such that
for a each free variable (VAR i) is shifted to:
- (VAR i + s1) if i >= b
- (VAR i + s2) if i < b
*/
class var_shifter : public var_shifter_core {
unsigned m_bound;
unsigned m_shift1;
unsigned m_shift2;
virtual void process_var(var * v);
public:
var_shifter(ast_manager & m):var_shifter_core(m) {}
void operator()(expr * t, unsigned bound, unsigned shift1, unsigned shift2, expr_ref & r);
void operator()(expr * t, unsigned s, expr_ref & r) {
operator()(t, 0, s, 0, r);
}
};
/**
\brief Functor used to shift the free variables of an AST by a negative amount.
Abstract implementation:
inv_shift(f(c_1, ..., c_n), d, s) =
f(inv_shift(c_1, d, s), ..., inv_shift(c_n, d, s))
inv_shift(var(i), d, s) =
if (i < d)
var(i)
else
assert(i - s >= d)
var(i-s)
inv_shift((forall (x) P), d, s) =
(forall (x) inv_shift(P, d+1, s))
This functor assumes that if we are shifting an expression F by N, then F
does not contain free variables #0, ... #N-1
See assertion above.
*/
class inv_var_shifter : public var_shifter_core {
protected:
unsigned m_shift;
virtual void process_var(var * v);
public:
inv_var_shifter(ast_manager & m):var_shifter_core(m) {}
void operator()(expr * t, unsigned shift, expr_ref & r);
};
template<typename Config>
class rewriter_tpl : public rewriter_core {
protected:
// Rewriter maintains a stack of frames.
// Each frame represents an expression that is being rewritten.
// The resultant expressions are store on the Result stack.
// Each frame is in a particular state.
// Let f(t_0,...,t_n) be the expression is the frame Fr. Then Fr can be is one of the
// following states:
// PROCESS_CHILDREN(i) the children t_0, ..., t_{i-1} have already been rewritten, and the result is on the Result stack.
// REWRITE_BUILTIN All t_0, ..., t_n have been rewritten to t_0',...,t_n', and the builtin rewriter (or plugin) produced a new term t
// that can be further rewritten.
// EXPAND_DEF All t_0, ..., t_n have been rewritten to t_0',...,t_n'.
// The function symbol f is a macro, and the body of the macro needs to be rewritten using the t_0',...,t_n' as bindings.
// REWRITE_RULE All t_0, ..., t_n have been rewritten to t_0',...,t_n'.
// There is rewrite rule lhs -> rhs s.t. f(t_0', ..., t_n') matches lhs with substitution delta.
// rhs is then rewritten using delta.
enum state {
PROCESS_CHILDREN,
REWRITE_BUILTIN,
EXPAND_DEF,
REWRITE_RULE
};
Config & m_cfg;
unsigned m_num_steps;
volatile bool m_cancel;
ptr_vector<expr> m_bindings;
var_shifter m_shifter;
expr_ref m_r;
proof_ref m_pr;
proof_ref m_pr2;
svector<frame> & frame_stack() { return this->m_frame_stack; }
svector<frame> const & frame_stack() const { return this->m_frame_stack; }
expr_ref_vector & result_stack() { return this->m_result_stack; }
expr_ref_vector const & result_stack() const { return this->m_result_stack; }
proof_ref_vector & result_pr_stack() { return this->m_result_pr_stack; }
proof_ref_vector const & result_pr_stack() const { return this->m_result_pr_stack; }
void set_new_child_flag(expr * old_t) {
SASSERT(frame_stack().empty() || frame_stack().back().m_state != PROCESS_CHILDREN || this->is_child_of_top_frame(old_t));
if (!frame_stack().empty())
frame_stack().back().m_new_child = true;
}
void set_new_child_flag(expr * old_t, expr * new_t) { if (old_t != new_t) set_new_child_flag(old_t); }
// cache the result of shared non atomic expressions.
bool cache_results() const { return m_cfg.cache_results(); }
// cache all results share and non shared expressions non atomic expressions.
bool cache_all_results() const { return m_cfg.cache_all_results(); }
// flat non shared AC terms
bool flat_assoc(func_decl * f) const { return m_cfg.flat_assoc(f); }
// rewrite patterns
bool rewrite_patterns() const { return m_cfg.rewrite_patterns(); }
// check maximum number of scopes
void check_max_scopes() const {
if (m_cfg.max_scopes_exceeded(this->m_scopes.size()))
throw rewriter_exception(TACTIC_MAX_SCOPES_MSG);
}
// check maximum size of the frame stack
void check_max_frames() const {
if (m_cfg.max_frames_exceeded(frame_stack().size()))
throw rewriter_exception(TACTIC_MAX_FRAMES_MSG);
}
// check maximum number of rewriting steps
void check_max_steps() const {
if (m_cfg.max_steps_exceeded(m_num_steps))
throw rewriter_exception(TACTIC_MAX_STEPS_MSG);
}
// If pre_visit returns false, then t children are not visited/rewritten.
// This should be used with care, since it may produce incorrect results
// when the rewriter is used to apply variable substitution.
bool pre_visit(expr * t) {
return m_cfg.pre_visit(t);
}
// Return true if the rewriting result of the given expression must be cached.
bool must_cache(expr * t) const {
if (cache_all_results())
return t != this->m_root && ((is_app(t) && to_app(t)->get_num_args() > 0) || is_quantifier(t));
if (cache_results())
return rewriter_core::must_cache(t);
return false;
}
bool get_macro(func_decl * f, expr * & def, quantifier * & q, proof * & def_pr) {
return m_cfg.get_macro(f, def, q, def_pr);
}
void push_frame(expr * t, bool mcache, unsigned max_depth) {
check_max_frames();
push_frame_core(t, mcache, PROCESS_CHILDREN, max_depth);
}
void begin_scope() {
check_max_scopes();
rewriter_core::begin_scope();
}
template<bool ProofGen>
void process_var(var * v);
template<bool ProofGen>
void process_const(app * t);
template<bool ProofGen>
bool visit(expr * t, unsigned max_depth);
template<bool ProofGen>
void cache_result(expr * t, expr * new_t, proof * pr, bool c) {
if (c) {
if (!ProofGen)
rewriter_core::cache_result(t, new_t);
else
rewriter_core::cache_result(t, new_t, pr);
}
}
template<bool ProofGen>
void process_app(app * t, frame & fr);
template<bool ProofGen>
void process_quantifier(quantifier * q, frame & fr);
bool first_visit(frame & fr) const {
return fr.m_state == PROCESS_CHILDREN && fr.m_i == 0;
}
bool not_rewriting() const;
template<bool ProofGen>
void main_loop(expr * t, expr_ref & result, proof_ref & result_pr);
template<bool ProofGen>
void resume_core(expr_ref & result, proof_ref & result_pr);
public:
rewriter_tpl(ast_manager & m, bool proof_gen, Config & cfg);
ast_manager & m() const { return this->m_manager; }
Config & cfg() { return m_cfg; }
Config const & cfg() const { return m_cfg; }
void set_cancel(bool f) { m_cancel = f; }
void cancel() { set_cancel(true); }
void reset_cancel() { set_cancel(false); }
~rewriter_tpl();
void reset();
void cleanup();
void set_bindings(unsigned num_bindings, expr * const * bindings);
void set_inv_bindings(unsigned num_bindings, expr * const * bindings);
void operator()(expr * t, expr_ref & result, proof_ref & result_pr);
void operator()(expr * t, expr_ref & result) { operator()(t, result, m_pr); }
void operator()(expr * n, unsigned num_bindings, expr * const * bindings, expr_ref & result) {
SASSERT(!m_proof_gen);
reset();
set_inv_bindings(num_bindings, bindings);
operator()(n, result);
}
void resume(expr_ref & result, proof_ref & result_pr);
void resume(expr_ref & result) { resume(result, m_pr); }
// Return the number of steps performed by the rewriter in the last call to operator().
unsigned get_num_steps() const { return m_num_steps; }
};
struct default_rewriter_cfg {
bool cache_all_results() const { return false; }
bool cache_results() const { return true; }
bool flat_assoc(func_decl * f) const { return false; }
bool rewrite_patterns() const { return true; }
bool max_scopes_exceeded(unsigned num_scopes) const { return false; }
bool max_frames_exceeded(unsigned num_frames) const { return false; }
bool max_steps_exceeded(unsigned num_steps) const { return false; }
bool pre_visit(expr * t) { return true; }
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { return BR_FAILED; }
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) {
return false;
}
bool reduce_var(var * t, expr_ref & result, proof_ref & result_pr) { return false; }
bool get_macro(func_decl * d, expr * & def, quantifier * & q, proof * & def_pr) { return false; }
bool get_subst(expr * s, expr * & t, proof * & t_pr) { return false; }
void reset() {}
void cleanup() {}
};
struct beta_reducer_cfg : public default_rewriter_cfg {
bool pre_visit(expr * t) { return !is_ground(t); }
};
class beta_reducer : public rewriter_tpl<beta_reducer_cfg> {
beta_reducer_cfg m_cfg;
public:
beta_reducer(ast_manager & m):
rewriter_tpl<beta_reducer_cfg>(m, false, m_cfg) {}
};
#endif

View file

@ -1,642 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
rewriter_def.h
Abstract:
Lean and mean rewriter
Author:
Leonardo (leonardo) 2011-03-31
Notes:
--*/
#include"rewriter.h"
#include"ast_smt2_pp.h"
template<typename Config>
template<bool ProofGen>
void rewriter_tpl<Config>::process_var(var * v) {
if (m_cfg.reduce_var(v, m_r, m_pr)) {
result_stack().push_back(m_r);
if (ProofGen) {
result_pr_stack().push_back(m_pr);
m_pr = 0;
}
set_new_child_flag(v);
m_r = 0;
return;
}
if (!ProofGen) {
// bindings are only used when Proof Generation is not enabled.
unsigned idx = v->get_idx();
if (idx < m_bindings.size()) {
expr * r = m_bindings[m_bindings.size() - idx - 1];
TRACE("process_var", if (r) tout << "idx: " << idx << " --> " << mk_ismt2_pp(r, m()) << "\n";
tout << "bindings:\n";
for (unsigned i = 0; i < m_bindings.size(); i++) if (m_bindings[i]) tout << i << ": " << mk_ismt2_pp(m_bindings[i], m()) << "\n";);
if (r != 0) {
if (m_num_qvars == 0 || is_ground(r)) {
result_stack().push_back(r);
}
else {
expr_ref new_term(m());
m_shifter(r, m_num_qvars, new_term);
result_stack().push_back(new_term);
}
set_new_child_flag(v);
return;
}
}
}
result_stack().push_back(v);
if (ProofGen)
result_pr_stack().push_back(0); // implicit reflexivity
}
template<typename Config>
template<bool ProofGen>
void rewriter_tpl<Config>::process_const(app * t) {
SASSERT(t->get_num_args() == 0);
br_status st = m_cfg.reduce_app(t->get_decl(), 0, 0, m_r, m_pr);
SASSERT(st == BR_FAILED || st == BR_DONE);
if (st == BR_DONE) {
result_stack().push_back(m_r.get());
if (ProofGen) {
if (m_pr)
result_pr_stack().push_back(m_pr);
else
result_pr_stack().push_back(m().mk_rewrite(t, m_r));
m_pr = 0;
}
m_r = 0;
set_new_child_flag(t);
}
else {
result_stack().push_back(t);
if (ProofGen)
result_pr_stack().push_back(0); // implicit reflexivity
}
}
/**
\brief visit expression t. Return true if t was rewritten and the result is on the top m_result_stack.
We may skip t if:
- pre_visit(t) returns false
- max_depth == 0
- t is already in the cache
Otherwise, return false and add a new frame stack for t with the updated max_depth.
*/
template<typename Config>
template<bool ProofGen>
bool rewriter_tpl<Config>::visit(expr * t, unsigned max_depth) {
TRACE("rewriter_visit", tout << "visiting\n" << mk_ismt2_pp(t, m()) << "\n";);
expr * new_t;
proof * new_t_pr;
if (m_cfg.get_subst(t, new_t, new_t_pr)) {
TRACE("rewriter_subst", tout << "subst\n" << mk_ismt2_pp(t, m()) << "\n---->\n" << mk_ismt2_pp(new_t, m()) << "\n";);
result_stack().push_back(new_t);
set_new_child_flag(t, new_t);
if (ProofGen)
result_pr_stack().push_back(new_t_pr);
return true;
}
if (max_depth == 0) {
result_stack().push_back(t);
if (ProofGen)
result_pr_stack().push_back(0); // implicit reflexivity
return true; // t is not going to be processed
}
SASSERT(max_depth > 0);
SASSERT(max_depth <= RW_UNBOUNDED_DEPTH);
bool c = must_cache(t);
if (c) {
#if 0
static unsigned checked_cache = 0;
checked_cache ++;
if (checked_cache % 100000 == 0)
std::cerr << "[rewriter] num-cache-checks: " << checked_cache << std::endl;
#endif
expr * r = get_cached(t);
if (r) {
result_stack().push_back(r);
set_new_child_flag(t, r);
if (ProofGen) {
proof * pr = get_cached_pr(t);
result_pr_stack().push_back(pr);
}
return true;
}
}
if (!pre_visit(t)) {
result_stack().push_back(t);
if (ProofGen)
result_pr_stack().push_back(0); // implicit reflexivity
return true; // t is not going to be processed
}
switch (t->get_kind()) {
case AST_APP:
if (to_app(t)->get_num_args() == 0) {
process_const<ProofGen>(to_app(t));
return true;
}
else {
if (max_depth != RW_UNBOUNDED_DEPTH)
max_depth--;
push_frame(t, c, max_depth);
return false;
}
case AST_VAR:
process_var<ProofGen>(to_var(t));
return true;
case AST_QUANTIFIER:
if (max_depth != RW_UNBOUNDED_DEPTH)
max_depth--;
push_frame(t, c, max_depth);
return false;
default:
UNREACHABLE();
return true;
}
}
template<typename Config>
template<bool ProofGen>
void rewriter_tpl<Config>::process_app(app * t, frame & fr) {
SASSERT(t->get_num_args() > 0);
SASSERT(!frame_stack().empty());
switch (fr.m_state) {
case PROCESS_CHILDREN: {
unsigned num_args = t->get_num_args();
while (fr.m_i < num_args) {
expr * arg = t->get_arg(fr.m_i);
fr.m_i++;
if (!visit<ProofGen>(arg, fr.m_max_depth))
return;
}
func_decl * f = t->get_decl();
// If AC flattening is enabled, f is associative, t is not shared, and there is a previous frame on the stack.
if (!ProofGen) {
// this optimization is only used when Proof generation is disabled.
if (f->is_associative() && t->get_ref_count() <= 1 && frame_stack().size() > 1) {
frame & prev_fr = frame_stack()[frame_stack().size() - 2];
if (is_app(prev_fr.m_curr) &&
to_app(prev_fr.m_curr)->get_decl() == f &&
prev_fr.m_state == PROCESS_CHILDREN &&
flat_assoc(f)) {
frame_stack().pop_back();
set_new_child_flag(t);
return;
}
}
}
unsigned new_num_args = result_stack().size() - fr.m_spos;
expr * const * new_args = result_stack().c_ptr() + fr.m_spos;
app * new_t;
if (ProofGen) {
elim_reflex_prs(fr.m_spos);
unsigned num_prs = result_pr_stack().size() - fr.m_spos;
if (num_prs == 0) {
new_t = t;
m_pr = 0;
}
else {
new_t = m().mk_app(f, new_num_args, new_args);
m_pr = m().mk_congruence(t, new_t, num_prs, result_pr_stack().c_ptr() + fr.m_spos);
}
}
br_status st = m_cfg.reduce_app(f, new_num_args, new_args, m_r, m_pr2);
TRACE("reduce_app",
tout << mk_ismt2_pp(t, m()) << "\n";
tout << "st: " << st;
if (m_r) tout << " --->\n" << mk_ismt2_pp(m_r, m());
tout << "\n";);
if (st != BR_FAILED) {
result_stack().shrink(fr.m_spos);
result_stack().push_back(m_r);
if (ProofGen) {
result_pr_stack().shrink(fr.m_spos);
if (!m_pr2)
m_pr2 = m().mk_rewrite(new_t, m_r);
m_pr = m().mk_transitivity(m_pr, m_pr2);
m_pr2 = 0;
result_pr_stack().push_back(m_pr);
}
if (st == BR_DONE) {
cache_result<ProofGen>(t, m_r, m_pr, fr.m_cache_result);
frame_stack().pop_back();
set_new_child_flag(t);
m_r = 0;
if (ProofGen)
m_pr = 0;
return;
}
else {
fr.m_state = REWRITE_BUILTIN;
SASSERT(st == BR_REWRITE1 || st == BR_REWRITE2 || st == BR_REWRITE3 || st == BR_REWRITE_FULL);
unsigned max_depth = static_cast<unsigned>(st);
SASSERT(0 <= max_depth && max_depth <= RW_UNBOUNDED_DEPTH);
SASSERT((st == BR_REWRITE1) == (max_depth == 0));
SASSERT((st == BR_REWRITE2) == (max_depth == 1));
SASSERT((st == BR_REWRITE3) == (max_depth == 2));
SASSERT((st == BR_REWRITE_FULL) == (max_depth == RW_UNBOUNDED_DEPTH));
if (max_depth != RW_UNBOUNDED_DEPTH)
max_depth++;
if (visit<ProofGen>(m_r, max_depth)) {
if (ProofGen) {
proof_ref pr2(m()), pr1(m());
pr2 = result_pr_stack().back();
result_pr_stack().pop_back();
pr1 = result_pr_stack().back();
result_pr_stack().pop_back();
m_pr = m().mk_transitivity(pr1, pr2);
result_pr_stack().push_back(m_pr);
}
m_r = result_stack().back();
result_stack().pop_back();
result_stack().pop_back();
result_stack().push_back(m_r);
cache_result<ProofGen>(t, m_r, m_pr, fr.m_cache_result);
frame_stack().pop_back();
set_new_child_flag(t);
m_r = 0;
if (ProofGen)
m_pr = 0;
return;
}
else {
// frame was created for processing m_r
m_r = 0;
if (ProofGen)
m_pr = 0;
return;
}
}
UNREACHABLE();
}
// TODO: add rewrite rules support
expr * def;
proof * def_pr;
quantifier * def_q;
// When get_macro succeeds, then
// we know that:
// forall X. f(X) = def[X]
// and def_pr is a proof for this quantifier.
//
// Remark: def_q is only used for proof generation.
// It is the quantifier forall X. f(X) = def[X]
if (get_macro(f, def, def_q, def_pr)) {
SASSERT(!f->is_associative() || !flat_assoc(f));
SASSERT(new_num_args == t->get_num_args());
if (is_ground(def)) {
m_r = def;
if (ProofGen) {
SASSERT(def_pr);
m_pr = m().mk_transitivity(m_pr, def_pr);
}
}
else {
if (ProofGen) {
NOT_IMPLEMENTED_YET();
// We do not support the use of bindings in proof generation mode.
// Thus we have to apply the subsitution here, and
// beta_reducer subst(m());
// subst.set_bindings(new_num_args, new_args);
// expr_ref r2(m());
// subst(def, r2);
}
else {
fr.m_state = EXPAND_DEF;
TRACE("get_macro", tout << "f: " << f->get_name() << ", def: \n" << mk_ismt2_pp(def, m()) << "\n";
tout << "Args num: " << num_args << "\n";
for (unsigned i = 0; i < num_args; i++) tout << mk_ismt2_pp(new_args[i], m()) << "\n";);
unsigned i = num_args;
while (i > 0) {
--i;
m_bindings.push_back(new_args[i]);
}
result_stack().push_back(def);
TRACE("get_macro", tout << "bindings:\n";
for (unsigned i = 0; i < m_bindings.size(); i++) tout << i << ": " << mk_ismt2_pp(m_bindings[i], m()) << "\n";);
begin_scope();
m_num_qvars = 0;
m_root = def;
push_frame(def, false, RW_UNBOUNDED_DEPTH);
return;
}
}
}
else {
if (ProofGen) {
m_r = new_t;
}
else {
if (fr.m_new_child) {
m_r = m().mk_app(f, new_num_args, new_args);
}
else {
TRACE("rewriter_reuse", tout << "reusing:\n" << mk_ismt2_pp(t, m()) << "\n";);
m_r = t;
}
}
}
result_stack().shrink(fr.m_spos);
result_stack().push_back(m_r);
cache_result<ProofGen>(t, m_r, m_pr, fr.m_cache_result);
if (ProofGen) {
result_pr_stack().shrink(fr.m_spos);
result_pr_stack().push_back(m_pr);
m_pr = 0;
}
frame_stack().pop_back();
set_new_child_flag(t, m_r);
m_r = 0;
return;
}
case REWRITE_BUILTIN:
SASSERT(fr.m_spos + 2 == result_stack().size());
if (ProofGen) {
proof_ref pr2(m()), pr1(m());
pr2 = result_pr_stack().back();
result_pr_stack().pop_back();
pr1 = result_pr_stack().back();
result_pr_stack().pop_back();
m_pr = m().mk_transitivity(pr1, pr2);
result_pr_stack().push_back(m_pr);
}
m_r = result_stack().back();
result_stack().pop_back();
result_stack().pop_back();
result_stack().push_back(m_r);
cache_result<ProofGen>(t, m_r, m_pr, fr.m_cache_result);
frame_stack().pop_back();
set_new_child_flag(t);
return;
case EXPAND_DEF:
SASSERT(fr.m_spos + t->get_num_args() + 2 == result_stack().size());
SASSERT(t->get_num_args() <= m_bindings.size());
if (!ProofGen) {
m_bindings.shrink(m_bindings.size() - t->get_num_args());
end_scope();
m_r = result_stack().back();
result_stack().shrink(fr.m_spos);
result_stack().push_back(m_r);
cache_result<ProofGen>(t, m_r, m_pr, fr.m_cache_result);
frame_stack().pop_back();
set_new_child_flag(t);
}
else {
// TODO
NOT_IMPLEMENTED_YET();
}
return;
case REWRITE_RULE:
// support for rewriting rules was not implemented yet.
NOT_IMPLEMENTED_YET();
break;
default:
UNREACHABLE();
break;
}
}
template<typename Config>
template<bool ProofGen>
void rewriter_tpl<Config>::process_quantifier(quantifier * q, frame & fr) {
SASSERT(fr.m_state == PROCESS_CHILDREN);
if (fr.m_i == 0) {
if (!ProofGen) {
begin_scope();
m_root = q->get_expr();
}
m_num_qvars += q->get_num_decls();
if (!ProofGen) {
for (unsigned i = 0; i < q->get_num_decls(); i++)
m_bindings.push_back(0);
}
}
unsigned num_children = rewrite_patterns() ? q->get_num_children() : 1;
while (fr.m_i < num_children) {
expr * child = q->get_child(fr.m_i);
fr.m_i++;
if (!visit<ProofGen>(child, fr.m_max_depth))
return;
}
SASSERT(fr.m_spos + num_children == result_stack().size());
expr * const * it = result_stack().c_ptr() + fr.m_spos;
expr * new_body = *it;
expr * const * new_pats;
expr * const * new_no_pats;
if (rewrite_patterns()) {
new_pats = it + 1;
new_no_pats = new_pats + q->get_num_patterns();
}
else {
new_pats = q->get_patterns();
new_no_pats = q->get_no_patterns();
}
if (ProofGen) {
quantifier * new_q = m().update_quantifier(q, q->get_num_patterns(), new_pats, q->get_num_no_patterns(), new_no_pats, new_body);
m_pr = q == new_q ? 0 : m().mk_quant_intro(q, new_q, result_pr_stack().get(fr.m_spos));
m_r = new_q;
proof_ref pr2(m());
if (m_cfg.reduce_quantifier(new_q, new_body, new_pats, new_no_pats, m_r, pr2)) {
m_pr = m().mk_transitivity(m_pr, pr2);
}
TRACE("reduce_quantifier_bug", tout << "m_pr is_null: " << (m_pr.get() == 0) << "\n";
if (m_pr) tout << mk_ismt2_pp(m_pr, m()) << "\n";);
result_pr_stack().shrink(fr.m_spos);
result_pr_stack().push_back(m_pr);
}
else {
if (!m_cfg.reduce_quantifier(q, new_body, new_pats, new_no_pats, m_r, m_pr)) {
if (fr.m_new_child) {
m_r = m().update_quantifier(q, q->get_num_patterns(), new_pats, q->get_num_no_patterns(), new_no_pats, new_body);
}
else {
TRACE("rewriter_reuse", tout << "reusing:\n" << mk_ismt2_pp(q, m()) << "\n";);
m_r = q;
}
}
}
result_stack().shrink(fr.m_spos);
result_stack().push_back(m_r.get());
if (!ProofGen) {
SASSERT(q->get_num_decls() <= m_bindings.size());
m_bindings.shrink(m_bindings.size() - q->get_num_decls());
end_scope();
cache_result<ProofGen>(q, m_r, m_pr, fr.m_cache_result);
}
else {
cache_result<ProofGen>(q, m_r, m_pr, fr.m_cache_result);
m_pr = 0;
}
m_r = 0;
frame_stack().pop_back();
set_new_child_flag(q, m_r);
}
template<typename Config>
bool rewriter_tpl<Config>::not_rewriting() const {
SASSERT(frame_stack().empty());
SASSERT(m_cache == m_cache_stack[0]);
return true;
}
template<typename Config>
rewriter_tpl<Config>::rewriter_tpl(ast_manager & m, bool proof_gen, Config & cfg):
rewriter_core(m, proof_gen),
m_cfg(cfg),
m_num_steps(0),
m_cancel(false),
m_shifter(m),
m_r(m),
m_pr(m),
m_pr2(m) {
}
template<typename Config>
rewriter_tpl<Config>::~rewriter_tpl() {
}
template<typename Config>
void rewriter_tpl<Config>::reset() {
m_cfg.reset();
rewriter_core::reset();
m_bindings.reset();
m_shifter.reset();
}
template<typename Config>
void rewriter_tpl<Config>::cleanup() {
m_cfg.cleanup();
rewriter_core::cleanup();
m_bindings.finalize();
m_shifter.cleanup();
}
template<typename Config>
void rewriter_tpl<Config>::set_bindings(unsigned num_bindings, expr * const * bindings) {
SASSERT(!m_proof_gen);
SASSERT(not_rewriting());
m_bindings.reset();
unsigned i = num_bindings;
while (i > 0) {
--i;
m_bindings.push_back(bindings[i]);
}
}
template<typename Config>
void rewriter_tpl<Config>::set_inv_bindings(unsigned num_bindings, expr * const * bindings) {
SASSERT(!m_proof_gen);
SASSERT(not_rewriting());
m_bindings.reset();
for (unsigned i = 0; i < num_bindings; i++) {
m_bindings.push_back(bindings[i]);
}
}
template<typename Config>
template<bool ProofGen>
void rewriter_tpl<Config>::main_loop(expr * t, expr_ref & result, proof_ref & result_pr) {
SASSERT(!ProofGen || result_stack().size() == result_pr_stack().size());
SASSERT(not_rewriting());
m_root = t;
m_num_qvars = 0;
m_num_steps = 0;
if (visit<ProofGen>(t, RW_UNBOUNDED_DEPTH)) {
result = result_stack().back();
result_stack().pop_back();
SASSERT(result_stack().empty());
if (ProofGen) {
result_pr = result_pr_stack().back();
result_pr_stack().pop_back();
if (result_pr.get() == 0)
result_pr = m().mk_reflexivity(t);
SASSERT(result_pr_stack().empty());
}
return;
}
resume_core<ProofGen>(result, result_pr);
}
/**
\brief Resume the execution when it was interrupted by cancel() or check_max_steps().
*/
template<typename Config>
template<bool ProofGen>
void rewriter_tpl<Config>::resume_core(expr_ref & result, proof_ref & result_pr) {
SASSERT(!frame_stack().empty());
while (!frame_stack().empty()) {
if (m_cancel)
throw rewriter_exception(TACTIC_CANCELED_MSG);
SASSERT(!ProofGen || result_stack().size() == result_pr_stack().size());
frame & fr = frame_stack().back();
expr * t = fr.m_curr;
TRACE("rewriter_step", tout << "step\n" << mk_ismt2_pp(t, m()) << "\n";);
m_num_steps++;
check_max_steps();
if (first_visit(fr) && fr.m_cache_result) {
expr * r = get_cached(t);
if (r) {
result_stack().push_back(r);
if (ProofGen) {
proof * pr = get_cached_pr(t);
result_pr_stack().push_back(pr);
}
frame_stack().pop_back();
set_new_child_flag(t, r);
continue;
}
}
switch (t->get_kind()) {
case AST_APP:
process_app<ProofGen>(to_app(t), fr);
break;
case AST_QUANTIFIER:
process_quantifier<ProofGen>(to_quantifier(t), fr);
break;
case AST_VAR:
frame_stack().pop_back();
process_var<ProofGen>(to_var(t));
break;
default:
UNREACHABLE();
break;
}
}
result = result_stack().back();
result_stack().pop_back();
SASSERT(result_stack().empty());
if (ProofGen) {
result_pr = result_pr_stack().back();
result_pr_stack().pop_back();
if (result_pr.get() == 0)
result_pr = m().mk_reflexivity(m_root);
SASSERT(result_pr_stack().empty());
}
}
template<typename Config>
void rewriter_tpl<Config>::operator()(expr * t, expr_ref & result, proof_ref & result_pr) {
if (m_proof_gen)
main_loop<true>(t, result, result_pr);
else
main_loop<false>(t, result, result_pr);
}
template<typename Config>
void rewriter_tpl<Config>::resume(expr_ref & result, proof_ref & result_pr) {
if (m_proof_gen)
resume_core<true>(result, result_pr);
else
resume_core<false>(result, result_pr);
}

View file

@ -1,51 +0,0 @@
/*++
Copyright (c) 2007 Microsoft Corporation
Module Name:
rewriter_types.h
Abstract:
Lean and mean rewriter
Author:
Leonardo (leonardo) 2011-04-10
Notes:
--*/
#ifndef _REWRITER_TYPES_H_
#define _REWRITER_TYPES_H_
#include"tactic_exception.h"
/**
\brief Builtin rewrite result status
*/
enum br_status {
BR_REWRITE1, // rewrite the result (bounded by depth 1)
BR_REWRITE2, // rewrite the result (bounded by depth 2)
BR_REWRITE3, // rewrite the result (bounded by depth 3)
BR_REWRITE_FULL, // rewrite the result unbounded
BR_DONE, // done, the result is simplified
BR_FAILED // no builtin rewrite is available
};
#define RW_UNBOUNDED_DEPTH 3
inline br_status unsigned2br_status(unsigned u) {
br_status r = u >= RW_UNBOUNDED_DEPTH ? BR_REWRITE_FULL : static_cast<br_status>(u);
SASSERT((u == 0) == (r == BR_REWRITE1));
SASSERT((u == 1) == (r == BR_REWRITE2));
SASSERT((u == 2) == (r == BR_REWRITE3));
SASSERT((u >= 3) == (r == BR_REWRITE_FULL));
return r;
}
class rewriter_exception : public tactic_exception {
public:
rewriter_exception(char const * msg):tactic_exception(msg) {}
};
#endif

View file

@ -1,800 +0,0 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
rpolynomial.cpp
Abstract:
Goodies for creating and handling polynomials in dense recursive representation.
Author:
Leonardo (leonardo) 2012-06-11
Notes:
--*/
#include"rpolynomial.h"
#include"tptr.h"
#include"buffer.h"
namespace rpolynomial {
typedef void poly_or_num;
inline bool is_poly(poly_or_num * p) { return GET_TAG(p) == 0; }
inline bool is_num(poly_or_num * p) { return GET_TAG(p) == 1; }
polynomial * to_poly(poly_or_num * p) { SASSERT(is_poly(p)); return UNTAG(polynomial*, p); }
manager::numeral * to_num_ptr(poly_or_num * p) { SASSERT(is_num(p)); return (UNTAG(manager::numeral *, p)); }
manager::numeral & to_num(poly_or_num * p) { return *to_num_ptr(p); }
poly_or_num * to_poly_or_num(polynomial * p) { return TAG(poly_or_num*, p, 0); }
poly_or_num * to_poly_or_num(manager::numeral * n) { return TAG(poly_or_num*, n, 1); }
class polynomial {
friend class manager;
friend struct manager::imp;
unsigned m_ref_count;
var m_var;
unsigned m_size;
poly_or_num * m_args[0];
public:
unsigned ref_count() const { return m_ref_count; }
void inc_ref() { m_ref_count++; }
void dec_ref() { SASSERT(m_ref_count > 0); m_ref_count--; }
static unsigned get_obj_size(unsigned n) { return sizeof(polynomial) + n*sizeof(void*); }
var max_var() const { return m_var; }
unsigned size() const { return m_size; }
poly_or_num * arg(unsigned i) const { SASSERT(i < size()); return m_args[i]; }
};
struct manager::imp {
manager & m_wrapper;
numeral_manager & m_manager;
small_object_allocator * m_allocator;
bool m_own_allocator;
volatile bool m_cancel;
imp(manager & w, numeral_manager & m, small_object_allocator * a):
m_wrapper(w),
m_manager(m),
m_allocator(a),
m_own_allocator(a == 0) {
if (a == 0)
m_allocator = alloc(small_object_allocator, "rpolynomial");
m_cancel = false;
}
~imp() {
if (m_own_allocator)
dealloc(m_allocator);
}
// Remark: recursive calls should be fine since I do not expect to have polynomials with more than 100 variables.
manager & pm() const { return m_wrapper; }
numeral * mk_numeral() {
void * mem = m_allocator->allocate(sizeof(numeral));
return new (mem) numeral();
}
void del_numeral(numeral * n) {
m_manager.del(*n);
m_allocator->deallocate(sizeof(numeral), n);
}
static void inc_ref(polynomial * p) {
if (p)
p->inc_ref();
}
static void inc_ref(poly_or_num * p) {
if (p && is_poly(p))
inc_ref(to_poly(p));
}
void del_poly(polynomial * p) {
SASSERT(p != 0);
ptr_buffer<polynomial> todo;
todo.push_back(p);
while (!todo.empty()) {
p = todo.back();
todo.pop_back();
unsigned sz = p->size();
for (unsigned i = 0; i < sz; i++) {
poly_or_num * pn = p->arg(i);
if (pn == 0)
continue;
if (is_num(pn)) {
del_numeral(to_num_ptr(pn));
}
else {
SASSERT(is_poly(p));
polynomial * p_arg = to_poly(p);
p_arg->dec_ref();
if (p_arg->ref_count() == 0) {
todo.push_back(p_arg);
}
}
}
unsigned obj_sz = polynomial::get_obj_size(sz);
m_allocator->deallocate(obj_sz, p);
}
}
void dec_ref(polynomial * p) {
if (p) {
p->dec_ref();
if (p->ref_count() == 0)
del_poly(p);
}
}
void dec_ref(poly_or_num * p) {
if (p && is_poly(p))
dec_ref(to_poly(p));
}
static bool is_const(polynomial const * p) {
SASSERT(p == 0 || (p->max_var() == null_var) == (p->size() == 1 && p->arg(0) != 0 && is_num(p->arg(0))));
return p == 0 || p->max_var() == null_var;
}
bool is_zero(polynomial const * p) {
return p == 0;
}
static bool is_univariate(polynomial const * p) {
if (is_const(p))
return false;
unsigned sz = p->size();
for (unsigned i = 0; i < sz; i++) {
poly_or_num * pn = p->arg(i);
if (pn == 0)
continue;
if (is_poly(pn))
return false;
}
return true;
}
bool is_monomial(polynomial const * p) {
if (is_const(p))
return true;
unsigned sz = p->size();
SASSERT(sz > 0);
SASSERT(p->arg(sz - 1) != 0);
for (unsigned i = 0; i < sz - 1; i++) {
if (p->arg(i) != 0)
return false;
}
SASSERT(is_poly(p->arg(sz - 1)));
return is_monomial(to_poly(p->arg(sz-1)));
}
unsigned degree(polynomial const * p) {
SASSERT(p != 0);
SASSERT(p->size() > 0);
return p == 0 ? 0 : p->size() - 1;
}
bool eq(polynomial const * p1, polynomial const * p2) {
if (p1 == p2)
return true;
if (p1 == 0 || p2 == 0)
return false;
if (p1->size() != p2->size())
return false;
if (p1->max_var() != p2->max_var())
return false;
unsigned sz = p1->size();
for (unsigned i = 0; i < sz; i++) {
poly_or_num * pn1 = p1->arg(i);
poly_or_num * pn2 = p2->arg(i);
if (pn1 == 0 && pn2 == 0)
continue;
if (pn1 == 0 || pn2 == 0)
return false;
if (is_num(pn1) && is_num(pn2)) {
if (!m_manager.eq(to_num(pn1), to_num(pn2)))
return false;
}
else if (is_poly(pn1) && is_poly(pn2)) {
if (!eq(to_poly(pn1), to_poly(pn2)))
return false;
}
else {
return false;
}
}
return true;
}
void inc_ref_args(unsigned sz, poly_or_num * const * args) {
for (unsigned i = 0; i < sz; i++) {
poly_or_num * pn = args[i];
if (pn == 0 || is_num(pn))
continue;
inc_ref(to_poly(pn));
}
}
void dec_ref_args(unsigned sz, poly_or_num * const * args) {
for (unsigned i = 0; i < sz; i++) {
poly_or_num * pn = args[i];
if (pn == 0 || is_num(pn))
continue;
dec_ref(to_poly(pn));
}
}
unsigned trim(unsigned sz, poly_or_num * const * args) {
while (sz > 0) {
if (args[sz - 1] != 0)
return sz;
sz--;
}
UNREACHABLE();
return UINT_MAX;
}
polynomial * allocate_poly(unsigned sz, poly_or_num * const * args, var max_var) {
SASSERT(sz > 0);
SASSERT((max_var == null_var) == (sz == 1 && is_num(args[0])));
unsigned obj_sz = polynomial::get_obj_size(sz);
void * mem = m_allocator->allocate(obj_sz);
polynomial * new_pol = new (mem) polynomial();
new_pol->m_ref_count = 0;
new_pol->m_var = max_var;
new_pol->m_size = sz;
for (unsigned i = 0; i < sz; i++) {
poly_or_num * pn = args[i];
if (is_poly(pn)) {
inc_ref(to_poly(pn));
new_pol->m_args[i] = pn;
SASSERT(max_var == null_var || to_poly(pn)->max_var() < max_var);
}
else {
SASSERT(!m_manager.is_zero(to_num(pn)));
new_pol->m_args[i] = pn;
}
}
return new_pol;
}
poly_or_num * mk_poly_core(unsigned sz, poly_or_num * const * args, var max_var) {
sz = trim(sz, args);
SASSERT(sz > 0);
if (sz == 1) {
poly_or_num * pn0 = args[0];
SASSERT(!is_num(pn0) || !m_manager.is_zero(to_num(pn0)));
return pn0;
}
SASSERT((max_var == null_var) == (sz == 1 && is_num(args[0])));
SASSERT(sz > 1);
return to_poly_or_num(allocate_poly(sz, args, max_var));
}
polynomial * mk_poly(unsigned sz, poly_or_num * const * args, var max_var) {
poly_or_num * _p = mk_poly_core(sz, args, max_var);
if (_p == 0)
return 0;
else if (is_num(_p))
return allocate_poly(1, &_p, null_var);
else
return to_poly(_p);
}
polynomial * mk_const(numeral const & n) {
if (m_manager.is_zero(n))
return 0;
numeral * a = mk_numeral();
m_manager.set(*a, n);
poly_or_num * _a = to_poly_or_num(a);
return allocate_poly(1, &_a, null_var);
}
polynomial * mk_const(rational const & a) {
SASSERT(a.is_int());
scoped_numeral tmp(m_manager);
m_manager.set(tmp, a.to_mpq().numerator());
return mk_const(tmp);
}
polynomial * mk_polynomial(var x, unsigned k) {
SASSERT(x != null_var);
if (k == 0) {
numeral one;
m_manager.set(one, 1);
return mk_const(one);
}
ptr_buffer<poly_or_num> new_args;
for (unsigned i = 0; i < k; i++)
new_args.push_back(0);
numeral * new_arg = mk_numeral();
m_manager.set(*new_arg, 1);
new_args.push_back(to_poly_or_num(new_arg));
return mk_poly(new_args.size(), new_args.c_ptr(), x);
}
poly_or_num * unpack(polynomial const * p) {
if (p == 0) {
return 0;
}
else if (is_const(p)) {
SASSERT(p->size() == 1);
SASSERT(p->max_var() == null_var);
return p->arg(0);
}
else {
return to_poly_or_num(const_cast<polynomial*>(p));
}
}
polynomial * pack(poly_or_num * p) {
if (p == 0)
return 0;
else if (is_num(p))
return mk_poly(1, &p, null_var);
else
return to_poly(p);
}
poly_or_num * mul_core(numeral const & c, poly_or_num * p) {
if (m_manager.is_zero(c) || p == 0) {
return 0;
}
else if (is_num(p)) {
numeral * r = mk_numeral();
m_manager.mul(c, to_num(p), *r);
return to_poly_or_num(r);
}
else {
polynomial * _p = to_poly(p);
unsigned sz = _p->size();
SASSERT(sz > 1);
ptr_buffer<poly_or_num> new_args;
for (unsigned i = 0; i < sz; i++) {
new_args.push_back(mul_core(c, _p->arg(i)));
}
return mk_poly_core(new_args.size(), new_args.c_ptr(), _p->max_var());
}
}
polynomial * mul(numeral const & c, polynomial const * p) {
return pack(mul_core(c, unpack(p)));
}
polynomial * neg(polynomial const * p) {
numeral minus_one;
m_manager.set(minus_one, -1);
return pack(mul_core(minus_one, unpack(p)));
}
poly_or_num * add_core(numeral const & c, poly_or_num * p) {
if (m_manager.is_zero(c)) {
return p;
}
else if (p == 0) {
numeral * r = mk_numeral();
m_manager.set(*r, c);
return to_poly_or_num(r);
}
else if (is_num(p)) {
numeral a;
m_manager.add(c, to_num(p), a);
if (m_manager.is_zero(a))
return 0;
numeral * new_arg = mk_numeral();
m_manager.swap(*new_arg, a);
return to_poly_or_num(new_arg);
}
else {
polynomial * _p = to_poly(p);
unsigned sz = _p->size();
SASSERT(sz > 1);
ptr_buffer<poly_or_num> new_args;
new_args.push_back(add_core(c, _p->arg(0)));
for (unsigned i = 1; i < sz; i++)
new_args.push_back(_p->arg(1));
return mk_poly_core(new_args.size(), new_args.c_ptr(), _p->max_var());
}
}
polynomial * add(numeral const & c, polynomial const * p) {
return pack(add_core(c, unpack(p)));
}
#if 0
polynomial * add_lt(polynomial const * p1, polynomial const * p2) {
// Add non-constant polynomials p1 and p2 when max_var(p1) < max_var(p2)
SASSERT(p1->max_var() != null_var);
SASSERT(p2->max_var() != null_var);
SASSERT(p1->max_var() < p2->max_var());
unsigned sz = p2->size();
ptr_buffer<poly_or_num> new_args;
poly_or_num * pn0 = p2->arg(0);
if (pn0 == 0) {
new_args.push_back(to_poly_or_num(const_cast<polynomial*>(p1)));
}
else if (is_num(pn0)) {
SASSERT(!is_const(p1));
polynomial * new_arg = add(to_num(pn0), p1);
SASSERT(!is_zero(new_arg));
SASSERT(!is_const(new_arg));
new_args.push_back(to_poly_or_num(new_arg));
}
else {
SASSERT(is_poly(pn0));
polynomial * new_arg = add(p1, to_poly(pn0));
new_args.push_back(to_poly_or_num(new_arg));
}
for (unsigned i = 1; i < sz; i++)
new_args.push_back(p2->arg(i));
return mk_poly(sz, new_args.c_ptr(), p2->max_var());
}
polynomial * add(polynomial const * p1, polynomial const * p2) {
if (is_zero(p1))
return const_cast<polynomial*>(p2);
if (is_zero(p2))
return const_cast<polynomial*>(p1);
var x1 = p1->max_var();
var x2 = p2->max_var();
if (x1 == null_var) {
SASSERT(is_const(p1));
return add(to_num(p1->arg(0)), p2);
}
if (x2 == null_var) {
SASSERT(is_const(p2));
return add(to_num(p2->arg(0)), p1);
}
if (x1 < x2)
return add_lt(p1, p2);
if (x2 < x1)
return add_lt(p2, p1);
SASSERT(x1 == x2);
unsigned sz1 = p1->size();
unsigned sz2 = p2->size();
unsigned msz = std::min(sz1, sz2);
ptr_buffer<poly_or_num> new_args;
for (unsigned i = 0; i < msz; i++) {
poly_or_num * pn1 = p1->arg(i);
poly_or_num * pn2 = p2->arg(i);
if (pn1 == 0) {
new_args.push_back(pn2);
continue;
}
if (pn2 == 0) {
new_args.push_back(pn1);
continue;
}
SASSERT(pn1 != 0 && pn2 != 0);
if (is_num(pn1)) {
if (is_num(pn2)) {
SASSERT(is_num(pn1) && is_num(pn2));
numeral a;
m_manager.add(to_num(pn1), to_num(pn2), a);
if (m_manager.is_zero(a)) {
new_args.push_back(0);
}
else {
numeral * new_arg = mk_numeral();
m_manager.swap(*new_arg, a);
new_args.push_back(to_poly_or_num(new_arg));
}
}
else {
SASSERT(is_num(pn1) && is_poly(pn2));
new_args.push_back(to_poly_or_num(add(to_num(pn1), to_poly(pn2))));
}
}
else {
if (is_num(pn2)) {
SASSERT(is_poly(pn1) && is_num(pn2));
new_args.push_back(to_poly_or_num(add(to_num(pn2), to_poly(pn1))));
}
else {
SASSERT(is_poly(pn1) && is_poly(pn2));
new_args.push_back(to_poly_or_num(add(to_poly(pn1), to_poly(pn2))));
}
}
}
SASSERT(new_args.size() == sz1 || new_args.size() == sz2);
for (unsigned i = msz; i < sz1; i++) {
new_args.push_back(p1->arg(i));
}
for (unsigned i = msz; i < sz2; i++) {
new_args.push_back(p2->arg(i));
}
SASSERT(new_args.size() == std::max(sz1, sz2));
return mk_poly(new_args.size(), new_args.c_ptr(), x1);
}
class resetter_mul_buffer;
friend class resetter_mul_buffer;
class resetter_mul_buffer {
imp & m_owner;
ptr_buffer<poly_or_num> m_buffer;
public:
resetter_mul_buffer(imp & o, ptr_buffer<poly_or_num> & b):m_owner(o), m_buffer(b) {}
~resetter_mul_buffer() {
m_owner.dec_ref_args(m_buffer.size(), m_buffer.c_ptr());
m_buffer.reset();
}
};
void acc_mul_xk(ptr_buffer<poly_or_num> & mul_buffer, unsigned k, polynomial * p) {
if (mul_buffer[k] == 0) {
mul_buffer[k] = to_poly_or_num(p);
inc_ref(p);
}
else {
polynomial * new_p;
if (is_num(mul_buffer[k]))
new_p = add(to_num(mul_buffer.get(k)), p);
else
new_p = add(p, to_poly(mul_buffer.get(k)));
if (is_zero(new_p)) {
dec_ref(mul_buffer[k]);
mul_buffer[k] = 0;
}
else {
inc_ref(new_p);
dec_ref(mul_buffer[k]);
mul_buffer[k] = to_poly_or_num(new_p);
}
}
}
void acc_mul_xk(ptr_buffer<poly_or_num> & mul_buffer, unsigned k, numeral & a) {
if (mul_buffer.get(k) == 0) {
numeral * new_arg = mk_numeral();
m_manager.swap(*new_arg, a);
mul_buffer[k] = to_poly_or_num(new_arg);
}
else {
if (is_num(mul_buffer[k])) {
m_manager.add(to_num(mul_buffer[k]), a, to_num(mul_buffer[k]));
if (m_manager.is_zero(to_num(mul_buffer[k]))) {
del_numeral(to_num_ptr(mul_buffer[k]));
mul_buffer[k] = 0;
}
}
else {
polynomial * new_p = add(a, to_poly(mul_buffer.get(k)));
if (is_zero(new_p)) {
dec_ref(mul_buffer[k]);
mul_buffer[k] = 0;
}
else {
inc_ref(new_p);
dec_ref(mul_buffer[k]);
mul_buffer[k] = to_poly_or_num(new_p);
}
}
}
}
polynomial * mul_lt(polynomial const * p1, polynomial const * p2) {
unsigned sz2 = p2->size();
// TODO
return 0;
}
polynomial * mul(polynomial const * p1, polynomial const * p2) {
var x1 = p1->max_var();
var x2 = p2->max_var();
if (x1 == null_var) {
SASSERT(is_const(p1));
return mul(to_num(p1->arg(0)), p2);
}
if (x2 == null_var) {
SASSERT(is_const(p2));
return mul(to_num(p2->arg(0)), p1);
}
if (x1 < x2)
return mul_lt(p1, p2);
if (x2 < x1)
return mul_lt(p2, p1);
SASSERT(x1 == x2);
if (degree(p1) < degree(p2))
std::swap(p1, p2);
unsigned sz = degree(p1) * degree(p2) + 1;
ptr_buffer<poly_or_num> mul_buffer;
resetter_mul_buffer resetter(*this, mul_buffer);
mul_buffer.resize(sz);
unsigned sz1 = p1->size();
unsigned sz2 = p2->size();
for (unsigned i1 = 0; i1 < sz1; i1++) {
poly_or_num * pn1 = p1->arg(i1);
if (pn1 == 0)
continue;
for (unsigned i2 = 0; i2 < sz2; i2++) {
poly_or_num * pn2 = p2->arg(i2);
if (pn2 == 0)
continue;
unsigned i = i1+i2;
if (is_num(pn1)) {
if (is_num(pn2)) {
SASSERT(is_num(pn1) && is_num(pn2));
scoped_numeral a(m_manager);
m_manager.mul(to_num(pn1), to_num(pn2), a);
acc_mul_xk(mul_buffer, i, a);
}
else {
SASSERT(is_num(pn1) && is_poly(pn2));
polynomial_ref p(pm());
p = mul(to_num(pn1), to_poly(pn2));
acc_mul_xk(mul_buffer, i, p);
}
}
else {
if (is_num(pn2)) {
SASSERT(is_poly(pn1) && is_num(pn2));
polynomial_ref p(pm());
p = mul(to_num(pn2), to_poly(pn1));
acc_mul_xk(mul_buffer, i, p);
}
else {
SASSERT(is_poly(pn1) && is_poly(pn2));
polynomial_ref p(pm());
p = mul(to_poly(pn2), to_poly(pn1));
acc_mul_xk(mul_buffer, i, p);
}
}
}
}
return mk_poly(mul_buffer.size(), mul_buffer.c_ptr(), x1);
}
#endif
void display(std::ostream & out, polynomial const * p, display_var_proc const & proc, bool use_star) {
var x = p->max_var();
bool first = true;
unsigned i = p->size();
while (i > 0) {
--i;
poly_or_num * pn = p->arg(i);
if (pn == 0)
continue;
if (first)
first = false;
else
out << " + ";
if (is_num(pn)) {
numeral & a = to_num(pn);
if (i == 0) {
m_manager.display(out, a);
}
else {
if (m_manager.is_one(a)) {
proc(out, x);
if (i > 1)
out << "^" << i;
}
else {
m_manager.display(out, a);
if (use_star)
out << "*";
else
out << " ";
proc(out, x);
if (i > 1)
out << "^" << i;
}
}
}
else {
SASSERT(is_poly(pn));
if (i == 0) {
display(out, to_poly(pn), proc, use_star);
}
else {
bool add_paren = false;
if (i > 0)
add_paren = !is_monomial(to_poly(pn));
if (add_paren)
out << "(";
display(out, to_poly(pn), proc, use_star);
if (add_paren)
out << ")";
if (i > 0) {
if (use_star)
out << "*";
else
out << " ";
proc(out, x);
if (i > 1)
out << "^" << i;
}
}
}
}
}
};
manager:: manager(numeral_manager & m, small_object_allocator * a) {
m_imp = alloc(imp, *this, m, a);
}
manager::~manager() {
dealloc(m_imp);
}
bool manager::is_zero(polynomial const * p) {
return p == 0;
}
#if 0
bool manager::is_const(polynomial const * p) {
return imp::is_const(p);
}
bool manager::is_univariate(polynomial const * p) {
return imp::is_univariate(p);
}
bool manager::is_monomial(polynomial const * p) const {
return m_imp->is_monomial(p);
}
bool manager::eq(polynomial const * p1, polynomial const * p2) {
return m_imp->eq(p1, p2);
}
polynomial * manager::mk_zero() {
return m_imp->mk_zero();
}
polynomial * manager::mk_const(numeral const & r) {
return m_imp->mk_const(r);
}
polynomial * manager::mk_const(rational const & a) {
return m_imp->mk_const(a);
}
polynomial * manager::mk_polynomial(var x, unsigned k) {
return m_imp->mk_polynomial(x, k);
}
polynomial * manager::mul(numeral const & r, polynomial const * p) {
return m_imp->mul(r, p);
}
polynomial * manager::neg(polynomial const * p) {
return m_imp->neg(p);
}
polynomial * manager::add(numeral const & r, polynomial const * p) {
return m_imp->add(r, p);
}
polynomial * manager::add(polynomial const * p1, polynomial const * p2) {
return m_imp->add(p1, p2);
}
var manager::max_var(polynomial const * p) {
return p->max_var();
}
unsigned manager::size(polynomial const * p) {
return p->size();
}
void manager::display(std::ostream & out, polynomial const * p, display_var_proc const & proc, bool use_star) const {
return m_imp->display(out, p, proc, use_star);
}
#endif
};

View file

@ -1,208 +0,0 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
rpolynomial.h
Abstract:
Goodies for creating and handling polynomials in dense recursive representation.
Author:
Leonardo (leonardo) 2012-06-11
Notes:
--*/
#ifndef _RPOLYNOMIAL_H_
#define _RPOLYNOMIAL_H_
#include"mpz.h"
#include"rational.h"
#include"obj_ref.h"
#include"ref_vector.h"
#include"z3_exception.h"
#include"polynomial.h"
namespace rpolynomial {
typedef polynomial::var var;
const var null_var = polynomial::null_var;
typedef polynomial::var_vector var_vector;
typedef polynomial::display_var_proc display_var_proc;
typedef polynomial::polynomial som_polynomial;
class polynomial;
class manager;
typedef obj_ref<polynomial, manager> polynomial_ref;
typedef ref_vector<polynomial, manager> polynomial_ref_vector;
typedef ptr_vector<polynomial> polynomial_vector;
class manager {
public:
typedef unsynch_mpz_manager numeral_manager;
typedef numeral_manager::numeral numeral;
typedef svector<numeral> numeral_vector;
typedef _scoped_numeral<numeral_manager> scoped_numeral;
typedef _scoped_numeral_vector<numeral_manager> scoped_numeral_vector;
struct imp;
private:
imp * m_imp;
public:
manager(numeral_manager & m, small_object_allocator * a = 0);
~manager();
numeral_manager & m() const;
small_object_allocator & allocator() const;
void set_cancel(bool f);
/**
\brief Create a new variable.
*/
var mk_var();
/**
\brief Return the number of variables in the manager.
*/
unsigned num_vars() const;
/**
\brief Return true if x is a valid variable in this manager.
*/
bool is_valid(var x) const { return x < num_vars(); }
/**
\brief Increment reference counter.
*/
void inc_ref(polynomial * p);
/**
\brief Decrement reference counter.
*/
void dec_ref(polynomial * p);
/**
\brief Return true if \c p is the zero polynomial.
*/
bool is_zero(polynomial const * p);
/**
\brief Return true if p1 == p2.
*/
bool eq(polynomial const * p1, polynomial const * p2);
/**
\brief Return true if \c p is the constant polynomial.
*/
static bool is_const(polynomial const * p);
/**
\brief Return true if \c p is an univariate polynomial.
*/
static bool is_univariate(polynomial const * p);
/**
\brief Return true if \c p is a monomial.
*/
bool is_monomial(polynomial const * p) const;
/**
\brief Return the maximal variable occurring in p.
Return null_var if p is a constant polynomial.
*/
static var max_var(polynomial const * p);
/**
\brief Return the size of the polynomail p.
It is the degree(p) on max_var(p) + 1.
*/
static unsigned size(polynomial const * p);
/**
\brief Return a polynomial h that is the coefficient of max_var(p)^k in p.
if p does not contain any monomial containing max_var(p)^k, then return 0.
*/
polynomial * coeff(polynomial const * p, unsigned k);
/**
\brief Create the zero polynomial.
*/
polynomial * mk_zero();
/**
\brief Create the constant polynomial \c r.
\warning r is a number managed by the numeral_manager in the polynomial manager
\warning r is reset.
*/
polynomial * mk_const(numeral const & r);
/**
\brief Create the constant polynomial \c r.
\pre r must be an integer
*/
polynomial * mk_const(rational const & r);
/**
\brief Create the polynomial x^k
*/
polynomial * mk_polynomial(var x, unsigned k = 1);
polynomial * mul(numeral const & r, polynomial const * p);
polynomial * neg(polynomial const * p);
polynomial * add(numeral const & r, polynomial const * p);
polynomial * add(int c, polynomial const * p);
polynomial * add(polynomial const * p1, polynomial const * p2);
/**
\brief Convert the given polynomial in sum-of-monomials form into a polynomial in dense recursive form.
*/
polynomial * translate(som_polynomial const * p);
void display(std::ostream & out, polynomial const * p, display_var_proc const & proc = display_var_proc(), bool use_star = false) const;
void display_smt2(std::ostream & out, polynomial const * p, display_var_proc const & proc = display_var_proc()) const;
friend std::ostream & operator<<(std::ostream & out, polynomial_ref const & p) {
p.m().display(out, p);
return out;
}
};
};
typedef rpolynomial::polynomial_ref rpolynomial_ref;
typedef rpolynomial::polynomial_ref_vector rpolynomial_ref_vector;
inline rpolynomial_ref neg(rpolynomial_ref const & p) {
rpolynomial::manager & m = p.m();
return rpolynomial_ref(m.neg(p), m);
}
inline rpolynomial_ref operator-(rpolynomial_ref const & p) {
rpolynomial::manager & m = p.m();
return rpolynomial_ref(m.neg(p), m);
}
inline rpolynomial_ref operator+(int a, rpolynomial_ref const & p) {
rpolynomial::manager & m = p.m();
return rpolynomial_ref(m.add(a, p), m);
}
inline rpolynomial_ref operator+(rpolynomial_ref const & p, int a) {
rpolynomial::manager & m = p.m();
return rpolynomial_ref(m.add(a, p), m);
}
#endif

View file

@ -1,288 +0,0 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
subpaving.cpp
Abstract:
Subpaving for non-linear arithmetic.
This is a wrapper for the different implementations
of the subpaving module.
This wrapper is the main interface between Z3 other modules and subpaving.
Thus, it assumes that polynomials have precise integer coefficients, and
bounds are rationals. If a particular implementation uses floats, then
internally the bounds are approximated.
Author:
Leonardo de Moura (leonardo) 2012-08-07.
Revision History:
--*/
#include"subpaving.h"
#include"subpaving_types.h"
#include"subpaving_mpq.h"
#include"subpaving_mpf.h"
#include"subpaving_hwf.h"
#include"subpaving_mpff.h"
#include"subpaving_mpfx.h"
namespace subpaving {
template<typename CTX>
class context_wrapper : public context {
protected:
CTX m_ctx;
public:
context_wrapper(typename CTX::numeral_manager & m, params_ref const & p, small_object_allocator * a):m_ctx(m, p, a) {}
virtual ~context_wrapper() {}
virtual unsigned num_vars() const { return m_ctx.num_vars(); }
virtual var mk_var(bool is_int) { return m_ctx.mk_var(is_int); }
virtual bool is_int(var x) const { return m_ctx.is_int(x); }
virtual var mk_monomial(unsigned sz, power const * pws) { return m_ctx.mk_monomial(sz, pws); }
virtual void inc_ref(ineq * a) { m_ctx.inc_ref(reinterpret_cast<typename CTX::ineq*>(a)); }
virtual void dec_ref(ineq * a) { m_ctx.dec_ref(reinterpret_cast<typename CTX::ineq*>(a)); }
virtual void add_clause(unsigned sz, ineq * const * atoms) { m_ctx.add_clause(sz, reinterpret_cast<typename CTX::ineq * const *>(atoms)); }
virtual void display_constraints(std::ostream & out, bool use_star) const { m_ctx.display_constraints(out, use_star); }
virtual void set_cancel(bool f) { m_ctx.set_cancel(f); }
virtual void set_display_proc(display_var_proc * p) { m_ctx.set_display_proc(p); }
virtual void reset_statistics() { m_ctx.reset_statistics(); }
virtual void collect_statistics(statistics & st) const { m_ctx.collect_statistics(st); }
virtual void collect_param_descrs(param_descrs & r) { m_ctx.collect_param_descrs(r); }
virtual void updt_params(params_ref const & p) { m_ctx.updt_params(p); }
virtual void operator()() { m_ctx(); }
virtual void display_bounds(std::ostream & out) const { m_ctx.display_bounds(out); }
};
class context_mpq_wrapper : public context_wrapper<context_mpq> {
scoped_mpq m_c;
scoped_mpq_vector m_as;
public:
context_mpq_wrapper(unsynch_mpq_manager & m, params_ref const & p, small_object_allocator * a):
context_wrapper<context_mpq>(m, p, a),
m_c(m),
m_as(m)
{}
virtual ~context_mpq_wrapper() {}
virtual unsynch_mpq_manager & qm() const { return m_ctx.nm(); }
virtual var mk_sum(mpz const & c, unsigned sz, mpz const * as, var const * xs) {
m_as.reserve(sz);
for (unsigned i = 0; i < sz; i++) {
m_ctx.nm().set(m_as[i], as[i]);
}
m_ctx.nm().set(m_c, c);
return m_ctx.mk_sum(m_c, sz, m_as.c_ptr(), xs);
}
virtual ineq * mk_ineq(var x, mpq const & k, bool lower, bool open) {
return reinterpret_cast<ineq*>(m_ctx.mk_ineq(x, k, lower, open));
}
};
class context_mpf_wrapper : public context_wrapper<context_mpf> {
f2n<mpf_manager> & m_fm;
unsynch_mpq_manager & m_qm;
scoped_mpf m_c;
scoped_mpf_vector m_as;
scoped_mpq m_q1, m_q2;
// Convert the mpz (integer) into a mpf, and throws an exception if the conversion is not precise.
void int2mpf(mpz const & a, mpf & o) {
m_qm.set(m_q1, a);
m_ctx.nm().set(o, m_q1);
m_ctx.nm().m().to_rational(o, m_q2);
if (!m_qm.eq(m_q1, m_q2))
throw subpaving::exception();
}
public:
context_mpf_wrapper(f2n<mpf_manager> & fm, params_ref const & p, small_object_allocator * a):
context_wrapper<context_mpf>(fm, p, a),
m_fm(fm),
m_qm(fm.m().mpq_manager()),
m_c(fm.m()),
m_as(fm.m()),
m_q1(m_qm),
m_q2(m_qm) {
}
virtual ~context_mpf_wrapper() {}
virtual unsynch_mpq_manager & qm() const { return m_qm; }
virtual var mk_sum(mpz const & c, unsigned sz, mpz const * as, var const * xs) {
try {
m_as.reserve(sz);
for (unsigned i = 0; i < sz; i++) {
int2mpf(as[i], m_as[i]);
}
int2mpf(c, m_c);
return m_ctx.mk_sum(m_c, sz, m_as.c_ptr(), xs);
}
catch (f2n<mpf_manager>::exception) {
throw subpaving::exception();
}
}
virtual ineq * mk_ineq(var x, mpq const & k, bool lower, bool open) {
try {
f2n<mpf_manager> & m = m_ctx.nm();
if (lower)
m.round_to_minus_inf();
else
m.round_to_plus_inf();
m.set(m_c, k);
return reinterpret_cast<ineq*>(m_ctx.mk_ineq(x, m_c, lower, open));
}
catch (f2n<mpf_manager>::exception) {
throw subpaving::exception();
}
}
};
class context_hwf_wrapper : public context_wrapper<context_hwf> {
f2n<hwf_manager> & m_fm;
unsynch_mpq_manager & m_qm;
hwf m_c;
svector<hwf> m_as;
// Convert the mpz (integer) into a hwf, and throws an exception if the conversion is not precise.
void int2hwf(mpz const & a, hwf & o) {
if (!m_qm.is_int64(a))
throw subpaving::exception();
int64 val = m_qm.get_int64(a);
double dval = static_cast<double>(val);
m_ctx.nm().set(o, dval);
double _dval = m_ctx.nm().m().to_double(o);
// TODO check the following test
if (static_cast<int64>(_dval) != val)
throw subpaving::exception();
}
public:
context_hwf_wrapper(f2n<hwf_manager> & fm, unsynch_mpq_manager & qm, params_ref const & p, small_object_allocator * a):
context_wrapper<context_hwf>(fm, p, a),
m_fm(fm),
m_qm(qm) {
}
virtual ~context_hwf_wrapper() {}
virtual unsynch_mpq_manager & qm() const { return m_qm; }
virtual var mk_sum(mpz const & c, unsigned sz, mpz const * as, var const * xs) {
try {
m_as.reserve(sz);
for (unsigned i = 0; i < sz; i++) {
int2hwf(as[i], m_as[i]);
}
int2hwf(c, m_c);
return m_ctx.mk_sum(m_c, sz, m_as.c_ptr(), xs);
}
catch (f2n<mpf_manager>::exception) {
throw subpaving::exception();
}
}
virtual ineq * mk_ineq(var x, mpq const & k, bool lower, bool open) {
try {
f2n<hwf_manager> & m = m_ctx.nm();
if (lower)
m.round_to_minus_inf();
else
m.round_to_plus_inf();
m.set(m_c, k);
return reinterpret_cast<ineq*>(m_ctx.mk_ineq(x, m_c, lower, open));
}
catch (f2n<mpf_manager>::exception) {
throw subpaving::exception();
}
}
};
template<typename context_fpoint>
class context_fpoint_wrapper : public context_wrapper<context_fpoint> {
unsynch_mpq_manager & m_qm;
_scoped_numeral<typename context_fpoint::numeral_manager> m_c;
_scoped_numeral_vector<typename context_fpoint::numeral_manager> m_as;
scoped_mpz m_z1, m_z2;
void int2fpoint(mpz const & a, typename context_fpoint::numeral & o) {
m_qm.set(m_z1, a);
this->m_ctx.nm().set(o, m_qm, m_z1);
this->m_ctx.nm().to_mpz(o, m_qm, m_z2);
if (!m_qm.eq(m_z1, m_z2))
throw subpaving::exception();
}
public:
context_fpoint_wrapper(typename context_fpoint::numeral_manager & m, unsynch_mpq_manager & qm, params_ref const & p, small_object_allocator * a):
context_wrapper<context_fpoint>(m, p, a),
m_qm(qm),
m_c(m),
m_as(m),
m_z1(m_qm),
m_z2(m_qm) {
}
virtual ~context_fpoint_wrapper() {}
virtual unsynch_mpq_manager & qm() const { return m_qm; }
virtual var mk_sum(mpz const & c, unsigned sz, mpz const * as, var const * xs) {
try {
m_as.reserve(sz);
for (unsigned i = 0; i < sz; i++) {
int2fpoint(as[i], m_as[i]);
}
int2fpoint(c, m_c);
return this->m_ctx.mk_sum(m_c, sz, m_as.c_ptr(), xs);
}
catch (typename context_fpoint::numeral_manager::exception) {
throw subpaving::exception();
}
}
virtual ineq * mk_ineq(var x, mpq const & k, bool lower, bool open) {
try {
typename context_fpoint::numeral_manager & m = this->m_ctx.nm();
if (lower)
m.round_to_minus_inf();
else
m.round_to_plus_inf();
m.set(m_c, m_qm, k);
return reinterpret_cast<ineq*>(this->m_ctx.mk_ineq(x, m_c, lower, open));
}
catch (typename context_fpoint::numeral_manager::exception) {
throw subpaving::exception();
}
}
};
typedef context_fpoint_wrapper<context_mpff> context_mpff_wrapper;
typedef context_fpoint_wrapper<context_mpfx> context_mpfx_wrapper;
context * mk_mpq_context(unsynch_mpq_manager & m, params_ref const & p, small_object_allocator * a) {
return alloc(context_mpq_wrapper, m, p, a);
}
context * mk_mpf_context(f2n<mpf_manager> & m, params_ref const & p, small_object_allocator * a) {
return alloc(context_mpf_wrapper, m, p, a);
}
context * mk_hwf_context(f2n<hwf_manager> & m, unsynch_mpq_manager & qm, params_ref const & p, small_object_allocator * a) {
return alloc(context_hwf_wrapper, m, qm, p, a);
}
context * mk_mpff_context(mpff_manager & m, unsynch_mpq_manager & qm, params_ref const & p, small_object_allocator * a) {
return alloc(context_mpff_wrapper, m, qm, p, a);
}
context * mk_mpfx_context(mpfx_manager & m, unsynch_mpq_manager & qm, params_ref const & p, small_object_allocator * a) {
return alloc(context_mpfx_wrapper, m, qm, p, a);
}
};

View file

@ -1,124 +0,0 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
subpaving.h
Abstract:
Subpaving for non-linear arithmetic.
This is a wrapper for the different implementations
of the subpaving module.
This wrapper is the main interface between Z3 other modules and subpaving.
Thus, it assumes that polynomials have precise integer coefficients, and
bounds are rationals. If a particular implementation uses floats, then
internally the bounds are approximated.
Author:
Leonardo de Moura (leonardo) 2012-08-07.
Revision History:
--*/
#ifndef __SUBPAVING_H_
#define __SUBPAVING_H_
#include"mpq.h"
#include"subpaving_types.h"
#include"params.h"
#include"statistics.h"
template<typename fmanager> class f2n;
class mpf_manager;
class hwf_manager;
class mpff_manager;
class mpfx_manager;
namespace subpaving {
class context {
public:
virtual ~context() {}
virtual unsynch_mpq_manager & qm() const = 0;
/**
\brief Return the number of variables in this subpaving object.
*/
virtual unsigned num_vars() const = 0;
/**
\brief Create a new variable.
*/
virtual var mk_var(bool is_int) = 0;
/**
\brief Return true if \c x is an integer variable.
*/
virtual bool is_int(var x) const = 0;
/**
\brief Create the monomial xs[0]^ks[0] * ... * xs[sz-1]^ks[sz-1].
The result is a variable y s.t. y = xs[0]^ks[0] * ... * xs[sz-1]^ks[sz-1].
\pre for all i \in [0, sz-1] : ks[i] > 0
\pre sz > 0
*/
virtual var mk_monomial(unsigned sz, power const * pws) = 0;
/**
\brief Create the sum c + as[0]*xs[0] + ... + as[sz-1]*xs[sz-1].
The result is a variable y s.t. y = c + as[0]*xs[0] + ... + as[sz-1]*xs[sz-1].
\pre sz > 0
\pre for all i \in [0, sz-1] : as[i] != 0
*/
virtual var mk_sum(mpz const & c, unsigned sz, mpz const * as, var const * xs) = 0;
/**
\brief Create an inequality.
*/
virtual ineq * mk_ineq(var x, mpq const & k, bool lower, bool open) = 0;
virtual void inc_ref(ineq * a) = 0;
virtual void dec_ref(ineq * a) = 0;
/**
\brief Assert the clause atoms[0] \/ ... \/ atoms[sz-1]
\pre sz >= 1
*/
virtual void add_clause(unsigned sz, ineq * const * atoms) = 0;
/**
\brief Display constraints asserted in the subpaving.
*/
virtual void display_constraints(std::ostream & out, bool use_star = false) const = 0;
virtual void set_cancel(bool f) = 0;
virtual void collect_param_descrs(param_descrs & r) = 0;
virtual void updt_params(params_ref const & p) = 0;
virtual void set_display_proc(display_var_proc * p) = 0;
virtual void reset_statistics() = 0;
virtual void collect_statistics(statistics & st) const = 0;
virtual void operator()() = 0;
virtual void display_bounds(std::ostream & out) const = 0;
};
context * mk_mpq_context(unsynch_mpq_manager & m, params_ref const & p = params_ref(), small_object_allocator * a = 0);
context * mk_mpf_context(f2n<mpf_manager> & m, params_ref const & p = params_ref(), small_object_allocator * a = 0);
context * mk_hwf_context(f2n<hwf_manager> & m, unsynch_mpq_manager & qm, params_ref const & p = params_ref(), small_object_allocator * a = 0);
context * mk_mpff_context(mpff_manager & m, unsynch_mpq_manager & qm, params_ref const & p = params_ref(), small_object_allocator * a = 0);
context * mk_mpfx_context(mpfx_manager & m, unsynch_mpq_manager & qm, params_ref const & p = params_ref(), small_object_allocator * a = 0);
};
#endif

View file

@ -1,23 +0,0 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
subpaving_hwf.cpp
Abstract:
Subpaving for non-linear arithmetic using hardware floats.
Author:
Leonardo de Moura (leonardo) 2012-08-06.
Revision History:
--*/
#include"subpaving_hwf.h"
#include"subpaving_t_def.h"
// force template instantiation
template class subpaving::context_t<subpaving::config_hwf>;

View file

@ -1,48 +0,0 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
subpaving_hwf.h
Abstract:
Subpaving for non-linear arithmetic using hardware floats.
Author:
Leonardo de Moura (leonardo) 2012-08-06.
Revision History:
--*/
#ifndef __SUBPAVING_HWF_H_
#define __SUBPAVING_HWF_H_
#include"subpaving_t.h"
#include"f2n.h"
#include"hwf.h"
namespace subpaving {
struct config_hwf {
f2n<hwf_manager> & m_manager;
public:
typedef f2n<hwf_manager> numeral_manager;
typedef f2n<hwf_manager>::exception exception;
static void round_to_minus_inf(numeral_manager & m) { m.round_to_minus_inf(); }
static void round_to_plus_inf(numeral_manager & m) { m.round_to_plus_inf(); }
static void set_rounding(numeral_manager & m, bool to_plus_inf) { m.set_rounding(to_plus_inf); }
config_hwf(f2n<hwf_manager> & m):m_manager(m) {}
f2n<hwf_manager> & m() const { return const_cast<f2n<hwf_manager> &>(m_manager); }
};
class context_hwf : public context_t<config_hwf> {
public:
context_hwf(f2n<hwf_manager> & m, params_ref const & p, small_object_allocator * a):context_t<config_hwf>(config_hwf(m), p, a) {}
};
};
#endif

View file

@ -1,23 +0,0 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
subpaving_mpf.cpp
Abstract:
Subpaving for non-linear arithmetic using multi-precision floats.
Author:
Leonardo de Moura (leonardo) 2012-07-31.
Revision History:
--*/
#include"subpaving_mpf.h"
#include"subpaving_t_def.h"
// force template instantiation
template class subpaving::context_t<subpaving::config_mpf>;

View file

@ -1,49 +0,0 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
subpaving_mpf.h
Abstract:
Subpaving for non-linear arithmetic using multi-precision floats.
Author:
Leonardo de Moura (leonardo) 2012-07-31.
Revision History:
--*/
#ifndef __SUBPAVING_MPF_H_
#define __SUBPAVING_MPF_H_
#include"subpaving_t.h"
#include"mpf.h"
#include"f2n.h"
namespace subpaving {
struct config_mpf {
f2n<mpf_manager> & m_manager;
public:
typedef f2n<mpf_manager> numeral_manager;
typedef mpf numeral;
typedef f2n<mpf_manager>::exception exception;
static void round_to_minus_inf(numeral_manager & m) { m.round_to_minus_inf(); }
static void round_to_plus_inf(numeral_manager & m) { m.round_to_plus_inf(); }
static void set_rounding(numeral_manager & m, bool to_plus_inf) { m.set_rounding(to_plus_inf); }
config_mpf(f2n<mpf_manager> & m):m_manager(m) {}
f2n<mpf_manager> & m() const { return const_cast<f2n<mpf_manager> &>(m_manager); }
};
class context_mpf : public context_t<config_mpf> {
public:
context_mpf(f2n<mpf_manager> & m, params_ref const & p, small_object_allocator * a):context_t<config_mpf>(config_mpf(m), p, a) {}
};
};
#endif

View file

@ -1,23 +0,0 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
subpaving_mpff.cpp
Abstract:
Subpaving for non-linear arithmetic using mpff numerals.
Author:
Leonardo de Moura (leonardo) 2012-09-18.
Revision History:
--*/
#include"subpaving_mpff.h"
#include"subpaving_t_def.h"
// force template instantiation
template class subpaving::context_t<subpaving::config_mpff>;

View file

@ -1,45 +0,0 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
subpaving_mpff.h
Abstract:
Subpaving for non-linear arithmetic using mpff numerals
Author:
Leonardo de Moura (leonardo) 2012-09-18.
Revision History:
--*/
#ifndef __SUBPAVING_MPFF_H_
#define __SUBPAVING_MPFF_H_
#include"subpaving_t.h"
#include"mpff.h"
namespace subpaving {
struct config_mpff {
typedef mpff_manager numeral_manager;
typedef mpff_manager::exception exception;
static void round_to_minus_inf(numeral_manager & m) { m.round_to_minus_inf(); }
static void round_to_plus_inf(numeral_manager & m) { m.round_to_plus_inf(); }
static void set_rounding(numeral_manager & m, bool to_plus_inf) { m.set_rounding(to_plus_inf); }
numeral_manager & m_manager;
config_mpff(numeral_manager & m):m_manager(m) {}
numeral_manager & m() const { return m_manager; }
};
typedef context_t<config_mpff> context_mpff;
};
#endif

View file

@ -1,23 +0,0 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
subpaving_mpfx.cpp
Abstract:
Subpaving for non-linear arithmetic using mpfx numerals.
Author:
Leonardo de Moura (leonardo) 2012-09-18.
Revision History:
--*/
#include"subpaving_mpfx.h"
#include"subpaving_t_def.h"
// force template instantiation
template class subpaving::context_t<subpaving::config_mpfx>;

View file

@ -1,45 +0,0 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
subpaving_mpfx.h
Abstract:
Subpaving for non-linear arithmetic using mpfx numerals
Author:
Leonardo de Moura (leonardo) 2012-09-20.
Revision History:
--*/
#ifndef __SUBPAVING_MPFX_H_
#define __SUBPAVING_MPFX_H_
#include"subpaving_t.h"
#include"mpfx.h"
namespace subpaving {
struct config_mpfx {
typedef mpfx_manager numeral_manager;
typedef mpfx_manager::exception exception;
static void round_to_minus_inf(numeral_manager & m) { m.round_to_minus_inf(); }
static void round_to_plus_inf(numeral_manager & m) { m.round_to_plus_inf(); }
static void set_rounding(numeral_manager & m, bool to_plus_inf) { m.set_rounding(to_plus_inf); }
numeral_manager & m_manager;
config_mpfx(numeral_manager & m):m_manager(m) {}
numeral_manager & m() const { return m_manager; }
};
typedef context_t<config_mpfx> context_mpfx;
};
#endif

View file

@ -1,23 +0,0 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
subpaving_mpq.cpp
Abstract:
Subpaving for non-linear arithmetic using rationals.
Author:
Leonardo de Moura (leonardo) 2012-07-31.
Revision History:
--*/
#include"subpaving_mpq.h"
#include"subpaving_t_def.h"
// force template instantiation
template class subpaving::context_t<subpaving::config_mpq>;

View file

@ -1,43 +0,0 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
subpaving_mpq.h
Abstract:
Subpaving for non-linear arithmetic using rationals
Author:
Leonardo de Moura (leonardo) 2012-07-31.
Revision History:
--*/
#ifndef __SUBPAVING_MPQ_H_
#define __SUBPAVING_MPQ_H_
#include"subpaving_t.h"
#include"mpq.h"
namespace subpaving {
struct config_mpq {
typedef unsynch_mpq_manager numeral_manager;
struct exception {};
static void round_to_minus_inf(numeral_manager & m) {}
static void round_to_plus_inf(numeral_manager & m) {}
static void set_rounding(numeral_manager & m, bool to_plus_info) {}
numeral_manager & m_manager;
config_mpq(numeral_manager & m):m_manager(m) {}
numeral_manager & m() const { return m_manager; }
};
typedef context_t<config_mpq> context_mpq;
};
#endif

View file

@ -1,853 +0,0 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
subpaving_t.h
Abstract:
Subpaving template for non-linear arithmetic.
Author:
Leonardo de Moura (leonardo) 2012-07-31.
Revision History:
--*/
#ifndef __SUBPAVING_T_H_
#define __SUBPAVING_T_H_
#include<iostream>
#include"tptr.h"
#include"small_object_allocator.h"
#include"chashtable.h"
#include"parray.h"
#include"interval.h"
#include"scoped_numeral_vector.h"
#include"subpaving_types.h"
#include"params.h"
#include"statistics.h"
#include"lbool.h"
#include"id_gen.h"
#ifdef _MSC_VER
#pragma warning(disable : 4200)
#pragma warning(disable : 4355)
#endif
namespace subpaving {
template<typename C>
class context_t {
public:
typedef typename C::numeral_manager numeral_manager;
typedef typename numeral_manager::numeral numeral;
/**
\brief Inequalities used to encode a problem.
*/
class ineq {
friend class context_t;
var m_x;
numeral m_val;
unsigned m_ref_count:30;
unsigned m_lower:1;
unsigned m_open:1;
public:
var x() const { return m_x; }
numeral const & value() const { return m_val; }
bool is_lower() const { return m_lower; }
bool is_open() const { return m_open; }
void display(std::ostream & out, numeral_manager & nm, display_var_proc const & proc = display_var_proc());
struct lt_var_proc { bool operator()(ineq const * a, ineq const * b) const { return a->m_x < b->m_x; } };
};
class node;
class constraint {
public:
enum kind {
CLAUSE, MONOMIAL, POLYNOMIAL
// TODO: add SIN, COS, TAN, ...
};
protected:
kind m_kind;
uint64 m_timestamp;
public:
constraint(kind k):m_kind(k), m_timestamp(0) {}
kind get_kind() const { return m_kind; }
// Return the timestamp of the last propagation visit
uint64 timestamp() const { return m_timestamp; }
// Reset propagation visit time
void set_visited(uint64 ts) { m_timestamp = ts; }
};
/**
\brief Clauses in the problem description and lemmas learned during paving.
*/
class clause : public constraint {
friend class context_t;
unsigned m_size; //!< Number of atoms in the clause.
unsigned m_lemma:1; //!< True if it is a learned clause.
unsigned m_watched:1; //!< True if it we are watching this clause. All non-lemmas are watched.
unsigned m_num_jst:30; //!< Number of times it is used to justify some bound.
ineq * m_atoms[0];
static unsigned get_obj_size(unsigned sz) { return sizeof(clause) + sz*sizeof(ineq*); }
public:
clause():constraint(constraint::CLAUSE) {}
unsigned size() const { return m_size; }
bool watched() const { return m_watched; }
ineq * operator[](unsigned i) const { SASSERT(i < size()); return m_atoms[i]; }
void display(std::ostream & out, numeral_manager & nm, display_var_proc const & proc = display_var_proc());
};
class justification {
void * m_data;
public:
enum kind {
AXIOM = 0,
ASSUMPTION,
CLAUSE,
VAR_DEF
};
justification(bool axiom = true) {
m_data = axiom ? reinterpret_cast<void*>(static_cast<size_t>(AXIOM)) : reinterpret_cast<void*>(static_cast<size_t>(ASSUMPTION));
}
justification(justification const & source) { m_data = source.m_data; }
explicit justification(clause * c) { m_data = TAG(void*, c, CLAUSE); }
explicit justification(var x) { m_data = BOXTAGINT(void*, x, VAR_DEF); }
kind get_kind() const { return static_cast<kind>(GET_TAG(m_data)); }
bool is_clause() const { return get_kind() == CLAUSE; }
bool is_axiom() const { return get_kind() == AXIOM; }
bool is_assumption() const { return get_kind() == ASSUMPTION; }
bool is_var_def() const { return get_kind() == VAR_DEF; }
clause * get_clause() const {
SASSERT(is_clause());
return UNTAG(clause*, m_data);
}
var get_var() const {
SASSERT(is_var_def());
return UNBOXINT(m_data);
}
bool operator==(justification const & other) const { return m_data == other.m_data; }
bool operator!=(justification const & other) const { return !operator==(other); }
};
class bound {
friend class context_t;
numeral m_val;
unsigned m_x:29;
unsigned m_lower:1;
unsigned m_open:1;
unsigned m_mark:1;
uint64 m_timestamp;
bound * m_prev;
justification m_jst;
void set_timestamp(uint64 ts) { m_timestamp = ts; }
public:
var x() const { return static_cast<var>(m_x); }
numeral const & value() const { return m_val; }
numeral & value() { return m_val; }
bool is_lower() const { return m_lower; }
bool is_open() const { return m_open; }
uint64 timestamp() const { return m_timestamp; }
bound * prev() const { return m_prev; }
justification jst() const { return m_jst; }
void display(std::ostream & out, numeral_manager & nm, display_var_proc const & proc = display_var_proc());
};
struct bound_array_config {
typedef context_t value_manager;
typedef small_object_allocator allocator;
typedef bound * value;
static const bool ref_count = false;
static const bool preserve_roots = true;
static const unsigned max_trail_sz = 16;
static const unsigned factor = 2;
};
// auxiliary declarations for parray_manager
void dec_ref(bound *) {}
void inc_ref(bound *) {}
typedef parray_manager<bound_array_config> bound_array_manager;
typedef typename bound_array_manager::ref bound_array;
/**
\brief Node in the context_t.
*/
class node {
bound_array_manager & m_bm;
bound_array m_lowers;
bound_array m_uppers;
var m_conflict;
unsigned m_id;
unsigned m_depth;
bound * m_trail;
node * m_parent; //!< parent node
node * m_first_child;
node * m_next_sibling;
// Doubly linked list of leaves to be processed
node * m_prev;
node * m_next;
public:
node(context_t & s, unsigned id);
node(node * parent, unsigned id);
// return unique indentifier.
unsigned id() const { return m_id; }
bound_array_manager & bm() const { return m_bm; }
bound_array & lowers() { return m_lowers; }
bound_array & uppers() { return m_uppers; }
bool inconsistent() const { return m_conflict != null_var; }
void set_conflict(var x) { SASSERT(!inconsistent()); m_conflict = x; }
bound * trail_stack() const { return m_trail; }
bound * parent_trail_stack() const { return m_parent == 0 ? 0 : m_parent->m_trail; }
bound * lower(var x) const { return bm().get(m_lowers, x); }
bound * upper(var x) const { return bm().get(m_uppers, x); }
node * parent() const { return m_parent; }
node * first_child() const { return m_first_child; }
node * next_sibling() const { return m_next_sibling; }
node * prev() const { return m_prev; }
node * next() const { return m_next; }
/**
\brief Return true if x is unbounded in this node
*/
bool is_unbounded(var x) const { return lower(x) == 0 && upper(x) == 0; }
void push(bound * b);
void set_first_child(node * n) { m_first_child = n; }
void set_next_sibling(node * n) { m_next_sibling = n; }
void set_next(node * n) { m_next = n; }
void set_prev(node * n) { m_prev = n; }
unsigned depth() const { return m_depth; }
};
/**
\brief Intervals are just temporary place holders.
The pavers maintain bounds.
*/
struct interval {
bool m_constant; // Flag: constant intervals are pairs <node*, var>
// constant intervals
node * m_node;
var m_x;
// mutable intervals
numeral m_l_val;
bool m_l_inf;
bool m_l_open;
numeral m_u_val;
bool m_u_inf;
bool m_u_open;
interval():m_constant(false) {}
void set_constant(node * n, var x) {
m_constant = true;
m_node = n;
m_x = x;
}
void set_mutable() { m_constant = false; }
};
class interval_config {
public:
typedef typename C::numeral_manager numeral_manager;
typedef typename numeral_manager::numeral numeral;
typedef typename context_t::interval interval;
private:
numeral_manager & m_manager;
public:
interval_config(numeral_manager & m):m_manager(m) {}
numeral_manager & m() const { return m_manager; }
void round_to_minus_inf() { C::round_to_minus_inf(m()); }
void round_to_plus_inf() { C::round_to_plus_inf(m()); }
void set_rounding(bool to_plus_inf) { C::set_rounding(m(), to_plus_inf); }
numeral const & lower(interval const & a) const {
if (a.m_constant) {
bound * b = a.m_node->lower(a.m_x);
return b == 0 ? a.m_l_val /* don't care */ : b->value();
}
return a.m_l_val;
}
numeral const & upper(interval const & a) const {
if (a.m_constant) {
bound * b = a.m_node->upper(a.m_x);
return b == 0 ? a.m_u_val /* don't care */ : b->value();
}
return a.m_u_val;
}
numeral & lower(interval & a) { SASSERT(!a.m_constant); return a.m_l_val; }
numeral & upper(interval & a) { SASSERT(!a.m_constant); return a.m_u_val; }
bool lower_is_inf(interval const & a) const { return a.m_constant ? a.m_node->lower(a.m_x) == 0 : a.m_l_inf; }
bool upper_is_inf(interval const & a) const { return a.m_constant ? a.m_node->upper(a.m_x) == 0 : a.m_u_inf; }
bool lower_is_open(interval const & a) const {
if (a.m_constant) {
bound * b = a.m_node->lower(a.m_x);
return b == 0 || b->is_open();
}
return a.m_l_open;
}
bool upper_is_open(interval const & a) const {
if (a.m_constant) {
bound * b = a.m_node->upper(a.m_x);
return b == 0 || b->is_open();
}
return a.m_u_open;
}
// Setters
void set_lower(interval & a, numeral const & n) { SASSERT(!a.m_constant); m().set(a.m_l_val, n); }
void set_upper(interval & a, numeral const & n) { SASSERT(!a.m_constant); m().set(a.m_u_val, n); }
void set_lower_is_open(interval & a, bool v) { SASSERT(!a.m_constant); a.m_l_open = v; }
void set_upper_is_open(interval & a, bool v) { SASSERT(!a.m_constant); a.m_u_open = v; }
void set_lower_is_inf(interval & a, bool v) { SASSERT(!a.m_constant); a.m_l_inf = v; }
void set_upper_is_inf(interval & a, bool v) { SASSERT(!a.m_constant); a.m_u_inf = v; }
};
typedef ::interval_manager<interval_config> interval_manager;
class definition : public constraint {
public:
definition(typename constraint::kind k):constraint(k) {}
};
class monomial : public definition {
friend class context_t;
unsigned m_size;
power m_powers[0];
monomial(unsigned sz, power const * pws);
static unsigned get_obj_size(unsigned sz) { return sizeof(monomial) + sz*sizeof(power); }
public:
unsigned size() const { return m_size; }
power const & get_power(unsigned idx) const { SASSERT(idx < size()); return m_powers[idx]; }
power const * get_powers() const { return m_powers; }
var x(unsigned idx) const { return get_power(idx).x(); }
unsigned degree(unsigned idx) const { return get_power(idx).degree(); }
void display(std::ostream & out, display_var_proc const & proc = display_var_proc(), bool use_star = false) const;
};
class polynomial : public definition {
friend class context_t;
unsigned m_size;
numeral m_c;
numeral * m_as;
var * m_xs;
static unsigned get_obj_size(unsigned sz) { return sizeof(polynomial) + sz*sizeof(numeral) + sz*sizeof(var); }
public:
polynomial():definition(constraint::POLYNOMIAL) {}
unsigned size() const { return m_size; }
numeral const & a(unsigned i) const { return m_as[i]; }
var x(unsigned i) const { return m_xs[i]; }
var const * xs() const { return m_xs; }
numeral const * as() const { return m_as; }
numeral const & c() const { return m_c; }
void display(std::ostream & out, numeral_manager & nm, display_var_proc const & proc = display_var_proc(), bool use_star = false) const;
};
/**
\brief Watched element (aka occurence) can be:
- A clause
- A definition (i.e., a variable)
Remark: we cannot use the two watched literal approach since we process multiple nodes.
*/
class watched {
public:
enum kind { CLAUSE=0, DEFINITION };
private:
void * m_data;
public:
watched():m_data(0) {}
explicit watched(var x) { m_data = BOXTAGINT(void*, x, DEFINITION); }
explicit watched(clause * c) { m_data = TAG(void*, c, CLAUSE); }
kind get_kind() const { return static_cast<kind>(GET_TAG(m_data)); }
bool is_clause() const { return get_kind() != DEFINITION; }
bool is_definition() const { return get_kind() == DEFINITION; }
clause * get_clause() const { SASSERT(is_clause()); return UNTAG(clause*, m_data); }
var get_var() const { SASSERT(is_definition()); return UNBOXINT(m_data); }
bool operator==(watched const & other) const { return m_data == other.m_data; }
bool operator!=(watched const & other) const { return !operator==(other); }
};
/**
\brief Abstract functor for selecting the next leaf node to be explored.
*/
class node_selector {
context_t * m_ctx;
public:
node_selector(context_t * ctx):m_ctx(ctx) {}
virtual ~node_selector() {}
context_t * ctx() const { return m_ctx; }
// Return the next leaf node to be processed.
// Front and back are the first and last nodes in the doubly linked list of
// leaf nodes.
// Remark: new nodes are always inserted in the front of the list.
virtual node * operator()(node * front, node * back) = 0;
};
/**
\brief Abstract functor for selecting the next variable to branch.
*/
class var_selector {
context_t * m_ctx;
public:
var_selector(context_t * ctx):m_ctx(ctx) {}
virtual ~var_selector() {}
context_t * ctx() const { return m_ctx; }
// Return the next variable to branch.
virtual var operator()(node * n) = 0;
// -----------------------------------
//
// Event handlers
//
// -----------------------------------
// Invoked when a new variable is created.
virtual void new_var_eh(var x) {}
// Invoked when node n is created
virtual void new_node_eh(node * n) {}
// Invoked before deleting node n.
virtual void del_node_eh(node * n) {}
// Invoked when variable x is used during conflict resolution.
virtual void used_var_eh(node * n, var x) {}
};
class node_splitter;
friend class node_splitter;
/**
\brief Abstract functor for creating children for node n by branching on a given variable.
*/
class node_splitter {
context_t * m_ctx;
public:
node_splitter(context_t * ctx):m_ctx(ctx) {}
virtual ~node_splitter() {}
context_t * ctx() const { return m_ctx; }
node * mk_node(node * p) { return ctx()->mk_node(p); }
bound * mk_decided_bound(var x, numeral const & val, bool lower, bool open, node * n) {
return ctx()->mk_bound(x, val, lower, open, n, justification());
}
/**
\brief Create children nodes for n by splitting on x.
\pre n is a leaf. The interval for x in n has more than one element.
*/
virtual void operator()(node * n, var x) = 0;
};
/**
\brief Return most recent splitting var for node n.
*/
var splitting_var(node * n) const;
/**
\brief Return true if x is a definition.
*/
bool is_definition(var x) const { return m_defs[x] != 0; }
typedef svector<watched> watch_list;
typedef _scoped_numeral_vector<numeral_manager> scoped_numeral_vector;
private:
C m_c;
bool m_arith_failed; //!< True if the arithmetic module produced an exception.
bool m_own_allocator;
small_object_allocator * m_allocator;
bound_array_manager m_bm;
interval_manager m_im;
scoped_numeral_vector m_num_buffer;
svector<bool> m_is_int;
ptr_vector<definition> m_defs;
vector<watch_list> m_wlist;
ptr_vector<ineq> m_unit_clauses;
ptr_vector<clause> m_clauses;
ptr_vector<clause> m_lemmas;
id_gen m_node_id_gen;
uint64 m_timestamp;
node * m_root;
// m_leaf_head is the head of a doubly linked list of leaf nodes to be processed.
node * m_leaf_head;
node * m_leaf_tail;
var m_conflict;
ptr_vector<bound> m_queue;
unsigned m_qhead;
display_var_proc m_default_display_proc;
display_var_proc * m_display_proc;
scoped_ptr<node_selector> m_node_selector;
scoped_ptr<var_selector> m_var_selector;
scoped_ptr<node_splitter> m_node_splitter;
svector<power> m_pws;
// Configuration
numeral m_epsilon; //!< If upper - lower < epsilon, then new bound is not propagated.
bool m_zero_epsilon;
numeral m_max_bound; //!< Bounds > m_max and < -m_max are not propagated
numeral m_minus_max_bound; //!< -m_max_bound
numeral m_nth_root_prec; //!< precision for computing the nth root
unsigned m_max_depth; //!< Maximum depth
unsigned m_max_nodes; //!< Maximum number of nodes in the tree
unsigned long long m_max_memory; // in bytes
// Counters
unsigned m_num_nodes;
// Statistics
unsigned m_num_conflicts;
unsigned m_num_mk_bounds;
unsigned m_num_splits;
unsigned m_num_visited;
// Temporary
numeral m_tmp1, m_tmp2, m_tmp3;
interval m_i_tmp1, m_i_tmp2, m_i_tmp3;
// Cancel flag
volatile bool m_cancel;
friend class node;
void set_arith_failed() { m_arith_failed = true; }
void checkpoint();
bound_array_manager & bm() { return m_bm; }
interval_manager & im() { return m_im; }
small_object_allocator & allocator() const { return *m_allocator; }
bound * mk_bound(var x, numeral const & val, bool lower, bool open, node * n, justification jst);
void del_bound(bound * b);
// Create a new bound and add it to the propagation queue.
void propagate_bound(var x, numeral const & val, bool lower, bool open, node * n, justification jst);
bool is_int(monomial const * m) const;
bool is_int(polynomial const * p) const;
bool is_monomial(var x) const { return m_defs[x] != 0 && m_defs[x]->get_kind() == constraint::MONOMIAL; }
monomial * get_monomial(var x) const { SASSERT(is_monomial(x)); return static_cast<monomial*>(m_defs[x]); }
bool is_polynomial(var x) const { return m_defs[x] != 0 && m_defs[x]->get_kind() == constraint::POLYNOMIAL; }
polynomial * get_polynomial(var x) const { SASSERT(is_polynomial(x)); return static_cast<polynomial*>(m_defs[x]); }
static void display(std::ostream & out, numeral_manager & nm, display_var_proc const & proc, var x, numeral & k, bool lower, bool open);
void display(std::ostream & out, var x) const;
void display_definition(std::ostream & out, definition const * d, bool use_star = false) const;
void display(std::ostream & out, constraint * a, bool use_star = false) const;
void display(std::ostream & out, bound * b) const;
void display(std::ostream & out, ineq * a) const;
void display_params(std::ostream & out) const;
void add_unit_clause(ineq * a, bool axiom);
// Remark: Not all lemmas need to be watched. Some of them can be used to justify clauses only.
void add_clause_core(unsigned sz, ineq * const * atoms, bool lemma, bool watched);
void del_clause(clause * cls);
node * mk_node(node * parent = 0);
void del_node(node * n);
void del_nodes();
void del(interval & a);
void del_clauses(ptr_vector<clause> & cs);
void del_unit_clauses();
void del_clauses();
void del_monomial(monomial * m);
void del_sum(polynomial * p);
void del_definitions();
/**
\brief Insert n in the beginning of the doubly linked list of leaves.
\pre n is a leaf, and it is not already in the list.
*/
void push_front(node * n);
/**
\brief Insert n in the end of the doubly linked list of leaves.
\pre n is a leaf, and it is not already in the list.
*/
void push_back(node * n);
/**
\brief Remove n from the doubly linked list of leaves.
\pre n is a leaf, and it is in the list.
*/
void remove_from_leaf_dlist(node * n);
/**
\brief Remove all nodes from the leaf dlist.
*/
void reset_leaf_dlist();
/**
\brief Add all leaves back to the leaf dlist.
*/
void rebuild_leaf_dlist(node * n);
// -----------------------------------
//
// Propagation
//
// -----------------------------------
/**
\brief Return true if the given node is in an inconsistent state.
*/
bool inconsistent(node * n) const { return n->inconsistent(); }
/**
\brief Set a conflict produced by the bounds of x at the given node.
*/
void set_conflict(var x, node * n);
/**
\brief Return true if bound b may propagate a new bound using constraint c at node n.
*/
bool may_propagate(bound * b, constraint * c, node * n);
/**
\brief Normalize bound if x is integer.
Examples:
x < 2 --> x <= 1
x <= 2.3 --> x <= 2
*/
void normalize_bound(var x, numeral & val, bool lower, bool & open);
/**
\brief Return true if (x, k, lower, open) is a relevant new bound at node n.
That is, it improves the current bound, and satisfies m_epsilon and m_max_bound.
*/
bool relevant_new_bound(var x, numeral const & k, bool lower, bool open, node * n);
/**
\brief Return true if the lower and upper bounds of x are 0 at node n.
*/
bool is_zero(var x, node * n) const;
/**
\brief Return true if upper bound of x is 0 at node n.
*/
bool is_upper_zero(var x, node * n) const;
/**
\brief Return true if lower and upper bounds of x are conflicting at node n. That is, upper(x) < lower(x)
*/
bool conflicting_bounds(var x, node * n) const;
/**
\brief Return true if x is unbounded at node n.
*/
bool is_unbounded(var x, node * n) const { return n->is_unbounded(x); }
/**
\brief Return true if b is the most recent lower/upper bound for variable b->x() at node n.
*/
bool most_recent(bound * b, node * n) const;
/**
\brief Add most recent bounds of node n into the propagation queue.
That is, all bounds b s.t. b is in the trail of n, but not in the tail of parent(n), and most_recent(b, n).
*/
void add_recent_bounds(node * n);
/**
\brief Propagate new bounds at node n using get_monomial(x)
\pre is_monomial(x)
*/
void propagate_monomial(var x, node * n);
void propagate_monomial_upward(var x, node * n);
void propagate_monomial_downward(var x, node * n, unsigned i);
/**
\brief Propagate new bounds at node n using get_polynomial(x)
\pre is_polynomial(x)
*/
void propagate_polynomial(var x, node * n);
// Propagate a new bound for y using the polynomial associated with x. x may be equal to y.
void propagate_polynomial(var x, node * n, var y);
/**
\brief Propagate new bounds at node n using clause c.
*/
void propagate_clause(clause * c, node * n);
/**
\brief Return the truth value of inequaliy t at node n.
*/
lbool value(ineq * t, node * n);
/**
\brief Propagate new bounds at node n using the definition of variable x.
\pre is_definition(x)
*/
void propagate_def(var x, node * n);
/**
\brief Propagate constraints in b->x()'s watch list.
*/
void propagate(node * n, bound * b);
/**
\brief Perform bound propagation at node n.
*/
void propagate(node * n);
/**
\brief Try to propagate at node n using all definitions.
*/
void propagate_all_definitions(node * n);
// -----------------------------------
//
// Main
//
// -----------------------------------
void init();
/**
\brief Assert unit clauses in the node n.
*/
void assert_units(node * n);
// -----------------------------------
//
// Debugging support
//
// -----------------------------------
/**
\brief Return true if b is a bound for node n.
*/
bool is_bound_of(bound * b, node * n) const;
/**
\brief Check the consistency of the doubly linked list of leaves.
*/
bool check_leaf_dlist() const;
/**
\brief Check paving tree structure.
*/
bool check_tree() const;
/**
\brief Check main invariants.
*/
bool check_invariant() const;
public:
context_t(C const & c, params_ref const & p, small_object_allocator * a);
~context_t();
/**
\brief Return true if the arithmetic module failed.
*/
bool arith_failed() const { return m_arith_failed; }
numeral_manager & nm() const { return m_c.m(); }
unsigned num_vars() const { return m_is_int.size(); }
bool is_int(var x) const { SASSERT(x < num_vars()); return m_is_int[x]; }
/**
\brief Create a new variable.
*/
var mk_var(bool is_int);
/**
\brief Create the monomial xs[0]^ks[0] * ... * xs[sz-1]^ks[sz-1].
The result is a variable y s.t. y = xs[0]^ks[0] * ... * xs[sz-1]^ks[sz-1].
\pre for all i \in [0, sz-1] : ks[i] > 0
\pre sz > 0
*/
var mk_monomial(unsigned sz, power const * pws);
/**
\brief Create the sum c + as[0]*xs[0] + ... + as[sz-1]*xs[sz-1].
The result is a variable y s.t. y = c + as[0]*xs[0] + ... + as[sz-1]*xs[sz-1].
\pre sz > 0
\pre for all i \in [0, sz-1] : as[i] != 0
*/
var mk_sum(numeral const & c, unsigned sz, numeral const * as, var const * xs);
/**
\brief Create an inequality.
*/
ineq * mk_ineq(var x, numeral const & k, bool lower, bool open);
void inc_ref(ineq * a);
void dec_ref(ineq * a);
/**
\brief Assert the clause atoms[0] \/ ... \/ atoms[sz-1]
\pre sz > 1
*/
void add_clause(unsigned sz, ineq * const * atoms) { add_clause_core(sz, atoms, false, true); }
/**
\brief Assert a constraint of one of the forms: x < k, x > k, x <= k, x >= k.
If axiom == true, then the constraint is not tracked in proofs.
*/
void add_ineq(var x, numeral const & k, bool lower, bool open, bool axiom);
/**
\brief Store in the given vector all leaves of the paving tree.
*/
void collect_leaves(ptr_vector<node> & leaves) const;
/**
\brief Display constraints asserted in the subpaving.
*/
void display_constraints(std::ostream & out, bool use_star = false) const;
/**
\brief Display bounds for each leaf of the tree.
*/
void display_bounds(std::ostream & out) const;
void display_bounds(std::ostream & out, node * n) const;
void set_display_proc(display_var_proc * p) { m_display_proc = p; }
void set_cancel(bool f) { m_cancel = f; im().set_cancel(f); }
void updt_params(params_ref const & p);
static void collect_param_descrs(param_descrs & d);
void reset_statistics();
void collect_statistics(statistics & st) const;
void operator()();
};
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,52 +0,0 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
subpaving_types.h
Abstract:
Subpaving auxiliary types.
Author:
Leonardo de Moura (leonardo) 2012-08-07.
Revision History:
--*/
#ifndef __SUBPAVING_TYPES_H_
#define __SUBPAVING_TYPES_H_
namespace subpaving {
class ineq;
typedef unsigned var;
const var null_var = UINT_MAX;
class exception {
};
class power : public std::pair<var, unsigned> {
public:
power():std::pair<var, unsigned>() {}
power(var v, unsigned d):std::pair<var, unsigned>(v, d) {}
power(power const & p):std::pair<var, unsigned>(p) {}
var x() const { return first; }
var get_var() const { return first; }
unsigned degree() const { return second; }
unsigned & degree() { return second; }
void set_var(var x) { first = x; }
struct lt_proc { bool operator()(power const & p1, power const & p2) { return p1.get_var() < p2.get_var(); } };
};
struct display_var_proc {
virtual void operator()(std::ostream & out, var x) const { out << "x" << x; }
};
};
#endif

View file

@ -1,770 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
th_rewriter.h
Abstract:
Rewriter for applying all builtin (cheap) theory rewrite rules.
Author:
Leonardo (leonardo) 2011-04-07
Notes:
--*/
#include"th_rewriter.h"
#include"bool_rewriter.h"
#include"arith_rewriter.h"
#include"bv_rewriter.h"
#include"datatype_rewriter.h"
#include"array_rewriter.h"
#include"float_rewriter.h"
#include"dl_rewriter.h"
#include"rewriter_def.h"
#include"expr_substitution.h"
#include"ast_smt2_pp.h"
#include"cooperate.h"
#include"var_subst.h"
#include"ast_util.h"
#include"well_sorted.h"
struct th_rewriter_cfg : public default_rewriter_cfg {
bool_rewriter m_b_rw;
arith_rewriter m_a_rw;
bv_rewriter m_bv_rw;
array_rewriter m_ar_rw;
datatype_rewriter m_dt_rw;
float_rewriter m_f_rw;
dl_rewriter m_dl_rw;
arith_util m_a_util;
bv_util m_bv_util;
unsigned long long m_max_memory; // in bytes
unsigned m_max_steps;
bool m_pull_cheap_ite;
bool m_flat;
bool m_cache_all;
bool m_push_ite_arith;
bool m_push_ite_bv;
// substitution support
expr_dependency_ref m_used_dependencies; // set of dependencies of used substitutions
expr_substitution * m_subst;
ast_manager & m() const { return m_b_rw.m(); }
void updt_local_params(params_ref const & p) {
m_flat = p.get_bool(":flat", true);
m_max_memory = megabytes_to_bytes(p.get_uint(":max-memory", UINT_MAX));
m_max_steps = p.get_uint(":max-steps", UINT_MAX);
m_pull_cheap_ite = p.get_bool(":pull-cheap-ite", false);
m_cache_all = p.get_bool(":cache-all", false);
m_push_ite_arith = p.get_bool(":push-ite-arith", false);
m_push_ite_bv = p.get_bool(":push-ite-bv", false);
}
void updt_params(params_ref const & p) {
m_b_rw.updt_params(p);
m_a_rw.updt_params(p);
m_bv_rw.updt_params(p);
m_ar_rw.updt_params(p);
updt_local_params(p);
}
bool flat_assoc(func_decl * f) const {
if (!m_flat) return false;
family_id fid = f->get_family_id();
if (fid == null_family_id)
return false;
decl_kind k = f->get_decl_kind();
if (fid == m_b_rw.get_fid())
return k == OP_AND || k == OP_OR;
if (fid == m_a_rw.get_fid())
return k == OP_ADD;
if (fid == m_bv_rw.get_fid())
return k == OP_BADD || k == OP_BOR || k == OP_BAND || k == OP_BXOR;
return false;
}
bool rewrite_patterns() const { return false; }
bool cache_all_results() const { return m_cache_all; }
bool max_steps_exceeded(unsigned num_steps) const {
cooperate("simplifier");
if (memory::get_allocation_size() > m_max_memory)
throw rewriter_exception(TACTIC_MAX_MEMORY_MSG);
return num_steps > m_max_steps;
}
// Return true if t is of the form
// (= t #b0)
// (= t #b1)
// (= #b0 t)
// (= #b1 t)
bool is_eq_bit(expr * t, expr * & x, unsigned & val) {
if (!m().is_eq(t))
return false;
expr * lhs = to_app(t)->get_arg(0);
if (!m_bv_rw.is_bv(lhs))
return false;
if (m_bv_rw.get_bv_size(lhs) != 1)
return false;
expr * rhs = to_app(t)->get_arg(1);
rational v;
unsigned sz;
if (m_bv_rw.is_numeral(lhs, v, sz)) {
x = rhs;
val = v.get_unsigned();
SASSERT(val == 0 || val == 1);
return true;
}
if (m_bv_rw.is_numeral(rhs, v, sz)) {
x = lhs;
val = v.get_unsigned();
SASSERT(val == 0 || val == 1);
return true;
}
return false;
}
// (iff (= x bit1) A)
// --->
// (= x (ite A bit1 bit0))
br_status apply_tamagotchi(expr * lhs, expr * rhs, expr_ref & result) {
expr * x;
unsigned val;
if (is_eq_bit(lhs, x, val)) {
result = m().mk_eq(x, m().mk_ite(rhs, m_bv_rw.mk_numeral(val, 1), m_bv_rw.mk_numeral(1-val, 1)));
return BR_REWRITE2;
}
if (is_eq_bit(rhs, x, val)) {
result = m().mk_eq(x, m().mk_ite(lhs, m_bv_rw.mk_numeral(val, 1), m_bv_rw.mk_numeral(1-val, 1)));
return BR_REWRITE2;
}
return BR_FAILED;
}
br_status reduce_app_core(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
family_id fid = f->get_family_id();
if (fid == null_family_id)
return BR_FAILED;
br_status st = BR_FAILED;
if (fid == m_b_rw.get_fid()) {
decl_kind k = f->get_decl_kind();
if (k == OP_EQ) {
// theory dispatch for =
SASSERT(num == 2);
family_id s_fid = m().get_sort(args[0])->get_family_id();
if (s_fid == m_a_rw.get_fid())
st = m_a_rw.mk_eq_core(args[0], args[1], result);
else if (s_fid == m_bv_rw.get_fid())
st = m_bv_rw.mk_eq_core(args[0], args[1], result);
else if (s_fid == m_dt_rw.get_fid())
st = m_dt_rw.mk_eq_core(args[0], args[1], result);
else if (s_fid == m_f_rw.get_fid())
st = m_f_rw.mk_eq_core(args[0], args[1], result);
if (st != BR_FAILED)
return st;
}
if (k == OP_EQ || k == OP_IFF) {
SASSERT(num == 2);
st = apply_tamagotchi(args[0], args[1], result);
if (st != BR_FAILED)
return st;
}
return m_b_rw.mk_app_core(f, num, args, result);
}
if (fid == m_a_rw.get_fid())
return m_a_rw.mk_app_core(f, num, args, result);
if (fid == m_bv_rw.get_fid())
return m_bv_rw.mk_app_core(f, num, args, result);
if (fid == m_ar_rw.get_fid())
return m_ar_rw.mk_app_core(f, num, args, result);
if (fid == m_dt_rw.get_fid())
return m_dt_rw.mk_app_core(f, num, args, result);
if (fid == m_f_rw.get_fid())
return m_f_rw.mk_app_core(f, num, args, result);
if (fid == m_dl_rw.get_fid())
return m_dl_rw.mk_app_core(f, num, args, result);
return BR_FAILED;
}
// auxiliary function for pull_ite_core
expr * mk_eq_value(expr * lhs, expr * value) {
SASSERT(m().is_value(value));
if (m().is_value(lhs)) {
return lhs == value ? m().mk_true() : m().mk_false();
}
return m().mk_eq(lhs, value);
}
template<bool SWAP>
br_status pull_ite_core(func_decl * p, app * ite, app * value, expr_ref & result) {
if (m().is_eq(p)) {
result = m().mk_ite(ite->get_arg(0),
mk_eq_value(ite->get_arg(1), value),
mk_eq_value(ite->get_arg(2), value));
return BR_REWRITE2;
}
else {
if (SWAP) {
result = m().mk_ite(ite->get_arg(0),
m().mk_app(p, value, ite->get_arg(1)),
m().mk_app(p, value, ite->get_arg(2)));
return BR_REWRITE2;
}
else {
result = m().mk_ite(ite->get_arg(0),
m().mk_app(p, ite->get_arg(1), value),
m().mk_app(p, ite->get_arg(2), value));
return BR_REWRITE2;
}
}
}
// Return true if t is an ite-value-tree form defined as:
// ite-value-tree := (ite c <subtree> <subtree>)
// subtree := value
// | (ite c <subtree> <subtree>)
//
bool is_ite_value_tree(expr * t) {
if (!m().is_ite(t))
return false;
ptr_buffer<app> todo;
todo.push_back(to_app(t));
while (!todo.empty()) {
app * ite = todo.back();
todo.pop_back();
expr * arg1 = ite->get_arg(1);
expr * arg2 = ite->get_arg(2);
if (m().is_ite(arg1) && arg1->get_ref_count() == 1) // do not apply on shared terms, since it may blowup
todo.push_back(to_app(arg1));
else if (!m().is_value(arg1))
return false;
if (m().is_ite(arg2) && arg2->get_ref_count() == 1) // do not apply on shared terms, since it may blowup
todo.push_back(to_app(arg2));
else if (!m().is_value(arg2))
return false;
}
return true;
}
br_status pull_ite(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
if (num == 2 && m().is_bool(f->get_range()) && !m().is_bool(args[0])) {
if (m().is_ite(args[0])) {
if (m().is_value(args[1]))
return pull_ite_core<false>(f, to_app(args[0]), to_app(args[1]), result);
if (m().is_ite(args[1]) && to_app(args[0])->get_arg(0) == to_app(args[1])->get_arg(0)) {
// (p (ite C A1 B1) (ite C A2 B2)) --> (ite (p A1 A2) (p B1 B2))
result = m().mk_ite(to_app(args[0])->get_arg(0),
m().mk_app(f, to_app(args[0])->get_arg(1), to_app(args[1])->get_arg(1)),
m().mk_app(f, to_app(args[0])->get_arg(2), to_app(args[1])->get_arg(2)));
return BR_REWRITE2;
}
}
if (m().is_ite(args[1]) && m().is_value(args[0]))
return pull_ite_core<true>(f, to_app(args[1]), to_app(args[0]), result);
}
family_id fid = f->get_family_id();
if (num == 2 && (fid == m().get_basic_family_id() || fid == m_a_rw.get_fid() || fid == m_bv_rw.get_fid())) {
// (f v3 (ite c v1 v2)) --> (ite v (f v3 v1) (f v3 v2))
if (m().is_value(args[0]) && is_ite_value_tree(args[1]))
return pull_ite_core<true>(f, to_app(args[1]), to_app(args[0]), result);
// (f (ite c v1 v2) v3) --> (ite v (f v1 v3) (f v2 v3))
if (m().is_value(args[1]) && is_ite_value_tree(args[0]))
return pull_ite_core<false>(f, to_app(args[0]), to_app(args[1]), result);
}
return BR_FAILED;
}
br_status pull_ite(expr_ref & result) {
expr * t = result.get();
if (is_app(t)) {
br_status st = pull_ite(to_app(t)->get_decl(), to_app(t)->get_num_args(), to_app(t)->get_args(), result);
if (st != BR_FAILED)
return st;
}
return BR_DONE;
}
bool is_arith_bv_app(expr * t) const {
if (!is_app(t))
return false;
family_id fid = to_app(t)->get_family_id();
return ((fid == m_a_rw.get_fid() && m_push_ite_arith) ||
(fid == m_bv_rw.get_fid() && m_push_ite_bv));
}
bool get_neutral_elem(app * t, expr_ref & n) {
family_id fid = t->get_family_id();
if (fid == m_a_rw.get_fid()) {
switch (t->get_decl_kind()) {
case OP_ADD: n = m_a_util.mk_numeral(rational(0), m().get_sort(t)); return true;
case OP_MUL: n = m_a_util.mk_numeral(rational(1), m().get_sort(t)); return true;
default:
return false;
}
}
if (fid == m_bv_rw.get_fid()) {
switch (t->get_decl_kind()) {
case OP_BADD: n = m_bv_util.mk_numeral(rational(0), m().get_sort(t)); return true;
case OP_BMUL: n = m_bv_util.mk_numeral(rational(1), m().get_sort(t)); return true;
default:
return false;
}
}
return false;
}
/**
\brief Try to "unify" t1 and t2
Examples
(+ 2 a) (+ 3 a) --> 2, 3, a
(+ 2 a) a --> 2, 0, a
...
*/
bool unify_core(app * t1, expr * t2, expr_ref & new_t1, expr_ref & new_t2, expr_ref & c, bool & first) {
if (t1->get_num_args() != 2)
return false;
expr * a1 = t1->get_arg(0);
expr * b1 = t1->get_arg(1);
if (t2 == b1) {
if (get_neutral_elem(t1, new_t2)) {
new_t1 = a1;
c = b1;
first = false;
return true;
}
}
else if (t2 == a1) {
if (get_neutral_elem(t1, new_t2)) {
new_t1 = b1;
c = a1;
first = true;
return true;
}
}
else if (is_app_of(t2, t1->get_decl()) && to_app(t2)->get_num_args() == 2) {
expr * a2 = to_app(t2)->get_arg(0);
expr * b2 = to_app(t2)->get_arg(1);
if (b1 == b2) {
new_t1 = a1;
new_t2 = a2;
c = b2;
first = false;
return true;
}
if (a1 == a2) {
new_t1 = b1;
new_t2 = b2;
c = a1;
first = true;
return true;
}
if (t1->get_decl()->is_commutative()) {
if (a1 == b2) {
new_t1 = b1;
new_t2 = a2;
c = a1;
first = true; // doesn't really matter for commutative ops.
return true;
}
if (b1 == a2) {
new_t1 = a1;
new_t2 = b2;
c = b1;
first = false; // doesn't really matter for commutative ops.
return true;
}
}
}
return false;
}
// Return true if t1 and t2 are of the form:
// t + a1*x1 + ... + an*xn
// t' + a1*x1 + ... + an*xn
// Store t in new_t1, t' in new_t2 and (a1*x1 + ... + an*xn) in c.
bool unify_add(app * t1, expr * t2, expr_ref & new_t1, expr_ref & new_t2, expr_ref & c) {
unsigned num1 = t1->get_num_args();
expr * const * ms1 = t1->get_args();
if (num1 < 2)
return false;
unsigned num2;
expr * const * ms2;
if (m_a_util.is_add(t2)) {
num2 = to_app(t2)->get_num_args();
ms2 = to_app(t2)->get_args();
}
else {
num2 = 1;
ms2 = &t2;
}
if (num1 != num2 && num1 != num2 + 1 && num1 != num2 - 1)
return false;
new_t1 = 0;
new_t2 = 0;
expr_fast_mark1 visited1;
expr_fast_mark2 visited2;
for (unsigned i = 0; i < num1; i++) {
expr * arg = ms1[i];
visited1.mark(arg);
}
for (unsigned i = 0; i < num2; i++) {
expr * arg = ms2[i];
visited2.mark(arg);
if (visited1.is_marked(arg))
continue;
if (new_t2)
return false; // more than one missing term
new_t2 = arg;
}
for (unsigned i = 0; i < num1; i++) {
expr * arg = ms1[i];
if (visited2.is_marked(arg))
continue;
if (new_t1)
return false; // more than one missing term
new_t1 = arg;
}
// terms matched...
bool is_int = m_a_util.is_int(t1);
if (!new_t1)
new_t1 = m_a_util.mk_numeral(rational(0), is_int);
if (!new_t2)
new_t2 = m_a_util.mk_numeral(rational(0), is_int);
// mk common part
ptr_buffer<expr> args;
for (unsigned i = 0; i < num1; i++) {
expr * arg = ms1[i];
if (arg == new_t1.get())
continue;
args.push_back(arg);
}
SASSERT(!args.empty());
if (args.size() == 1)
c = args[0];
else
c = m_a_util.mk_add(args.size(), args.c_ptr());
return true;
}
bool unify(expr * t1, expr * t2, func_decl * & f, expr_ref & new_t1, expr_ref & new_t2, expr_ref & c, bool & first) {
#if 0
// Did not work for ring benchmarks
// Hack for handling more complex cases of + apps
// such as (+ 2 t1 t2 t3) and (+ 3 t3 t2 t1)
if (m_a_util.is_add(t1)) {
first = true; // doesn't matter for AC ops
f = to_app(t1)->get_decl();
if (unify_add(to_app(t1), t2, new_t1, new_t2, c))
return true;
}
if (m_a_util.is_add(t2)) {
first = true; // doesn't matter for AC ops
f = to_app(t2)->get_decl();
if (unify_add(to_app(t2), t1, new_t2, new_t1, c))
return true;
}
#endif
if (is_arith_bv_app(t1)) {
f = to_app(t1)->get_decl();
return unify_core(to_app(t1), t2, new_t1, new_t2, c, first);
}
else {
f = to_app(t2)->get_decl();
return unify_core(to_app(t2), t1, new_t2, new_t1, c, first);
}
}
// Apply transformations of the form
//
// (ite c (+ k1 a) (+ k2 a)) --> (+ (ite c k1 k2) a)
// (ite c (* k1 a) (* k2 a)) --> (* (ite c k1 k2) a)
//
// These transformations are useful for bit-vector problems, since
// they will minimize the number of adders/multipliers/etc
br_status push_ite(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
if (!m().is_ite(f))
return BR_FAILED;
expr * c = args[0];
expr * t = args[1];
expr * e = args[2];
func_decl * f_prime = 0;
expr_ref new_t(m()), new_e(m()), common(m());
bool first;
TRACE("push_ite", tout << "unifying:\n" << mk_ismt2_pp(t, m()) << "\n" << mk_ismt2_pp(e, m()) << "\n";);
if (unify(t, e, f_prime, new_t, new_e, common, first)) {
if (first)
result = m().mk_app(f_prime, common, m().mk_ite(c, new_t, new_e));
else
result = m().mk_app(f_prime, m().mk_ite(c, new_t, new_e), common);
return BR_DONE;
}
TRACE("push_ite", tout << "failed\n";);
return BR_FAILED;
}
br_status push_ite(expr_ref & result) {
expr * t = result.get();
if (m().is_ite(t)) {
br_status st = push_ite(to_app(t)->get_decl(), to_app(t)->get_num_args(), to_app(t)->get_args(), result);
if (st != BR_FAILED)
return st;
}
return BR_DONE;
}
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
result_pr = 0;
br_status st = reduce_app_core(f, num, args, result);
if (st != BR_DONE && st != BR_FAILED) {
CTRACE("th_rewriter_step", st != BR_FAILED,
tout << f->get_name() << "\n";
for (unsigned i = 0; i < num; i++) tout << mk_ismt2_pp(args[i], m()) << "\n";
tout << "---------->\n" << mk_ismt2_pp(result, m()) << "\n";);
return st;
}
if (m_push_ite_bv || m_push_ite_arith) {
if (st == BR_FAILED)
st = push_ite(f, num, args, result);
else
st = push_ite(result);
}
if (m_pull_cheap_ite) {
if (st == BR_FAILED)
st = pull_ite(f, num, args, result);
else
st = pull_ite(result);
}
CTRACE("th_rewriter_step", st != BR_FAILED,
tout << f->get_name() << "\n";
for (unsigned i = 0; i < num; i++) tout << mk_ismt2_pp(args[i], m()) << "\n";
tout << "---------->\n" << mk_ismt2_pp(result, m()) << "\n";);
return st;
}
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());
proof * p1 = 0;
if (is_quantifier(new_body) &&
to_quantifier(new_body)->is_forall() == old_q->is_forall() &&
!old_q->has_patterns() &&
!to_quantifier(new_body)->has_patterns()) {
quantifier * nested_q = to_quantifier(new_body);
ptr_buffer<sort> sorts;
buffer<symbol> names;
sorts.append(old_q->get_num_decls(), old_q->get_decl_sorts());
names.append(old_q->get_num_decls(), old_q->get_decl_names());
sorts.append(nested_q->get_num_decls(), nested_q->get_decl_sorts());
names.append(nested_q->get_num_decls(), nested_q->get_decl_names());
q1 = m().mk_quantifier(old_q->is_forall(),
sorts.size(),
sorts.c_ptr(),
names.c_ptr(),
nested_q->get_expr(),
std::min(old_q->get_weight(), nested_q->get_weight()),
old_q->get_qid(),
old_q->get_skid(),
0, 0, 0, 0);
SASSERT(is_well_sorted(m(), q1));
if (m().proofs_enabled()) {
SASSERT(old_q->get_expr() == new_body);
p1 = m().mk_pull_quant(old_q, q1);
}
}
else {
ptr_buffer<expr> new_patterns_buf;
ptr_buffer<expr> new_no_patterns_buf;
new_patterns_buf.append(old_q->get_num_patterns(), new_patterns);
new_no_patterns_buf.append(old_q->get_num_no_patterns(), new_no_patterns);
remove_duplicates(new_patterns_buf);
remove_duplicates(new_no_patterns_buf);
q1 = m().update_quantifier(old_q,
new_patterns_buf.size(), new_patterns_buf.c_ptr(), new_no_patterns_buf.size(), new_no_patterns_buf.c_ptr(),
new_body);
TRACE("reduce_quantifier", tout << mk_ismt2_pp(old_q, m()) << "\n----->\n" << mk_ismt2_pp(q1, m()) << "\n";);
SASSERT(is_well_sorted(m(), q1));
}
elim_unused_vars(m(), q1, result);
TRACE("reduce_quantifier", tout << "after elim_unused_vars:\n" << mk_ismt2_pp(result, m()) << "\n";);
result_pr = 0;
if (m().proofs_enabled()) {
proof * p2 = 0;
if (q1.get() != result.get())
p2 = m().mk_elim_unused_vars(q1, result);
result_pr = m().mk_transitivity(p1, p2);
}
return true;
}
th_rewriter_cfg(ast_manager & m, params_ref const & p):
m_b_rw(m, p),
m_a_rw(m, p),
m_bv_rw(m, p),
m_ar_rw(m, p),
m_dt_rw(m),
m_f_rw(m, p),
m_dl_rw(m),
m_a_util(m),
m_bv_util(m),
m_used_dependencies(m),
m_subst(0) {
updt_local_params(p);
}
void set_substitution(expr_substitution * s) {
reset();
m_subst = s;
}
void reset() {
m_subst = 0;
}
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;
}
void set_cancel(bool f) {
m_a_rw.set_cancel(f);
}
};
template class rewriter_tpl<th_rewriter_cfg>;
struct th_rewriter::imp : public rewriter_tpl<th_rewriter_cfg> {
th_rewriter_cfg m_cfg;
imp(ast_manager & m, params_ref const & p):
rewriter_tpl<th_rewriter_cfg>(m, m.proofs_enabled(), m_cfg),
m_cfg(m, p) {
}
};
th_rewriter::th_rewriter(ast_manager & m, params_ref const & p):
m_params(p) {
m_imp = alloc(imp, m, p);
}
ast_manager & th_rewriter::m() const {
return m_imp->m();
}
void th_rewriter::updt_params(params_ref const & p) {
m_params = p;
m_imp->cfg().updt_params(p);
}
void th_rewriter::get_param_descrs(param_descrs & r) {
bool_rewriter::get_param_descrs(r);
arith_rewriter::get_param_descrs(r);
bv_rewriter::get_param_descrs(r);
array_rewriter::get_param_descrs(r);
insert_max_memory(r);
insert_max_steps(r);
r.insert(":push-ite-arith", CPK_BOOL, "(default: false) push if-then-else over arithmetic terms.");
r.insert(":push-ite-bv", CPK_BOOL, "(default: false) push if-then-else over bit-vector terms.");
r.insert(":pull-cheap-ite", CPK_BOOL, "(default: false) pull if-then-else terms when cheap.");
r.insert(":cache-all", CPK_BOOL, "(default: false) cache all intermediate results.");
}
th_rewriter::~th_rewriter() {
dealloc(m_imp);
}
unsigned th_rewriter::get_cache_size() const {
return m_imp->get_cache_size();
}
unsigned th_rewriter::get_num_steps() const {
return m_imp->get_num_steps();
}
void th_rewriter::set_cancel(bool f) {
#pragma omp critical (th_rewriter)
{
m_imp->set_cancel(f);
m_imp->cfg().set_cancel(f);
}
}
void th_rewriter::cleanup() {
ast_manager & m = m_imp->m();
#pragma omp critical (th_rewriter)
{
dealloc(m_imp);
m_imp = alloc(imp, m, m_params);
}
}
void th_rewriter::reset() {
m_imp->reset();
m_imp->cfg().reset();
}
void th_rewriter::operator()(expr_ref & term) {
expr_ref result(term.get_manager());
m_imp->operator()(term, result);
term = result;
}
void th_rewriter::operator()(expr * t, expr_ref & result) {
m_imp->operator()(t, result);
}
void th_rewriter::operator()(expr * t, expr_ref & result, proof_ref & result_pr) {
m_imp->operator()(t, result, result_pr);
}
void th_rewriter::operator()(expr * n, unsigned num_bindings, expr * const * bindings, expr_ref & result) {
m_imp->operator()(n, num_bindings, bindings, result);
}
void th_rewriter::set_substitution(expr_substitution * s) {
m_imp->reset(); // reset the cache
m_imp->cfg().set_substitution(s);
}
expr_dependency * th_rewriter::get_used_dependencies() {
return m_imp->cfg().m_used_dependencies;
}
void th_rewriter::reset_used_dependencies() {
if (get_used_dependencies() != 0) {
set_substitution(m_imp->cfg().m_subst); // reset cache preserving subst
m_imp->cfg().m_used_dependencies = 0;
}
}

View file

@ -1,65 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
th_rewriter.h
Abstract:
Rewriter for applying all builtin (cheap) theory rewrite rules.
Author:
Leonardo (leonardo) 2011-04-07
Notes:
--*/
#ifndef _TH_REWRITER_H_
#define _TH_REWRITER_H_
#include"ast.h"
#include"rewriter_types.h"
#include"params.h"
class expr_substitution;
class th_rewriter {
struct imp;
imp * m_imp;
params_ref m_params;
public:
th_rewriter(ast_manager & m, params_ref const & p = params_ref());
~th_rewriter();
ast_manager & m () const;
void updt_params(params_ref const & p);
static void get_param_descrs(param_descrs & r);
unsigned get_cache_size() const;
unsigned get_num_steps() const;
void operator()(expr_ref& term);
void operator()(expr * t, expr_ref & result);
void operator()(expr * t, expr_ref & result, proof_ref & result_pr);
void operator()(expr * n, unsigned num_bindings, expr * const * bindings, expr_ref & result);
void cancel() { set_cancel(true); }
void reset_cancel() { set_cancel(false); }
void set_cancel(bool f);
void cleanup();
void reset();
void set_substitution(expr_substitution * s);
// Dependency tracking is very coarse.
// The rewriter just keeps accumulating the dependencies of the used substitutions.
// The following methods are used to recover and reset them.
// Remark: reset_used_dependecies will reset the internal cache if get_used_dependencies() != 0
expr_dependency * get_used_dependencies();
void reset_used_dependencies();
};
#endif

View file

@ -1,113 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
used_vars.cpp
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-01-14.
Revision History:
--*/
#include"used_vars.h"
void used_vars::process(expr * n, unsigned delta) {
unsigned j, idx;
m_cache.reset();
m_todo.reset();
m_todo.push_back(expr_delta_pair(n, delta));
while (!m_todo.empty()) {
expr_delta_pair const & p = m_todo.back();
n = p.m_node;
if (n->get_ref_count() > 1 && m_cache.contains(p)) {
m_todo.pop_back();
continue;
}
if (n->get_ref_count() > 1) {
// cache only shared and non-constant nodes
m_cache.insert(p);
}
delta = p.m_delta;
m_todo.pop_back();
switch (n->get_kind()) {
case AST_APP:
j = to_app(n)->get_num_args();
while (j > 0) {
--j;
expr * arg = to_app(n)->get_arg(j);
m_todo.push_back(expr_delta_pair(arg, delta));
}
break;
case AST_VAR:
idx = to_var(n)->get_idx();
if (idx >= delta) {
idx = idx - delta;
if (idx >= m_found_vars.size())
m_found_vars.resize(idx + 1, 0);
m_found_vars[idx] = to_var(n)->get_sort();
}
break;
case AST_QUANTIFIER:
// recurse so that memoization is correct with respect to 'delta'.
delta += to_quantifier(n)->get_num_decls();
j = to_quantifier(n)->get_num_patterns();
while (j > 0) {
--j;
m_todo.push_back(expr_delta_pair(to_quantifier(n)->get_pattern(j), delta));
}
j = to_quantifier(n)->get_num_no_patterns();
while (j > 0) {
--j;
m_todo.push_back(expr_delta_pair(to_quantifier(n)->get_no_pattern(j), delta));
}
m_todo.push_back(expr_delta_pair(to_quantifier(n)->get_expr(), delta));
break;
default:
break;
}
}
}
bool used_vars::uses_all_vars(unsigned num_decls) const {
if (num_decls > m_found_vars.size())
return false;
for (unsigned i = 0; i < num_decls; i++) {
if (!m_found_vars[i])
return false;
}
return true;
}
bool used_vars::uses_a_var(unsigned num_decls) const {
num_decls = std::min(num_decls, m_found_vars.size());
for (unsigned i = 0; i < num_decls; i++) {
if (m_found_vars[i])
return true;
}
return false;
}
unsigned used_vars::get_num_vars() const {
unsigned r = 0;
unsigned num = m_found_vars.size();
for (unsigned i = 0; i < num; i++) {
if (m_found_vars[i])
return r++;
}
return r;
}

View file

@ -1,59 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
used_vars.h
Abstract:
Functor used to collect the set of used variables.
Author:
Leonardo de Moura (leonardo) 2008-01-14.
Revision History:
--*/
#ifndef _USED_VARS_H_
#define _USED_VARS_H_
#include"ast.h"
#include"expr_delta_pair.h"
class used_vars {
ptr_vector<sort> m_found_vars;
typedef hashtable<expr_delta_pair, obj_hash<expr_delta_pair>, default_eq<expr_delta_pair> > cache;
cache m_cache;
svector<expr_delta_pair> m_todo;
void process(expr * n, unsigned delta);
public:
void operator()(expr * n) {
m_found_vars.reset();
process(n, 0);
}
void reset() {
m_found_vars.reset();
}
void process(expr * n) {
process(n, 0);
}
unsigned get_max_found_var_idx_plus_1() const { return m_found_vars.size(); }
sort * get(unsigned var_idx) const { return m_found_vars[var_idx]; }
sort * contains(unsigned var_idx) const { return var_idx < m_found_vars.size() ? m_found_vars[var_idx] : 0; }
bool uses_all_vars(unsigned num_decls) const;
bool uses_a_var(unsigned num_decls) const;
unsigned get_num_vars() const;
};
#endif /* _USED_VARS_H_ */

View file

@ -1,211 +0,0 @@
/*++
Copyright (c) 2007 Microsoft Corporation
Module Name:
var_subst.cpp
Abstract:
Variable substitution.
Author:
Leonardo (leonardo) 2008-01-10
Notes:
--*/
#include"var_subst.h"
#include"used_vars.h"
#include"ast_ll_pp.h"
#include"ast_pp.h"
#include"ast_smt2_pp.h"
#include"well_sorted.h"
#include"for_each_expr.h"
void var_subst::operator()(expr * n, unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(is_well_sorted(result.m(), n));
m_reducer.reset();
if (m_std_order)
m_reducer.set_inv_bindings(num_args, args);
else
m_reducer.set_bindings(num_args, args);
m_reducer(n, result);
SASSERT(is_well_sorted(m_reducer.m(), result));
TRACE("var_subst_bug",
tout << "m_std_order: " << m_std_order << "\n" << mk_ismt2_pp(n, m_reducer.m()) << "\nusing\n";
for (unsigned i = 0; i < num_args; i++) tout << mk_ismt2_pp(args[i], m_reducer.m()) << "\n";
tout << "\n------>\n";
tout << mk_ismt2_pp(result, m_reducer.m()) << "\n";);
}
void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & result) {
SASSERT(is_well_sorted(m, q));
if (is_ground(q->get_expr())) {
// ignore patterns if the body is a ground formula.
result = q->get_expr();
return;
}
if (!q->may_have_unused_vars()) {
result = q;
return;
}
used_vars used;
used.process(q->get_expr());
unsigned num_patterns = q->get_num_patterns();
for (unsigned i = 0; i < num_patterns; i++)
used.process(q->get_pattern(i));
unsigned num_no_patterns = q->get_num_no_patterns();
for (unsigned i = 0; i < num_no_patterns; i++)
used.process(q->get_no_pattern(i));
unsigned num_decls = q->get_num_decls();
if (used.uses_all_vars(num_decls)) {
q->set_no_unused_vars();
result = q;
return;
}
ptr_buffer<sort> used_decl_sorts;
buffer<symbol> used_decl_names;
for (unsigned i = 0; i < num_decls; ++i) {
if (used.contains(num_decls - i - 1)) {
used_decl_sorts.push_back(q->get_decl_sort(i));
used_decl_names.push_back(q->get_decl_name(i));
}
}
unsigned num_removed = 0;
expr_ref_buffer var_mapping(m);
int next_idx = 0;
unsigned sz = used.get_max_found_var_idx_plus_1();
for (unsigned i = 0; i < num_decls; ++i) {
sort * s = used.contains(i);
if (s) {
var_mapping.push_back(m.mk_var(next_idx, s));
next_idx++;
}
else {
num_removed++;
var_mapping.push_back(0);
}
}
// (VAR 0) is in the first position of var_mapping.
for (unsigned i = num_decls; i < sz; i++) {
sort * s = used.contains(i);
if (s)
var_mapping.push_back(m.mk_var(i - num_removed, s));
else
var_mapping.push_back(0);
}
// Remark:
// (VAR 0) should be in the last position of var_mapping.
// ...
// (VAR (var_mapping.size() - 1)) should be in the first position.
std::reverse(var_mapping.c_ptr(), var_mapping.c_ptr() + var_mapping.size());
expr_ref new_expr(m);
var_subst subst(m);
subst(q->get_expr(), var_mapping.size(), var_mapping.c_ptr(), new_expr);
if (num_removed == num_decls) {
result = new_expr;
return;
}
expr_ref tmp(m);
expr_ref_buffer new_patterns(m);
expr_ref_buffer new_no_patterns(m);
for (unsigned i = 0; i < num_patterns; i++) {
subst(q->get_pattern(i), var_mapping.size(), var_mapping.c_ptr(), tmp);
new_patterns.push_back(tmp);
}
for (unsigned i = 0; i < num_no_patterns; i++) {
subst(q->get_no_pattern(i), var_mapping.size(), var_mapping.c_ptr(), tmp);
new_no_patterns.push_back(tmp);
}
result = m.mk_quantifier(q->is_forall(),
used_decl_sorts.size(),
used_decl_sorts.c_ptr(),
used_decl_names.c_ptr(),
new_expr,
q->get_weight(),
q->get_qid(),
q->get_skid(),
num_patterns,
new_patterns.c_ptr(),
num_no_patterns,
new_no_patterns.c_ptr());
to_quantifier(result)->set_no_unused_vars();
SASSERT(is_well_sorted(m, result));
}
void instantiate(ast_manager & m, quantifier * q, expr * const * exprs, expr_ref & result) {
var_subst subst(m);
expr_ref new_expr(m);
subst(q->get_expr(), q->get_num_decls(), exprs, new_expr);
TRACE("var_subst", tout << mk_pp(q, m) << "\n" << mk_pp(new_expr, m) << "\n";);
inv_var_shifter shift(m);
shift(new_expr, q->get_num_decls(), result);
SASSERT(is_well_sorted(m, result));
TRACE("instantiate_bug", tout << mk_ismt2_pp(q, m) << "\nusing\n";
for (unsigned i = 0; i < q->get_num_decls(); i++) tout << mk_ismt2_pp(exprs[i], m) << "\n";
tout << "\n----->\n" << mk_ismt2_pp(result, m) << "\n";);
}
static void get_free_vars_offset(expr* e, unsigned offset, ptr_vector<sort>& sorts) {
ast_mark mark;
ptr_vector<expr> todo;
todo.push_back(e);
while (!todo.empty()) {
e = todo.back();
todo.pop_back();
if (mark.is_marked(e)) {
continue;
}
mark.mark(e, true);
switch(e->get_kind()) {
case AST_QUANTIFIER: {
quantifier* q = to_quantifier(e);
get_free_vars_offset(q->get_expr(), offset+q->get_num_decls(), sorts);
break;
}
case AST_VAR: {
var* v = to_var(e);
if (v->get_idx() >= offset) {
unsigned idx = v->get_idx()-offset;
if (sorts.size() <= idx) {
sorts.resize(idx+1);
}
if (!sorts[idx]) {
sorts[idx] = v->get_sort();
}
SASSERT(sorts[idx] == v->get_sort());
}
break;
}
case AST_APP: {
app* a = to_app(e);
for (unsigned i = 0; i < a->get_num_args(); ++i) {
todo.push_back(a->get_arg(i));
}
break;
}
default:
UNREACHABLE();
}
}
}
void get_free_vars(expr* e, ptr_vector<sort>& sorts) {
get_free_vars_offset(e, 0, sorts);
}

View file

@ -1,78 +0,0 @@
/*++
Copyright (c) 2007 Microsoft Corporation
Module Name:
var_subst.h
Abstract:
Variable substitution.
Author:
Leonardo (leonardo) 2008-01-10
Notes:
--*/
#ifndef _VAR_SUBST_H_
#define _VAR_SUBST_H_
#include"rewriter.h"
/**
\brief Alias for var_shifter class.
*/
typedef var_shifter shift_vars;
/**
\brief Variable substitution functor. It substitutes variables by expressions.
The expressions may contain variables.
*/
class var_subst {
beta_reducer m_reducer;
bool m_std_order;
public:
var_subst(ast_manager & m, bool std_order = true):m_reducer(m), m_std_order(std_order) {}
bool std_order() const { return m_std_order; }
/**
When std_order() == true,
I'm using the same standard used in quantifier instantiation.
(VAR 0) is stored in the last position of the array.
...
(VAR (num_args - 1)) is stored in the first position of the array.
Otherwise, (VAR 0) is stored in the first position, (VAR 1) in the second, and so on.
*/
void operator()(expr * n, unsigned num_args, expr * const * args, expr_ref & result);
void reset() { m_reducer.reset(); }
};
/**
\brief Eliminate the unused variables from \c q. Store the result in \c r.
*/
void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & r);
/**
\brief Instantiate quantifier q using the given exprs.
The vector exprs should contain at least q->get_num_decls() expressions.
I'm using the same standard used in quantifier instantiation.
(VAR 0) is stored in the last position of the array.
...
(VAR (q->get_num_decls() - 1)) is stored in the first position of the array.
*/
void instantiate(ast_manager & m, quantifier * q, expr * const * exprs, expr_ref & result);
/**
\brief Enumerate set of free variables in expression.
Return the sorts of the free variables.
*/
void get_free_vars(expr* e, ptr_vector<sort>& sorts);
#endif