mirror of
https://github.com/Z3Prover/z3
synced 2025-08-28 14:08:55 +00:00
merge with master branch
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
commit
651587ce01
1602 changed files with 40496 additions and 27837 deletions
|
@ -3,22 +3,29 @@ z3_add_component(rewriter
|
|||
arith_rewriter.cpp
|
||||
array_rewriter.cpp
|
||||
ast_counter.cpp
|
||||
bit2int.cpp
|
||||
bool_rewriter.cpp
|
||||
bv_bounds.cpp
|
||||
bv_elim.cpp
|
||||
bv_rewriter.cpp
|
||||
datatype_rewriter.cpp
|
||||
der.cpp
|
||||
distribute_forall.cpp
|
||||
dl_rewriter.cpp
|
||||
elim_bounds.cpp
|
||||
enum2bv_rewriter.cpp
|
||||
expr_replacer.cpp
|
||||
expr_safe_replace.cpp
|
||||
factor_rewriter.cpp
|
||||
fpa_rewriter.cpp
|
||||
inj_axiom.cpp
|
||||
label_rewriter.cpp
|
||||
maximize_ac_sharing.cpp
|
||||
mk_simplified_app.cpp
|
||||
pb_rewriter.cpp
|
||||
pb2bv_rewriter.cpp
|
||||
push_app_ite.cpp
|
||||
pull_ite_tree.cpp
|
||||
quant_hoist.cpp
|
||||
rewriter.cpp
|
||||
seq_rewriter.cpp
|
||||
|
|
|
@ -16,17 +16,17 @@ Author:
|
|||
Notes:
|
||||
|
||||
--*/
|
||||
#include"arith_rewriter.h"
|
||||
#include"arith_rewriter_params.hpp"
|
||||
#include"poly_rewriter_def.h"
|
||||
#include"algebraic_numbers.h"
|
||||
#include"ast_pp.h"
|
||||
#include "ast/rewriter/arith_rewriter.h"
|
||||
#include "ast/rewriter/arith_rewriter_params.hpp"
|
||||
#include "ast/rewriter/poly_rewriter_def.h"
|
||||
#include "math/polynomial/algebraic_numbers.h"
|
||||
#include "ast/ast_pp.h"
|
||||
|
||||
void arith_rewriter::updt_local_params(params_ref const & _p) {
|
||||
arith_rewriter_params p(_p);
|
||||
m_arith_lhs = p.arith_lhs();
|
||||
m_arith_ineq_lhs = p.arith_ineq_lhs();
|
||||
m_gcd_rounding = p.gcd_rounding();
|
||||
m_eq2ineq = p.eq2ineq();
|
||||
m_elim_to_real = p.elim_to_real();
|
||||
m_push_to_real = p.push_to_real();
|
||||
m_anum_simp = p.algebraic_number_evaluator();
|
||||
|
@ -35,6 +35,7 @@ void arith_rewriter::updt_local_params(params_ref const & _p) {
|
|||
m_mul2power = p.mul_to_power();
|
||||
m_elim_rem = p.elim_rem();
|
||||
m_expand_tan = p.expand_tan();
|
||||
m_eq2ineq = p.eq2ineq();
|
||||
set_sort_sums(p.sort_sums());
|
||||
}
|
||||
|
||||
|
@ -370,8 +371,8 @@ br_status arith_rewriter::mk_le_ge_eq_core(expr * arg1, expr * arg2, op_kind kin
|
|||
if ((is_zero(arg1) && is_reduce_power_target(arg2, kind == EQ)) ||
|
||||
(is_zero(arg2) && is_reduce_power_target(arg1, kind == EQ)))
|
||||
return reduce_power(arg1, arg2, kind, result);
|
||||
br_status st = cancel_monomials(arg1, arg2, m_arith_lhs, new_arg1, new_arg2);
|
||||
TRACE("mk_le_bug", tout << "st: " << st << "\n";);
|
||||
br_status st = cancel_monomials(arg1, arg2, m_arith_ineq_lhs || m_arith_lhs, new_arg1, new_arg2);
|
||||
TRACE("mk_le_bug", tout << "st: " << st << " " << new_arg1 << " " << new_arg2 << "\n";);
|
||||
if (st != BR_FAILED) {
|
||||
arg1 = new_arg1;
|
||||
arg2 = new_arg2;
|
||||
|
@ -454,7 +455,16 @@ br_status arith_rewriter::mk_le_ge_eq_core(expr * arg1, expr * arg2, op_kind kin
|
|||
st = BR_DONE;
|
||||
}
|
||||
}
|
||||
if (st == BR_DONE && arg1 == orig_arg1 && arg2 == orig_arg2) {
|
||||
if ((m_arith_lhs || m_arith_ineq_lhs) && is_numeral(arg2, a2) && is_neg_poly(arg1, new_arg1)) {
|
||||
a2.neg();
|
||||
new_arg2 = m_util.mk_numeral(a2, m_util.is_int(new_arg1));
|
||||
switch (kind) {
|
||||
case LE: result = m_util.mk_ge(new_arg1, new_arg2); return BR_DONE;
|
||||
case GE: result = m_util.mk_le(new_arg1, new_arg2); return BR_DONE;
|
||||
case EQ: result = m_util.mk_eq(new_arg1, new_arg2); return BR_DONE;
|
||||
}
|
||||
}
|
||||
else if (st == BR_DONE && arg1 == orig_arg1 && arg2 == orig_arg2) {
|
||||
// Nothing new; return BR_FAILED to avoid rewriting loops.
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
@ -486,12 +496,69 @@ br_status arith_rewriter::mk_gt_core(expr * arg1, expr * arg2, expr_ref & result
|
|||
return BR_REWRITE2;
|
||||
}
|
||||
|
||||
bool arith_rewriter::is_arith_term(expr * n) const {
|
||||
return n->get_kind() == AST_APP && to_app(n)->get_family_id() == get_fid();
|
||||
}
|
||||
|
||||
br_status arith_rewriter::mk_eq_core(expr * arg1, expr * arg2, expr_ref & result) {
|
||||
if (m_eq2ineq) {
|
||||
result = m().mk_and(m_util.mk_le(arg1, arg2), m_util.mk_ge(arg1, arg2));
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
return mk_le_ge_eq_core(arg1, arg2, EQ, result);
|
||||
if (m_arith_lhs || is_arith_term(arg1) || is_arith_term(arg2)) {
|
||||
return mk_le_ge_eq_core(arg1, arg2, EQ, result);
|
||||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
expr_ref arith_rewriter::neg_monomial(expr* e) const {
|
||||
expr_ref_vector args(m());
|
||||
rational a1;
|
||||
if (is_app(e) & m_util.is_mul(e)) {
|
||||
if (is_numeral(to_app(e)->get_arg(0), a1)) {
|
||||
if (!a1.is_minus_one()) {
|
||||
args.push_back(m_util.mk_numeral(-a1, m_util.is_int(e)));
|
||||
}
|
||||
args.append(to_app(e)->get_num_args() - 1, to_app(e)->get_args() + 1);
|
||||
}
|
||||
else {
|
||||
args.push_back(m_util.mk_numeral(rational(-1), m_util.is_int(e)));
|
||||
args.push_back(e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
args.push_back(m_util.mk_numeral(rational(-1), m_util.is_int(e)));
|
||||
args.push_back(e);
|
||||
}
|
||||
if (args.size() == 1) {
|
||||
return expr_ref(args.back(), m());
|
||||
}
|
||||
else {
|
||||
return expr_ref(m_util.mk_mul(args.size(), args.c_ptr()), m());
|
||||
}
|
||||
}
|
||||
|
||||
bool arith_rewriter::is_neg_poly(expr* t, expr_ref& neg) const {
|
||||
rational r;
|
||||
if (m_util.is_mul(t) && is_numeral(to_app(t)->get_arg(0), r) && r.is_neg()) {
|
||||
neg = neg_monomial(t);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!m_util.is_add(t)) {
|
||||
return false;
|
||||
}
|
||||
expr * t2 = to_app(t)->get_arg(0);
|
||||
|
||||
if (m_util.is_mul(t2) && is_numeral(to_app(t2)->get_arg(0), r) && r.is_neg()) {
|
||||
expr_ref_vector args1(m());
|
||||
for (expr* e1 : *to_app(t)) {
|
||||
args1.push_back(neg_monomial(e1));
|
||||
}
|
||||
neg = m_util.mk_add(args1.size(), args1.c_ptr());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool arith_rewriter::is_anum_simp_target(unsigned num_args, expr * const * args) {
|
||||
|
@ -680,8 +747,7 @@ br_status arith_rewriter::mk_div_core(expr * arg1, expr * arg2, expr_ref & resul
|
|||
if (m_util.is_numeral(arg2, v2, is_int)) {
|
||||
SASSERT(!is_int);
|
||||
if (v2.is_zero()) {
|
||||
result = m_util.mk_div0(arg1);
|
||||
return BR_REWRITE1;
|
||||
return BR_FAILED;
|
||||
}
|
||||
else if (m_util.is_numeral(arg1, v1, is_int)) {
|
||||
result = m_util.mk_numeral(v1/v2, false);
|
||||
|
@ -734,10 +800,6 @@ br_status arith_rewriter::mk_idiv_core(expr * arg1, expr * arg2, expr_ref & resu
|
|||
result = m_util.mk_numeral(div(v1, v2), is_int);
|
||||
return BR_DONE;
|
||||
}
|
||||
if (m_util.is_numeral(arg2, v2, is_int) && v2.is_zero()) {
|
||||
result = m_util.mk_idiv0(arg1);
|
||||
return BR_REWRITE1;
|
||||
}
|
||||
expr_ref quot(m());
|
||||
if (divides(arg1, arg2, quot)) {
|
||||
result = m_util.mk_mul(quot, m_util.mk_idiv(arg1, arg1));
|
||||
|
@ -800,6 +862,13 @@ br_status arith_rewriter::mk_mod_core(expr * arg1, expr * arg2, expr_ref & resul
|
|||
return BR_DONE;
|
||||
}
|
||||
|
||||
if (arg1 == arg2 && !m_util.is_numeral(arg2)) {
|
||||
expr_ref zero(m_util.mk_int(0), m()), abs(m());
|
||||
mk_abs_core(arg2, abs);
|
||||
result = m().mk_ite(m().mk_eq(arg2, zero), m_util.mk_mod(zero, zero), abs);
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
// mod is idempotent on non-zero modulus.
|
||||
expr* t1, *t2;
|
||||
if (m_util.is_mod(arg1, t1, t2) && t2 == arg2 && m_util.is_numeral(arg2, v2, is_int) && is_int && !v2.is_zero()) {
|
||||
|
|
|
@ -19,8 +19,8 @@ Notes:
|
|||
#ifndef ARITH_REWRITER_H_
|
||||
#define ARITH_REWRITER_H_
|
||||
|
||||
#include"poly_rewriter.h"
|
||||
#include"arith_decl_plugin.h"
|
||||
#include "ast/rewriter/poly_rewriter.h"
|
||||
#include "ast/arith_decl_plugin.h"
|
||||
|
||||
class arith_rewriter_core {
|
||||
protected:
|
||||
|
@ -35,7 +35,6 @@ protected:
|
|||
|
||||
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); }
|
||||
|
@ -45,16 +44,19 @@ protected:
|
|||
decl_kind power_decl_kind() const { return OP_POWER; }
|
||||
public:
|
||||
arith_rewriter_core(ast_manager & m):m_util(m) {}
|
||||
bool is_zero(expr * n) const { return m_util.is_zero(n); }
|
||||
};
|
||||
|
||||
class arith_rewriter : public poly_rewriter<arith_rewriter_core> {
|
||||
bool m_arith_lhs;
|
||||
bool m_arith_ineq_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;
|
||||
bool m_eq2ineq;
|
||||
bool m_process_all_eqs;
|
||||
unsigned m_max_degree;
|
||||
|
||||
void get_coeffs_gcd(expr * t, numeral & g, bool & first, unsigned & num_consts);
|
||||
|
@ -82,12 +84,16 @@ class arith_rewriter : public poly_rewriter<arith_rewriter_core> {
|
|||
expr * reduce_power(expr * arg, bool is_eq);
|
||||
br_status reduce_power(expr * arg1, expr * arg2, op_kind kind, expr_ref & result);
|
||||
|
||||
bool is_arith_term(expr * n) const;
|
||||
|
||||
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);
|
||||
bool is_neg_poly(expr* e, expr_ref& neg) const;
|
||||
expr_ref neg_monomial(expr * e) const;
|
||||
expr * mk_sin_value(rational const & k);
|
||||
app * mk_sqrt(rational const & k);
|
||||
bool divides(expr* d, expr* n, expr_ref& quot);
|
||||
|
|
|
@ -6,10 +6,11 @@ def_module_params(module_name='rewriter',
|
|||
("expand_power", BOOL, False, "expand (^ t k) into (* t ... t) if 1 < k <= max_degree."),
|
||||
("expand_tan", BOOL, False, "replace (tan x) with (/ (sin x) (cos x))."),
|
||||
("max_degree", UINT, 64, "max degree of algebraic numbers (and power operators) processed by simplifier."),
|
||||
("eq2ineq", BOOL, False, "split arithmetic equalities into two inequalities."),
|
||||
("sort_sums", BOOL, False, "sort the arguments of + application."),
|
||||
("gcd_rounding", BOOL, False, "use gcd rounding on integer arithmetic atoms."),
|
||||
("arith_lhs", BOOL, False, "all monomials are moved to the left-hand-side, and the right-hand-side is just a constant."),
|
||||
("arith_ineq_lhs", BOOL, False, "rewrite inequalities so that right-hand-side is a constant."),
|
||||
("elim_to_real", BOOL, False, "eliminate to_real from arithmetic predicates that contain only integers."),
|
||||
("push_to_real", BOOL, True, "distribute to_real over * and +."),
|
||||
("eq2ineq", BOOL, False, "expand equalities into two inequalities"),
|
||||
("elim_rem", BOOL, False, "replace (rem x y) with (ite (>= y 0) (mod x y) (- (mod x y))).")))
|
||||
|
|
|
@ -16,10 +16,10 @@ Author:
|
|||
Notes:
|
||||
|
||||
--*/
|
||||
#include"array_rewriter.h"
|
||||
#include"array_rewriter_params.hpp"
|
||||
#include"ast_lt.h"
|
||||
#include"ast_pp.h"
|
||||
#include "ast/rewriter/array_rewriter.h"
|
||||
#include "ast/rewriter/array_rewriter_params.hpp"
|
||||
#include "ast/ast_lt.h"
|
||||
#include "ast/ast_pp.h"
|
||||
|
||||
void array_rewriter::updt_params(params_ref const & _p) {
|
||||
array_rewriter_params p(_p);
|
||||
|
|
|
@ -19,10 +19,10 @@ Notes:
|
|||
#ifndef ARRAY_REWRITER_H_
|
||||
#define ARRAY_REWRITER_H_
|
||||
|
||||
#include"array_decl_plugin.h"
|
||||
#include"rewriter_types.h"
|
||||
#include"lbool.h"
|
||||
#include"params.h"
|
||||
#include "ast/array_decl_plugin.h"
|
||||
#include "ast/rewriter/rewriter_types.h"
|
||||
#include "util/lbool.h"
|
||||
#include "util/params.h"
|
||||
|
||||
/**
|
||||
\brief Cheap rewrite rules for Arrays
|
||||
|
|
|
@ -17,7 +17,7 @@ Revision History:
|
|||
|
||||
--*/
|
||||
|
||||
#include "ast_counter.h"
|
||||
#include "ast/rewriter/ast_counter.h"
|
||||
|
||||
void counter::update(unsigned el, int delta) {
|
||||
int & counter = get(el);
|
||||
|
|
|
@ -24,10 +24,10 @@ Revision History:
|
|||
#ifndef AST_COUNTER_H_
|
||||
#define AST_COUNTER_H_
|
||||
|
||||
#include "ast.h"
|
||||
#include "map.h"
|
||||
#include "uint_set.h"
|
||||
#include "var_subst.h"
|
||||
#include "ast/ast.h"
|
||||
#include "util/map.h"
|
||||
#include "util/uint_set.h"
|
||||
#include "ast/rewriter/var_subst.h"
|
||||
|
||||
class counter {
|
||||
protected:
|
||||
|
|
420
src/ast/rewriter/bit2int.cpp
Normal file
420
src/ast/rewriter/bit2int.cpp
Normal file
|
@ -0,0 +1,420 @@
|
|||
/*++
|
||||
Copyright (c) 2009 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
bit2cpp.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Routines for simplifying bit2int expressions.
|
||||
This propagates bv2int over arithmetical symbols as much as possible,
|
||||
converting arithmetic operations into bit-vector operations.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2009-08-28
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "ast/ast_pp.h"
|
||||
#include "ast/ast_ll_pp.h"
|
||||
#include "ast/for_each_ast.h"
|
||||
#include "ast/rewriter/bit2int.h"
|
||||
|
||||
|
||||
#define CHECK(_x_) if (!(_x_)) { UNREACHABLE(); }
|
||||
|
||||
bit2int::bit2int(ast_manager & m) :
|
||||
m_manager(m), m_bv_util(m), m_rewriter(m), m_arith_util(m), m_cache(m), m_bit0(m) {
|
||||
m_bit0 = m_bv_util.mk_numeral(0,1);
|
||||
}
|
||||
|
||||
void bit2int::operator()(expr * m, expr_ref & result, proof_ref& p) {
|
||||
flush_cache();
|
||||
expr_reduce emap(*this);
|
||||
for_each_ast(emap, m);
|
||||
result = get_cached(m);
|
||||
if (m_manager.proofs_enabled() && m != result.get()) {
|
||||
// TBD: rough
|
||||
p = m_manager.mk_rewrite(m, result);
|
||||
}
|
||||
TRACE("bit2int",
|
||||
tout << mk_pp(m, m_manager) << "======>\n"
|
||||
<< mk_pp(result, m_manager) << "\n";);
|
||||
|
||||
}
|
||||
|
||||
|
||||
unsigned bit2int::get_b2i_size(expr* n) {
|
||||
SASSERT(m_bv_util.is_bv2int(n));
|
||||
return m_bv_util.get_bv_size(to_app(n)->get_arg(0));
|
||||
}
|
||||
|
||||
unsigned bit2int::get_numeral_bits(numeral const& k) {
|
||||
numeral two(2);
|
||||
numeral n(abs(k));
|
||||
unsigned num_bits = 1;
|
||||
n = div(n, two);
|
||||
while (n.is_pos()) {
|
||||
++num_bits;
|
||||
n = div(n, two);
|
||||
}
|
||||
return num_bits;
|
||||
}
|
||||
|
||||
void bit2int::align_size(expr* e, unsigned sz, expr_ref& result) {
|
||||
unsigned sz1 = m_bv_util.get_bv_size(e);
|
||||
SASSERT(sz1 <= sz);
|
||||
result = m_rewriter.mk_zero_extend(sz-sz1, e);
|
||||
}
|
||||
|
||||
void bit2int::align_sizes(expr_ref& a, expr_ref& b) {
|
||||
unsigned sz1 = m_bv_util.get_bv_size(a);
|
||||
unsigned sz2 = m_bv_util.get_bv_size(b);
|
||||
expr_ref tmp(m_manager);
|
||||
if (sz1 > sz2) {
|
||||
tmp = m_rewriter.mk_zero_extend(sz1-sz2, b);
|
||||
b = tmp;
|
||||
}
|
||||
else if (sz2 > sz1) {
|
||||
tmp = m_rewriter.mk_zero_extend(sz2-sz1, a);
|
||||
a = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
bool bit2int::extract_bv(expr* n, unsigned& sz, bool& sign, expr_ref& bv) {
|
||||
numeral k;
|
||||
bool is_int;
|
||||
if (m_bv_util.is_bv2int(n)) {
|
||||
bv = to_app(n)->get_arg(0);
|
||||
sz = m_bv_util.get_bv_size(bv);
|
||||
sign = false;
|
||||
return true;
|
||||
}
|
||||
else if (m_arith_util.is_numeral(n, k, is_int) && is_int) {
|
||||
sz = get_numeral_bits(k);
|
||||
bv = m_bv_util.mk_numeral(k, m_bv_util.mk_sort(sz));
|
||||
sign = k.is_neg();
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool bit2int::mk_add(expr* e1, expr* e2, expr_ref& result) {
|
||||
unsigned sz1, sz2;
|
||||
bool sign1, sign2;
|
||||
expr_ref tmp1(m_manager), tmp2(m_manager), tmp3(m_manager);
|
||||
|
||||
if (extract_bv(e1, sz1, sign1, tmp1) && !sign1 &&
|
||||
extract_bv(e2, sz2, sign2, tmp2) && !sign2) {
|
||||
unsigned sz;
|
||||
numeral k;
|
||||
if (m_bv_util.is_numeral(tmp1, k, sz) && k.is_zero()) {
|
||||
result = e2;
|
||||
return true;
|
||||
}
|
||||
if (m_bv_util.is_numeral(tmp2, k, sz) && k.is_zero()) {
|
||||
result = e1;
|
||||
return true;
|
||||
}
|
||||
align_sizes(tmp1, tmp2);
|
||||
tmp1 = m_rewriter.mk_zero_extend(1, tmp1);
|
||||
tmp2 = m_rewriter.mk_zero_extend(1, tmp2);
|
||||
SASSERT(m_bv_util.get_bv_size(tmp1) == m_bv_util.get_bv_size(tmp2));
|
||||
tmp3 = m_rewriter.mk_bv_add(tmp1, tmp2);
|
||||
result = m_rewriter.mk_bv2int(tmp3);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bit2int::mk_comp(eq_type ty, expr* e1, expr* e2, expr_ref& result) {
|
||||
unsigned sz1, sz2;
|
||||
bool sign1, sign2;
|
||||
expr_ref tmp1(m_manager), tmp2(m_manager), tmp3(m_manager);
|
||||
if (extract_bv(e1, sz1, sign1, tmp1) && !sign1 &&
|
||||
extract_bv(e2, sz2, sign2, tmp2) && !sign2) {
|
||||
align_sizes(tmp1, tmp2);
|
||||
SASSERT(m_bv_util.get_bv_size(tmp1) == m_bv_util.get_bv_size(tmp2));
|
||||
switch(ty) {
|
||||
case lt:
|
||||
tmp3 = m_rewriter.mk_ule(tmp2, tmp1);
|
||||
result = m_manager.mk_not(tmp3);
|
||||
break;
|
||||
case le:
|
||||
result = m_rewriter.mk_ule(tmp1, tmp2);
|
||||
break;
|
||||
case eq:
|
||||
result = m_manager.mk_eq(tmp1, tmp2);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bit2int::mk_mul(expr* e1, expr* e2, expr_ref& result) {
|
||||
unsigned sz1, sz2;
|
||||
bool sign1, sign2;
|
||||
expr_ref tmp1(m_manager), tmp2(m_manager);
|
||||
expr_ref tmp3(m_manager);
|
||||
|
||||
if (extract_bv(e1, sz1, sign1, tmp1) &&
|
||||
extract_bv(e2, sz2, sign2, tmp2)) {
|
||||
align_sizes(tmp1, tmp2);
|
||||
tmp1 = m_rewriter.mk_zero_extend(m_bv_util.get_bv_size(tmp1), tmp1);
|
||||
tmp2 = m_rewriter.mk_zero_extend(m_bv_util.get_bv_size(tmp2), tmp2);
|
||||
|
||||
SASSERT(m_bv_util.get_bv_size(tmp1) == m_bv_util.get_bv_size(tmp2));
|
||||
tmp3 = m_rewriter.mk_bv_mul(tmp1, tmp2);
|
||||
result = m_rewriter.mk_bv2int(tmp3);
|
||||
if (sign1 != sign2) {
|
||||
result = m_arith_util.mk_uminus(result);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bit2int::is_bv_poly(expr* n, expr_ref& pos, expr_ref& neg) {
|
||||
ptr_vector<expr> todo;
|
||||
expr_ref tmp(m_manager);
|
||||
numeral k;
|
||||
bool is_int;
|
||||
todo.push_back(n);
|
||||
neg = pos = m_rewriter.mk_bv2int(m_bit0);
|
||||
|
||||
while (!todo.empty()) {
|
||||
n = todo.back();
|
||||
todo.pop_back();
|
||||
if (m_bv_util.is_bv2int(n)) {
|
||||
CHECK(mk_add(n, pos, pos));
|
||||
}
|
||||
else if (m_arith_util.is_numeral(n, k, is_int) && is_int) {
|
||||
if (k.is_nonneg()) {
|
||||
CHECK(mk_add(n, pos, pos));
|
||||
}
|
||||
else {
|
||||
tmp = m_arith_util.mk_numeral(-k, true);
|
||||
CHECK(mk_add(tmp, neg, neg));
|
||||
}
|
||||
}
|
||||
else if (m_arith_util.is_add(n)) {
|
||||
for (unsigned i = 0; i < to_app(n)->get_num_args(); ++i) {
|
||||
todo.push_back(to_app(n)->get_arg(i));
|
||||
}
|
||||
}
|
||||
else if (m_arith_util.is_mul(n) &&
|
||||
to_app(n)->get_num_args() == 2 &&
|
||||
m_arith_util.is_numeral(to_app(n)->get_arg(0), k, is_int) && is_int && k.is_minus_one() &&
|
||||
m_bv_util.is_bv2int(to_app(n)->get_arg(1))) {
|
||||
CHECK(mk_add(to_app(n)->get_arg(1), neg, neg));
|
||||
}
|
||||
else if (m_arith_util.is_mul(n) &&
|
||||
to_app(n)->get_num_args() == 2 &&
|
||||
m_arith_util.is_numeral(to_app(n)->get_arg(1), k, is_int) && is_int && k.is_minus_one() &&
|
||||
m_bv_util.is_bv2int(to_app(n)->get_arg(0))) {
|
||||
CHECK(mk_add(to_app(n)->get_arg(0), neg, neg));
|
||||
}
|
||||
else if (m_arith_util.is_uminus(n) &&
|
||||
m_bv_util.is_bv2int(to_app(n)->get_arg(0))) {
|
||||
CHECK(mk_add(to_app(n)->get_arg(0), neg, neg));
|
||||
}
|
||||
else {
|
||||
TRACE("bit2int", tout << "Not a poly: " << mk_pp(n, m_manager) << "\n";);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void bit2int::visit(quantifier* q) {
|
||||
expr_ref result(m_manager);
|
||||
result = get_cached(q->get_expr());
|
||||
result = m_manager.update_quantifier(q, result);
|
||||
cache_result(q, result);
|
||||
}
|
||||
|
||||
void bit2int::visit(app* n) {
|
||||
func_decl* f = n->get_decl();
|
||||
unsigned num_args = n->get_num_args();
|
||||
|
||||
m_args.reset();
|
||||
for (unsigned i = 0; i < num_args; ++i) {
|
||||
m_args.push_back(get_cached(n->get_arg(i)));
|
||||
}
|
||||
|
||||
expr* const* args = m_args.c_ptr();
|
||||
|
||||
bool has_b2i =
|
||||
m_arith_util.is_le(n) || m_arith_util.is_ge(n) || m_arith_util.is_gt(n) ||
|
||||
m_arith_util.is_lt(n) || m_manager.is_eq(n);
|
||||
expr_ref result(m_manager);
|
||||
for (unsigned i = 0; !has_b2i && i < num_args; ++i) {
|
||||
has_b2i = m_bv_util.is_bv2int(args[i]);
|
||||
}
|
||||
if (!has_b2i) {
|
||||
result = m_manager.mk_app(f, num_args, args);
|
||||
cache_result(n, result);
|
||||
return;
|
||||
}
|
||||
//
|
||||
// bv2int(x) + bv2int(y) -> bv2int(pad(x) + pad(y))
|
||||
// bv2int(x) + k -> bv2int(pad(x) + pad(k))
|
||||
// bv2int(x) * bv2int(y) -> bv2int(pad(x) * pad(y))
|
||||
// bv2int(x) * k -> sign(k)*bv2int(pad(x) * pad(k))
|
||||
// bv2int(x) - bv2int(y) <= z -> bv2int(x) <= bv2int(y) + z
|
||||
// bv2int(x) <= z - bv2int(y) -> bv2int(x) + bv2int(y) <= z
|
||||
//
|
||||
|
||||
expr* e1 = 0, *e2 = 0;
|
||||
expr_ref tmp1(m_manager), tmp2(m_manager);
|
||||
expr_ref tmp3(m_manager);
|
||||
expr_ref pos1(m_manager), neg1(m_manager);
|
||||
expr_ref pos2(m_manager), neg2(m_manager);
|
||||
expr_ref e2bv(m_manager);
|
||||
bool sign2;
|
||||
numeral k;
|
||||
unsigned sz2;
|
||||
|
||||
if (num_args >= 2) {
|
||||
e1 = args[0];
|
||||
e2 = args[1];
|
||||
}
|
||||
|
||||
if (m_arith_util.is_add(n) && num_args >= 1) {
|
||||
result = e1;
|
||||
for (unsigned i = 1; i < num_args; ++i) {
|
||||
e1 = result;
|
||||
e2 = args[i];
|
||||
if (!mk_add(e1, e2, result)) {
|
||||
result = m_manager.mk_app(f, num_args, args);
|
||||
cache_result(n, result);
|
||||
return;
|
||||
}
|
||||
}
|
||||
cache_result(n, result);
|
||||
}
|
||||
else if (m_arith_util.is_mul(n) && num_args >= 1) {
|
||||
result = e1;
|
||||
for (unsigned i = 1; i < num_args; ++i) {
|
||||
e1 = result;
|
||||
e2 = args[i];
|
||||
if (!mk_mul(e1, e2, result)) {
|
||||
result = m_manager.mk_app(f, num_args, args);
|
||||
cache_result(n, result);
|
||||
return;
|
||||
}
|
||||
}
|
||||
cache_result(n, result);
|
||||
}
|
||||
else if (m_manager.is_eq(n) &&
|
||||
is_bv_poly(e1, pos1, neg1) &&
|
||||
is_bv_poly(e2, pos2, neg2) &&
|
||||
mk_add(pos1, neg2, tmp1) &&
|
||||
mk_add(neg1, pos2, tmp2) &&
|
||||
mk_comp(eq, tmp1, tmp2, result)) {
|
||||
cache_result(n, result);
|
||||
}
|
||||
else if (m_arith_util.is_le(n) &&
|
||||
is_bv_poly(e1, pos1, neg1) &&
|
||||
is_bv_poly(e2, pos2, neg2) &&
|
||||
mk_add(pos1, neg2, tmp1) &&
|
||||
mk_add(neg1, pos2, tmp2) &&
|
||||
mk_comp(le, tmp1, tmp2, result)) {
|
||||
cache_result(n, result);
|
||||
}
|
||||
else if (m_arith_util.is_lt(n) &&
|
||||
is_bv_poly(e1, pos1, neg1) &&
|
||||
is_bv_poly(e2, pos2, neg2) &&
|
||||
mk_add(pos1, neg2, tmp1) &&
|
||||
mk_add(neg1, pos2, tmp2) &&
|
||||
mk_comp(lt, tmp1, tmp2, result)) {
|
||||
cache_result(n, result);
|
||||
}
|
||||
else if (m_arith_util.is_ge(n) &&
|
||||
is_bv_poly(e1, pos1, neg1) &&
|
||||
is_bv_poly(e2, pos2, neg2) &&
|
||||
mk_add(pos1, neg2, tmp1) &&
|
||||
mk_add(neg1, pos2, tmp2) &&
|
||||
mk_comp(le, tmp2, tmp1, result)) {
|
||||
cache_result(n, result);
|
||||
}
|
||||
else if (m_arith_util.is_gt(n) &&
|
||||
is_bv_poly(e1, pos1, neg1) &&
|
||||
is_bv_poly(e2, pos2, neg2) &&
|
||||
mk_add(pos1, neg2, tmp1) &&
|
||||
mk_add(neg1, pos2, tmp2) &&
|
||||
mk_comp(lt, tmp2, tmp1, result)) {
|
||||
cache_result(n, result);
|
||||
}
|
||||
else if (m_arith_util.is_mod(n) &&
|
||||
is_bv_poly(e1, pos1, neg1) &&
|
||||
extract_bv(e2, sz2, sign2, e2bv) && !sign2) {
|
||||
//
|
||||
// (pos1 - neg1) mod e2 = (pos1 + (e2 - (neg1 mod e2))) mod e2
|
||||
//
|
||||
unsigned sz_p, sz_n, sz;
|
||||
bool sign_p, sign_n;
|
||||
expr_ref tmp_p(m_manager), tmp_n(m_manager);
|
||||
CHECK(extract_bv(pos1, sz_p, sign_p, tmp_p));
|
||||
CHECK(extract_bv(neg1, sz_n, sign_n, tmp_n));
|
||||
SASSERT(!sign_p && !sign_n);
|
||||
|
||||
// pos1 mod e2
|
||||
if (m_bv_util.is_numeral(tmp_n, k, sz) && k.is_zero()) {
|
||||
tmp1 = tmp_p;
|
||||
tmp2 = e2bv;
|
||||
align_sizes(tmp1, tmp2);
|
||||
tmp3 = m_rewriter.mk_bv_urem(tmp1, tmp2);
|
||||
result = m_rewriter.mk_bv2int(tmp3);
|
||||
cache_result(n, result);
|
||||
return;
|
||||
}
|
||||
|
||||
// neg1 mod e2;
|
||||
tmp1 = tmp_n;
|
||||
tmp2 = e2bv;
|
||||
align_sizes(tmp1, tmp2);
|
||||
tmp3 = m_rewriter.mk_bv_urem(tmp1, tmp2);
|
||||
// e2 - (neg1 mod e2)
|
||||
tmp1 = e2bv;
|
||||
tmp2 = tmp3;
|
||||
align_sizes(tmp1, tmp2);
|
||||
tmp3 = m_rewriter.mk_bv_sub(tmp1, tmp2);
|
||||
// pos1 + (e2 - (neg1 mod e2))
|
||||
tmp1 = tmp_p;
|
||||
tmp2 = tmp3;
|
||||
align_sizes(tmp1, tmp2);
|
||||
tmp_p = m_rewriter.mk_zero_extend(1, tmp1);
|
||||
tmp_n = m_rewriter.mk_zero_extend(1, tmp2);
|
||||
tmp1 = m_rewriter.mk_bv_add(tmp_p, tmp_n);
|
||||
// (pos1 + (e2 - (neg1 mod e2))) mod e2
|
||||
tmp2 = e2bv;
|
||||
align_sizes(tmp1, tmp2);
|
||||
tmp3 = m_rewriter.mk_bv_urem(tmp1, tmp2);
|
||||
result = m_rewriter.mk_bv2int(tmp3);
|
||||
|
||||
cache_result(n, result);
|
||||
}
|
||||
else {
|
||||
result = m_manager.mk_app(f, num_args, args);
|
||||
cache_result(n, result);
|
||||
}
|
||||
}
|
||||
|
||||
expr * bit2int::get_cached(expr * n) const {
|
||||
return const_cast<bit2int*>(this)->m_cache.find(n);
|
||||
}
|
||||
|
||||
void bit2int::cache_result(expr * n, expr * r) {
|
||||
TRACE("bit2int_verbose", tout << "caching:\n" << mk_ll_pp(n, m_manager) <<
|
||||
"======>\n" << mk_ll_pp(r, m_manager) << "\n";);
|
||||
m_cache.insert(n, r);
|
||||
}
|
93
src/ast/rewriter/bit2int.h
Normal file
93
src/ast/rewriter/bit2int.h
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*++
|
||||
Copyright (c) 2009 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
bit2int.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Routines for simplifying bit2int expressions.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2009-08-28
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef BIT2INT_H_
|
||||
#define BIT2INT_H_
|
||||
|
||||
#include "ast/bv_decl_plugin.h"
|
||||
#include "ast/arith_decl_plugin.h"
|
||||
#include "ast/act_cache.h"
|
||||
#include "ast/rewriter/bv_rewriter.h"
|
||||
|
||||
class bit2int {
|
||||
protected:
|
||||
typedef rational numeral;
|
||||
|
||||
enum eq_type {
|
||||
lt,
|
||||
le,
|
||||
eq
|
||||
};
|
||||
|
||||
class expr_reduce {
|
||||
bit2int& m_super;
|
||||
public:
|
||||
expr_reduce(bit2int& s) : m_super(s) {}
|
||||
|
||||
void operator()(var* v) {
|
||||
m_super.cache_result(v, v);
|
||||
}
|
||||
|
||||
void operator()(quantifier* q) {
|
||||
m_super.visit(q);
|
||||
}
|
||||
|
||||
void operator()(app* a) {
|
||||
m_super.visit(a);
|
||||
}
|
||||
|
||||
void operator()(ast* a) {}
|
||||
|
||||
};
|
||||
|
||||
typedef act_cache expr_map;
|
||||
ast_manager & m_manager;
|
||||
bv_util m_bv_util;
|
||||
bv_rewriter m_rewriter;
|
||||
arith_util m_arith_util;
|
||||
|
||||
expr_map m_cache; // map: ast -> ast ref. counters are incremented when inserted here.
|
||||
expr_ref m_bit0;
|
||||
ptr_vector<expr> m_args;
|
||||
|
||||
|
||||
void visit(app* n);
|
||||
void visit(quantifier* q);
|
||||
unsigned get_b2i_size(expr * n);
|
||||
bool extract_bv(expr* n, unsigned& sz, bool& sign, expr_ref& bv);
|
||||
unsigned get_numeral_bits(numeral const& k);
|
||||
bool is_bv_poly(expr* n, expr_ref& pos, expr_ref& neg);
|
||||
bool mk_mul(expr* a, expr* b, expr_ref& result);
|
||||
bool mk_comp(eq_type ty, expr* e1, expr* e2, expr_ref& result);
|
||||
bool mk_add(expr* e1, expr* e2, expr_ref& result);
|
||||
|
||||
expr * get_cached(expr * n) const;
|
||||
bool is_cached(expr * n) const { return get_cached(n) != 0; }
|
||||
void cache_result(expr * n, expr * r);
|
||||
void reset_cache() { m_cache.reset(); }
|
||||
void flush_cache() { m_cache.cleanup(); }
|
||||
void align_size(expr* e, unsigned sz, expr_ref& result);
|
||||
void align_sizes(expr_ref& a, expr_ref& b);
|
||||
|
||||
public:
|
||||
bit2int(ast_manager & m);
|
||||
void operator()(expr * m, expr_ref & result, proof_ref& p);
|
||||
};
|
||||
|
||||
#endif /* BIT2INT_H_ */
|
||||
|
|
@ -4,5 +4,4 @@ z3_add_component(bit_blaster
|
|||
bit_blaster_rewriter.cpp
|
||||
COMPONENT_DEPENDENCIES
|
||||
rewriter
|
||||
simplifier
|
||||
)
|
||||
|
|
|
@ -16,10 +16,10 @@ Author:
|
|||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"bit_blaster.h"
|
||||
#include"bit_blaster_tpl_def.h"
|
||||
#include"ast_pp.h"
|
||||
#include"bv_decl_plugin.h"
|
||||
#include "ast/rewriter/bit_blaster/bit_blaster.h"
|
||||
#include "ast/rewriter/bit_blaster/bit_blaster_tpl_def.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "ast/bv_decl_plugin.h"
|
||||
|
||||
bit_blaster_cfg::bit_blaster_cfg(bv_util & u, bit_blaster_params const & p, bool_rewriter& rw):
|
||||
m_util(u),
|
||||
|
|
|
@ -19,11 +19,11 @@ Revision History:
|
|||
#ifndef BIT_BLASTER_H_
|
||||
#define BIT_BLASTER_H_
|
||||
|
||||
#include"bool_rewriter.h"
|
||||
#include"bit_blaster_params.h"
|
||||
#include"bit_blaster_tpl.h"
|
||||
#include"bv_decl_plugin.h"
|
||||
#include"rational.h"
|
||||
#include "ast/rewriter/bool_rewriter.h"
|
||||
#include "ast/rewriter/bit_blaster/bit_blaster_params.h"
|
||||
#include "ast/rewriter/bit_blaster/bit_blaster_tpl.h"
|
||||
#include "ast/bv_decl_plugin.h"
|
||||
#include "util/rational.h"
|
||||
|
||||
class bit_blaster_cfg {
|
||||
public:
|
||||
|
|
|
@ -16,13 +16,13 @@ Author:
|
|||
Notes:
|
||||
|
||||
--*/
|
||||
#include"bit_blaster_rewriter.h"
|
||||
#include"bv_decl_plugin.h"
|
||||
#include"bit_blaster_tpl_def.h"
|
||||
#include"rewriter_def.h"
|
||||
#include"bool_rewriter.h"
|
||||
#include"ref_util.h"
|
||||
#include"ast_smt2_pp.h"
|
||||
#include "ast/rewriter/bit_blaster/bit_blaster_rewriter.h"
|
||||
#include "ast/bv_decl_plugin.h"
|
||||
#include "ast/rewriter/bit_blaster/bit_blaster_tpl_def.h"
|
||||
#include "ast/rewriter/rewriter_def.h"
|
||||
#include "ast/rewriter/bool_rewriter.h"
|
||||
#include "util/ref_util.h"
|
||||
#include "ast/ast_smt2_pp.h"
|
||||
|
||||
struct blaster_cfg {
|
||||
typedef rational numeral;
|
||||
|
|
|
@ -19,9 +19,9 @@ Notes:
|
|||
#ifndef BIT_BLASTER_REWRITER_H_
|
||||
#define BIT_BLASTER_REWRITER_H_
|
||||
|
||||
#include"ast.h"
|
||||
#include"obj_hashtable.h"
|
||||
#include"params.h"
|
||||
#include "ast/ast.h"
|
||||
#include "util/obj_hashtable.h"
|
||||
#include "util/params.h"
|
||||
|
||||
class bit_blaster_rewriter {
|
||||
struct imp;
|
||||
|
|
|
@ -19,7 +19,7 @@ Revision History:
|
|||
#ifndef BIT_BLASTER_TPL_H_
|
||||
#define BIT_BLASTER_TPL_H_
|
||||
|
||||
#include"rational.h"
|
||||
#include "util/rational.h"
|
||||
|
||||
template<typename Cfg>
|
||||
class bit_blaster_tpl : public Cfg {
|
||||
|
|
|
@ -16,12 +16,12 @@ Author:
|
|||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"bit_blaster_tpl.h"
|
||||
#include"rational.h"
|
||||
#include"ast_pp.h"
|
||||
#include"cooperate.h"
|
||||
#include"common_msgs.h"
|
||||
#include"rewriter_types.h"
|
||||
#include "ast/rewriter/bit_blaster/bit_blaster_tpl.h"
|
||||
#include "util/rational.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "util/cooperate.h"
|
||||
#include "util/common_msgs.h"
|
||||
#include "ast/rewriter/rewriter_types.h"
|
||||
|
||||
|
||||
template<typename Cfg>
|
||||
|
|
|
@ -16,9 +16,9 @@ Author:
|
|||
Notes:
|
||||
|
||||
--*/
|
||||
#include"bool_rewriter.h"
|
||||
#include"bool_rewriter_params.hpp"
|
||||
#include"rewriter_def.h"
|
||||
#include "ast/rewriter/bool_rewriter.h"
|
||||
#include "ast/rewriter/bool_rewriter_params.hpp"
|
||||
#include "ast/rewriter/rewriter_def.h"
|
||||
|
||||
void bool_rewriter::updt_params(params_ref const & _p) {
|
||||
bool_rewriter_params p(_p);
|
||||
|
@ -629,61 +629,23 @@ br_status bool_rewriter::try_ite_value(app * ite, app * val, expr_ref & result)
|
|||
return BR_REWRITE2;
|
||||
}
|
||||
}
|
||||
expr* cond2, *t2, *e2;
|
||||
if (m().is_ite(t, cond2, t2, e2) && m().is_value(t2) && m().is_value(e2)) {
|
||||
try_ite_value(to_app(t), val, result);
|
||||
result = m().mk_ite(cond, result, m().mk_eq(e, val));
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
if (m().is_ite(e, cond2, t2, e2) && m().is_value(t2) && m().is_value(e2)) {
|
||||
try_ite_value(to_app(e), val, result);
|
||||
result = m().mk_ite(cond, m().mk_eq(t, val), result);
|
||||
return BR_REWRITE2;
|
||||
{
|
||||
expr* cond2, *t2, *e2;
|
||||
if (m().is_ite(t, cond2, t2, e2) && m().is_value(t2) && m().is_value(e2)) {
|
||||
try_ite_value(to_app(t), val, result);
|
||||
result = m().mk_ite(cond, result, m().mk_eq(e, val));
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
if (m().is_ite(e, cond2, t2, e2) && m().is_value(t2) && m().is_value(e2)) {
|
||||
try_ite_value(to_app(e), val, result);
|
||||
result = m().mk_ite(cond, m().mk_eq(t, val), result);
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
}
|
||||
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
#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 (m().are_equal(lhs, rhs)) {
|
||||
|
@ -697,26 +659,20 @@ br_status bool_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) {
|
|||
}
|
||||
|
||||
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";);
|
||||
tout << mk_bounded_pp(lhs, m()) << "\n" << mk_bounded_pp(rhs, m()) << "\n--->\n" << mk_bounded_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";);
|
||||
tout << mk_bounded_pp(lhs, m()) << "\n" << mk_bounded_pp(rhs, m()) << "\n--->\n" << mk_bounded_pp(result, m()) << "\n";);
|
||||
}
|
||||
if (r != BR_FAILED)
|
||||
return r;
|
||||
|
||||
|
||||
if (m().is_bool(lhs)) {
|
||||
bool unfolded = false;
|
||||
|
|
|
@ -19,9 +19,9 @@ Notes:
|
|||
#ifndef BOOL_REWRITER_H_
|
||||
#define BOOL_REWRITER_H_
|
||||
|
||||
#include"ast.h"
|
||||
#include"rewriter.h"
|
||||
#include"params.h"
|
||||
#include "ast/ast.h"
|
||||
#include "ast/rewriter/rewriter.h"
|
||||
#include "util/params.h"
|
||||
|
||||
/**
|
||||
\brief Apply basic Boolean rewriting operations.
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
|
||||
Revision History:
|
||||
--*/
|
||||
#include"bv_bounds.h"
|
||||
#include"ast_smt2_pp.h"
|
||||
#include "ast/rewriter/bv_bounds.h"
|
||||
#include "ast/ast_smt2_pp.h"
|
||||
|
||||
bv_bounds::~bv_bounds() {
|
||||
reset();
|
||||
|
|
|
@ -19,9 +19,9 @@
|
|||
--*/
|
||||
#ifndef BV_BOUNDS_H_23754
|
||||
#define BV_BOUNDS_H_23754
|
||||
#include"ast.h"
|
||||
#include"bv_decl_plugin.h"
|
||||
#include"rewriter_types.h"
|
||||
#include "ast/ast.h"
|
||||
#include "ast/bv_decl_plugin.h"
|
||||
#include "ast/rewriter/rewriter_types.h"
|
||||
|
||||
/* \brief A class to analyze constraints on bit vectors.
|
||||
|
||||
|
|
115
src/ast/rewriter/bv_elim.cpp
Normal file
115
src/ast/rewriter/bv_elim.cpp
Normal file
|
@ -0,0 +1,115 @@
|
|||
|
||||
/*++
|
||||
Copyright (c) 2015 Microsoft Corporation
|
||||
|
||||
--*/
|
||||
|
||||
#include "ast/rewriter/bv_elim.h"
|
||||
#include "ast/bv_decl_plugin.h"
|
||||
#include "ast/rewriter/var_subst.h"
|
||||
#include "ast/rewriter/rewriter_def.h"
|
||||
#include <sstream>
|
||||
|
||||
bool bv_elim_cfg::reduce_quantifier(quantifier * q,
|
||||
expr * body,
|
||||
expr * const * new_patterns,
|
||||
expr * const * new_no_patterns,
|
||||
expr_ref & result,
|
||||
proof_ref & result_pr) {
|
||||
|
||||
|
||||
svector<symbol> names, _names;
|
||||
sort_ref_buffer sorts(m), _sorts(m);
|
||||
expr_ref_buffer pats(m);
|
||||
expr_ref_buffer no_pats(m);
|
||||
expr_ref_buffer subst_map(m), _subst_map(m);
|
||||
var_subst subst(m);
|
||||
bv_util bv(m);
|
||||
expr_ref new_body(m);
|
||||
expr* old_body = body;
|
||||
unsigned num_decls = q->get_num_decls();
|
||||
family_id bfid = m.mk_family_id("bv");
|
||||
|
||||
//
|
||||
// Traverse sequence of bound variables to eliminate
|
||||
// bit-vecctor variables and replace them by
|
||||
// Booleans.
|
||||
//
|
||||
unsigned var_idx = 0;
|
||||
bool found = false;
|
||||
for (unsigned i = num_decls; i > 0; ) {
|
||||
--i;
|
||||
sort* s = q->get_decl_sort(i);
|
||||
symbol nm = q->get_decl_name(i);
|
||||
|
||||
if (bv.is_bv_sort(s)) {
|
||||
// convert n-bit bit-vector variable into sequence of n-Booleans.
|
||||
unsigned num_bits = bv.get_bv_size(s);
|
||||
expr_ref_buffer args(m);
|
||||
expr_ref bv(m);
|
||||
found = true;
|
||||
for (unsigned j = 0; j < num_bits; ++j) {
|
||||
std::ostringstream new_name;
|
||||
new_name << nm.str();
|
||||
new_name << "_";
|
||||
new_name << j;
|
||||
var* v = m.mk_var(var_idx++, m.mk_bool_sort());
|
||||
args.push_back(v);
|
||||
_sorts.push_back(m.mk_bool_sort());
|
||||
_names.push_back(symbol(new_name.str().c_str()));
|
||||
}
|
||||
bv = m.mk_app(bfid, OP_MKBV, 0, 0, args.size(), args.c_ptr());
|
||||
_subst_map.push_back(bv.get());
|
||||
}
|
||||
else {
|
||||
_subst_map.push_back(m.mk_var(var_idx++, s));
|
||||
_sorts.push_back(s);
|
||||
_names.push_back(nm);
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
return false;
|
||||
}
|
||||
//
|
||||
// reverse the vectors.
|
||||
//
|
||||
SASSERT(_names.size() == _sorts.size());
|
||||
for (unsigned i = _names.size(); i > 0; ) {
|
||||
--i;
|
||||
names.push_back(_names[i]);
|
||||
sorts.push_back(_sorts[i]);
|
||||
}
|
||||
for (unsigned i = _subst_map.size(); i > 0; ) {
|
||||
--i;
|
||||
subst_map.push_back(_subst_map[i]);
|
||||
}
|
||||
|
||||
expr* const* sub = subst_map.c_ptr();
|
||||
unsigned sub_size = subst_map.size();
|
||||
|
||||
subst(old_body, sub_size, sub, new_body);
|
||||
|
||||
for (unsigned j = 0; j < q->get_num_patterns(); j++) {
|
||||
expr_ref pat(m);
|
||||
subst(new_patterns[j], sub_size, sub, pat);
|
||||
pats.push_back(pat);
|
||||
}
|
||||
for (unsigned j = 0; j < q->get_num_no_patterns(); j++) {
|
||||
expr_ref nopat(m);
|
||||
subst(new_no_patterns[j], sub_size, sub, nopat);
|
||||
no_pats.push_back(nopat);
|
||||
}
|
||||
|
||||
result = m.mk_quantifier(true,
|
||||
names.size(),
|
||||
sorts.c_ptr(),
|
||||
names.c_ptr(),
|
||||
new_body.get(),
|
||||
q->get_weight(),
|
||||
q->get_qid(),
|
||||
q->get_skid(),
|
||||
pats.size(), pats.c_ptr(),
|
||||
no_pats.size(), no_pats.c_ptr());
|
||||
result_pr = m.mk_rewrite(q, result);
|
||||
return true;
|
||||
}
|
50
src/ast/rewriter/bv_elim.h
Normal file
50
src/ast/rewriter/bv_elim.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
bv_elim.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Eliminate bit-vectors variables from clauses, by
|
||||
replacing them by bound Boolean variables.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2008-12-16.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef BV_ELIM_H_
|
||||
#define BV_ELIM_H_
|
||||
|
||||
#include "ast/ast.h"
|
||||
#include "ast/rewriter/rewriter.h"
|
||||
|
||||
class bv_elim_cfg : public default_rewriter_cfg {
|
||||
ast_manager& m;
|
||||
public:
|
||||
bv_elim_cfg(ast_manager& m) : m(m) {}
|
||||
|
||||
bool reduce_quantifier(quantifier * old_q,
|
||||
expr * new_body,
|
||||
expr * const * new_patterns,
|
||||
expr * const * new_no_patterns,
|
||||
expr_ref & result,
|
||||
proof_ref & result_pr);
|
||||
};
|
||||
|
||||
class bv_elim_rw : public rewriter_tpl<bv_elim_cfg> {
|
||||
protected:
|
||||
bv_elim_cfg m_cfg;
|
||||
public:
|
||||
bv_elim_rw(ast_manager & m):
|
||||
rewriter_tpl<bv_elim_cfg>(m, m.proofs_enabled(), m_cfg),
|
||||
m_cfg(m)
|
||||
{}
|
||||
};
|
||||
|
||||
#endif /* BV_ELIM_H_ */
|
||||
|
|
@ -16,10 +16,11 @@ Author:
|
|||
Notes:
|
||||
|
||||
--*/
|
||||
#include"bv_rewriter.h"
|
||||
#include"bv_rewriter_params.hpp"
|
||||
#include"poly_rewriter_def.h"
|
||||
#include"ast_smt2_pp.h"
|
||||
#include "ast/rewriter/bv_rewriter.h"
|
||||
#include "ast/rewriter/bv_rewriter_params.hpp"
|
||||
#include "ast/rewriter/poly_rewriter_def.h"
|
||||
#include "ast/ast_smt2_pp.h"
|
||||
#include "ast/ast_lt.h"
|
||||
|
||||
|
||||
void bv_rewriter::updt_local_params(params_ref const & _p) {
|
||||
|
@ -1365,13 +1366,88 @@ br_status bv_rewriter::mk_bv2int(expr * arg, expr_ref & result) {
|
|||
result = m_autil.mk_numeral(v, true);
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
// TODO: add other simplifications
|
||||
if (m_util.is_concat(arg)) {
|
||||
if (to_app(arg)->get_num_args() == 0) {
|
||||
result = m_autil.mk_int(0);
|
||||
return BR_DONE;
|
||||
}
|
||||
expr_ref_vector args(m());
|
||||
|
||||
unsigned num_args = to_app(arg)->get_num_args();
|
||||
for (expr* x : *to_app(arg)) {
|
||||
args.push_back(m_util.mk_bv2int(x));
|
||||
}
|
||||
unsigned sz = get_bv_size(to_app(arg)->get_arg(num_args-1));
|
||||
for (unsigned i = num_args - 1; i > 0; ) {
|
||||
expr_ref tmp(m());
|
||||
--i;
|
||||
tmp = args[i].get();
|
||||
tmp = m_autil.mk_mul(m_autil.mk_numeral(power(numeral(2), sz), true), tmp);
|
||||
args[i] = tmp;
|
||||
sz += get_bv_size(to_app(arg)->get_arg(i));
|
||||
}
|
||||
result = m_autil.mk_add(args.size(), args.c_ptr());
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
if (is_mul_no_overflow(arg)) {
|
||||
expr_ref_vector args(m());
|
||||
for (expr* x : *to_app(arg)) args.push_back(m_util.mk_bv2int(x));
|
||||
result = m_autil.mk_mul(args.size(), args.c_ptr());
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
if (is_add_no_overflow(arg)) {
|
||||
expr_ref_vector args(m());
|
||||
for (expr* x : *to_app(arg)) args.push_back(m_util.mk_bv2int(x));
|
||||
result = m_autil.mk_add(args.size(), args.c_ptr());
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
|
||||
bool bv_rewriter::is_mul_no_overflow(expr* e) {
|
||||
if (!m_util.is_bv_mul(e)) return false;
|
||||
unsigned sz = get_bv_size(e);
|
||||
unsigned sum = 0;
|
||||
for (expr* x : *to_app(e)) sum += sz-num_leading_zero_bits(x);
|
||||
return sum < sz;
|
||||
}
|
||||
|
||||
bool bv_rewriter::is_add_no_overflow(expr* e) {
|
||||
if (!is_add(e)) return false;
|
||||
for (expr* x : *to_app(e)) {
|
||||
if (0 == num_leading_zero_bits(x)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned bv_rewriter::num_leading_zero_bits(expr* e) {
|
||||
numeral v;
|
||||
unsigned sz = get_bv_size(e);
|
||||
if (m_util.is_numeral(e, v)) {
|
||||
while (v.is_pos()) {
|
||||
SASSERT(sz > 0);
|
||||
--sz;
|
||||
v = div(v, numeral(2));
|
||||
}
|
||||
return sz;
|
||||
}
|
||||
else if (m_util.is_concat(e)) {
|
||||
app* a = to_app(e);
|
||||
unsigned sz1 = get_bv_size(a->get_arg(0));
|
||||
unsigned nb1 = num_leading_zero_bits(a->get_arg(0));
|
||||
if (sz1 == nb1) {
|
||||
nb1 += num_leading_zero_bits(a->get_arg(1));
|
||||
}
|
||||
return nb1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
br_status bv_rewriter::mk_concat(unsigned num_args, expr * const * args, expr_ref & result) {
|
||||
expr_ref_buffer new_args(m());
|
||||
numeral v1;
|
||||
|
@ -2314,7 +2390,7 @@ void bv_rewriter::mk_t1_add_t2_eq_c(expr * t1, expr * t2, expr * c, expr_ref & r
|
|||
result = m().mk_eq(t1, m_util.mk_bv_sub(c, t2));
|
||||
}
|
||||
|
||||
#include "ast_pp.h"
|
||||
#include "ast/ast_pp.h"
|
||||
|
||||
bool bv_rewriter::isolate_term(expr* lhs, expr* rhs, expr_ref& result) {
|
||||
if (!m_util.is_numeral(lhs) || !is_add(rhs)) {
|
||||
|
|
|
@ -19,11 +19,11 @@ Notes:
|
|||
#ifndef BV_REWRITER_H_
|
||||
#define BV_REWRITER_H_
|
||||
|
||||
#include"poly_rewriter.h"
|
||||
#include"bv_decl_plugin.h"
|
||||
#include"arith_decl_plugin.h"
|
||||
#include"mk_extract_proc.h"
|
||||
#include"bv_trailing.h"
|
||||
#include "ast/rewriter/poly_rewriter.h"
|
||||
#include "ast/bv_decl_plugin.h"
|
||||
#include "ast/arith_decl_plugin.h"
|
||||
#include "ast/rewriter/mk_extract_proc.h"
|
||||
#include "ast/rewriter/bv_trailing.h"
|
||||
|
||||
class bv_rewriter_core {
|
||||
protected:
|
||||
|
@ -42,6 +42,7 @@ protected:
|
|||
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) {}
|
||||
};
|
||||
|
@ -98,17 +99,20 @@ class bv_rewriter : public poly_rewriter<bv_rewriter_core> {
|
|||
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(expr* a, expr* b, expr_ref& result) { expr* args[2] = { a, b }; return mk_bv_add(2, args, result); }
|
||||
br_status mk_bv_sub(expr* a, expr* b, expr_ref& result) { expr* args[2] = { a, b }; return mk_sub(2, args, result); }
|
||||
br_status mk_bv_mul(expr* a, expr* b, expr_ref& result) { expr* args[2] = { a, b }; return mk_bv_mul(2, args, 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);
|
||||
bool is_add_no_overflow(expr* e);
|
||||
bool is_mul_no_overflow(expr* e);
|
||||
unsigned num_leading_zero_bits(expr* e);
|
||||
|
||||
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);
|
||||
|
@ -185,6 +189,38 @@ public:
|
|||
bool hi_div0() const { return m_hi_div0; }
|
||||
|
||||
bv_util & get_util() { return m_util; }
|
||||
|
||||
#define MK_BV_BINARY(OP) \
|
||||
expr_ref OP(expr* a, expr* b) { \
|
||||
expr_ref result(m()); \
|
||||
if (BR_FAILED == OP(a, b, result)) \
|
||||
result = m_util.OP(a, b); \
|
||||
return result; \
|
||||
} \
|
||||
|
||||
expr_ref mk_zero_extend(unsigned n, expr * arg) {
|
||||
expr_ref result(m());
|
||||
if (BR_FAILED == mk_zero_extend(n, arg, result))
|
||||
result = m_util.mk_zero_extend(n, arg);
|
||||
return result;
|
||||
}
|
||||
|
||||
MK_BV_BINARY(mk_bv_urem);
|
||||
MK_BV_BINARY(mk_ule);
|
||||
MK_BV_BINARY(mk_bv_add);
|
||||
MK_BV_BINARY(mk_bv_mul);
|
||||
MK_BV_BINARY(mk_bv_sub);
|
||||
|
||||
|
||||
expr_ref mk_bv2int(expr* a) {
|
||||
expr_ref result(m());
|
||||
if (BR_FAILED == mk_bv2int(a, result))
|
||||
result = m_util.mk_bv2int(a);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
|
||||
Revision History:
|
||||
--*/
|
||||
#include"bv_trailing.h"
|
||||
#include"bv_decl_plugin.h"
|
||||
#include"ast_smt2_pp.h"
|
||||
#include "ast/rewriter/bv_trailing.h"
|
||||
#include "ast/bv_decl_plugin.h"
|
||||
#include "ast/ast_smt2_pp.h"
|
||||
|
||||
// The analyzer gives up analysis after going TRAILING_DEPTH deep.
|
||||
// This number shouldn't be too big.
|
||||
|
|
|
@ -18,9 +18,9 @@
|
|||
--*/
|
||||
#ifndef BV_TRAILING_H_
|
||||
#define BV_TRAILING_H_
|
||||
#include"ast.h"
|
||||
#include"rewriter_types.h"
|
||||
#include"mk_extract_proc.h"
|
||||
#include "ast/ast.h"
|
||||
#include "ast/rewriter/rewriter_types.h"
|
||||
#include "ast/rewriter/mk_extract_proc.h"
|
||||
class bv_trailing {
|
||||
public:
|
||||
bv_trailing(mk_extract_proc& ep);
|
||||
|
|
|
@ -16,13 +16,14 @@ Author:
|
|||
Notes:
|
||||
|
||||
--*/
|
||||
#include"datatype_rewriter.h"
|
||||
#include "ast/rewriter/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:
|
||||
case OP_DT_IS:
|
||||
//
|
||||
// simplify is_cons(cons(x,y)) -> true
|
||||
// simplify is_cons(nil) -> false
|
||||
|
@ -47,11 +48,11 @@ br_status datatype_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr
|
|||
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();
|
||||
ptr_vector<func_decl> const & acc = *m_util.get_constructor_accessors(c_decl);
|
||||
SASSERT(acc.size() == a->get_num_args());
|
||||
unsigned num = acc.size();
|
||||
for (unsigned i = 0; i < num; ++i) {
|
||||
if (f == (*acc)[i]) {
|
||||
if (f == acc[i]) {
|
||||
// found it.
|
||||
result = a->get_arg(i);
|
||||
return BR_DONE;
|
||||
|
@ -70,13 +71,13 @@ br_status datatype_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr
|
|||
result = a;
|
||||
return BR_DONE;
|
||||
}
|
||||
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();
|
||||
ptr_vector<func_decl> const & acc = *m_util.get_constructor_accessors(c_decl);
|
||||
SASSERT(acc.size() == a->get_num_args());
|
||||
unsigned num = acc.size();
|
||||
ptr_buffer<expr> new_args;
|
||||
for (unsigned i = 0; i < num; ++i) {
|
||||
|
||||
if (f == (*acc)[i]) {
|
||||
if (f == acc[i]) {
|
||||
new_args.push_back(args[1]);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -19,8 +19,8 @@ Notes:
|
|||
#ifndef DATATYPE_REWRITER_H_
|
||||
#define DATATYPE_REWRITER_H_
|
||||
|
||||
#include"datatype_decl_plugin.h"
|
||||
#include"rewriter_types.h"
|
||||
#include "ast/datatype_decl_plugin.h"
|
||||
#include "ast/rewriter/rewriter_types.h"
|
||||
|
||||
class datatype_rewriter {
|
||||
datatype_util m_util;
|
||||
|
|
|
@ -18,13 +18,13 @@ Revision History:
|
|||
Christoph Wintersteiger, 2010-03-30: Added Destr. Multi-Equality Resolution
|
||||
|
||||
--*/
|
||||
#include"der.h"
|
||||
#include"occurs.h"
|
||||
#include"for_each_expr.h"
|
||||
#include"rewriter_def.h"
|
||||
#include"ast_pp.h"
|
||||
#include"ast_ll_pp.h"
|
||||
#include"ast_smt2_pp.h"
|
||||
#include "ast/rewriter/der.h"
|
||||
#include "ast/occurs.h"
|
||||
#include "ast/for_each_expr.h"
|
||||
#include "ast/rewriter/rewriter_def.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "ast/ast_ll_pp.h"
|
||||
#include "ast/ast_smt2_pp.h"
|
||||
|
||||
static bool is_var(expr * e, unsigned num_decls) {
|
||||
return is_var(e) && to_var(e)->get_idx() < num_decls;
|
||||
|
|
|
@ -21,8 +21,8 @@ Revision History:
|
|||
#ifndef DER_H_
|
||||
#define DER_H_
|
||||
|
||||
#include"ast.h"
|
||||
#include"var_subst.h"
|
||||
#include "ast/ast.h"
|
||||
#include "ast/rewriter/var_subst.h"
|
||||
|
||||
/*
|
||||
New DER: the class DER (above) eliminates variables one by one.
|
||||
|
|
|
@ -18,11 +18,11 @@ Revision History:
|
|||
Christoph Wintersteiger 2010-04-06: Added implementation.
|
||||
|
||||
--*/
|
||||
#include"var_subst.h"
|
||||
#include"ast_ll_pp.h"
|
||||
#include"ast_util.h"
|
||||
#include"distribute_forall.h"
|
||||
#include"bool_rewriter.h"
|
||||
#include "ast/rewriter/var_subst.h"
|
||||
#include "ast/ast_ll_pp.h"
|
||||
#include "ast/ast_util.h"
|
||||
#include "ast/rewriter/distribute_forall.h"
|
||||
#include "ast/rewriter/bool_rewriter.h"
|
||||
|
||||
distribute_forall::distribute_forall(ast_manager & m) :
|
||||
m_manager(m),
|
||||
|
|
|
@ -21,8 +21,8 @@ Revision History:
|
|||
#ifndef DISTRIBUTE_FORALL_H_
|
||||
#define DISTRIBUTE_FORALL_H_
|
||||
|
||||
#include"ast.h"
|
||||
#include"act_cache.h"
|
||||
#include "ast/ast.h"
|
||||
#include "ast/act_cache.h"
|
||||
|
||||
/**
|
||||
\brief Apply the following transformation
|
||||
|
|
|
@ -17,7 +17,7 @@ Revision History:
|
|||
|
||||
--*/
|
||||
|
||||
#include"dl_rewriter.h"
|
||||
#include "ast/rewriter/dl_rewriter.h"
|
||||
|
||||
br_status dl_rewriter::mk_app_core(
|
||||
func_decl * f, unsigned num_args, expr* const* args, expr_ref& result) {
|
||||
|
|
|
@ -19,8 +19,8 @@ Notes:
|
|||
#ifndef DL_REWRITER_H_
|
||||
#define DL_REWRITER_H_
|
||||
|
||||
#include"dl_decl_plugin.h"
|
||||
#include"rewriter_types.h"
|
||||
#include "ast/dl_decl_plugin.h"
|
||||
#include "ast/rewriter/rewriter_types.h"
|
||||
|
||||
class dl_rewriter {
|
||||
datalog::dl_decl_util m_util;
|
||||
|
|
203
src/ast/rewriter/elim_bounds.cpp
Normal file
203
src/ast/rewriter/elim_bounds.cpp
Normal file
|
@ -0,0 +1,203 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
elim_bounds.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-06-28.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef ELIM_BOUNDS_H_
|
||||
#define ELIM_BOUNDS_H_
|
||||
|
||||
#include "ast/used_vars.h"
|
||||
#include "util/obj_hashtable.h"
|
||||
#include "ast/rewriter/var_subst.h"
|
||||
#include "ast/rewriter/elim_bounds.h"
|
||||
#include "ast/ast_pp.h"
|
||||
|
||||
elim_bounds_cfg::elim_bounds_cfg(ast_manager & m):
|
||||
m(m),
|
||||
m_util(m) {
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Find bounds of the form
|
||||
|
||||
(<= x k)
|
||||
(<= (+ x (* -1 y)) k)
|
||||
(<= (+ x (* -1 t)) k)
|
||||
(<= (+ t (* -1 x)) k)
|
||||
|
||||
x and y are a bound variables, t is a ground term and k is a numeral
|
||||
|
||||
It also detects >=, and the atom can be negated.
|
||||
*/
|
||||
bool elim_bounds_cfg::is_bound(expr * n, var * & lower, var * & upper) {
|
||||
upper = 0;
|
||||
lower = 0;
|
||||
bool neg = false;
|
||||
if (m.is_not(n)) {
|
||||
n = to_app(n)->get_arg(0);
|
||||
neg = true;
|
||||
}
|
||||
|
||||
expr* l = 0, *r = 0;
|
||||
bool le = false;
|
||||
if (m_util.is_le(n, l, r) && m_util.is_numeral(r)) {
|
||||
n = l;
|
||||
le = true;
|
||||
}
|
||||
else if (m_util.is_ge(n, l, r) && m_util.is_numeral(r)) {
|
||||
n = l;
|
||||
le = false;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (neg)
|
||||
le = !le;
|
||||
|
||||
if (is_var(n)) {
|
||||
upper = to_var(n);
|
||||
}
|
||||
else if (m_util.is_add(n, l, r)) {
|
||||
expr * arg1 = l;
|
||||
expr * arg2 = r;
|
||||
if (is_var(arg1))
|
||||
upper = to_var(arg1);
|
||||
else if (!is_ground(arg1))
|
||||
return false;
|
||||
rational k;
|
||||
bool is_int;
|
||||
if (m_util.is_mul(arg2) && m_util.is_numeral(to_app(arg2)->get_arg(0), k, is_int) && k.is_minus_one()) {
|
||||
arg2 = to_app(arg2)->get_arg(1);
|
||||
if (is_var(arg2))
|
||||
lower = to_var(arg2);
|
||||
else if (!is_ground(arg2))
|
||||
return false; // not supported
|
||||
}
|
||||
else {
|
||||
return false; // not supported
|
||||
}
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!le)
|
||||
std::swap(upper, lower);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool elim_bounds_cfg::is_bound(expr * n) {
|
||||
var * lower, * upper;
|
||||
return is_bound(n, lower, upper);
|
||||
}
|
||||
|
||||
|
||||
bool elim_bounds_cfg::reduce_quantifier(quantifier * q,
|
||||
expr * n,
|
||||
expr * const * new_patterns,
|
||||
expr * const * new_no_patterns,
|
||||
expr_ref & result,
|
||||
proof_ref & result_pr) {
|
||||
if (!q->is_forall()) {
|
||||
return false;
|
||||
}
|
||||
unsigned num_vars = q->get_num_decls();
|
||||
ptr_buffer<expr> atoms;
|
||||
if (m.is_or(n))
|
||||
atoms.append(to_app(n)->get_num_args(), to_app(n)->get_args());
|
||||
else
|
||||
atoms.push_back(n);
|
||||
used_vars used_vars;
|
||||
// collect non-candidates
|
||||
for (expr * a : atoms) {
|
||||
if (!is_bound(a))
|
||||
used_vars.process(a);
|
||||
}
|
||||
if (used_vars.uses_all_vars(q->get_num_decls())) {
|
||||
return false;
|
||||
}
|
||||
// collect candidates
|
||||
obj_hashtable<var> lowers;
|
||||
obj_hashtable<var> uppers;
|
||||
obj_hashtable<var> candidate_set;
|
||||
ptr_buffer<var> candidates;
|
||||
#define ADD_CANDIDATE(V) if (!lowers.contains(V) && !uppers.contains(V)) { candidate_set.insert(V); candidates.push_back(V); }
|
||||
for (expr * a : atoms) {
|
||||
var * lower = 0;
|
||||
var * upper = 0;
|
||||
if (is_bound(a, lower, upper)) {
|
||||
if (lower != 0 && !used_vars.contains(lower->get_idx()) && lower->get_idx() < num_vars) {
|
||||
ADD_CANDIDATE(lower);
|
||||
lowers.insert(lower);
|
||||
}
|
||||
if (upper != 0 && !used_vars.contains(upper->get_idx()) && upper->get_idx() < num_vars) {
|
||||
ADD_CANDIDATE(upper);
|
||||
uppers.insert(upper);
|
||||
}
|
||||
}
|
||||
}
|
||||
TRACE("elim_bounds", tout << "candidates:\n"; for (unsigned i = 0; i < candidates.size(); i++) tout << mk_pp(candidates[i], m) << "\n";);
|
||||
// remove candidates that have lower and upper bounds
|
||||
|
||||
for (var * v : candidates) {
|
||||
if (lowers.contains(v) && uppers.contains(v))
|
||||
candidate_set.erase(v);
|
||||
}
|
||||
TRACE("elim_bounds", tout << "candidates after filter:\n"; for (unsigned i = 0; i < candidates.size(); i++) tout << mk_pp(candidates[i], m) << "\n";);
|
||||
if (candidate_set.empty()) {
|
||||
return false;
|
||||
}
|
||||
// remove bounds that contain variables in candidate_set
|
||||
unsigned j = 0;
|
||||
for (unsigned i = 0; i < atoms.size(); ++i) {
|
||||
expr * a = atoms[i];
|
||||
var * lower = 0;
|
||||
var * upper = 0;
|
||||
if (is_bound(a, lower, upper) && ((lower != 0 && candidate_set.contains(lower)) || (upper != 0 && candidate_set.contains(upper))))
|
||||
continue;
|
||||
atoms[j] = a;
|
||||
j++;
|
||||
}
|
||||
if (j == atoms.size()) {
|
||||
return false;
|
||||
}
|
||||
atoms.resize(j);
|
||||
expr * new_body = 0;
|
||||
switch (atoms.size()) {
|
||||
case 0:
|
||||
result = m.mk_false();
|
||||
result_pr = m.mk_rewrite(q, result);
|
||||
TRACE("elim_bounds", tout << mk_pp(q, m) << "\n" << result << "\n";);
|
||||
return true;
|
||||
case 1:
|
||||
new_body = atoms[0];
|
||||
break;
|
||||
default:
|
||||
new_body = m.mk_or(atoms.size(), atoms.c_ptr());
|
||||
break;
|
||||
}
|
||||
quantifier_ref new_q(m);
|
||||
new_q = m.update_quantifier(q, new_body);
|
||||
elim_unused_vars(m, new_q, params_ref(), result);
|
||||
result_pr = m.mk_rewrite(q, result);
|
||||
TRACE("elim_bounds", tout << mk_pp(q, m) << "\n" << result << "\n";);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* ELIM_BOUNDS_H_ */
|
77
src/ast/rewriter/elim_bounds.h
Normal file
77
src/ast/rewriter/elim_bounds.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
elim_bounds2.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-06-28.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef ELIM_BOUNDS2_H_
|
||||
#define ELIM_BOUNDS2_H_
|
||||
|
||||
#include "ast/ast.h"
|
||||
#include "ast/arith_decl_plugin.h"
|
||||
#include "ast/rewriter/rewriter.h"
|
||||
|
||||
/**
|
||||
\brief Functor for eliminating irrelevant bounds in quantified formulas.
|
||||
|
||||
Example:
|
||||
(forall (x Int) (y Int) (or (not (>= y x) (not (>= x 0)) (= (select a x) 1))))
|
||||
|
||||
The bound (>= y x) is irrelevant and can be eliminated.
|
||||
|
||||
This can be easily proved by using Fourier-Motzkin elimination.
|
||||
|
||||
Limitations & Assumptions:
|
||||
- It assumes the input formula was already simplified.
|
||||
- It can only handle bounds in the diff-logic fragment.
|
||||
|
||||
\remark This operation is subsumed by Fourier-Motzkin elimination.
|
||||
*/
|
||||
class elim_bounds_cfg : public default_rewriter_cfg {
|
||||
ast_manager & m;
|
||||
arith_util m_util;
|
||||
bool is_bound(expr * n, var * & lower, var * & upper);
|
||||
bool is_bound(expr * n);
|
||||
public:
|
||||
elim_bounds_cfg(ast_manager & m);
|
||||
|
||||
bool reduce_quantifier(quantifier * old_q,
|
||||
expr * new_body,
|
||||
expr * const * new_patterns,
|
||||
expr * const * new_no_patterns,
|
||||
expr_ref & result,
|
||||
proof_ref & result_pr);
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Functor for applying elim_bounds2 in all
|
||||
universal quantifiers in an expression.
|
||||
|
||||
Assumption: the formula was already skolemized.
|
||||
*/
|
||||
class elim_bounds_rw : public rewriter_tpl<elim_bounds_cfg> {
|
||||
protected:
|
||||
elim_bounds_cfg m_cfg;
|
||||
public:
|
||||
elim_bounds_rw(ast_manager & m):
|
||||
rewriter_tpl<elim_bounds_cfg>(m, m.proofs_enabled(), m_cfg),
|
||||
m_cfg(m)
|
||||
{}
|
||||
|
||||
virtual ~elim_bounds_rw() {}
|
||||
};
|
||||
|
||||
#endif /* ELIM_BOUNDS2_H_ */
|
||||
|
|
@ -17,11 +17,11 @@ Notes:
|
|||
|
||||
--*/
|
||||
|
||||
#include"rewriter.h"
|
||||
#include"rewriter_def.h"
|
||||
#include"enum2bv_rewriter.h"
|
||||
#include"ast_util.h"
|
||||
#include"ast_pp.h"
|
||||
#include "ast/rewriter/rewriter.h"
|
||||
#include "ast/rewriter/rewriter_def.h"
|
||||
#include "ast/rewriter/enum2bv_rewriter.h"
|
||||
#include "ast/ast_util.h"
|
||||
#include "ast/ast_pp.h"
|
||||
|
||||
struct enum2bv_rewriter::imp {
|
||||
ast_manager& m;
|
||||
|
|
|
@ -19,9 +19,9 @@ Notes:
|
|||
#ifndef ENUM_REWRITER_H_
|
||||
#define ENUM_REWRITER_H_
|
||||
|
||||
#include"datatype_decl_plugin.h"
|
||||
#include"rewriter_types.h"
|
||||
#include"expr_functors.h"
|
||||
#include "ast/datatype_decl_plugin.h"
|
||||
#include "ast/rewriter/rewriter_types.h"
|
||||
#include "ast/expr_functors.h"
|
||||
|
||||
class enum2bv_rewriter {
|
||||
struct imp;
|
||||
|
|
|
@ -16,10 +16,10 @@ Author:
|
|||
Notes:
|
||||
|
||||
--*/
|
||||
#include"expr_replacer.h"
|
||||
#include"rewriter_def.h"
|
||||
#include"th_rewriter.h"
|
||||
#include"cooperate.h"
|
||||
#include "ast/rewriter/expr_replacer.h"
|
||||
#include "ast/rewriter/rewriter_def.h"
|
||||
#include "ast/rewriter/th_rewriter.h"
|
||||
#include "util/cooperate.h"
|
||||
|
||||
void expr_replacer::operator()(expr * t, expr_ref & result, proof_ref & result_pr) {
|
||||
expr_dependency_ref result_dep(m());
|
||||
|
|
|
@ -19,9 +19,9 @@ Notes:
|
|||
#ifndef EXPR_REPLACER_H_
|
||||
#define EXPR_REPLACER_H_
|
||||
|
||||
#include"ast.h"
|
||||
#include"expr_substitution.h"
|
||||
#include"params.h"
|
||||
#include "ast/ast.h"
|
||||
#include "ast/expr_substitution.h"
|
||||
#include "util/params.h"
|
||||
|
||||
/**
|
||||
\brief Abstract interface for functors that replace constants with expressions.
|
||||
|
|
|
@ -18,9 +18,9 @@ Revision History:
|
|||
|
||||
--*/
|
||||
|
||||
#include "expr_safe_replace.h"
|
||||
#include "rewriter.h"
|
||||
#include "ast_pp.h"
|
||||
#include "ast/rewriter/expr_safe_replace.h"
|
||||
#include "ast/rewriter/rewriter.h"
|
||||
#include "ast/ast_pp.h"
|
||||
|
||||
|
||||
void expr_safe_replace::insert(expr* src, expr* dst) {
|
||||
|
|
|
@ -22,7 +22,7 @@ Revision History:
|
|||
#ifndef EXPR_SAFE_REPLACE_H_
|
||||
#define EXPR_SAFE_REPLACE_H_
|
||||
|
||||
#include "ast.h"
|
||||
#include "ast/ast.h"
|
||||
|
||||
class expr_safe_replace {
|
||||
ast_manager& m;
|
||||
|
|
|
@ -18,9 +18,9 @@ Notes:
|
|||
|
||||
--*/
|
||||
|
||||
#include"factor_rewriter.h"
|
||||
#include"ast_pp.h"
|
||||
#include"rewriter_def.h"
|
||||
#include "ast/rewriter/factor_rewriter.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "ast/rewriter/rewriter_def.h"
|
||||
|
||||
factor_rewriter::factor_rewriter(ast_manager & m): m_manager(m), m_arith(m), m_factors(m) {
|
||||
}
|
||||
|
|
|
@ -20,9 +20,9 @@ Notes:
|
|||
#ifndef FACTOR_REWRITER_H_
|
||||
#define FACTOR_REWRITER_H_
|
||||
|
||||
#include"ast.h"
|
||||
#include"rewriter.h"
|
||||
#include"arith_decl_plugin.h"
|
||||
#include "ast/ast.h"
|
||||
#include "ast/rewriter/rewriter.h"
|
||||
#include "ast/arith_decl_plugin.h"
|
||||
|
||||
class factor_rewriter {
|
||||
typedef obj_map<expr,unsigned> powers_t;
|
||||
|
|
|
@ -16,9 +16,9 @@ Author:
|
|||
Notes:
|
||||
|
||||
--*/
|
||||
#include"fpa_rewriter.h"
|
||||
#include"fpa_rewriter_params.hpp"
|
||||
#include"ast_smt2_pp.h"
|
||||
#include "ast/rewriter/fpa_rewriter.h"
|
||||
#include "ast/rewriter/fpa_rewriter_params.hpp"
|
||||
#include "ast/ast_smt2_pp.h"
|
||||
|
||||
fpa_rewriter::fpa_rewriter(ast_manager & m, params_ref const & p) :
|
||||
m_util(m),
|
||||
|
|
|
@ -19,11 +19,11 @@ Notes:
|
|||
#ifndef FLOAT_REWRITER_H_
|
||||
#define FLOAT_REWRITER_H_
|
||||
|
||||
#include"ast.h"
|
||||
#include"rewriter.h"
|
||||
#include"params.h"
|
||||
#include"fpa_decl_plugin.h"
|
||||
#include"mpf.h"
|
||||
#include "ast/ast.h"
|
||||
#include "ast/rewriter/rewriter.h"
|
||||
#include "util/params.h"
|
||||
#include "ast/fpa_decl_plugin.h"
|
||||
#include "util/mpf.h"
|
||||
|
||||
class fpa_rewriter {
|
||||
fpa_util m_util;
|
||||
|
|
139
src/ast/rewriter/inj_axiom.cpp
Normal file
139
src/ast/rewriter/inj_axiom.cpp
Normal file
|
@ -0,0 +1,139 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
inj_axiom.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-06-23.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include "ast/rewriter/inj_axiom.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "ast/ast_ll_pp.h"
|
||||
#include "ast/has_free_vars.h"
|
||||
#include "ast/well_sorted.h"
|
||||
|
||||
/**
|
||||
\brief Little HACK for simplifying injectivity axioms
|
||||
|
||||
\remark It is not covering all possible cases.
|
||||
*/
|
||||
bool simplify_inj_axiom(ast_manager & m, quantifier * q, expr_ref & result) {
|
||||
expr * n = q->get_expr();
|
||||
expr* arg1 = 0, * arg2 = 0, *narg = 0;
|
||||
expr* app1 = 0, * app2 = 0;
|
||||
expr* var1 = 0, * var2 = 0;
|
||||
if (q->is_forall() && m.is_or(n, arg1, arg2)) {
|
||||
if (m.is_not(arg2))
|
||||
std::swap(arg1, arg2);
|
||||
if (m.is_not(arg1, narg) &&
|
||||
m.is_eq(narg, app1, app2) &&
|
||||
m.is_eq(arg2, var1, var2)) {
|
||||
if (is_app(app1) &&
|
||||
is_app(app2) &&
|
||||
to_app(app1)->get_decl() == to_app(app2)->get_decl() &&
|
||||
to_app(app1)->get_num_args() == to_app(app2)->get_num_args() &&
|
||||
to_app(app1)->get_family_id() == null_family_id &&
|
||||
to_app(app1)->get_num_args() > 0 &&
|
||||
is_var(var1) &&
|
||||
is_var(var2) &&
|
||||
var1 != var2) {
|
||||
app * f1 = to_app(app1);
|
||||
app * f2 = to_app(app2);
|
||||
bool found_vars = false;
|
||||
unsigned num = f1->get_num_args();
|
||||
unsigned idx = UINT_MAX;
|
||||
unsigned num_vars = 1;
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
expr * c1 = f1->get_arg(i);
|
||||
expr * c2 = f2->get_arg(i);
|
||||
if (!is_var(c1) && !is_uninterp_const(c1))
|
||||
return false;
|
||||
if ((c1 == var1 && c2 == var2) || (c1 == var2 && c2 == var1)) {
|
||||
if (found_vars)
|
||||
return false;
|
||||
found_vars = true;
|
||||
idx = i;
|
||||
}
|
||||
else if (c1 == c2 && c1 != var1 && c1 != var2) {
|
||||
if (is_var(c1)) {
|
||||
++num_vars;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (found_vars && !has_free_vars(q)) {
|
||||
TRACE("inj_axiom",
|
||||
tout << "Cadidate for simplification:\n" << mk_ll_pp(q, m) << mk_pp(app1, m) << "\n" << mk_pp(app2, m) << "\n" <<
|
||||
mk_pp(var1, m) << "\n" << mk_pp(var2, m) << "\nnum_vars: " << num_vars << "\n";);
|
||||
// Building new (optimized) axiom
|
||||
func_decl * decl = f1->get_decl();
|
||||
unsigned var_idx = 0;
|
||||
ptr_buffer<expr> f_args, inv_vars;
|
||||
ptr_buffer<sort> decls;
|
||||
buffer<symbol> names;
|
||||
|
||||
expr * var = 0;
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
expr * c = f1->get_arg(i);
|
||||
if (is_var(c)) {
|
||||
names.push_back(symbol(i));
|
||||
sort * s = decl->get_domain(i);
|
||||
decls.push_back(s);
|
||||
expr * new_c = m.mk_var(var_idx, s);
|
||||
var_idx++;
|
||||
f_args.push_back(new_c);
|
||||
if (i == idx) {
|
||||
var = new_c;
|
||||
}
|
||||
else {
|
||||
inv_vars.push_back(new_c);
|
||||
}
|
||||
}
|
||||
else {
|
||||
SASSERT(is_uninterp_const(c));
|
||||
f_args.push_back(c);
|
||||
}
|
||||
}
|
||||
SASSERT(var != 0);
|
||||
app * f = m.mk_app(decl, f_args.size(), f_args.c_ptr());
|
||||
|
||||
ptr_vector<sort> domain;
|
||||
inv_vars.push_back(f);
|
||||
for (unsigned i = 0; i < inv_vars.size(); ++i) {
|
||||
domain.push_back(m.get_sort(inv_vars[i]));
|
||||
}
|
||||
sort * d = decl->get_domain(idx);
|
||||
func_decl * inv_decl = m.mk_fresh_func_decl("inj", domain.size(), domain.c_ptr(), d);
|
||||
|
||||
expr * proj = m.mk_app(inv_decl, inv_vars.size(), inv_vars.c_ptr());
|
||||
expr * eq = m.mk_eq(proj, var);
|
||||
expr * p = m.mk_pattern(f);
|
||||
|
||||
// decls are in the wrong order...
|
||||
// Remark: the sort of the var 0 must be in the last position.
|
||||
std::reverse(decls.begin(), decls.end());
|
||||
|
||||
result = m.mk_forall(decls.size(), decls.c_ptr(), names.c_ptr(), eq,
|
||||
0, symbol(), symbol(), 1, &p);
|
||||
TRACE("inj_axiom", tout << "new axiom:\n" << mk_pp(result, m) << "\n";);
|
||||
SASSERT(is_well_sorted(m, result));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
27
src/ast/rewriter/inj_axiom.h
Normal file
27
src/ast/rewriter/inj_axiom.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
inj_axiom.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-06-23.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef INJ_AXIOM_H_
|
||||
#define INJ_AXIOM_H_
|
||||
|
||||
#include "ast/ast.h"
|
||||
|
||||
bool simplify_inj_axiom(ast_manager & m, quantifier * q, expr_ref & result);
|
||||
|
||||
#endif /* INJ_AXIOM_H_ */
|
||||
|
|
@ -17,9 +17,9 @@ Notes:
|
|||
|
||||
--*/
|
||||
|
||||
#include"rewriter.h"
|
||||
#include"rewriter_def.h"
|
||||
#include"label_rewriter.h"
|
||||
#include "ast/rewriter/rewriter.h"
|
||||
#include "ast/rewriter/rewriter_def.h"
|
||||
#include "ast/rewriter/label_rewriter.h"
|
||||
|
||||
|
||||
label_rewriter::label_rewriter(ast_manager & m) :
|
||||
|
|
|
@ -19,8 +19,8 @@ Notes:
|
|||
#ifndef LABEL_REWRITER_H_
|
||||
#define LABEL_REWRITER_H_
|
||||
|
||||
#include"ast.h"
|
||||
#include"rewriter_types.h"
|
||||
#include "ast/ast.h"
|
||||
#include "ast/rewriter/rewriter_types.h"
|
||||
|
||||
|
||||
class label_rewriter : public default_rewriter_cfg {
|
||||
|
|
175
src/ast/rewriter/maximize_ac_sharing.cpp
Normal file
175
src/ast/rewriter/maximize_ac_sharing.cpp
Normal file
|
@ -0,0 +1,175 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
maximize_ac_sharing.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-10-22.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "ast/rewriter/maximize_ac_sharing.h"
|
||||
#include "ast/ast_pp.h"
|
||||
|
||||
|
||||
void maximize_ac_sharing::register_kind(decl_kind k) {
|
||||
m_kinds.push_back(k);
|
||||
}
|
||||
|
||||
|
||||
br_status maximize_ac_sharing::reduce_app(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result, proof_ref& result_pr) {
|
||||
decl_kind k = f->get_kind();
|
||||
if (!f->is_associative())
|
||||
return BR_FAILED;
|
||||
if (num_args <= 2)
|
||||
return BR_FAILED;
|
||||
if (std::find(m_kinds.begin(), m_kinds.end(), k) == m_kinds.end())
|
||||
return BR_FAILED;
|
||||
ptr_buffer<expr, 128> _args;
|
||||
expr * numeral = 0;
|
||||
if (is_numeral(args[0])) {
|
||||
numeral = args[0];
|
||||
for (unsigned i = 1; i < num_args; i++)
|
||||
_args.push_back(args[i]);
|
||||
num_args--;
|
||||
}
|
||||
else {
|
||||
_args.append(num_args, args);
|
||||
}
|
||||
|
||||
TRACE("ac_sharing_detail", tout << "before-reuse: num_args: " << num_args << "\n";);
|
||||
|
||||
#define MAX_NUM_ARGS_FOR_OPT 128
|
||||
|
||||
// Try to reuse already created circuits.
|
||||
TRACE("ac_sharing_detail", tout << "args: "; for (unsigned i = 0; i < num_args; i++) tout << mk_pp(_args[i], m) << "\n";);
|
||||
try_to_reuse:
|
||||
if (num_args > 1 && num_args < MAX_NUM_ARGS_FOR_OPT) {
|
||||
for (unsigned i = 0; i < num_args - 1; i++) {
|
||||
for (unsigned j = i + 1; j < num_args; j++) {
|
||||
if (contains(f, _args[i], _args[j])) {
|
||||
TRACE("ac_sharing_detail", tout << "reusing args: " << i << " " << j << "\n";);
|
||||
_args[i] = m.mk_app(f, _args[i], _args[j]);
|
||||
SASSERT(num_args > 1);
|
||||
for (unsigned w = j; w < num_args - 1; w++) {
|
||||
_args[w] = _args[w+1];
|
||||
}
|
||||
num_args--;
|
||||
goto try_to_reuse;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Create "tree-like circuit"
|
||||
while (true) {
|
||||
TRACE("ac_sharing_detail", tout << "tree-loop: num_args: " << num_args << "\n";);
|
||||
unsigned j = 0;
|
||||
for (unsigned i = 0; i < num_args; i += 2, j++) {
|
||||
if (i == num_args - 1) {
|
||||
_args[j] = _args[i];
|
||||
}
|
||||
else {
|
||||
insert(f, _args[i], _args[i+1]);
|
||||
_args[j] = m.mk_app(f, _args[i], _args[i+1]);
|
||||
}
|
||||
}
|
||||
num_args = j;
|
||||
if (num_args == 1) {
|
||||
if (numeral == 0) {
|
||||
result = _args[0];
|
||||
}
|
||||
else {
|
||||
result = m.mk_app(f, numeral, _args[0]);
|
||||
}
|
||||
TRACE("ac_sharing_detail", tout << "result: " << mk_pp(result, m) << "\n";);
|
||||
return BR_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
bool maximize_ac_sharing::contains(func_decl * f, expr * arg1, expr * arg2) {
|
||||
entry e(f, arg1, arg2);
|
||||
return m_cache.contains(&e);
|
||||
}
|
||||
|
||||
void maximize_ac_sharing::insert(func_decl * f, expr * arg1, expr * arg2) {
|
||||
entry * e = new (m_region) entry(f, arg1, arg2);
|
||||
m_entries.push_back(e);
|
||||
m_cache.insert(e);
|
||||
m.inc_ref(arg1);
|
||||
m.inc_ref(arg2);
|
||||
}
|
||||
|
||||
maximize_ac_sharing::maximize_ac_sharing(ast_manager & m):
|
||||
m(m),
|
||||
m_init(false) {
|
||||
}
|
||||
|
||||
maximize_ac_sharing::~maximize_ac_sharing() {
|
||||
restore_entries(0);
|
||||
}
|
||||
|
||||
|
||||
void maximize_ac_sharing::push_scope() {
|
||||
init();
|
||||
m_scopes.push_back(m_entries.size());
|
||||
m_region.push_scope();
|
||||
}
|
||||
|
||||
void maximize_ac_sharing::pop_scope(unsigned num_scopes) {
|
||||
SASSERT(num_scopes <= m_scopes.size());
|
||||
unsigned new_lvl = m_scopes.size() - num_scopes;
|
||||
unsigned old_lim = m_scopes[new_lvl];
|
||||
restore_entries(old_lim);
|
||||
m_region.pop_scope(num_scopes);
|
||||
m_scopes.shrink(new_lvl);
|
||||
}
|
||||
|
||||
void maximize_ac_sharing::restore_entries(unsigned old_lim) {
|
||||
unsigned i = m_entries.size();
|
||||
while (i != old_lim) {
|
||||
--i;
|
||||
entry * e = m_entries[i];
|
||||
m.dec_ref(e->m_arg1);
|
||||
m.dec_ref(e->m_arg2);
|
||||
}
|
||||
m_entries.shrink(old_lim);
|
||||
}
|
||||
|
||||
void maximize_ac_sharing::reset() {
|
||||
restore_entries(0);
|
||||
m_entries.reset();
|
||||
m_cache.reset();
|
||||
m_region.reset();
|
||||
m_scopes.reset();
|
||||
}
|
||||
|
||||
void maximize_bv_sharing::init_core() {
|
||||
register_kind(OP_BADD);
|
||||
register_kind(OP_BMUL);
|
||||
register_kind(OP_BOR);
|
||||
register_kind(OP_BAND);
|
||||
}
|
||||
|
||||
bool maximize_bv_sharing::is_numeral(expr * n) const {
|
||||
return m_util.is_numeral(n);
|
||||
}
|
||||
|
||||
maximize_bv_sharing::maximize_bv_sharing(ast_manager & m):
|
||||
maximize_ac_sharing(m),
|
||||
m_util(m) {
|
||||
}
|
125
src/ast/rewriter/maximize_ac_sharing.h
Normal file
125
src/ast/rewriter/maximize_ac_sharing.h
Normal file
|
@ -0,0 +1,125 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
maximize_ac_sharing.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-10-22.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef MAXIMIZE_AC_SHARING_H_
|
||||
#define MAXIMIZE_AC_SHARING_H_
|
||||
|
||||
#include "util/hashtable.h"
|
||||
#include "util/region.h"
|
||||
#include "ast/bv_decl_plugin.h"
|
||||
#include "ast/rewriter/rewriter.h"
|
||||
|
||||
/**
|
||||
\brief Functor used to maximize the amount of shared terms in an expression.
|
||||
The idea is to rewrite AC terms to maximize sharing.
|
||||
Example:
|
||||
|
||||
(f (bvadd a (bvadd b c)) (bvadd a (bvadd b d)))
|
||||
|
||||
is rewritten to:
|
||||
|
||||
(f (bvadd (bvadd a b) c) (bvadd (bvadd a b) d))
|
||||
|
||||
\warning This class uses an opportunistic heuristic to maximize sharing.
|
||||
There is no guarantee that the optimal expression will be produced.
|
||||
*/
|
||||
class maximize_ac_sharing : public default_rewriter_cfg {
|
||||
|
||||
struct entry {
|
||||
func_decl * m_decl;
|
||||
expr * m_arg1;
|
||||
expr * m_arg2;
|
||||
|
||||
entry(func_decl * d = 0, expr * arg1 = 0, expr * arg2 = 0):m_decl(d), m_arg1(arg1), m_arg2(arg2) {
|
||||
SASSERT((d == 0 && arg1 == 0 && arg2 == 0) || (d != 0 && arg1 != 0 && arg2 != 0));
|
||||
if (arg1->get_id() > arg2->get_id())
|
||||
std::swap(m_arg1, m_arg2);
|
||||
}
|
||||
|
||||
unsigned hash() const {
|
||||
unsigned a = m_decl->get_id();
|
||||
unsigned b = m_arg1->get_id();
|
||||
unsigned c = m_arg2->get_id();
|
||||
mix(a,b,c);
|
||||
return c;
|
||||
}
|
||||
|
||||
bool operator==(entry const & e) const {
|
||||
return m_decl == e.m_decl && m_arg1 == e.m_arg1 && m_arg2 == e.m_arg2;
|
||||
}
|
||||
};
|
||||
|
||||
typedef ptr_hashtable<entry, obj_ptr_hash<entry>, deref_eq<entry> > cache;
|
||||
|
||||
protected:
|
||||
void register_kind(decl_kind k);
|
||||
|
||||
private:
|
||||
ast_manager & m;
|
||||
bool m_init;
|
||||
region m_region;
|
||||
cache m_cache;
|
||||
ptr_vector<entry> m_entries;
|
||||
unsigned_vector m_scopes;
|
||||
svector<decl_kind> m_kinds; //!< kinds to be processed
|
||||
|
||||
bool contains(func_decl * f, expr * arg1, expr * arg2);
|
||||
void insert(func_decl * f, expr * arg1, expr * arg2);
|
||||
void restore_entries(unsigned old_lim);
|
||||
void init() {
|
||||
if (!m_init) {
|
||||
init_core();
|
||||
m_init = true;
|
||||
}
|
||||
}
|
||||
protected:
|
||||
virtual void init_core() = 0;
|
||||
virtual bool is_numeral(expr * n) const = 0;
|
||||
public:
|
||||
maximize_ac_sharing(ast_manager & m);
|
||||
virtual ~maximize_ac_sharing();
|
||||
void push_scope();
|
||||
void pop_scope(unsigned num_scopes);
|
||||
void reset();
|
||||
br_status reduce_app(func_decl* f, unsigned n, expr * const* args, expr_ref& result, proof_ref& result_pr);
|
||||
|
||||
};
|
||||
|
||||
class maximize_bv_sharing : public maximize_ac_sharing {
|
||||
bv_util m_util;
|
||||
protected:
|
||||
virtual void init_core();
|
||||
virtual bool is_numeral(expr * n) const;
|
||||
public:
|
||||
maximize_bv_sharing(ast_manager & m);
|
||||
};
|
||||
|
||||
class maximize_bv_sharing_rw : public rewriter_tpl<maximize_bv_sharing> {
|
||||
maximize_bv_sharing m_cfg;
|
||||
public:
|
||||
maximize_bv_sharing_rw(ast_manager& m):
|
||||
rewriter_tpl<maximize_bv_sharing>(m, m.proofs_enabled(), m_cfg),
|
||||
m_cfg(m)
|
||||
{}
|
||||
void push_scope() { m_cfg.push_scope(); }
|
||||
void pop_scope(unsigned n) { m_cfg.pop_scope(n); }
|
||||
void reset() { m_cfg.reset(); }
|
||||
};
|
||||
|
||||
#endif /* MAXIMIZE_AC_SHARING_H_ */
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
Revision History:
|
||||
--*/
|
||||
#include"mk_extract_proc.h"
|
||||
#include "ast/rewriter/mk_extract_proc.h"
|
||||
mk_extract_proc::mk_extract_proc(bv_util & u):
|
||||
m_util(u),
|
||||
m_high(0),
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
--*/
|
||||
#ifndef MK_EXTRACT_PROC_H_
|
||||
#define MK_EXTRACT_PROC_H_
|
||||
#include"ast.h"
|
||||
#include"bv_decl_plugin.h"
|
||||
#include "ast/ast.h"
|
||||
#include "ast/bv_decl_plugin.h"
|
||||
class mk_extract_proc {
|
||||
bv_util & m_util;
|
||||
unsigned m_high;
|
||||
|
|
|
@ -16,13 +16,13 @@ Author:
|
|||
Notes:
|
||||
|
||||
--*/
|
||||
#include"mk_simplified_app.h"
|
||||
#include"bool_rewriter.h"
|
||||
#include"arith_rewriter.h"
|
||||
#include"bv_rewriter.h"
|
||||
#include"datatype_rewriter.h"
|
||||
#include"array_rewriter.h"
|
||||
#include"fpa_rewriter.h"
|
||||
#include "ast/rewriter/mk_simplified_app.h"
|
||||
#include "ast/rewriter/bool_rewriter.h"
|
||||
#include "ast/rewriter/arith_rewriter.h"
|
||||
#include "ast/rewriter/bv_rewriter.h"
|
||||
#include "ast/rewriter/datatype_rewriter.h"
|
||||
#include "ast/rewriter/array_rewriter.h"
|
||||
#include "ast/rewriter/fpa_rewriter.h"
|
||||
|
||||
struct mk_simplified_app::imp {
|
||||
ast_manager & m;
|
||||
|
|
|
@ -19,9 +19,9 @@ Notes:
|
|||
#ifndef MK_SIMPLIFIED_APP_H_
|
||||
#define MK_SIMPLIFIED_APP_H_
|
||||
|
||||
#include"ast.h"
|
||||
#include"params.h"
|
||||
#include"rewriter_types.h"
|
||||
#include "ast/ast.h"
|
||||
#include "util/params.h"
|
||||
#include "ast/rewriter/rewriter_types.h"
|
||||
|
||||
class mk_simplified_app {
|
||||
struct imp;
|
||||
|
|
|
@ -17,16 +17,16 @@ Notes:
|
|||
|
||||
--*/
|
||||
|
||||
#include"rewriter.h"
|
||||
#include"rewriter_def.h"
|
||||
#include"statistics.h"
|
||||
#include"pb2bv_rewriter.h"
|
||||
#include"sorting_network.h"
|
||||
#include"ast_util.h"
|
||||
#include"ast_pp.h"
|
||||
#include"lbool.h"
|
||||
#include"uint_set.h"
|
||||
#include"gparams.h"
|
||||
#include "ast/rewriter/rewriter.h"
|
||||
#include "ast/rewriter/rewriter_def.h"
|
||||
#include "util/statistics.h"
|
||||
#include "ast/rewriter/pb2bv_rewriter.h"
|
||||
#include "util/sorting_network.h"
|
||||
#include "ast/ast_util.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "util/lbool.h"
|
||||
#include "util/uint_set.h"
|
||||
#include "util/gparams.h"
|
||||
|
||||
const unsigned g_primes[7] = { 2, 3, 5, 7, 11, 13, 17};
|
||||
|
||||
|
|
|
@ -19,9 +19,9 @@ Notes:
|
|||
#ifndef PB2BV_REWRITER_H_
|
||||
#define PB2BV_REWRITER_H_
|
||||
|
||||
#include"pb_decl_plugin.h"
|
||||
#include"rewriter_types.h"
|
||||
#include"expr_functors.h"
|
||||
#include "ast/pb_decl_plugin.h"
|
||||
#include "ast/rewriter/rewriter_types.h"
|
||||
#include "ast/expr_functors.h"
|
||||
|
||||
class pb2bv_rewriter {
|
||||
struct imp;
|
||||
|
|
|
@ -17,11 +17,11 @@ Notes:
|
|||
|
||||
--*/
|
||||
|
||||
#include "pb_rewriter.h"
|
||||
#include "pb_rewriter_def.h"
|
||||
#include "ast_pp.h"
|
||||
#include "ast_util.h"
|
||||
#include "ast_smt_pp.h"
|
||||
#include "ast/rewriter/pb_rewriter.h"
|
||||
#include "ast/rewriter/pb_rewriter_def.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "ast/ast_util.h"
|
||||
#include "ast/ast_smt_pp.h"
|
||||
|
||||
|
||||
class pb_ast_rewriter_util {
|
||||
|
|
|
@ -19,10 +19,10 @@ Notes:
|
|||
#ifndef PB_REWRITER_H_
|
||||
#define PB_REWRITER_H_
|
||||
|
||||
#include"pb_decl_plugin.h"
|
||||
#include"rewriter_types.h"
|
||||
#include"params.h"
|
||||
#include"lbool.h"
|
||||
#include "ast/pb_decl_plugin.h"
|
||||
#include "ast/rewriter/rewriter_types.h"
|
||||
#include "util/params.h"
|
||||
#include "util/lbool.h"
|
||||
|
||||
|
||||
template<typename PBU>
|
||||
|
|
|
@ -19,7 +19,7 @@ Notes:
|
|||
#ifndef PB_REWRITER_DEF_H_
|
||||
#define PB_REWRITER_DEF_H_
|
||||
|
||||
#include"pb_rewriter.h"
|
||||
#include "ast/rewriter/pb_rewriter.h"
|
||||
|
||||
|
||||
template<typename PBU>
|
||||
|
|
|
@ -19,10 +19,10 @@ Notes:
|
|||
#ifndef POLY_REWRITER_H_
|
||||
#define POLY_REWRITER_H_
|
||||
|
||||
#include"ast.h"
|
||||
#include"obj_hashtable.h"
|
||||
#include"rewriter_types.h"
|
||||
#include"params.h"
|
||||
#include "ast/ast.h"
|
||||
#include "util/obj_hashtable.h"
|
||||
#include "ast/rewriter/rewriter_types.h"
|
||||
#include "util/params.h"
|
||||
|
||||
template<typename Config>
|
||||
class poly_rewriter : public Config {
|
||||
|
@ -36,10 +36,10 @@ protected:
|
|||
bool m_sort_sums;
|
||||
bool m_hoist_mul;
|
||||
bool m_hoist_cmul;
|
||||
bool m_ast_order;
|
||||
|
||||
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); }
|
||||
|
@ -49,7 +49,6 @@ protected:
|
|||
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);
|
||||
|
@ -86,6 +85,14 @@ protected:
|
|||
bool is_mul(expr * t, numeral & c, expr * & pp);
|
||||
void hoist_cmul(expr_ref_buffer & args);
|
||||
|
||||
class mon_lt {
|
||||
poly_rewriter& rw;
|
||||
int ordinal(expr* e) const;
|
||||
public:
|
||||
mon_lt(poly_rewriter& rw): rw(rw) {}
|
||||
bool operator()(expr* e1, expr * e2) const;
|
||||
};
|
||||
|
||||
public:
|
||||
poly_rewriter(ast_manager & m, params_ref const & p = params_ref()):
|
||||
Config(m),
|
||||
|
@ -111,6 +118,10 @@ public:
|
|||
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()); }
|
||||
bool is_times_minus_one(expr * n, expr*& r) const;
|
||||
bool is_var_plus_ground(expr * n, bool & inv, var * & v, expr_ref & t);
|
||||
bool is_zero(expr* e) const;
|
||||
|
||||
|
||||
br_status mk_mul_core(unsigned num_args, expr * const * args, expr_ref & result) {
|
||||
SASSERT(num_args > 0);
|
||||
|
|
|
@ -16,11 +16,12 @@ Author:
|
|||
Notes:
|
||||
|
||||
--*/
|
||||
#include"poly_rewriter.h"
|
||||
#include"poly_rewriter_params.hpp"
|
||||
#include"ast_lt.h"
|
||||
#include"ast_ll_pp.h"
|
||||
#include"ast_smt2_pp.h"
|
||||
#include "ast/rewriter/poly_rewriter.h"
|
||||
#include "ast/rewriter/poly_rewriter_params.hpp"
|
||||
#include "ast/rewriter/arith_rewriter_params.hpp"
|
||||
#include "ast/ast_lt.h"
|
||||
#include "ast/ast_ll_pp.h"
|
||||
#include "ast/ast_smt2_pp.h"
|
||||
|
||||
|
||||
template<typename Config>
|
||||
|
@ -33,6 +34,8 @@ void poly_rewriter<Config>::updt_params(params_ref const & _p) {
|
|||
m_som_blowup = p.som_blowup();
|
||||
if (!m_flat) m_som = false;
|
||||
if (m_som) m_hoist_mul = false;
|
||||
arith_rewriter_params ap(_p);
|
||||
m_ast_order = !ap.arith_ineq_lhs();
|
||||
}
|
||||
|
||||
template<typename Config>
|
||||
|
@ -64,6 +67,13 @@ expr * poly_rewriter<Config>::get_power_body(expr * t, rational & k) {
|
|||
return t;
|
||||
}
|
||||
|
||||
template<typename Config>
|
||||
bool poly_rewriter<Config>::is_zero(expr* e) const {
|
||||
rational v;
|
||||
return is_numeral(e, v) && v.is_zero();
|
||||
}
|
||||
|
||||
|
||||
template<typename Config>
|
||||
expr * poly_rewriter<Config>::mk_mul_app(unsigned num_args, expr * const * args) {
|
||||
switch (num_args) {
|
||||
|
@ -118,6 +128,9 @@ expr * poly_rewriter<Config>::mk_mul_app(numeral const & c, expr * arg) {
|
|||
if (c.is_one()) {
|
||||
return arg;
|
||||
}
|
||||
else if (is_zero(arg)) {
|
||||
return arg;
|
||||
}
|
||||
else {
|
||||
expr * new_args[2] = { mk_numeral(c), arg };
|
||||
return mk_mul_app(2, new_args);
|
||||
|
@ -181,21 +194,9 @@ br_status poly_rewriter<Config>::mk_flat_mul_core(unsigned num_args, expr * cons
|
|||
}
|
||||
|
||||
|
||||
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) {
|
||||
mon_lt lt(*this);
|
||||
SASSERT(num_args >= 2);
|
||||
// cheap case
|
||||
numeral a;
|
||||
|
@ -310,11 +311,8 @@ br_status poly_rewriter<Config>::mk_nflat_mul_core(unsigned num_args, expr * con
|
|||
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",
|
||||
std::sort(new_args.begin(), new_args.end(), lt);
|
||||
TRACE("poly_rewriter",
|
||||
tout << "after sorting:\n";
|
||||
for (unsigned i = 0; i < new_args.size(); i++) {
|
||||
if (i > 0)
|
||||
|
@ -488,8 +486,45 @@ void poly_rewriter<Config>::hoist_cmul(expr_ref_buffer & args) {
|
|||
args.resize(j);
|
||||
}
|
||||
|
||||
template<typename Config>
|
||||
bool poly_rewriter<Config>::mon_lt::operator()(expr* e1, expr * e2) const {
|
||||
if (rw.m_ast_order)
|
||||
return lt(e1,e2);
|
||||
return ordinal(e1) < ordinal(e2);
|
||||
}
|
||||
|
||||
inline bool is_essentially_var(expr * n, family_id fid) {
|
||||
SASSERT(is_var(n) || is_app(n));
|
||||
return is_var(n) || to_app(n)->get_family_id() != fid;
|
||||
}
|
||||
|
||||
template<typename Config>
|
||||
int poly_rewriter<Config>::mon_lt::ordinal(expr* e) const {
|
||||
rational k;
|
||||
if (is_essentially_var(e, rw.get_fid())) {
|
||||
return e->get_id();
|
||||
}
|
||||
else if (rw.is_mul(e)) {
|
||||
if (rw.is_numeral(to_app(e)->get_arg(0)))
|
||||
return to_app(e)->get_arg(1)->get_id();
|
||||
else
|
||||
return e->get_id();
|
||||
}
|
||||
else if (rw.is_numeral(e)) {
|
||||
return -1;
|
||||
}
|
||||
else if (rw.use_power() && rw.is_power(e) && rw.is_numeral(to_app(e)->get_arg(1), k) && k > rational(1)) {
|
||||
return to_app(e)->get_arg(0)->get_id();
|
||||
}
|
||||
else {
|
||||
return e->get_id();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename Config>
|
||||
br_status poly_rewriter<Config>::mk_nflat_add_core(unsigned num_args, expr * const * args, expr_ref & result) {
|
||||
mon_lt lt(*this);
|
||||
SASSERT(num_args >= 2);
|
||||
numeral c;
|
||||
unsigned num_coeffs = 0;
|
||||
|
@ -498,22 +533,22 @@ br_status poly_rewriter<Config>::mk_nflat_add_core(unsigned num_args, expr * con
|
|||
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;
|
||||
bool ordered = true;
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
expr * arg = args[i];
|
||||
|
||||
if (is_numeral(arg, a)) {
|
||||
num_coeffs++;
|
||||
c += a;
|
||||
ordered = !m_sort_sums || i == 0;
|
||||
}
|
||||
else {
|
||||
// arg is not a numeral
|
||||
if (m_sort_sums && ordered) {
|
||||
if (prev != 0 && lt(arg, prev))
|
||||
ordered = false;
|
||||
prev = arg;
|
||||
}
|
||||
else 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);
|
||||
|
@ -525,8 +560,8 @@ br_status poly_rewriter<Config>::mk_nflat_add_core(unsigned num_args, expr * con
|
|||
}
|
||||
normalize(c);
|
||||
SASSERT(m_sort_sums || ordered);
|
||||
TRACE("sort_sums",
|
||||
tout << "ordered: " << ordered << "\n";
|
||||
TRACE("rewriter",
|
||||
tout << "ordered: " << ordered << " sort sums: " << m_sort_sums << "\n";
|
||||
for (unsigned i = 0; i < num_args; i++) tout << mk_ismt2_pp(args[i], m()) << "\n";);
|
||||
|
||||
if (has_multiple) {
|
||||
|
@ -579,13 +614,14 @@ br_status poly_rewriter<Config>::mk_nflat_add_core(unsigned num_args, expr * con
|
|||
hoist_cmul(new_args);
|
||||
}
|
||||
else if (m_sort_sums) {
|
||||
TRACE("sort_sums_bug", tout << "new_args.size(): " << new_args.size() << "\n";);
|
||||
TRACE("rewriter_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());
|
||||
std::sort(new_args.c_ptr(), new_args.c_ptr() + new_args.size(), mon_lt(*this));
|
||||
else
|
||||
std::sort(new_args.c_ptr() + 1, new_args.c_ptr() + new_args.size(), ast_to_lt());
|
||||
std::sort(new_args.c_ptr() + 1, new_args.c_ptr() + new_args.size(), mon_lt(*this));
|
||||
}
|
||||
result = mk_add_app(new_args.size(), new_args.c_ptr());
|
||||
TRACE("rewriter", tout << result << "\n";);
|
||||
if (hoist_multiplication(result)) {
|
||||
return BR_REWRITE_FULL;
|
||||
}
|
||||
|
@ -613,10 +649,10 @@ br_status poly_rewriter<Config>::mk_nflat_add_core(unsigned num_args, expr * con
|
|||
}
|
||||
else if (!ordered) {
|
||||
if (c.is_zero())
|
||||
std::sort(new_args.c_ptr(), new_args.c_ptr() + new_args.size(), ast_to_lt());
|
||||
std::sort(new_args.c_ptr(), new_args.c_ptr() + new_args.size(), lt);
|
||||
else
|
||||
std::sort(new_args.c_ptr() + 1, new_args.c_ptr() + new_args.size(), ast_to_lt());
|
||||
}
|
||||
std::sort(new_args.c_ptr() + 1, new_args.c_ptr() + new_args.size(), lt);
|
||||
}
|
||||
result = mk_add_app(new_args.size(), new_args.c_ptr());
|
||||
if (hoist_multiplication(result)) {
|
||||
return BR_REWRITE_FULL;
|
||||
|
@ -654,6 +690,7 @@ br_status poly_rewriter<Config>::mk_sub(unsigned num_args, expr * const * args,
|
|||
ptr_buffer<expr> new_args;
|
||||
new_args.push_back(args[0]);
|
||||
for (unsigned i = 1; i < num_args; i++) {
|
||||
if (is_zero(args[i])) continue;
|
||||
expr * aux_args[2] = { minus_one, args[i] };
|
||||
new_args.push_back(mk_mul_app(2, aux_args));
|
||||
}
|
||||
|
@ -669,6 +706,7 @@ br_status poly_rewriter<Config>::mk_sub(unsigned num_args, expr * const * args,
|
|||
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));
|
||||
mon_lt lt(*this);
|
||||
unsigned lhs_sz;
|
||||
expr * const * lhs_monomials = get_monomials(lhs, lhs_sz);
|
||||
unsigned rhs_sz;
|
||||
|
@ -693,8 +731,10 @@ br_status poly_rewriter<Config>::cancel_monomials(expr * lhs, expr * rhs, bool m
|
|||
}
|
||||
}
|
||||
|
||||
if (move && num_coeffs == 0 && is_numeral(rhs))
|
||||
if (move && num_coeffs == 0 && is_numeral(rhs)) {
|
||||
TRACE("mk_le_bug", tout << "no coeffs\n";);
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < rhs_sz; i++) {
|
||||
expr * arg = rhs_monomials[i];
|
||||
|
@ -712,15 +752,17 @@ br_status poly_rewriter<Config>::cancel_monomials(expr * lhs, expr * rhs, bool m
|
|||
}
|
||||
|
||||
normalize(c);
|
||||
|
||||
|
||||
if (!has_multiple && num_coeffs <= 1) {
|
||||
if (move) {
|
||||
if (is_numeral(rhs))
|
||||
if (is_numeral(rhs)) {
|
||||
return BR_FAILED;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (num_coeffs == 0 || is_numeral(rhs))
|
||||
if (num_coeffs == 0 || is_numeral(rhs)) {
|
||||
return BR_FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -811,7 +853,7 @@ br_status poly_rewriter<Config>::cancel_monomials(expr * lhs, expr * rhs, bool m
|
|||
if (move) {
|
||||
if (m_sort_sums) {
|
||||
// + 1 to skip coefficient
|
||||
std::sort(new_lhs_monomials.begin() + 1, new_lhs_monomials.end(), ast_to_lt());
|
||||
std::sort(new_lhs_monomials.begin() + 1, new_lhs_monomials.end(), lt);
|
||||
}
|
||||
c_at_rhs = true;
|
||||
}
|
||||
|
@ -836,6 +878,7 @@ br_status poly_rewriter<Config>::cancel_monomials(expr * lhs, expr * rhs, bool m
|
|||
new_lhs_monomials[0] = insert_c_lhs ? mk_numeral(c) : NULL;
|
||||
lhs_result = mk_add_app(new_lhs_monomials.size() - lhs_offset, new_lhs_monomials.c_ptr() + lhs_offset);
|
||||
rhs_result = mk_add_app(new_rhs_monomials.size() - rhs_offset, new_rhs_monomials.c_ptr() + rhs_offset);
|
||||
TRACE("mk_le_bug", tout << lhs_result << " " << rhs_result << "\n";);
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
|
@ -931,3 +974,63 @@ expr* poly_rewriter<Config>::merge_muls(expr* x, expr* y) {
|
|||
m1[k] = mk_add_app(2, args);
|
||||
return mk_mul_app(k+1, m1.c_ptr());
|
||||
}
|
||||
|
||||
template<typename Config>
|
||||
bool poly_rewriter<Config>::is_times_minus_one(expr * n, expr* & r) const {
|
||||
if (is_mul(n) && to_app(n)->get_num_args() == 2 && is_minus_one(to_app(n)->get_arg(0))) {
|
||||
r = to_app(n)->get_arg(1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return true if n is can be put into the form (+ v t) or (+ (- v) t)
|
||||
\c inv = true will contain true if (- v) is found, and false otherwise.
|
||||
*/
|
||||
template<typename Config>
|
||||
bool poly_rewriter<Config>::is_var_plus_ground(expr * n, bool & inv, var * & v, expr_ref & t) {
|
||||
if (!is_add(n) || is_ground(n))
|
||||
return false;
|
||||
|
||||
ptr_buffer<expr> args;
|
||||
v = 0;
|
||||
expr * curr = to_app(n);
|
||||
bool stop = false;
|
||||
inv = false;
|
||||
while (!stop) {
|
||||
expr * arg;
|
||||
expr * neg_arg;
|
||||
if (is_add(curr)) {
|
||||
arg = to_app(curr)->get_arg(0);
|
||||
curr = to_app(curr)->get_arg(1);
|
||||
}
|
||||
else {
|
||||
arg = curr;
|
||||
stop = true;
|
||||
}
|
||||
if (is_ground(arg)) {
|
||||
TRACE("model_checker_bug", tout << "pushing:\n" << mk_pp(arg, m()) << "\n";);
|
||||
args.push_back(arg);
|
||||
}
|
||||
else if (is_var(arg)) {
|
||||
if (v != 0)
|
||||
return false; // already found variable
|
||||
v = to_var(arg);
|
||||
}
|
||||
else if (is_times_minus_one(arg, neg_arg) && is_var(neg_arg)) {
|
||||
if (v != 0)
|
||||
return false; // already found variable
|
||||
v = to_var(neg_arg);
|
||||
inv = true;
|
||||
}
|
||||
else {
|
||||
return false; // non ground term.
|
||||
}
|
||||
}
|
||||
if (v == 0)
|
||||
return false; // did not find variable
|
||||
SASSERT(!args.empty());
|
||||
mk_add(args.size(), args.c_ptr(), t);
|
||||
return true;
|
||||
}
|
||||
|
|
221
src/ast/rewriter/pull_ite_tree.cpp
Normal file
221
src/ast/rewriter/pull_ite_tree.cpp
Normal file
|
@ -0,0 +1,221 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
pull_ite_tree.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-06-22.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include "ast/rewriter/pull_ite_tree.h"
|
||||
#include "ast/recurse_expr_def.h"
|
||||
#include "ast/for_each_expr.h"
|
||||
#include "ast/ast_pp.h"
|
||||
|
||||
pull_ite_tree::pull_ite_tree(ast_manager & m):
|
||||
m_manager(m),
|
||||
m_rewriter(m),
|
||||
m_cache(m) {
|
||||
}
|
||||
|
||||
void pull_ite_tree::cache_result(expr * n, expr * r, proof * pr) {
|
||||
m_cache.insert(n, r, pr);
|
||||
}
|
||||
|
||||
void pull_ite_tree::visit(expr * n, bool & visited) {
|
||||
if (!is_cached(n)) {
|
||||
m_todo.push_back(n);
|
||||
visited = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool pull_ite_tree::visit_children(expr * n) {
|
||||
if (m_manager.is_ite(n)) {
|
||||
bool visited = true;
|
||||
visit(to_app(n)->get_arg(1), visited);
|
||||
visit(to_app(n)->get_arg(2), visited);
|
||||
return visited;
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void pull_ite_tree::reduce(expr * n) {
|
||||
// Remark: invoking the simplifier to build the new expression saves a lot of memory.
|
||||
if (m_manager.is_ite(n)) {
|
||||
expr * c = to_app(n)->get_arg(0);
|
||||
expr * t_old = to_app(n)->get_arg(1);
|
||||
expr * e_old = to_app(n)->get_arg(2);
|
||||
expr * t = 0;
|
||||
proof * t_pr = 0;
|
||||
expr * e = 0;
|
||||
proof * e_pr = 0;
|
||||
get_cached(t_old, t, t_pr);
|
||||
get_cached(e_old, e, e_pr);
|
||||
expr_ref r(m_manager);
|
||||
expr * args[3] = {c, t, e};
|
||||
r = m_rewriter.mk_app(to_app(n)->get_decl(), 3, args);
|
||||
if (!m_manager.proofs_enabled()) {
|
||||
// expr * r = m_manager.mk_ite(c, t, e);
|
||||
cache_result(n, r, 0);
|
||||
}
|
||||
else {
|
||||
// t_pr is a proof for (m_p ... t_old ...) == t
|
||||
// e_pr is a proof for (m_p ... e_old ...) == e
|
||||
expr_ref old(m_manager);
|
||||
expr_ref p_t_old(m_manager);
|
||||
expr_ref p_e_old(m_manager);
|
||||
old = mk_p_arg(n); // (m_p ... n ...) where n is (ite c t_old e_old)
|
||||
p_t_old = mk_p_arg(t_old); // (m_p ... t_old ...)
|
||||
p_e_old = mk_p_arg(e_old); // (m_p ... e_old ...)
|
||||
expr_ref tmp1(m_manager);
|
||||
tmp1 = m_manager.mk_ite(c, p_t_old, p_e_old); // (ite c (m_p ... t_old ...) (m_p ... e_old ...))
|
||||
proof * pr1 = m_manager.mk_rewrite(old, tmp1); // proof for (m_p ... (ite c t_old e_old) ...) = (ite c (m_p ... t_old ...) (m_p ... e_old ...))
|
||||
expr_ref tmp2(m_manager);
|
||||
tmp2 = m_manager.mk_ite(c, t, e); // (ite c t e)
|
||||
proof * pr2 = 0; // it will contain a proof for (ite c (m_p ... t_old ...) (m_p ... e_old ...)) = (ite c t e)
|
||||
proof * pr3 = 0; // it will contain a proof for (m_p ... (ite c t_old e_old) ...) = (ite c t e)
|
||||
proof * proofs[2];
|
||||
unsigned num_proofs = 0;
|
||||
if (t_pr != 0) {
|
||||
proofs[num_proofs] = t_pr;
|
||||
num_proofs++;
|
||||
}
|
||||
if (e_pr != 0) {
|
||||
proofs[num_proofs] = e_pr;
|
||||
num_proofs++;
|
||||
}
|
||||
if (num_proofs > 0) {
|
||||
pr2 = m_manager.mk_congruence(to_app(tmp1), to_app(tmp2), num_proofs, proofs);
|
||||
pr3 = m_manager.mk_transitivity(pr1, pr2);
|
||||
}
|
||||
else {
|
||||
pr3 = pr1;
|
||||
}
|
||||
proof * pr4 = 0; // it will contain a proof for (ite c t e) = r
|
||||
proof * pr5 = 0; // it will contain a proof for (m_p ... (ite c t_old e_old) ...) = r
|
||||
if (tmp2 != r) {
|
||||
pr4 = m_manager.mk_rewrite(tmp2, r);
|
||||
pr5 = m_manager.mk_transitivity(pr3, pr4);
|
||||
}
|
||||
else {
|
||||
pr5 = pr3;
|
||||
}
|
||||
cache_result(n, r, pr5);
|
||||
}
|
||||
}
|
||||
else {
|
||||
expr_ref r(m_manager);
|
||||
m_args[m_arg_idx] = n;
|
||||
r = m_rewriter.mk_app(m_p, m_args.size(), m_args.c_ptr());
|
||||
if (!m_manager.proofs_enabled()) {
|
||||
// expr * r = m_manager.mk_app(m_p, m_args.size(), m_args.c_ptr());
|
||||
cache_result(n, r, 0);
|
||||
}
|
||||
else {
|
||||
expr_ref old(m_manager);
|
||||
proof * p;
|
||||
old = mk_p_arg(n);
|
||||
if (old == r)
|
||||
p = 0;
|
||||
else
|
||||
p = m_manager.mk_rewrite(old, r);
|
||||
cache_result(n, r, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pull_ite_tree::operator()(app * n, app_ref & r, proof_ref & pr) {
|
||||
unsigned num_args = n->get_num_args();
|
||||
m_args.resize(num_args);
|
||||
m_p = n->get_decl();
|
||||
expr * ite = 0;
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
expr * arg = n->get_arg(i);
|
||||
if (ite) {
|
||||
m_args[i] = arg;
|
||||
}
|
||||
else if (m_manager.is_ite(arg)) {
|
||||
m_arg_idx = i;
|
||||
m_args[i] = 0;
|
||||
ite = arg;
|
||||
}
|
||||
else {
|
||||
m_args[i] = arg;
|
||||
}
|
||||
}
|
||||
if (!ite) {
|
||||
r = n;
|
||||
pr = 0;
|
||||
return;
|
||||
}
|
||||
m_todo.push_back(ite);
|
||||
while (!m_todo.empty()) {
|
||||
expr * n = m_todo.back();
|
||||
if (is_cached(n))
|
||||
m_todo.pop_back();
|
||||
else if (visit_children(n)) {
|
||||
m_todo.pop_back();
|
||||
reduce(n);
|
||||
}
|
||||
}
|
||||
SASSERT(is_cached(ite));
|
||||
expr * _r = 0;
|
||||
proof * _pr = 0;
|
||||
get_cached(ite, _r, _pr);
|
||||
r = to_app(_r);
|
||||
pr = _pr;
|
||||
m_cache.reset();
|
||||
m_todo.reset();
|
||||
}
|
||||
|
||||
|
||||
|
||||
pull_ite_tree_cfg::pull_ite_tree_cfg(ast_manager & m):
|
||||
m(m),
|
||||
m_trail(m),
|
||||
m_proc(m) {
|
||||
}
|
||||
|
||||
bool pull_ite_tree_cfg::get_subst(expr * n, expr* & r, proof* & p) {
|
||||
if (is_app(n) && is_target(to_app(n))) {
|
||||
app_ref tmp(m);
|
||||
proof_ref pr(m);
|
||||
m_proc(to_app(n), tmp, pr);
|
||||
if (tmp != n) {
|
||||
r = tmp;
|
||||
p = pr;
|
||||
m_trail.push_back(r);
|
||||
m_trail.push_back(p);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pull_cheap_ite_tree_cfg::is_target(app * n) const {
|
||||
bool r =
|
||||
n->get_num_args() == 2 &&
|
||||
n->get_family_id() != null_family_id &&
|
||||
m.is_bool(n) &&
|
||||
(m.is_value(n->get_arg(0)) || m.is_value(n->get_arg(1))) &&
|
||||
(m.is_term_ite(n->get_arg(0)) || m.is_term_ite(n->get_arg(1)));
|
||||
TRACE("pull_ite_target", tout << mk_pp(n, m) << "\nresult: " << r << "\n";);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
113
src/ast/rewriter/pull_ite_tree.h
Normal file
113
src/ast/rewriter/pull_ite_tree.h
Normal file
|
@ -0,0 +1,113 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
pull_ite_tree.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-06-22.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef PULL_ITE_TREE_H_
|
||||
#define PULL_ITE_TREE_H_
|
||||
|
||||
#include "ast/ast.h"
|
||||
#include "ast/rewriter/rewriter.h"
|
||||
#include "ast/rewriter/th_rewriter.h"
|
||||
#include "ast/expr_map.h"
|
||||
#include "ast/recurse_expr.h"
|
||||
#include "util/obj_hashtable.h"
|
||||
|
||||
/**
|
||||
\brief Functor for applying the following transformation
|
||||
F[(p (ite c t1 t2) args)] = F'[(ite c t1 t2), p, args]
|
||||
|
||||
F'[(ite c t1 t2), p, args] = (ite c F'[t1, p, args] F'[t2, p, args])
|
||||
F'[t, p, args] = (p t args)
|
||||
*/
|
||||
class pull_ite_tree {
|
||||
ast_manager & m_manager;
|
||||
th_rewriter m_rewriter;
|
||||
func_decl * m_p;
|
||||
ptr_vector<expr> m_args;
|
||||
unsigned m_arg_idx; //!< position of the ite argument
|
||||
expr_map m_cache;
|
||||
ptr_vector<expr> m_todo;
|
||||
|
||||
bool is_cached(expr * n) const { return m_cache.contains(n); }
|
||||
void get_cached(expr * n, expr * & r, proof * & p) const { m_cache.get(n, r, p); }
|
||||
void cache_result(expr * n, expr * r, proof * pr);
|
||||
void visit(expr * n, bool & visited);
|
||||
bool visit_children(expr * n);
|
||||
void reduce(expr * n);
|
||||
/**
|
||||
\brief Creante an application (m_p ... n ...) where n is the argument m_arg_idx and the other arguments
|
||||
are in m_args.
|
||||
*/
|
||||
expr * mk_p_arg(expr * n) {
|
||||
m_args[m_arg_idx] = n;
|
||||
return m_manager.mk_app(m_p, m_args.size(), m_args.c_ptr());
|
||||
}
|
||||
public:
|
||||
pull_ite_tree(ast_manager & m);
|
||||
/**
|
||||
\brief Apply the transformation above if n contains an ite-expression.
|
||||
Store the result in r. If n does not contain an ite-expression, then
|
||||
store n in r.
|
||||
|
||||
When proof generation is enabled, pr is a proof for n = r.
|
||||
*/
|
||||
void operator()(app * n, app_ref & r, proof_ref & pr);
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Functor for applying the pull_ite_tree on subexpressions n that
|
||||
satisfy the is_target virtual predicate.
|
||||
*/
|
||||
class pull_ite_tree_cfg : public default_rewriter_cfg {
|
||||
protected:
|
||||
ast_manager& m;
|
||||
expr_ref_vector m_trail;
|
||||
pull_ite_tree m_proc;
|
||||
public:
|
||||
pull_ite_tree_cfg(ast_manager & m);
|
||||
virtual ~pull_ite_tree_cfg() {}
|
||||
virtual bool is_target(app * n) const = 0;
|
||||
bool get_subst(expr * n, expr* & r, proof* & p);
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Apply pull_ite_tree on predicates of the form
|
||||
(p ite v) and (p v ite)
|
||||
|
||||
where:
|
||||
- p is an interpreted predicate
|
||||
- ite is an ite-term expression
|
||||
- v is a value
|
||||
*/
|
||||
class pull_cheap_ite_tree_cfg : public pull_ite_tree_cfg {
|
||||
public:
|
||||
pull_cheap_ite_tree_cfg(ast_manager & m):pull_ite_tree_cfg(m) {}
|
||||
virtual ~pull_cheap_ite_tree_cfg() {}
|
||||
virtual bool is_target(app * n) const;
|
||||
};
|
||||
|
||||
class pull_cheap_ite_tree_rw : public rewriter_tpl<pull_cheap_ite_tree_cfg> {
|
||||
pull_cheap_ite_tree_cfg m_cfg;
|
||||
public:
|
||||
pull_cheap_ite_tree_rw(ast_manager& m):
|
||||
rewriter_tpl<pull_cheap_ite_tree_cfg>(m, m.proofs_enabled(), m_cfg),
|
||||
m_cfg(m)
|
||||
{}
|
||||
};
|
||||
|
||||
#endif /* PULL_ITE_TREE_H_ */
|
||||
|
91
src/ast/rewriter/push_app_ite.cpp
Normal file
91
src/ast/rewriter/push_app_ite.cpp
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
push_app_ite.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
TODO: Write a better ite lifter
|
||||
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-05-14.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include "ast/rewriter/push_app_ite.h"
|
||||
#include "ast/ast_pp.h"
|
||||
|
||||
|
||||
static int has_ite_arg(ast_manager& m, unsigned num_args, expr * const * args) {
|
||||
for (unsigned i = 0; i < num_args; i++)
|
||||
if (m.is_ite(args[i]))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Default (conservative) implementation. Return true if there one and only one ite-term argument.
|
||||
*/
|
||||
bool push_app_ite_cfg::is_target(func_decl * decl, unsigned num_args, expr * const * args) {
|
||||
if (m.is_ite(decl))
|
||||
return false;
|
||||
bool found_ite = false;
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
if (m.is_ite(args[i]) && !m.is_bool(args[i])) {
|
||||
if (found_ite) {
|
||||
if (m_conservative)
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
found_ite = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
CTRACE("push_app_ite", found_ite, tout << "found target for push app ite:\n";
|
||||
tout << decl->get_name();
|
||||
for (unsigned i = 0; i < num_args; i++) tout << " " << mk_pp(args[i], m);
|
||||
tout << "\n";);
|
||||
return found_ite;
|
||||
}
|
||||
|
||||
br_status push_app_ite_cfg::reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
|
||||
if (!is_target(f, num, args)) {
|
||||
return BR_FAILED;
|
||||
}
|
||||
int ite_arg_idx = has_ite_arg(m, num, args);
|
||||
if (ite_arg_idx < 0) {
|
||||
return BR_FAILED;
|
||||
}
|
||||
app * ite = to_app(args[ite_arg_idx]);
|
||||
expr * c = 0, * t = 0, * e = 0;
|
||||
VERIFY(m.is_ite(ite, c, t, e));
|
||||
expr ** args_prime = const_cast<expr**>(args);
|
||||
expr * old = args_prime[ite_arg_idx];
|
||||
args_prime[ite_arg_idx] = t;
|
||||
expr_ref t_new(m.mk_app(f, num, args_prime), m);
|
||||
args_prime[ite_arg_idx] = e;
|
||||
expr_ref e_new(m.mk_app(f, num, args_prime), m);
|
||||
args_prime[ite_arg_idx] = old;
|
||||
result = m.mk_ite(c, t_new, e_new);
|
||||
TRACE("push_app_ite", tout << result << "\n";);
|
||||
if (m.proofs_enabled()) {
|
||||
result_pr = m.mk_rewrite(m.mk_app(f, num, args), result);
|
||||
}
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
|
||||
bool ng_push_app_ite_cfg::is_target(func_decl * decl, unsigned num_args, expr * const * args) {
|
||||
bool r = push_app_ite_cfg::is_target(decl, num_args, args);
|
||||
if (!r)
|
||||
return false;
|
||||
for (unsigned i = 0; i < num_args; i++)
|
||||
if (!is_ground(args[i]))
|
||||
return true;
|
||||
return false;
|
||||
}
|
74
src/ast/rewriter/push_app_ite.h
Normal file
74
src/ast/rewriter/push_app_ite.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
push_app_ite.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-05-14.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef PUSH_APP_ITE_H_
|
||||
#define PUSH_APP_ITE_H_
|
||||
|
||||
#include "ast/ast.h"
|
||||
#include "ast/rewriter/rewriter.h"
|
||||
|
||||
/**
|
||||
\brief Functor for applying the following transformation:
|
||||
|
||||
(f s (ite c t1 t2)) ==> (ite c (f s t1) (f s t2))
|
||||
*/
|
||||
|
||||
struct push_app_ite_cfg : public default_rewriter_cfg {
|
||||
ast_manager& m;
|
||||
bool m_conservative;
|
||||
virtual bool is_target(func_decl * decl, unsigned num_args, expr * const * args);
|
||||
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr);
|
||||
push_app_ite_cfg(ast_manager& m, bool conservative = true): m(m), m_conservative(conservative) {}
|
||||
bool rewrite_patterns() const { return false; }
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Variation of push_app_ite that applies the transformation on nonground terms only.
|
||||
|
||||
\remark This functor uses the app::is_ground method. This method is not
|
||||
completly precise, for instance, any term containing a quantifier is marked as non ground.
|
||||
*/
|
||||
class ng_push_app_ite_cfg : public push_app_ite_cfg {
|
||||
protected:
|
||||
virtual bool is_target(func_decl * decl, unsigned num_args, expr * const * args);
|
||||
public:
|
||||
ng_push_app_ite_cfg(ast_manager& m, bool conservative = true): push_app_ite_cfg(m, conservative) {}
|
||||
virtual ~ng_push_app_ite_cfg() {}
|
||||
};
|
||||
|
||||
struct push_app_ite_rw : public rewriter_tpl<push_app_ite_cfg> {
|
||||
push_app_ite_cfg m_cfg;
|
||||
public:
|
||||
push_app_ite_rw(ast_manager& m, bool conservative = true):
|
||||
rewriter_tpl<push_app_ite_cfg>(m, m.proofs_enabled(), m_cfg),
|
||||
m_cfg(m, conservative)
|
||||
{}
|
||||
};
|
||||
|
||||
struct ng_push_app_ite_rw : public rewriter_tpl<ng_push_app_ite_cfg> {
|
||||
ng_push_app_ite_cfg m_cfg;
|
||||
public:
|
||||
ng_push_app_ite_rw(ast_manager& m, bool conservative = true):
|
||||
rewriter_tpl<ng_push_app_ite_cfg>(m, m.proofs_enabled(), m_cfg),
|
||||
m_cfg(m, conservative)
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
#endif /* PUSH_APP_ITE_H_ */
|
||||
|
|
@ -19,14 +19,14 @@ Revision History:
|
|||
|
||||
--*/
|
||||
|
||||
#include "quant_hoist.h"
|
||||
#include "expr_functors.h"
|
||||
#include "ast_smt_pp.h"
|
||||
#include "bool_rewriter.h"
|
||||
#include "var_subst.h"
|
||||
#include "ast_pp.h"
|
||||
#include "ast_counter.h"
|
||||
#include "expr_safe_replace.h"
|
||||
#include "ast/rewriter/quant_hoist.h"
|
||||
#include "ast/expr_functors.h"
|
||||
#include "ast/ast_smt_pp.h"
|
||||
#include "ast/rewriter/bool_rewriter.h"
|
||||
#include "ast/rewriter/var_subst.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "ast/rewriter/ast_counter.h"
|
||||
#include "ast/rewriter/expr_safe_replace.h"
|
||||
|
||||
//
|
||||
// Bring quantifiers of common type into prenex form.
|
||||
|
@ -41,9 +41,9 @@ public:
|
|||
m_rewriter(m)
|
||||
{}
|
||||
|
||||
void operator()(expr* fml, app_ref_vector& vars, bool& is_fa, expr_ref& result) {
|
||||
void operator()(expr* fml, app_ref_vector& vars, bool& is_fa, expr_ref& result, bool use_fresh, bool rewrite_ok) {
|
||||
quantifier_type qt = Q_none_pos;
|
||||
pull_quantifier(fml, qt, vars, result);
|
||||
pull_quantifier(fml, qt, vars, result, use_fresh, rewrite_ok);
|
||||
TRACE("qe_verbose",
|
||||
tout << mk_pp(fml, m) << "\n";
|
||||
tout << mk_pp(result, m) << "\n";);
|
||||
|
@ -51,36 +51,38 @@ public:
|
|||
is_fa = (Q_forall_pos == qt);
|
||||
}
|
||||
|
||||
void pull_exists(expr* fml, app_ref_vector& vars, expr_ref& result) {
|
||||
void pull_exists(expr* fml, app_ref_vector& vars, expr_ref& result, bool use_fresh, bool rewrite_ok) {
|
||||
quantifier_type qt = Q_exists_pos;
|
||||
pull_quantifier(fml, qt, vars, result);
|
||||
pull_quantifier(fml, qt, vars, result, use_fresh, rewrite_ok);
|
||||
TRACE("qe_verbose",
|
||||
tout << mk_pp(fml, m) << "\n";
|
||||
tout << mk_pp(result, m) << "\n";);
|
||||
}
|
||||
|
||||
void pull_quantifier(bool is_forall, expr_ref& fml, app_ref_vector& vars) {
|
||||
void pull_quantifier(bool is_forall, expr_ref& fml, app_ref_vector& vars, bool use_fresh, bool rewrite_ok) {
|
||||
quantifier_type qt = is_forall?Q_forall_pos:Q_exists_pos;
|
||||
expr_ref result(m);
|
||||
pull_quantifier(fml, qt, vars, result);
|
||||
pull_quantifier(fml, qt, vars, result, use_fresh, rewrite_ok);
|
||||
TRACE("qe_verbose",
|
||||
tout << mk_pp(fml, m) << "\n";
|
||||
tout << mk_pp(result, m) << "\n";);
|
||||
fml = result;
|
||||
}
|
||||
|
||||
void extract_quantifier(quantifier* q, app_ref_vector& vars, expr_ref& result) {
|
||||
void extract_quantifier(quantifier* q, app_ref_vector& vars, expr_ref& result, bool use_fresh) {
|
||||
unsigned nd = q->get_num_decls();
|
||||
for (unsigned i = 0; i < nd; ++i) {
|
||||
sort* s = q->get_decl_sort(i);
|
||||
app* a = m.mk_fresh_const(q->get_decl_name(i).str().c_str(), s);
|
||||
symbol const& sym = q->get_decl_name (i);
|
||||
app* a = use_fresh ? m.mk_fresh_const(sym.str ().c_str (), s)
|
||||
: m.mk_const (sym, s);
|
||||
vars.push_back(a);
|
||||
}
|
||||
expr * const * exprs = (expr* const*) (vars.c_ptr() + vars.size()- nd);
|
||||
instantiate(m, q, exprs, result);
|
||||
}
|
||||
|
||||
unsigned pull_quantifier(bool is_forall, expr_ref& fml, ptr_vector<sort>* sorts, svector<symbol>* names) {
|
||||
unsigned pull_quantifier(bool is_forall, expr_ref& fml, ptr_vector<sort>* sorts, svector<symbol>* names, bool use_fresh, bool rewrite_ok) {
|
||||
unsigned index = var_counter().get_next_var(fml);
|
||||
while (is_quantifier(fml) && (is_forall == to_quantifier(fml)->is_forall())) {
|
||||
quantifier* q = to_quantifier(fml);
|
||||
|
@ -97,7 +99,7 @@ public:
|
|||
return index;
|
||||
}
|
||||
app_ref_vector vars(m);
|
||||
pull_quantifier(is_forall, fml, vars);
|
||||
pull_quantifier(is_forall, fml, vars, use_fresh, rewrite_ok);
|
||||
if (vars.empty()) {
|
||||
return index;
|
||||
}
|
||||
|
@ -192,7 +194,7 @@ private:
|
|||
}
|
||||
|
||||
|
||||
void pull_quantifier(expr* fml, quantifier_type& qt, app_ref_vector& vars, expr_ref& result) {
|
||||
void pull_quantifier(expr* fml, quantifier_type& qt, app_ref_vector& vars, expr_ref& result, bool use_fresh, bool rewrite_ok) {
|
||||
|
||||
if (!has_quantifiers(fml)) {
|
||||
result = fml;
|
||||
|
@ -209,38 +211,48 @@ private:
|
|||
if (m.is_and(fml)) {
|
||||
num_args = a->get_num_args();
|
||||
for (unsigned i = 0; i < num_args; ++i) {
|
||||
pull_quantifier(a->get_arg(i), qt, vars, tmp);
|
||||
pull_quantifier(a->get_arg(i), qt, vars, tmp, use_fresh, rewrite_ok);
|
||||
args.push_back(tmp);
|
||||
}
|
||||
if (rewrite_ok) {
|
||||
m_rewriter.mk_and(args.size(), args.c_ptr(), result);
|
||||
}
|
||||
else {
|
||||
result = m.mk_and (args.size (), args.c_ptr ());
|
||||
}
|
||||
}
|
||||
else if (m.is_or(fml)) {
|
||||
num_args = to_app(fml)->get_num_args();
|
||||
for (unsigned i = 0; i < num_args; ++i) {
|
||||
pull_quantifier(to_app(fml)->get_arg(i), qt, vars, tmp);
|
||||
pull_quantifier(to_app(fml)->get_arg(i), qt, vars, tmp, use_fresh, rewrite_ok);
|
||||
args.push_back(tmp);
|
||||
}
|
||||
if (rewrite_ok) {
|
||||
m_rewriter.mk_or(args.size(), args.c_ptr(), result);
|
||||
}
|
||||
else {
|
||||
result = m.mk_or (args.size (), args.c_ptr ());
|
||||
}
|
||||
}
|
||||
else if (m.is_not(fml)) {
|
||||
pull_quantifier(to_app(fml)->get_arg(0), negate(qt), vars, tmp);
|
||||
pull_quantifier(to_app(fml)->get_arg(0), negate(qt), vars, tmp, use_fresh, rewrite_ok);
|
||||
negate(qt);
|
||||
result = m.mk_not(tmp);
|
||||
}
|
||||
else if (m.is_implies(fml, t1, t2)) {
|
||||
pull_quantifier(t1, negate(qt), vars, tmp);
|
||||
pull_quantifier(t1, negate(qt), vars, tmp, use_fresh, rewrite_ok);
|
||||
negate(qt);
|
||||
pull_quantifier(t2, qt, vars, result);
|
||||
pull_quantifier(t2, qt, vars, result, use_fresh, rewrite_ok);
|
||||
result = m.mk_implies(tmp, result);
|
||||
}
|
||||
else if (m.is_ite(fml, t1, t2, t3)) {
|
||||
expr_ref tt1(m), tt2(m), tt3(m), ntt1(m), nt1(m);
|
||||
pull_quantifier(t2, qt, vars, tt2);
|
||||
pull_quantifier(t3, qt, vars, tt3);
|
||||
pull_quantifier(t2, qt, vars, tt2, use_fresh, rewrite_ok);
|
||||
pull_quantifier(t3, qt, vars, tt3, use_fresh, rewrite_ok);
|
||||
if (has_quantifiers(t1)) {
|
||||
pull_quantifier(t1, qt, vars, tt1);
|
||||
pull_quantifier(t1, qt, vars, tt1, use_fresh, rewrite_ok);
|
||||
nt1 = m.mk_not(t1);
|
||||
pull_quantifier(nt1, qt, vars, ntt1);
|
||||
pull_quantifier(nt1, qt, vars, ntt1, use_fresh, rewrite_ok);
|
||||
result = m.mk_and(m.mk_or(ntt1, tt2), m.mk_or(tt1, tt3));
|
||||
}
|
||||
else {
|
||||
|
@ -249,12 +261,12 @@ private:
|
|||
}
|
||||
else if ((m.is_eq(fml, t1, t2) && m.is_bool(t1)) || m.is_iff(fml, t1, t2)) {
|
||||
expr_ref tt1(m), tt2(m), ntt1(m), ntt2(m), nt1(m), nt2(m);
|
||||
pull_quantifier(t1, qt, vars, tt1);
|
||||
pull_quantifier(t2, qt, vars, tt2);
|
||||
pull_quantifier(t1, qt, vars, tt1, use_fresh, rewrite_ok);
|
||||
pull_quantifier(t2, qt, vars, tt2, use_fresh, rewrite_ok);
|
||||
nt1 = m.mk_not(t1);
|
||||
nt2 = m.mk_not(t2);
|
||||
pull_quantifier(nt1, qt, vars, ntt1);
|
||||
pull_quantifier(nt2, qt, vars, ntt2);
|
||||
pull_quantifier(nt1, qt, vars, ntt1, use_fresh, rewrite_ok);
|
||||
pull_quantifier(nt2, qt, vars, ntt2, use_fresh, rewrite_ok);
|
||||
result = m.mk_and(m.mk_or(ntt1, tt2), m.mk_or(ntt2, tt1));
|
||||
}
|
||||
else {
|
||||
|
@ -271,8 +283,8 @@ private:
|
|||
break;
|
||||
}
|
||||
set_quantifier_type(qt, q->is_forall());
|
||||
extract_quantifier(q, vars, tmp);
|
||||
pull_quantifier(tmp, qt, vars, result);
|
||||
extract_quantifier(q, vars, tmp, use_fresh);
|
||||
pull_quantifier(tmp, qt, vars, result, use_fresh, rewrite_ok);
|
||||
break;
|
||||
}
|
||||
case AST_VAR:
|
||||
|
@ -295,18 +307,18 @@ quantifier_hoister::~quantifier_hoister() {
|
|||
dealloc(m_impl);
|
||||
}
|
||||
|
||||
void quantifier_hoister::operator()(expr* fml, app_ref_vector& vars, bool& is_fa, expr_ref& result) {
|
||||
(*m_impl)(fml, vars, is_fa, result);
|
||||
void quantifier_hoister::operator()(expr* fml, app_ref_vector& vars, bool& is_fa, expr_ref& result, bool use_fresh, bool rewrite_ok) {
|
||||
(*m_impl)(fml, vars, is_fa, result, use_fresh, rewrite_ok);
|
||||
}
|
||||
|
||||
void quantifier_hoister::pull_exists(expr* fml, app_ref_vector& vars, expr_ref& result) {
|
||||
m_impl->pull_exists(fml, vars, result);
|
||||
void quantifier_hoister::pull_exists(expr* fml, app_ref_vector& vars, expr_ref& result, bool use_fresh, bool rewrite_ok) {
|
||||
m_impl->pull_exists(fml, vars, result, use_fresh, rewrite_ok);
|
||||
}
|
||||
|
||||
void quantifier_hoister::pull_quantifier(bool is_forall, expr_ref& fml, app_ref_vector& vars) {
|
||||
m_impl->pull_quantifier(is_forall, fml, vars);
|
||||
void quantifier_hoister::pull_quantifier(bool is_forall, expr_ref& fml, app_ref_vector& vars, bool use_fresh, bool rewrite_ok) {
|
||||
m_impl->pull_quantifier(is_forall, fml, vars, use_fresh, rewrite_ok);
|
||||
}
|
||||
|
||||
unsigned quantifier_hoister::pull_quantifier(bool is_forall, expr_ref& fml, ptr_vector<sort>* sorts, svector<symbol>* names) {
|
||||
return m_impl->pull_quantifier(is_forall, fml, sorts, names);
|
||||
unsigned quantifier_hoister::pull_quantifier(bool is_forall, expr_ref& fml, ptr_vector<sort>* sorts, svector<symbol>* names, bool use_fresh, bool rewrite_ok) {
|
||||
return m_impl->pull_quantifier(is_forall, fml, sorts, names, use_fresh, rewrite_ok);
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ Revision History:
|
|||
#ifndef QUANTIFIER_HOISTER_H_
|
||||
#define QUANTIFIER_HOISTER_H_
|
||||
|
||||
#include "ast.h"
|
||||
#include "ast/ast.h"
|
||||
|
||||
class quantifier_hoister {
|
||||
class impl;
|
||||
|
@ -43,14 +43,14 @@ public:
|
|||
or, and, implies, ite (then and else branch only).
|
||||
*/
|
||||
|
||||
void operator()(expr* fml, app_ref_vector& vars, bool& is_fa, expr_ref& result);
|
||||
void operator()(expr* fml, app_ref_vector& vars, bool& is_fa, expr_ref& result, bool use_fresh = true, bool rewrite_ok = true);
|
||||
|
||||
/**
|
||||
\brief Pull top-most existential quantifier up.
|
||||
|
||||
The list of variables is empty if there are no top-level existential quantifier.
|
||||
*/
|
||||
void pull_exists(expr* fml, app_ref_vector& vars, expr_ref& result);
|
||||
void pull_exists(expr* fml, app_ref_vector& vars, expr_ref& result, bool use_fresh = true, bool rewrite_ok = true);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -58,7 +58,7 @@ public:
|
|||
|
||||
The list of variables is empty if there are no top-level universal/existential quantifier.
|
||||
*/
|
||||
void pull_quantifier(bool is_forall, expr_ref& fml, app_ref_vector& vars);
|
||||
void pull_quantifier(bool is_forall, expr_ref& fml, app_ref_vector& vars, bool use_fresh = true, bool rewrite_ok = true);
|
||||
|
||||
/**
|
||||
\brief Pull top-most universal (is_forall true) or existential (is_forall=false) quantifier up.
|
||||
|
@ -66,7 +66,7 @@ public:
|
|||
Return index of maximal variable.
|
||||
*/
|
||||
|
||||
unsigned pull_quantifier(bool is_forall, expr_ref& fml, ptr_vector<sort>* sorts, svector<symbol>* names);
|
||||
unsigned pull_quantifier(bool is_forall, expr_ref& fml, ptr_vector<sort>* sorts, svector<symbol>* names, bool use_fresh = true, bool rewrite_ok = true);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -16,9 +16,9 @@ Author:
|
|||
Notes:
|
||||
|
||||
--*/
|
||||
#include"rewriter_def.h"
|
||||
#include"ast_ll_pp.h"
|
||||
#include"ast_smt2_pp.h"
|
||||
#include "ast/rewriter/rewriter_def.h"
|
||||
#include "ast/ast_ll_pp.h"
|
||||
#include "ast/ast_smt2_pp.h"
|
||||
|
||||
void rewriter_core::init_cache_stack() {
|
||||
SASSERT(m_cache_stack.empty());
|
||||
|
|
|
@ -19,9 +19,9 @@ Notes:
|
|||
#ifndef REWRITER_H_
|
||||
#define REWRITER_H_
|
||||
|
||||
#include"ast.h"
|
||||
#include"rewriter_types.h"
|
||||
#include"act_cache.h"
|
||||
#include "ast/ast.h"
|
||||
#include "ast/rewriter/rewriter_types.h"
|
||||
#include "ast/act_cache.h"
|
||||
|
||||
/**
|
||||
\brief Common infrastructure for AST rewriters.
|
||||
|
|
|
@ -16,8 +16,9 @@ Author:
|
|||
Notes:
|
||||
|
||||
--*/
|
||||
#include"rewriter.h"
|
||||
#include"ast_smt2_pp.h"
|
||||
#include "ast/rewriter/rewriter.h"
|
||||
#include "ast/ast_smt2_pp.h"
|
||||
#include "ast/ast_ll_pp.h"
|
||||
|
||||
template<typename Config>
|
||||
template<bool ProofGen>
|
||||
|
@ -259,10 +260,10 @@ void rewriter_tpl<Config>::process_app(app * t, frame & fr) {
|
|||
}
|
||||
br_status st = m_cfg.reduce_app(f, new_num_args, new_args, m_r, m_pr2);
|
||||
SASSERT(st != BR_DONE || m().get_sort(m_r) == m().get_sort(t));
|
||||
TRACE("reduce_app",
|
||||
tout << mk_ismt2_pp(t, m()) << "\n";
|
||||
CTRACE("reduce_app", st != BR_FAILED,
|
||||
tout << mk_bounded_pp(t, m()) << "\n";
|
||||
tout << "st: " << st;
|
||||
if (m_r) tout << " --->\n" << mk_ismt2_pp(m_r, m());
|
||||
if (m_r) tout << " --->\n" << mk_bounded_pp(m_r, m());
|
||||
tout << "\n";);
|
||||
if (st != BR_FAILED) {
|
||||
result_stack().shrink(fr.m_spos);
|
||||
|
@ -496,6 +497,7 @@ void rewriter_tpl<Config>::process_quantifier(quantifier * q, frame & fr) {
|
|||
expr * const * new_pats;
|
||||
expr * const * new_no_pats;
|
||||
if (rewrite_patterns()) {
|
||||
TRACE("reduce_quantifier_bug", tout << "rewrite patterns\n";);
|
||||
new_pats = it + 1;
|
||||
new_no_pats = new_pats + q->get_num_patterns();
|
||||
}
|
||||
|
@ -518,7 +520,7 @@ void rewriter_tpl<Config>::process_quantifier(quantifier * q, frame & fr) {
|
|||
}
|
||||
else {
|
||||
expr_ref tmp(m());
|
||||
|
||||
TRACE("reduce_quantifier_bug", tout << mk_ismt2_pp(q, m()) << " " << mk_ismt2_pp(new_body, m()) << "\n";);
|
||||
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);
|
||||
|
|
|
@ -9,5 +9,6 @@ def_module_params('rewriter',
|
|||
("pull_cheap_ite", BOOL, False, "pull if-then-else terms when cheap."),
|
||||
("bv_ineq_consistency_test_max", UINT, 0, "max size of conjunctions on which to perform consistency test based on inequalities on bitvectors."),
|
||||
("cache_all", BOOL, False, "cache all intermediate results."),
|
||||
("rewrite_patterns", BOOL, False, "rewrite patterns."),
|
||||
("ignore_patterns_on_ground_qbody", BOOL, True, "ignores patterns on quantifiers that don't mention their bound variables.")))
|
||||
|
||||
|
|
|
@ -19,8 +19,8 @@ Notes:
|
|||
#ifndef REWRITER_TYPES_H_
|
||||
#define REWRITER_TYPES_H_
|
||||
|
||||
#include"z3_exception.h"
|
||||
#include"common_msgs.h"
|
||||
#include "util/z3_exception.h"
|
||||
#include "util/common_msgs.h"
|
||||
|
||||
/**
|
||||
\brief Builtin rewrite result status
|
||||
|
|
|
@ -18,15 +18,16 @@ Notes:
|
|||
|
||||
--*/
|
||||
|
||||
#include"seq_rewriter.h"
|
||||
#include"arith_decl_plugin.h"
|
||||
#include"ast_pp.h"
|
||||
#include"ast_util.h"
|
||||
#include"uint_set.h"
|
||||
#include"automaton.h"
|
||||
#include"well_sorted.h"
|
||||
#include"var_subst.h"
|
||||
#include"symbolic_automata_def.h"
|
||||
#include "ast/rewriter/seq_rewriter.h"
|
||||
#include "ast/arith_decl_plugin.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "ast/ast_util.h"
|
||||
#include "util/uint_set.h"
|
||||
#include "math/automata/automaton.h"
|
||||
#include "ast/well_sorted.h"
|
||||
#include "ast/rewriter/var_subst.h"
|
||||
#include "ast/rewriter/bool_rewriter.h"
|
||||
#include "math/automata/symbolic_automata_def.h"
|
||||
|
||||
|
||||
expr_ref sym_expr::accept(expr* e) {
|
||||
|
@ -102,7 +103,6 @@ public:
|
|||
return sym_expr::mk_pred(fml, x->get_sort());
|
||||
}
|
||||
}
|
||||
|
||||
sort* s = x->get_sort();
|
||||
if (m.is_bool(s)) s = y->get_sort();
|
||||
var_ref v(m.mk_var(0, s), m);
|
||||
|
@ -112,7 +112,10 @@ public:
|
|||
return y;
|
||||
}
|
||||
if (m.is_true(fml2)) return x;
|
||||
expr_ref fml(m.mk_and(fml1, fml2), m);
|
||||
if (fml1 == fml2) return x;
|
||||
bool_rewriter br(m);
|
||||
expr_ref fml(m);
|
||||
br.mk_and(fml1, fml2, fml);
|
||||
return sym_expr::mk_pred(fml, x->get_sort());
|
||||
}
|
||||
virtual T mk_or(T x, T y) {
|
||||
|
@ -120,12 +123,15 @@ public:
|
|||
x->get_char() == y->get_char()) {
|
||||
return x;
|
||||
}
|
||||
if (x == y) return x;
|
||||
var_ref v(m.mk_var(0, x->get_sort()), m);
|
||||
expr_ref fml1 = x->accept(v);
|
||||
expr_ref fml2 = y->accept(v);
|
||||
if (m.is_false(fml1)) return y;
|
||||
if (m.is_false(fml2)) return x;
|
||||
expr_ref fml(m.mk_or(fml1, fml2), m);
|
||||
bool_rewriter br(m);
|
||||
expr_ref fml(m);
|
||||
br.mk_or(fml1, fml2, fml);
|
||||
return sym_expr::mk_pred(fml, x->get_sort());
|
||||
}
|
||||
|
||||
|
@ -197,10 +203,10 @@ void re2automaton::set_solver(expr_solver* solver) {
|
|||
|
||||
eautomaton* re2automaton::operator()(expr* e) {
|
||||
eautomaton* r = re2aut(e);
|
||||
if (r) {
|
||||
display_expr1 disp(m);
|
||||
if (r) {
|
||||
r->compress();
|
||||
TRACE("seq", r->display(tout, disp););
|
||||
bool_rewriter br(m);
|
||||
TRACE("seq", display_expr1 disp(m); r->display(tout, disp););
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
@ -597,6 +603,45 @@ br_status seq_rewriter::mk_seq_extract(expr* a, expr* b, expr* c, expr_ref& resu
|
|||
return BR_FAILED;
|
||||
}
|
||||
|
||||
bool seq_rewriter::cannot_contain_suffix(expr* a, expr* b) {
|
||||
|
||||
if (m_util.str.is_unit(a) && m_util.str.is_unit(b) && m().are_distinct(a, b)) {
|
||||
return true;
|
||||
}
|
||||
zstring A, B;
|
||||
if (m_util.str.is_string(a, A) && m_util.str.is_string(b, B)) {
|
||||
// some prefix of a is a suffix of b
|
||||
bool found = false;
|
||||
for (unsigned i = 1; !found && i <= A.length(); ++i) {
|
||||
found = A.extract(0, i).suffixof(B);
|
||||
}
|
||||
return !found;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool seq_rewriter::cannot_contain_prefix(expr* a, expr* b) {
|
||||
|
||||
if (m_util.str.is_unit(a) && m_util.str.is_unit(b) && m().are_distinct(a, b)) {
|
||||
return true;
|
||||
}
|
||||
zstring A, B;
|
||||
if (m_util.str.is_string(a, A) && m_util.str.is_string(b, B)) {
|
||||
// some suffix of a is a prefix of b
|
||||
bool found = false;
|
||||
for (unsigned i = 0; !found && i < A.length(); ++i) {
|
||||
found = A.extract(i, A.length()-i).suffixof(B);
|
||||
}
|
||||
return !found;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) {
|
||||
zstring c, d;
|
||||
if (m_util.str.is_string(a, c) && m_util.str.is_string(b, d)) {
|
||||
|
@ -608,6 +653,7 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) {
|
|||
m_util.str.get_concat(a, as);
|
||||
m_util.str.get_concat(b, bs);
|
||||
bool all_values = true;
|
||||
TRACE("seq", tout << mk_pp(a, m()) << " contains " << mk_pp(b, m()) << "\n";);
|
||||
|
||||
if (bs.empty()) {
|
||||
result = m().mk_true();
|
||||
|
@ -652,12 +698,21 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) {
|
|||
return BR_REWRITE2;
|
||||
}
|
||||
|
||||
if (bs.size() == 1 && m_util.str.is_string(bs[0].get(), c)) {
|
||||
for (auto a_i : as) {
|
||||
if (m_util.str.is_string(a_i, d) && d.contains(c)) {
|
||||
result = m().mk_true();
|
||||
return BR_DONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned offs = 0;
|
||||
unsigned sz = as.size();
|
||||
expr* b0 = bs[0].get();
|
||||
expr* bL = bs[bs.size()-1].get();
|
||||
for (; offs < as.size() && m().are_distinct(b0, as[offs].get()); ++offs) {};
|
||||
for (; sz > offs && m().are_distinct(bL, as[sz-1].get()); --sz) {}
|
||||
for (; offs < as.size() && cannot_contain_prefix(as[offs].get(), b0); ++offs) {}
|
||||
for (; sz > offs && cannot_contain_suffix(as[sz-1].get(), bL); --sz) {}
|
||||
if (offs == sz) {
|
||||
result = m().mk_eq(b, m_util.str.mk_empty(m().get_sort(b)));
|
||||
return BR_REWRITE2;
|
||||
|
@ -815,11 +870,11 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) {
|
|||
expr_ref_vector as(m()), bs(m());
|
||||
|
||||
if (a1 != b1 && isc1 && isc2) {
|
||||
TRACE("seq", tout << s1 << " " << s2 << "\n";);
|
||||
if (s1.length() <= s2.length()) {
|
||||
if (s1.prefixof(s2)) {
|
||||
if (a == a1) {
|
||||
result = m().mk_true();
|
||||
TRACE("seq", tout << s1 << " " << s2 << " " << result << "\n";);
|
||||
return BR_DONE;
|
||||
}
|
||||
m_util.str.get_concat(a, as);
|
||||
|
@ -829,10 +884,12 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) {
|
|||
bs[0] = m_util.str.mk_string(s2);
|
||||
result = m_util.str.mk_prefix(m_util.str.mk_concat(as.size()-1, as.c_ptr()+1),
|
||||
m_util.str.mk_concat(bs.size(), bs.c_ptr()));
|
||||
TRACE("seq", tout << s1 << " " << s2 << " " << result << "\n";);
|
||||
return BR_REWRITE_FULL;
|
||||
}
|
||||
else {
|
||||
result = m().mk_false();
|
||||
TRACE("seq", tout << s1 << " " << s2 << " " << result << "\n";);
|
||||
return BR_DONE;
|
||||
}
|
||||
}
|
||||
|
@ -840,6 +897,7 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) {
|
|||
if (s2.prefixof(s1)) {
|
||||
if (b == b1) {
|
||||
result = m().mk_false();
|
||||
TRACE("seq", tout << s1 << " " << s2 << " " << result << "\n";);
|
||||
return BR_DONE;
|
||||
}
|
||||
m_util.str.get_concat(a, as);
|
||||
|
@ -849,10 +907,12 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) {
|
|||
as[0] = m_util.str.mk_string(s1);
|
||||
result = m_util.str.mk_prefix(m_util.str.mk_concat(as.size(), as.c_ptr()),
|
||||
m_util.str.mk_concat(bs.size()-1, bs.c_ptr()+1));
|
||||
TRACE("seq", tout << s1 << " " << s2 << " " << result << "\n";);
|
||||
return BR_REWRITE_FULL;
|
||||
}
|
||||
else {
|
||||
result = m().mk_false();
|
||||
TRACE("seq", tout << s1 << " " << s2 << " " << result << "\n";);
|
||||
return BR_DONE;
|
||||
}
|
||||
}
|
||||
|
@ -881,9 +941,6 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) {
|
|||
if (i == as.size()) {
|
||||
result = mk_and(eqs);
|
||||
TRACE("seq", tout << result << "\n";);
|
||||
if (m().is_true(result)) {
|
||||
return BR_DONE;
|
||||
}
|
||||
return BR_REWRITE3;
|
||||
}
|
||||
SASSERT(i < as.size());
|
||||
|
@ -1023,19 +1080,40 @@ br_status seq_rewriter::mk_seq_suffix(expr* a, expr* b, expr_ref& result) {
|
|||
br_status seq_rewriter::mk_str_itos(expr* a, expr_ref& result) {
|
||||
rational r;
|
||||
if (m_autil.is_numeral(a, r)) {
|
||||
result = m_util.str.mk_string(symbol(r.to_string().c_str()));
|
||||
if (r.is_int() && !r.is_neg()) {
|
||||
result = m_util.str.mk_string(symbol(r.to_string().c_str()));
|
||||
}
|
||||
else {
|
||||
result = m_util.str.mk_string(symbol(""));
|
||||
}
|
||||
return BR_DONE;
|
||||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief rewrite str.to.int according to the rules:
|
||||
- if the expression is a string which is a non-empty
|
||||
sequence of digits 0-9 extract the corresponding numeral.
|
||||
- if the expression is a string that contains any other character
|
||||
or is empty, produce -1
|
||||
- if the expression is int.to.str(x) produce
|
||||
ite(x >= 0, x, -1)
|
||||
|
||||
*/
|
||||
br_status seq_rewriter::mk_str_stoi(expr* a, expr_ref& result) {
|
||||
zstring str;
|
||||
if (m_util.str.is_string(a, str)) {
|
||||
std::string s = str.encode();
|
||||
if (s.length() == 0) {
|
||||
result = m_autil.mk_int(-1);
|
||||
return BR_DONE;
|
||||
}
|
||||
for (unsigned i = 0; i < s.length(); ++i) {
|
||||
if (s[i] == '-') { if (i != 0) return BR_FAILED; }
|
||||
else if ('0' <= s[i] && s[i] <= '9') continue;
|
||||
return BR_FAILED;
|
||||
if (!('0' <= s[i] && s[i] <= '9')) {
|
||||
result = m_autil.mk_int(-1);
|
||||
return BR_DONE;
|
||||
}
|
||||
}
|
||||
rational r(s.c_str());
|
||||
result = m_autil.mk_numeral(r, true);
|
||||
|
@ -1043,7 +1121,7 @@ br_status seq_rewriter::mk_str_stoi(expr* a, expr_ref& result) {
|
|||
}
|
||||
expr* b;
|
||||
if (m_util.str.is_itos(a, b)) {
|
||||
result = b;
|
||||
result = m().mk_ite(m_autil.mk_ge(b, m_autil.mk_int(0)), b, m_autil.mk_int(-1));
|
||||
return BR_DONE;
|
||||
}
|
||||
return BR_FAILED;
|
||||
|
@ -1874,7 +1952,7 @@ bool seq_rewriter::solve_itos(unsigned szl, expr* const* ls, unsigned szr, expr*
|
|||
}
|
||||
}
|
||||
|
||||
if (szr == 1 && m_util.str.is_itos(rs[0], r) && !m_util.str.is_itos(ls[0])) {
|
||||
if (szr == 1 && szl >= 1 && m_util.str.is_itos(rs[0], r) && !m_util.str.is_itos(ls[0])) {
|
||||
return solve_itos(szr, rs, szl, ls, rhs, lhs, is_sat);
|
||||
}
|
||||
|
||||
|
@ -1942,6 +2020,7 @@ void seq_rewriter::split_units(expr_ref_vector& lhs, expr_ref_vector& rhs) {
|
|||
}
|
||||
|
||||
|
||||
|
||||
bool seq_rewriter::is_epsilon(expr* e) const {
|
||||
expr* e1;
|
||||
return m_util.re.is_to_re(e, e1) && m_util.str.is_empty(e1);
|
||||
|
|
|
@ -19,13 +19,13 @@ Notes:
|
|||
#ifndef SEQ_REWRITER_H_
|
||||
#define SEQ_REWRITER_H_
|
||||
|
||||
#include"seq_decl_plugin.h"
|
||||
#include"arith_decl_plugin.h"
|
||||
#include"rewriter_types.h"
|
||||
#include"params.h"
|
||||
#include"lbool.h"
|
||||
#include"automaton.h"
|
||||
#include"symbolic_automata.h"
|
||||
#include "ast/seq_decl_plugin.h"
|
||||
#include "ast/arith_decl_plugin.h"
|
||||
#include "ast/rewriter/rewriter_types.h"
|
||||
#include "util/params.h"
|
||||
#include "util/lbool.h"
|
||||
#include "math/automata/automaton.h"
|
||||
#include "math/automata/symbolic_automata.h"
|
||||
|
||||
class sym_expr {
|
||||
enum ty {
|
||||
|
@ -122,6 +122,9 @@ class seq_rewriter {
|
|||
br_status mk_re_loop(unsigned num_args, expr* const* args, expr_ref& result);
|
||||
br_status mk_re_range(expr* lo, expr* hi, expr_ref& result);
|
||||
|
||||
bool cannot_contain_prefix(expr* a, expr* b);
|
||||
bool cannot_contain_suffix(expr* a, expr* b);
|
||||
|
||||
bool set_empty(unsigned sz, expr* const* es, bool all, expr_ref_vector& lhs, expr_ref_vector& rhs);
|
||||
bool is_subsequence(unsigned n, expr* const* l, unsigned m, expr* const* r,
|
||||
expr_ref_vector& lhs, expr_ref_vector& rhs, bool& is_sat);
|
||||
|
|
|
@ -16,24 +16,24 @@ Author:
|
|||
Notes:
|
||||
|
||||
--*/
|
||||
#include"th_rewriter.h"
|
||||
#include"rewriter_params.hpp"
|
||||
#include"bool_rewriter.h"
|
||||
#include"arith_rewriter.h"
|
||||
#include"bv_rewriter.h"
|
||||
#include"datatype_rewriter.h"
|
||||
#include"array_rewriter.h"
|
||||
#include"fpa_rewriter.h"
|
||||
#include"dl_rewriter.h"
|
||||
#include"pb_rewriter.h"
|
||||
#include"seq_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"
|
||||
#include "ast/rewriter/th_rewriter.h"
|
||||
#include "ast/rewriter/rewriter_params.hpp"
|
||||
#include "ast/rewriter/bool_rewriter.h"
|
||||
#include "ast/rewriter/arith_rewriter.h"
|
||||
#include "ast/rewriter/bv_rewriter.h"
|
||||
#include "ast/rewriter/datatype_rewriter.h"
|
||||
#include "ast/rewriter/array_rewriter.h"
|
||||
#include "ast/rewriter/fpa_rewriter.h"
|
||||
#include "ast/rewriter/dl_rewriter.h"
|
||||
#include "ast/rewriter/pb_rewriter.h"
|
||||
#include "ast/rewriter/seq_rewriter.h"
|
||||
#include "ast/rewriter/rewriter_def.h"
|
||||
#include "ast/expr_substitution.h"
|
||||
#include "ast/ast_smt2_pp.h"
|
||||
#include "util/cooperate.h"
|
||||
#include "ast/rewriter/var_subst.h"
|
||||
#include "ast/ast_util.h"
|
||||
#include "ast/well_sorted.h"
|
||||
|
||||
struct th_rewriter_cfg : public default_rewriter_cfg {
|
||||
bool_rewriter m_b_rw;
|
||||
|
@ -55,6 +55,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
|
|||
bool m_push_ite_arith;
|
||||
bool m_push_ite_bv;
|
||||
bool m_ignore_patterns_on_ground_qbody;
|
||||
bool m_rewrite_patterns;
|
||||
|
||||
// substitution support
|
||||
expr_dependency_ref m_used_dependencies; // set of dependencies of used substitutions
|
||||
|
@ -72,6 +73,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
|
|||
m_push_ite_arith = p.push_ite_arith();
|
||||
m_push_ite_bv = p.push_ite_bv();
|
||||
m_ignore_patterns_on_ground_qbody = p.ignore_patterns_on_ground_qbody();
|
||||
m_rewrite_patterns = p.rewrite_patterns();
|
||||
}
|
||||
|
||||
void updt_params(params_ref const & p) {
|
||||
|
@ -99,7 +101,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool rewrite_patterns() const { return false; }
|
||||
bool rewrite_patterns() const { return m_rewrite_patterns; }
|
||||
|
||||
bool cache_all_results() const { return m_cache_all; }
|
||||
|
||||
|
@ -734,6 +736,7 @@ ast_manager & th_rewriter::m() const {
|
|||
void th_rewriter::updt_params(params_ref const & p) {
|
||||
m_params = p;
|
||||
m_imp->cfg().updt_params(p);
|
||||
IF_VERBOSE(10, verbose_stream() << p << "\n";);
|
||||
}
|
||||
|
||||
void th_rewriter::get_param_descrs(param_descrs & r) {
|
||||
|
|
|
@ -19,9 +19,9 @@ Notes:
|
|||
#ifndef TH_REWRITER_H_
|
||||
#define TH_REWRITER_H_
|
||||
|
||||
#include"ast.h"
|
||||
#include"rewriter_types.h"
|
||||
#include"params.h"
|
||||
#include "ast/ast.h"
|
||||
#include "ast/rewriter/rewriter_types.h"
|
||||
#include "util/params.h"
|
||||
|
||||
class expr_substitution;
|
||||
|
||||
|
|
|
@ -16,12 +16,12 @@ Author:
|
|||
Notes:
|
||||
|
||||
--*/
|
||||
#include"var_subst.h"
|
||||
#include"ast_ll_pp.h"
|
||||
#include"ast_pp.h"
|
||||
#include"ast_smt2_pp.h"
|
||||
#include"well_sorted.h"
|
||||
#include"for_each_expr.h"
|
||||
#include "ast/rewriter/var_subst.h"
|
||||
#include "ast/ast_ll_pp.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "ast/ast_smt2_pp.h"
|
||||
#include "ast/well_sorted.h"
|
||||
#include "ast/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));
|
||||
|
|
|
@ -19,9 +19,9 @@ Notes:
|
|||
#ifndef VAR_SUBST_H_
|
||||
#define VAR_SUBST_H_
|
||||
|
||||
#include"rewriter.h"
|
||||
#include"used_vars.h"
|
||||
#include"params.h"
|
||||
#include "ast/rewriter/rewriter.h"
|
||||
#include "ast/used_vars.h"
|
||||
#include "util/params.h"
|
||||
|
||||
/**
|
||||
\brief Alias for var_shifter class.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue