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:
parent
9a84cba6c9
commit
ded42feeb6
62 changed files with 4 additions and 115 deletions
|
@ -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;
|
||||
}
|
|
@ -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
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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_ */
|
||||
|
144
lib/ast_lt.cpp
144
lib/ast_lt.cpp
|
@ -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;
|
||||
}
|
35
lib/ast_lt.h
35
lib/ast_lt.h
|
@ -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
|
1224
lib/ast_smt_pp.cpp
1224
lib/ast_smt_pp.cpp
File diff suppressed because it is too large
Load diff
103
lib/ast_smt_pp.h
103
lib/ast_smt_pp.h
|
@ -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
|
|
@ -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());
|
||||
}
|
|
@ -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
|
|
@ -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>;
|
|
@ -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
|
2076
lib/bv_rewriter.cpp
2076
lib/bv_rewriter.cpp
File diff suppressed because it is too large
Load diff
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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
|
|
@ -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_ */
|
||||
|
|
@ -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();
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
630
lib/goal.cpp
630
lib/goal.cpp
|
@ -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;
|
||||
}
|
255
lib/goal.h
255
lib/goal.h
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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());
|
||||
}
|
402
lib/rewriter.cpp
402
lib/rewriter.cpp
|
@ -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>;
|
399
lib/rewriter.h
399
lib/rewriter.h
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
|
||||
};
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
||||
};
|
124
lib/subpaving.h
124
lib/subpaving.h
|
@ -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
|
|
@ -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>;
|
|
@ -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
|
|
@ -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>;
|
|
@ -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
|
|
@ -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>;
|
|
@ -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
|
|
@ -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>;
|
|
@ -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
|
|
@ -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>;
|
|
@ -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
|
|
@ -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
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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_ */
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue