mirror of
https://github.com/Z3Prover/z3
synced 2025-04-23 09:05:31 +00:00
Merge branch 'master' into polysat
This commit is contained in:
commit
f54f33551e
308 changed files with 6606 additions and 18485 deletions
|
@ -365,7 +365,6 @@ inline func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, bool is_real) {
|
|||
case OP_MOD: return m_i_mod_decl;
|
||||
case OP_DIV0: return m_manager->mk_func_decl(symbol("/0"), m_real_decl, m_real_decl, m_real_decl, func_decl_info(m_family_id, OP_DIV0));
|
||||
case OP_IDIV0: return m_manager->mk_func_decl(symbol("div0"), m_int_decl, m_int_decl, m_int_decl, func_decl_info(m_family_id, OP_IDIV0));
|
||||
case OP_REM0: return m_manager->mk_func_decl(symbol("rem0"), m_int_decl, m_int_decl, m_int_decl, func_decl_info(m_family_id, OP_REM0));
|
||||
case OP_MOD0: return m_manager->mk_func_decl(symbol("mod0"), m_int_decl, m_int_decl, m_int_decl, func_decl_info(m_family_id, OP_MOD0));
|
||||
case OP_POWER0:
|
||||
if (is_real) {
|
||||
|
@ -612,7 +611,6 @@ void arith_decl_plugin::get_op_names(svector<builtin_name>& op_names, symbol con
|
|||
op_names.push_back(builtin_name("euler", OP_E));
|
||||
op_names.push_back(builtin_name("/0",OP_DIV0));
|
||||
op_names.push_back(builtin_name("div0",OP_IDIV0));
|
||||
op_names.push_back(builtin_name("rem0",OP_REM0));
|
||||
op_names.push_back(builtin_name("mod0",OP_MOD0));
|
||||
}
|
||||
}
|
||||
|
@ -821,7 +819,7 @@ bool arith_util::is_considered_uninterpreted(func_decl* f, unsigned n, expr* con
|
|||
}
|
||||
if (is_decl_of(f, arith_family_id, OP_REM) && n == 2 && is_numeral(args[1], r) && r.is_zero()) {
|
||||
sort* rs[2] = { mk_int(), mk_int() };
|
||||
f_out = m_manager.mk_func_decl(arith_family_id, OP_REM0, 0, nullptr, 2, rs, mk_int());
|
||||
f_out = m_manager.mk_func_decl(arith_family_id, OP_MOD0, 0, nullptr, 2, rs, mk_int());
|
||||
return true;
|
||||
}
|
||||
if (is_decl_of(f, arith_family_id, OP_POWER) && n == 2 && is_numeral(args[1], r) && r.is_zero() && is_numeral(args[0], r) && r.is_zero()) {
|
||||
|
@ -857,7 +855,7 @@ func_decl* arith_util::mk_idiv0() {
|
|||
|
||||
func_decl* arith_util::mk_rem0() {
|
||||
sort* rs[2] = { mk_int(), mk_int() };
|
||||
return m_manager.mk_func_decl(arith_family_id, OP_REM0, 0, nullptr, 2, rs, mk_int());
|
||||
return m_manager.mk_func_decl(arith_family_id, OP_MOD0, 0, nullptr, 2, rs, mk_int());
|
||||
}
|
||||
|
||||
func_decl* arith_util::mk_mod0() {
|
||||
|
@ -942,7 +940,6 @@ bool arith_util::is_underspecified(expr* e) const {
|
|||
case OP_MOD:
|
||||
case OP_DIV0:
|
||||
case OP_IDIV0:
|
||||
case OP_REM0:
|
||||
case OP_MOD0:
|
||||
return true;
|
||||
default:
|
||||
|
|
|
@ -50,7 +50,6 @@ enum arith_op_kind {
|
|||
OP_IDIVIDES,
|
||||
OP_REM,
|
||||
OP_MOD,
|
||||
OP_REM0,
|
||||
OP_MOD0,
|
||||
OP_TO_REAL,
|
||||
OP_TO_INT,
|
||||
|
@ -216,7 +215,6 @@ public:
|
|||
case OP_U_ACOS:
|
||||
case OP_DIV0:
|
||||
case OP_IDIV0:
|
||||
case OP_REM0:
|
||||
case OP_MOD0:
|
||||
case OP_POWER0:
|
||||
return true;
|
||||
|
@ -270,7 +268,7 @@ public:
|
|||
|
||||
bool is_div0(func_decl const * n) const { return is_decl_of(n, arith_family_id, OP_DIV0); }
|
||||
bool is_idiv0(func_decl const * n) const { return is_decl_of(n, arith_family_id, OP_IDIV0); }
|
||||
bool is_rem0(func_decl const * n) const { return is_decl_of(n, arith_family_id, OP_REM0); }
|
||||
bool is_rem0(func_decl const * n) const { return is_decl_of(n, arith_family_id, OP_MOD0); }
|
||||
bool is_mod0(func_decl const * n) const { return is_decl_of(n, arith_family_id, OP_MOD0); }
|
||||
bool is_power0(func_decl const * n) const { return is_decl_of(n, arith_family_id, OP_POWER0); }
|
||||
bool is_power(func_decl const * n) const { return is_decl_of(n, arith_family_id, OP_POWER); }
|
||||
|
@ -296,7 +294,7 @@ public:
|
|||
bool is_mod(expr const * n) const { return is_app_of(n, arith_family_id, OP_MOD); }
|
||||
bool is_rem(expr const * n) const { return is_app_of(n, arith_family_id, OP_REM); }
|
||||
bool is_mod0(expr const * n) const { return is_app_of(n, arith_family_id, OP_MOD0); }
|
||||
bool is_rem0(expr const * n) const { return is_app_of(n, arith_family_id, OP_REM0); }
|
||||
bool is_rem0(expr const * n) const { return is_app_of(n, arith_family_id, OP_MOD0); }
|
||||
bool is_to_real(expr const * n) const { return is_app_of(n, arith_family_id, OP_TO_REAL); }
|
||||
bool is_to_int(expr const * n) const { return is_app_of(n, arith_family_id, OP_TO_INT); }
|
||||
bool is_is_int(expr const * n) const { return is_app_of(n, arith_family_id, OP_IS_INT); }
|
||||
|
@ -355,7 +353,7 @@ public:
|
|||
MATCH_BINARY(is_div);
|
||||
MATCH_BINARY(is_idiv);
|
||||
MATCH_BINARY(is_mod0);
|
||||
MATCH_BINARY(is_rem0);
|
||||
// MATCH_BINARY(is_rem0);
|
||||
MATCH_BINARY(is_div0);
|
||||
MATCH_BINARY(is_idiv0);
|
||||
MATCH_BINARY(is_power);
|
||||
|
@ -465,7 +463,7 @@ public:
|
|||
app * mk_mod(expr * arg1, expr * arg2) { return m_manager.mk_app(arith_family_id, OP_MOD, arg1, arg2); }
|
||||
app * mk_div0(expr * arg1, expr * arg2) { return m_manager.mk_app(arith_family_id, OP_DIV0, arg1, arg2); }
|
||||
app * mk_idiv0(expr * arg1, expr * arg2) { return m_manager.mk_app(arith_family_id, OP_IDIV0, arg1, arg2); }
|
||||
app * mk_rem0(expr * arg1, expr * arg2) { return m_manager.mk_app(arith_family_id, OP_REM0, arg1, arg2); }
|
||||
app * mk_rem0(expr * arg1, expr * arg2) { return m_manager.mk_app(arith_family_id, OP_MOD0, arg1, arg2); }
|
||||
app * mk_mod0(expr * arg1, expr * arg2) { return m_manager.mk_app(arith_family_id, OP_MOD0, arg1, arg2); }
|
||||
app * mk_to_real(expr * arg1) { return m_manager.mk_app(arith_family_id, OP_TO_REAL, arg1); }
|
||||
app * mk_to_int(expr * arg1) { return m_manager.mk_app(arith_family_id, OP_TO_INT, arg1); }
|
||||
|
|
|
@ -315,13 +315,13 @@ func_decl * array_decl_plugin::mk_store(unsigned arity, sort * const * domain) {
|
|||
|
||||
func_decl * array_decl_plugin::mk_array_ext(unsigned arity, sort * const * domain, unsigned i) {
|
||||
if (arity != 2 || domain[0] != domain[1]) {
|
||||
UNREACHABLE();
|
||||
m_manager->raise_exception("incorrect arguments passed to array-ext");
|
||||
return nullptr;
|
||||
}
|
||||
sort * s = domain[0];
|
||||
unsigned num_parameters = s->get_num_parameters();
|
||||
if (num_parameters == 0 || i >= num_parameters - 1) {
|
||||
UNREACHABLE();
|
||||
m_manager->raise_exception("incorrect arguments passed to array-ext");
|
||||
return nullptr;
|
||||
}
|
||||
sort * r = to_sort(s->get_parameter(i).get_ast());
|
||||
|
|
|
@ -2322,6 +2322,14 @@ func_decl * ast_manager::mk_fresh_func_decl(symbol const & prefix, symbol const
|
|||
return d;
|
||||
}
|
||||
|
||||
bool ast_manager::is_parametric_function(func_decl* f, func_decl *& g) const {
|
||||
// is-as-array
|
||||
// is-map
|
||||
// is-transitive-closure
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
sort * ast_manager::mk_fresh_sort(char const * prefix) {
|
||||
string_buffer<32> buffer;
|
||||
buffer << prefix << "!" << m_fresh_id;
|
||||
|
@ -3296,7 +3304,7 @@ proof * ast_manager::mk_redundant_del(expr* e) {
|
|||
return mk_clause_trail_elem(nullptr, e, PR_REDUNDANT_DEL);
|
||||
}
|
||||
|
||||
proof * ast_manager::mk_clause_trail(unsigned n, proof* const* ps) {
|
||||
proof * ast_manager::mk_clause_trail(unsigned n, expr* const* ps) {
|
||||
ptr_buffer<expr> args;
|
||||
args.append(n, (expr**) ps);
|
||||
return mk_app(basic_family_id, PR_CLAUSE_TRAIL, 0, nullptr, args.size(), args.data());
|
||||
|
|
|
@ -180,13 +180,13 @@ public:
|
|||
*/
|
||||
void del_eh(ast_manager & m, family_id fid);
|
||||
|
||||
int get_int() const { return std::get<int>(m_val); }
|
||||
ast * get_ast() const { return std::get<ast*>(m_val); }
|
||||
symbol get_symbol() const { return std::get<symbol>(m_val); }
|
||||
rational const & get_rational() const { return *std::get<rational*>(m_val); }
|
||||
zstring const& get_zstring() const { return *std::get<zstring*>(m_val); }
|
||||
double get_double() const { return std::get<double>(m_val); }
|
||||
unsigned get_ext_id() const { return std::get<unsigned>(m_val); }
|
||||
int get_int() const { SASSERT(is_int()); return std::get<int>(m_val); }
|
||||
ast * get_ast() const { SASSERT(is_ast()); return std::get<ast*>(m_val); }
|
||||
symbol get_symbol() const { SASSERT(is_symbol()); return std::get<symbol>(m_val); }
|
||||
rational const & get_rational() const { SASSERT(is_rational()); return *std::get<rational*>(m_val); }
|
||||
zstring const& get_zstring() const { SASSERT(is_zstring()); return *std::get<zstring*>(m_val); }
|
||||
double get_double() const { SASSERT(is_double()); return std::get<double>(m_val); }
|
||||
unsigned get_ext_id() const { SASSERT(is_external()); return std::get<unsigned>(m_val); }
|
||||
|
||||
bool operator==(parameter const & p) const;
|
||||
bool operator!=(parameter const & p) const { return !operator==(p); }
|
||||
|
@ -1924,6 +1924,8 @@ public:
|
|||
return mk_fresh_func_decl(symbol(prefix), symbol::null, arity, domain, range, skolem);
|
||||
}
|
||||
|
||||
bool is_parametric_function(func_decl* f, func_decl *& g) const;
|
||||
|
||||
app * mk_fresh_const(char const * prefix, sort * s, bool skolem = true) {
|
||||
return mk_const(mk_fresh_func_decl(prefix, 0, nullptr, s, skolem));
|
||||
}
|
||||
|
@ -2335,7 +2337,7 @@ public:
|
|||
proof * mk_th_assumption_add(proof* pr, expr* e);
|
||||
proof * mk_th_lemma_add(proof* pr, expr* e);
|
||||
proof * mk_redundant_del(expr* e);
|
||||
proof * mk_clause_trail(unsigned n, proof* const* ps);
|
||||
proof * mk_clause_trail(unsigned n, expr* const* ps);
|
||||
|
||||
proof * mk_def_axiom(expr * ax);
|
||||
proof * mk_unit_resolution(unsigned num_proofs, proof * const * proofs);
|
||||
|
|
|
@ -43,11 +43,11 @@ void ast_pp_util::display_decls(std::ostream& out) {
|
|||
for (unsigned i = m_sorts; i < n; ++i)
|
||||
pp.display_sort_decl(out, coll.get_sorts()[i], seen);
|
||||
m_sorts = n;
|
||||
|
||||
|
||||
n = coll.get_num_decls();
|
||||
for (unsigned i = m_decls; i < n; ++i) {
|
||||
func_decl* f = coll.get_func_decls()[i];
|
||||
if (f->get_family_id() == null_family_id && !m_removed.contains(f))
|
||||
if (coll.should_declare(f) && !m_removed.contains(f))
|
||||
ast_smt2_pp(out, f, m_env) << "\n";
|
||||
}
|
||||
m_decls = n;
|
||||
|
@ -80,7 +80,7 @@ void ast_pp_util::display_skolem_decls(std::ostream& out) {
|
|||
unsigned n = coll.get_num_decls();
|
||||
for (unsigned i = m_decls; i < n; ++i) {
|
||||
func_decl* f = coll.get_func_decls()[i];
|
||||
if (f->get_family_id() == null_family_id && !m_removed.contains(f) && f->is_skolem())
|
||||
if (coll.should_declare(f) && !m_removed.contains(f) && f->is_skolem())
|
||||
ast_smt2_pp(out, f, m_env) << "\n";
|
||||
}
|
||||
m_decls = n;
|
||||
|
|
|
@ -121,8 +121,10 @@ format * smt2_pp_environment::pp_fdecl_params(format * fname, func_decl * f) {
|
|||
std::string str = f->get_parameter(i).get_rational().to_string();
|
||||
fs.push_back(mk_string(get_manager(), str));
|
||||
}
|
||||
else
|
||||
fs.push_back(pp_fdecl_ref(to_func_decl(f->get_parameter(i).get_ast())));
|
||||
else {
|
||||
unsigned len;
|
||||
fs.push_back(pp_fdecl_name(to_func_decl(f->get_parameter(i).get_ast()), len));
|
||||
}
|
||||
}
|
||||
return mk_seq1(get_manager(), fs.begin(), fs.end(), f2f(), "_");
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ Revision History:
|
|||
#include "ast/for_each_ast.h"
|
||||
#include "ast/decl_collector.h"
|
||||
#include "math/polynomial/algebraic_numbers.h"
|
||||
#include "ast/pp_params.hpp"
|
||||
|
||||
|
||||
// ---------------------------------------
|
||||
|
@ -911,7 +912,9 @@ ast_smt_pp::ast_smt_pp(ast_manager& m):
|
|||
void ast_smt_pp::display_expr_smt2(std::ostream& strm, expr* n, unsigned indent, unsigned num_var_names, char const* const* var_names) {
|
||||
ptr_vector<quantifier> ql;
|
||||
smt_renaming rn;
|
||||
smt_printer p(strm, m_manager, ql, rn, m_logic, false, m_simplify_implies, indent, num_var_names, var_names);
|
||||
pp_params params;
|
||||
bool no_lets = params.no_lets();
|
||||
smt_printer p(strm, m_manager, ql, rn, m_logic, no_lets, m_simplify_implies, indent, num_var_names, var_names);
|
||||
p(n);
|
||||
}
|
||||
|
||||
|
|
|
@ -118,9 +118,22 @@ void bv_decl_plugin::finalize() {
|
|||
DEC_REF(m_bv_redand);
|
||||
DEC_REF(m_bv_comp);
|
||||
|
||||
DEC_REF(m_bv_mul_no_ovfl);
|
||||
DEC_REF(m_bv_smul_no_ovfl);
|
||||
DEC_REF(m_bv_smul_no_udfl);
|
||||
|
||||
DEC_REF(m_bv_mul_ovfl);
|
||||
DEC_REF(m_bv_smul_ovfl);
|
||||
DEC_REF(m_bv_smul_udfl);
|
||||
|
||||
DEC_REF(m_bv_neg_ovfl);
|
||||
|
||||
DEC_REF(m_bv_uadd_ovfl);
|
||||
DEC_REF(m_bv_sadd_ovfl);
|
||||
|
||||
DEC_REF(m_bv_usub_ovfl);
|
||||
DEC_REF(m_bv_ssub_ovfl);
|
||||
|
||||
DEC_REF(m_bv_sdiv_ovfl);
|
||||
|
||||
DEC_REF(m_bv_shl);
|
||||
DEC_REF(m_bv_lshr);
|
||||
|
@ -245,6 +258,16 @@ func_decl * bv_decl_plugin::mk_bv2int(unsigned bv_size, unsigned num_parameters,
|
|||
return m_bv2int[bv_size];
|
||||
}
|
||||
|
||||
func_decl * bv_decl_plugin::mk_unary_pred(ptr_vector<func_decl> & decls, decl_kind k, char const * name, unsigned bv_size) {
|
||||
force_ptr_array_size(decls, bv_size+1);
|
||||
|
||||
if (decls[bv_size] == 0) {
|
||||
decls[bv_size] = m_manager->mk_func_decl(symbol(name), get_bv_sort(bv_size), m_manager->mk_bool_sort(), func_decl_info(m_family_id, k));
|
||||
m_manager->inc_ref(decls[bv_size]);
|
||||
}
|
||||
return decls[bv_size];
|
||||
}
|
||||
|
||||
func_decl * bv_decl_plugin::mk_pred(ptr_vector<func_decl> & decls, decl_kind k, char const * name, unsigned bv_size) {
|
||||
force_ptr_array_size(decls, bv_size + 1);
|
||||
|
||||
|
@ -289,6 +312,7 @@ func_decl * bv_decl_plugin::mk_comp(unsigned bv_size) {
|
|||
func_decl * bv_decl_plugin::mk_func_decl(decl_kind k, unsigned bv_size) {
|
||||
switch (k) {
|
||||
case OP_BNEG: return mk_unary(m_bv_neg, k, "bvneg", bv_size);
|
||||
case OP_BNEG_OVFL: return mk_unary_pred(m_bv_neg_ovfl, k, "bvnego", bv_size);
|
||||
case OP_BADD: return mk_binary(m_bv_add, k, "bvadd", bv_size, true);
|
||||
case OP_BSUB: return mk_binary(m_bv_sub, k, "bvsub", bv_size, false);
|
||||
case OP_BMUL: return mk_binary(m_bv_mul, k, "bvmul", bv_size, true);
|
||||
|
@ -327,9 +351,16 @@ func_decl * bv_decl_plugin::mk_func_decl(decl_kind k, unsigned bv_size) {
|
|||
case OP_BREDOR: return mk_reduction(m_bv_redor, k, "bvredor", bv_size);
|
||||
case OP_BREDAND: return mk_reduction(m_bv_redand, k, "bvredand", bv_size);
|
||||
case OP_BCOMP: return mk_comp(bv_size);
|
||||
case OP_BUMUL_NO_OVFL: return mk_pred(m_bv_mul_ovfl, k, "bvumul_noovfl", bv_size);
|
||||
case OP_BSMUL_NO_OVFL: return mk_pred(m_bv_smul_ovfl, k, "bvsmul_noovfl", bv_size);
|
||||
case OP_BSMUL_NO_UDFL: return mk_pred(m_bv_smul_udfl, k, "bvsmul_noudfl", bv_size);
|
||||
case OP_BUMUL_NO_OVFL: return mk_pred(m_bv_mul_no_ovfl, k, "bvumul_noovfl", bv_size);
|
||||
case OP_BSMUL_NO_OVFL: return mk_pred(m_bv_smul_no_ovfl, k, "bvsmul_noovfl", bv_size);
|
||||
case OP_BSMUL_NO_UDFL: return mk_pred(m_bv_smul_no_udfl, k, "bvsmul_noudfl", bv_size);
|
||||
case OP_BUMUL_OVFL: return mk_pred(m_bv_mul_ovfl, k, "bvumulo", bv_size);
|
||||
case OP_BSMUL_OVFL: return mk_pred(m_bv_smul_ovfl, k, "bvsmulo", bv_size);
|
||||
case OP_BSDIV_OVFL: return mk_pred(m_bv_sdiv_ovfl, k, "bvsdivo", bv_size);
|
||||
case OP_BUADD_OVFL: return mk_pred(m_bv_uadd_ovfl, k, "bvuaddo", bv_size);
|
||||
case OP_BSADD_OVFL: return mk_pred(m_bv_sadd_ovfl, k, "bvsaddo", bv_size);
|
||||
case OP_BUSUB_OVFL: return mk_pred(m_bv_usub_ovfl, k, "bvusubo", bv_size);
|
||||
case OP_BSSUB_OVFL: return mk_pred(m_bv_ssub_ovfl, k, "bvssubo", bv_size);
|
||||
|
||||
case OP_BSHL: return mk_binary(m_bv_shl, k, "bvshl", bv_size, false);
|
||||
case OP_BLSHR: return mk_binary(m_bv_lshr, k, "bvlshr", bv_size, false);
|
||||
|
@ -681,10 +712,18 @@ void bv_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol const
|
|||
op_names.push_back(builtin_name("bit1",OP_BIT1));
|
||||
op_names.push_back(builtin_name("bit0",OP_BIT0));
|
||||
op_names.push_back(builtin_name("bvneg",OP_BNEG));
|
||||
op_names.push_back(builtin_name("bvnego", OP_BNEG_OVFL));
|
||||
op_names.push_back(builtin_name("bvadd",OP_BADD));
|
||||
op_names.push_back(builtin_name("bvuaddo",OP_BUADD_OVFL));
|
||||
op_names.push_back(builtin_name("bvsaddo",OP_BSADD_OVFL));
|
||||
op_names.push_back(builtin_name("bvsub",OP_BSUB));
|
||||
op_names.push_back(builtin_name("bvusubo",OP_BUSUB_OVFL));
|
||||
op_names.push_back(builtin_name("bvssubo",OP_BSSUB_OVFL));
|
||||
op_names.push_back(builtin_name("bvmul",OP_BMUL));
|
||||
op_names.push_back(builtin_name("bvumulo",OP_BUMUL_OVFL));
|
||||
op_names.push_back(builtin_name("bvsmulo",OP_BSMUL_OVFL));
|
||||
op_names.push_back(builtin_name("bvsdiv",OP_BSDIV));
|
||||
op_names.push_back(builtin_name("bvsdivo",OP_BSDIV_OVFL));
|
||||
op_names.push_back(builtin_name("bvudiv",OP_BUDIV));
|
||||
op_names.push_back(builtin_name("bvsrem",OP_BSREM));
|
||||
op_names.push_back(builtin_name("bvurem",OP_BUREM));
|
||||
|
|
|
@ -93,6 +93,19 @@ enum bv_op_kind {
|
|||
OP_BSMUL_NO_OVFL, // no signed multiplication overflow predicate
|
||||
OP_BSMUL_NO_UDFL, // no signed multiplication underflow predicate
|
||||
|
||||
OP_BUMUL_OVFL, // unsigned multiplication overflow predicate (negation of OP_BUMUL_NO_OVFL)
|
||||
OP_BSMUL_OVFL, // signed multiplication over/underflow predicate
|
||||
|
||||
OP_BSDIV_OVFL, // signed division overflow perdicate
|
||||
|
||||
OP_BNEG_OVFL, // negation overflow predicate
|
||||
|
||||
OP_BUADD_OVFL, // unsigned addition overflow predicate
|
||||
OP_BSADD_OVFL, // signed addition overflow predicate
|
||||
|
||||
OP_BUSUB_OVFL, // unsigned subtraction overflow predicate
|
||||
OP_BSSUB_OVFL, // signed subtraction overflow predicate
|
||||
|
||||
OP_BIT2BOOL, // predicate
|
||||
OP_MKBV, // bools to bv
|
||||
OP_INT2BV,
|
||||
|
@ -189,9 +202,22 @@ protected:
|
|||
ptr_vector<func_decl> m_bv_redand;
|
||||
ptr_vector<func_decl> m_bv_comp;
|
||||
|
||||
ptr_vector<func_decl> m_bv_mul_ovfl;
|
||||
ptr_vector<func_decl> m_bv_smul_ovfl;
|
||||
ptr_vector<func_decl> m_bv_smul_udfl;
|
||||
ptr_vector<func_decl> m_bv_mul_no_ovfl;
|
||||
ptr_vector<func_decl> m_bv_smul_no_ovfl;
|
||||
ptr_vector<func_decl> m_bv_smul_no_udfl;
|
||||
|
||||
ptr_vector<func_decl> m_bv_mul_ovfl;
|
||||
ptr_vector<func_decl> m_bv_smul_ovfl;
|
||||
|
||||
ptr_vector<func_decl> m_bv_sdiv_ovfl;
|
||||
|
||||
ptr_vector<func_decl> m_bv_neg_ovfl;
|
||||
|
||||
ptr_vector<func_decl> m_bv_uadd_ovfl;
|
||||
ptr_vector<func_decl> m_bv_sadd_ovfl;
|
||||
|
||||
ptr_vector<func_decl> m_bv_usub_ovfl;
|
||||
ptr_vector<func_decl> m_bv_ssub_ovfl;
|
||||
|
||||
ptr_vector<func_decl> m_bv_shl;
|
||||
ptr_vector<func_decl> m_bv_lshr;
|
||||
|
@ -213,6 +239,7 @@ protected:
|
|||
func_decl * mk_unary(ptr_vector<func_decl> & decls, decl_kind k, char const * name, unsigned bv_size);
|
||||
func_decl * mk_pred(ptr_vector<func_decl> & decls, decl_kind k,
|
||||
char const * name, unsigned bv_size);
|
||||
func_decl * mk_unary_pred(ptr_vector<func_decl> & decls, decl_kind k, char const * name, unsigned bv_size);
|
||||
func_decl * mk_reduction(ptr_vector<func_decl> & decls, decl_kind k, char const * name, unsigned bv_size);
|
||||
func_decl * mk_comp(unsigned bv_size);
|
||||
bool get_bv_size(sort * t, int & result);
|
||||
|
@ -490,9 +517,19 @@ public:
|
|||
|
||||
app * mk_bv2int(expr* e);
|
||||
|
||||
// TODO: all these binary ops commute (right?) but it'd be more logical to swap `n` & `m` in the `return`
|
||||
app * mk_bvsmul_no_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BSMUL_NO_OVFL, n, m); }
|
||||
app * mk_bvsmul_no_udfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BSMUL_NO_UDFL, n, m); }
|
||||
app * mk_bvumul_no_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BUMUL_NO_OVFL, n, m); }
|
||||
app * mk_bvsmul_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BSMUL_OVFL, n, m); }
|
||||
app * mk_bvumul_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BUMUL_OVFL, n, m); }
|
||||
app * mk_bvsdiv_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BSDIV_OVFL, m, n); }
|
||||
app * mk_bvneg_ovfl(expr* m) { return m_manager.mk_app(get_fid(), OP_BNEG_OVFL, m); }
|
||||
app * mk_bvuadd_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BUADD_OVFL, n, m); }
|
||||
app * mk_bvsadd_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BSADD_OVFL, n, m); }
|
||||
app * mk_bvusub_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BUSUB_OVFL, m, n); }
|
||||
app * mk_bvssub_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BSSUB_OVFL, m, n); }
|
||||
|
||||
app * mk_bit2bool(expr* e, unsigned idx) { parameter p(idx); return m_manager.mk_app(get_fid(), OP_BIT2BOOL, 1, &p, 1, &e); }
|
||||
|
||||
private:
|
||||
|
|
|
@ -19,6 +19,7 @@ Author:
|
|||
#include "ast/ast_ll_pp.h"
|
||||
#include "ast/ast_util.h"
|
||||
#include "ast/arith_decl_plugin.h"
|
||||
#include "ast/seq_decl_plugin.h"
|
||||
#include "ast/converters/expr_inverter.h"
|
||||
|
||||
class basic_expr_inverter : public iexpr_inverter {
|
||||
|
@ -742,6 +743,54 @@ public:
|
|||
};
|
||||
|
||||
|
||||
class seq_expr_inverter : public iexpr_inverter {
|
||||
seq_util seq;
|
||||
public:
|
||||
seq_expr_inverter(ast_manager& m) : iexpr_inverter(m), seq(m) {}
|
||||
|
||||
family_id get_fid() const override { return seq.get_family_id(); }
|
||||
|
||||
bool operator()(func_decl* f, unsigned num, expr* const* args, expr_ref& r) override {
|
||||
switch (f->get_decl_kind()) {
|
||||
case _OP_STRING_CONCAT:
|
||||
case OP_SEQ_CONCAT: {
|
||||
expr* x, *y;
|
||||
|
||||
if (uncnstr(args[0]) && num == 2 &&
|
||||
args[1]->get_ref_count() == 1 &&
|
||||
seq.str.is_concat(args[1], x, y) &&
|
||||
uncnstr(x)) {
|
||||
mk_fresh_uncnstr_var_for(f, r);
|
||||
if (m_mc) {
|
||||
add_def(args[0], seq.str.mk_empty(args[0]->get_sort()));
|
||||
add_def(x, r);
|
||||
}
|
||||
r = seq.str.mk_concat(r, y);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!uncnstr(num, args))
|
||||
return false;
|
||||
mk_fresh_uncnstr_var_for(f, r);
|
||||
if (m_mc) {
|
||||
add_def(args[0], r);
|
||||
for (unsigned i = 1; i < num; ++i)
|
||||
add_def(args[i], seq.str.mk_empty(args[0]->get_sort()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool mk_diff(expr* t, expr_ref& r) override {
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
expr_inverter::~expr_inverter() {
|
||||
for (auto* v : m_inverters)
|
||||
|
@ -796,6 +845,7 @@ expr_inverter::expr_inverter(ast_manager& m): iexpr_inverter(m) {
|
|||
add(alloc(array_expr_inverter, m, *this));
|
||||
add(alloc(dt_expr_inverter, m));
|
||||
add(alloc(basic_expr_inverter, m, *this));
|
||||
add(alloc(seq_expr_inverter, m));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ Revision History:
|
|||
void decl_collector::visit_sort(sort * n) {
|
||||
SASSERT(!m_visited.is_marked(n));
|
||||
family_id fid = n->get_family_id();
|
||||
if (m().is_uninterp(n))
|
||||
if (m.is_uninterp(n))
|
||||
m_sorts.push_back(n);
|
||||
else if (fid == m_dt_fid) {
|
||||
m_sorts.push_back(n);
|
||||
|
@ -43,7 +43,7 @@ void decl_collector::visit_sort(sort * n) {
|
|||
}
|
||||
|
||||
bool decl_collector::is_bool(sort * s) {
|
||||
return m().is_bool(s);
|
||||
return m.is_bool(s);
|
||||
}
|
||||
|
||||
void decl_collector::visit_func(func_decl * n) {
|
||||
|
@ -51,10 +51,10 @@ void decl_collector::visit_func(func_decl * n) {
|
|||
|
||||
if (!m_visited.is_marked(n)) {
|
||||
family_id fid = n->get_family_id();
|
||||
if (fid == null_family_id)
|
||||
if (should_declare(n))
|
||||
m_decls.push_back(n);
|
||||
else if (fid == m_rec_fid) {
|
||||
recfun::util u(m());
|
||||
recfun::util u(m);
|
||||
if (u.has_def(n)) {
|
||||
m_rec_decls.push_back(n);
|
||||
m_todo.push_back(u.get_def(n).get_rhs());
|
||||
|
@ -69,12 +69,17 @@ void decl_collector::visit_func(func_decl * n) {
|
|||
}
|
||||
}
|
||||
|
||||
bool decl_collector::should_declare(func_decl* f) const {
|
||||
return f->get_family_id() == null_family_id || m.is_model_value(f);
|
||||
}
|
||||
|
||||
|
||||
decl_collector::decl_collector(ast_manager & m):
|
||||
m_manager(m),
|
||||
m(m),
|
||||
m_trail(m),
|
||||
m_dt_util(m),
|
||||
m_ar_util(m) {
|
||||
m_basic_fid = m_manager.get_basic_family_id();
|
||||
m_basic_fid = m.get_basic_family_id();
|
||||
m_dt_fid = m_dt_util.get_family_id();
|
||||
recfun::util rec_util(m);
|
||||
m_rec_fid = rec_util.get_family_id();
|
||||
|
@ -83,7 +88,7 @@ decl_collector::decl_collector(ast_manager & m):
|
|||
void decl_collector::visit(ast* n) {
|
||||
if (m_visited.is_marked(n))
|
||||
return;
|
||||
datatype_util util(m());
|
||||
datatype_util util(m);
|
||||
m_todo.push_back(n);
|
||||
while (!m_todo.empty()) {
|
||||
n = m_todo.back();
|
||||
|
|
|
@ -26,7 +26,7 @@ Revision History:
|
|||
#include "ast/array_decl_plugin.h"
|
||||
|
||||
class decl_collector {
|
||||
ast_manager & m_manager;
|
||||
ast_manager & m;
|
||||
lim_svector<sort*> m_sorts;
|
||||
lim_svector<func_decl*> m_decls;
|
||||
lim_svector<func_decl*> m_rec_decls;
|
||||
|
@ -48,10 +48,10 @@ class decl_collector {
|
|||
void collect_deps(top_sort<sort>& st);
|
||||
void collect_deps(sort* s, sort_set& set);
|
||||
|
||||
|
||||
public:
|
||||
decl_collector(ast_manager & m);
|
||||
ast_manager & m() { return m_manager; }
|
||||
|
||||
bool should_declare(func_decl* f) const;
|
||||
|
||||
void reset() { m_sorts.reset(); m_decls.reset(); m_visited.reset(); m_trail.reset(); }
|
||||
void visit_func(func_decl* n);
|
||||
|
|
|
@ -47,6 +47,8 @@ struct dimacs_pp {
|
|||
}
|
||||
for (unsigned j = 0; j < num_lits; j++) {
|
||||
expr * l = lits[j];
|
||||
if (m.is_false(l))
|
||||
continue;
|
||||
if (m.is_not(l))
|
||||
l = to_app(l)->get_arg(0);
|
||||
if (!is_uninterp_const(l))
|
||||
|
@ -101,6 +103,12 @@ struct dimacs_pp {
|
|||
}
|
||||
for (unsigned j = 0; j < num_lits; j++) {
|
||||
expr * l = lits[j];
|
||||
if (m.is_false(l))
|
||||
continue;
|
||||
if (m.is_true(l)) {
|
||||
out << "1 -1 ";
|
||||
continue;
|
||||
}
|
||||
if (m.is_not(l)) {
|
||||
out << "-";
|
||||
l = to_app(l)->get_arg(0);
|
||||
|
|
|
@ -67,6 +67,8 @@ namespace euf {
|
|||
}
|
||||
|
||||
enode_bool_pair egraph::insert_table(enode* p) {
|
||||
TRACE("euf", tout << bpp(p) << "\n");
|
||||
//SASSERT(!m_table.contains_ptr(p));
|
||||
auto rc = m_table.insert(p);
|
||||
p->m_cg = rc.first;
|
||||
return rc;
|
||||
|
@ -280,6 +282,7 @@ namespace euf {
|
|||
if (!m.is_bool(n->get_sort()))
|
||||
return;
|
||||
if (enable_merge_tf != n->merge_tf()) {
|
||||
TRACE("euf", tout << "set tf " << enable_merge_tf << " " << bpp(n) << "\n");
|
||||
n->set_merge_tf(enable_merge_tf);
|
||||
m_updates.push_back(update_record(n, update_record::toggle_merge_tf()));
|
||||
}
|
||||
|
@ -487,6 +490,7 @@ namespace euf {
|
|||
}
|
||||
|
||||
void egraph::remove_parents(enode* r) {
|
||||
TRACE("euf", tout << bpp(r) << "\n");
|
||||
for (enode* p : enode_parents(r)) {
|
||||
if (p->is_marked1())
|
||||
continue;
|
||||
|
@ -496,6 +500,7 @@ namespace euf {
|
|||
SASSERT(m_table.contains_ptr(p));
|
||||
p->mark1();
|
||||
erase_from_table(p);
|
||||
CTRACE("euf", m_table.contains_ptr(p), tout << bpp(p) << "\n"; display(tout));
|
||||
SASSERT(!m_table.contains_ptr(p));
|
||||
}
|
||||
else if (p->is_equality())
|
||||
|
|
|
@ -44,6 +44,49 @@ unsigned get_num_exprs(expr * n) {
|
|||
return get_num_exprs(n, visited);
|
||||
}
|
||||
|
||||
|
||||
void get_num_internal_exprs(unsigned_vector& counts, ptr_vector<expr>& todo, expr * n) {
|
||||
counts.reserve(n->get_id() + 1);
|
||||
unsigned& rc = counts[n->get_id()];
|
||||
if (rc > 0) {
|
||||
--rc;
|
||||
return;
|
||||
}
|
||||
rc = n->get_ref_count() - 1;
|
||||
unsigned i = todo.size();
|
||||
todo.push_back(n);
|
||||
for (; i < todo.size(); ++i) {
|
||||
n = todo[i];
|
||||
if (!is_app(n))
|
||||
continue;
|
||||
for (expr* arg : *to_app(n)) {
|
||||
unsigned id = arg->get_id();
|
||||
counts.reserve(id + 1);
|
||||
unsigned& rc = counts[id];
|
||||
if (rc > 0) {
|
||||
--rc;
|
||||
continue;
|
||||
}
|
||||
rc = arg->get_ref_count() - 1;
|
||||
todo.push_back(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned count_internal_nodes(unsigned_vector& counts, ptr_vector<expr>& todo) {
|
||||
unsigned internal_nodes = 0;
|
||||
for (expr* t : todo) {
|
||||
if (counts[t->get_id()] == 0)
|
||||
++internal_nodes;
|
||||
else
|
||||
counts[t->get_id()] = 0;
|
||||
}
|
||||
todo.reset();
|
||||
return internal_nodes;
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace has_skolem_functions_ns {
|
||||
struct found {};
|
||||
struct proc {
|
||||
|
|
|
@ -163,10 +163,13 @@ struct for_each_expr_proc : public EscapeProc {
|
|||
unsigned get_num_exprs(expr * n);
|
||||
unsigned get_num_exprs(expr * n, expr_mark & visited);
|
||||
unsigned get_num_exprs(expr * n, expr_fast_mark1 & visited);
|
||||
void get_num_internal_exprs(unsigned_vector& counts, ptr_vector<expr>& todo, expr * n);
|
||||
unsigned count_internal_nodes(unsigned_vector& counts, ptr_vector<expr>& todo);
|
||||
|
||||
bool has_skolem_functions(expr * n);
|
||||
|
||||
// pre-order traversal of subterms
|
||||
|
||||
class subterms {
|
||||
bool m_include_bound = false;
|
||||
expr_ref_vector m_es;
|
||||
|
|
|
@ -149,7 +149,7 @@ class skolemizer {
|
|||
p = nullptr;
|
||||
if (m_proofs_enabled) {
|
||||
if (q->get_kind() == forall_k)
|
||||
p = m.mk_skolemization(mk_not(m, q), mk_not(m, r));
|
||||
p = m.mk_skolemization(mk_not(m, q), m.mk_not(r));
|
||||
else
|
||||
p = m.mk_skolemization(q, r);
|
||||
}
|
||||
|
|
|
@ -405,6 +405,44 @@ bool pattern_inference_cfg::pattern_weight_lt::operator()(expr * n1, expr * n2)
|
|||
return num_free_vars1 > num_free_vars2 || (num_free_vars1 == num_free_vars2 && i1.m_size < i2.m_size);
|
||||
}
|
||||
|
||||
|
||||
app* pattern_inference_cfg::mk_pattern(app* candidate) {
|
||||
auto has_var_arg = [&](expr* e) {
|
||||
if (!is_app(e))
|
||||
return false;
|
||||
for (expr* arg : *to_app(e))
|
||||
if (is_var(arg))
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
if (has_var_arg(candidate))
|
||||
return m.mk_pattern(candidate);
|
||||
m_args.reset();
|
||||
for (expr* arg : *candidate) {
|
||||
if (!is_app(arg))
|
||||
return m.mk_pattern(candidate);
|
||||
m_args.push_back(to_app(arg));
|
||||
}
|
||||
for (unsigned i = 0; i < m_args.size(); ++i) {
|
||||
app* arg = m_args[i];
|
||||
if (has_var_arg(arg))
|
||||
continue;
|
||||
m_args[i] = m_args.back();
|
||||
--i;
|
||||
m_args.pop_back();
|
||||
|
||||
if (is_ground(arg))
|
||||
continue;
|
||||
|
||||
for (expr* e : *to_app(arg)) {
|
||||
if (!is_app(e))
|
||||
return m.mk_pattern(candidate);
|
||||
m_args.push_back(to_app(e));
|
||||
}
|
||||
}
|
||||
return m.mk_pattern(m_args.size(), m_args.data());
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Create unary patterns (single expressions that contain all
|
||||
bound variables). If a candidate does not contain all bound
|
||||
|
@ -418,7 +456,7 @@ void pattern_inference_cfg::candidates2unary_patterns(ptr_vector<app> const & ca
|
|||
expr2info::obj_map_entry * e = m_candidates_info.find_core(candidate);
|
||||
info const & i = e->get_data().m_value;
|
||||
if (i.m_free_vars.num_elems() == m_num_bindings) {
|
||||
app * new_pattern = m.mk_pattern(candidate);
|
||||
app * new_pattern = mk_pattern(candidate);
|
||||
result.push_back(new_pattern);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -188,6 +188,9 @@ class pattern_inference_cfg : public default_rewriter_cfg {
|
|||
ptr_vector<pre_pattern> m_pre_patterns;
|
||||
expr_pattern_match m_database;
|
||||
|
||||
ptr_buffer<app> m_args;
|
||||
app* mk_pattern(app* candidate);
|
||||
|
||||
void candidates2unary_patterns(ptr_vector<app> const & candidate_patterns,
|
||||
ptr_vector<app> & remaining_candidate_patterns,
|
||||
app_ref_buffer & result);
|
||||
|
|
|
@ -6,6 +6,7 @@ def_module_params('pp',
|
|||
('max_width', UINT, 80, 'max. width in pretty printer'),
|
||||
('max_ribbon', UINT, 80, 'max. ribbon (width - indentation) in pretty printer'),
|
||||
('max_depth', UINT, 5, 'max. term depth (when pretty printing SMT2 terms/formulas)'),
|
||||
('no_lets', BOOL, False, 'dont print lets in low level SMT printer'),
|
||||
('min_alias_size', UINT, 10, 'min. size for creating an alias for a shared term (when pretty printing SMT2 terms/formulas)'),
|
||||
('decimal', BOOL, False, 'pretty print real numbers using decimal notation (the output may be truncated). Z3 adds a ? if the value is not precise'),
|
||||
('decimal_precision', UINT, 10, 'maximum number of decimal places to be used when pp.decimal=true'),
|
||||
|
|
|
@ -492,7 +492,7 @@ namespace recfun {
|
|||
def* plugin::mk_def(replace& subst, bool is_macro,
|
||||
symbol const& name, unsigned n, sort ** params, sort * range,
|
||||
unsigned n_vars, var ** vars, expr * rhs) {
|
||||
promise_def d = mk_def(name, n, params, range);
|
||||
promise_def d = mk_def(name, n, params, range, false);
|
||||
SASSERT(! m_defs.contains(d.get_def()->get_decl()));
|
||||
set_definition(subst, d, is_macro, n_vars, vars, rhs);
|
||||
return d.get_def();
|
||||
|
@ -581,7 +581,7 @@ namespace recfun {
|
|||
}
|
||||
|
||||
symbol fresh_name("fold-rec-" + std::to_string(m().mk_fresh_id()));
|
||||
auto pd = mk_def(fresh_name, n, domain.data(), max_expr->get_sort());
|
||||
auto pd = mk_def(fresh_name, n, domain.data(), max_expr->get_sort(), false);
|
||||
func_decl* f = pd.get_def()->get_decl();
|
||||
expr_ref new_body(m().mk_app(f, n, args.data()), m());
|
||||
set_definition(subst, pd, false, n, vars, max_expr);
|
||||
|
|
|
@ -192,9 +192,9 @@ namespace recfun {
|
|||
|
||||
void get_op_names(svector<builtin_name> & op_names, symbol const & logic) override;
|
||||
|
||||
promise_def mk_def(symbol const& name, unsigned n, sort *const * params, sort * range, bool is_generated = false);
|
||||
promise_def mk_def(symbol const& name, unsigned n, sort *const * params, sort * range, bool is_generated);
|
||||
|
||||
promise_def ensure_def(symbol const& name, unsigned n, sort *const * params, sort * range, bool is_generated = false);
|
||||
promise_def ensure_def(symbol const& name, unsigned n, sort *const * params, sort * range, bool is_generated);
|
||||
|
||||
void set_definition(replace& r, promise_def & d, bool is_macro, unsigned n_vars, var * const * vars, expr * rhs);
|
||||
|
||||
|
@ -248,6 +248,7 @@ namespace recfun {
|
|||
bool is_defined(expr * e) const { return is_app_of(e, m_fid, OP_FUN_DEFINED); }
|
||||
bool is_defined(func_decl* f) const { return is_decl_of(f, m_fid, OP_FUN_DEFINED); }
|
||||
bool is_generated(func_decl* f) const { return is_defined(f) && f->get_parameter(0).get_int() == 1; }
|
||||
bool is_macro(func_decl* f) { return is_defined(f) && get_def(f).is_macro(); }
|
||||
bool is_num_rounds(expr * e) const { return is_app_of(e, m_fid, OP_NUM_ROUNDS); }
|
||||
bool owns_app(app * e) const { return e->get_family_id() == m_fid; }
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ Author:
|
|||
Notes:
|
||||
|
||||
--*/
|
||||
|
||||
#include "params/arith_rewriter_params.hpp"
|
||||
#include "ast/rewriter/arith_rewriter.h"
|
||||
#include "ast/rewriter/poly_rewriter_def.h"
|
||||
|
@ -1046,19 +1047,21 @@ br_status arith_rewriter::mk_idiv_core(expr * arg1, expr * arg2, expr_ref & resu
|
|||
set_curr_sort(arg1->get_sort());
|
||||
numeral v1, v2;
|
||||
bool is_int;
|
||||
if (m_util.is_numeral(arg1, v1, is_int) && m_util.is_numeral(arg2, v2, is_int) && !v2.is_zero()) {
|
||||
bool is_num1 = m_util.is_numeral(arg1, v1, is_int);
|
||||
bool is_num2 = m_util.is_numeral(arg2, v2, is_int);
|
||||
if (is_num1 && is_num2 && !v2.is_zero()) {
|
||||
result = m_util.mk_numeral(div(v1, v2), is_int);
|
||||
return BR_DONE;
|
||||
}
|
||||
if (m_util.is_numeral(arg2, v2, is_int) && v2.is_one()) {
|
||||
if (is_num2 && v2.is_one()) {
|
||||
result = arg1;
|
||||
return BR_DONE;
|
||||
}
|
||||
if (m_util.is_numeral(arg2, v2, is_int) && v2.is_minus_one()) {
|
||||
if (is_num2 && v2.is_minus_one()) {
|
||||
result = m_util.mk_mul(m_util.mk_int(-1), arg1);
|
||||
return BR_REWRITE1;
|
||||
}
|
||||
if (m_util.is_numeral(arg2, v2, is_int) && v2.is_zero()) {
|
||||
if (is_num2 && v2.is_zero()) {
|
||||
return BR_FAILED;
|
||||
}
|
||||
if (arg1 == arg2) {
|
||||
|
@ -1066,7 +1069,7 @@ br_status arith_rewriter::mk_idiv_core(expr * arg1, expr * arg2, expr_ref & resu
|
|||
result = m.mk_ite(m.mk_eq(arg1, zero), m_util.mk_idiv(zero, zero), m_util.mk_int(1));
|
||||
return BR_REWRITE3;
|
||||
}
|
||||
if (m_util.is_numeral(arg2, v2, is_int) && v2.is_pos() && m_util.is_add(arg1)) {
|
||||
if (is_num2 && v2.is_pos() && m_util.is_add(arg1)) {
|
||||
expr_ref_buffer args(m);
|
||||
bool change = false;
|
||||
rational add(0);
|
||||
|
@ -1092,7 +1095,14 @@ br_status arith_rewriter::mk_idiv_core(expr * arg1, expr * arg2, expr_ref & resu
|
|||
expr_ref zero(m_util.mk_int(0), m);
|
||||
result = m.mk_ite(m.mk_eq(zero, arg2), m_util.mk_idiv(arg1, zero), result);
|
||||
return BR_REWRITE_FULL;
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
expr* x = nullptr, *y = nullptr, *z = nullptr;
|
||||
if (is_num2 && m_util.is_idiv(arg1, x, y) && m_util.is_numeral(y, v1) && v1 > 0 && v2 > 0) {
|
||||
result = m_util.mk_idiv(x, m_util.mk_numeral(v1*v2, is_int));
|
||||
return BR_DONE;
|
||||
}
|
||||
#endif
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ Notes:
|
|||
#include "params/bool_rewriter_params.hpp"
|
||||
#include "ast/rewriter/rewriter_def.h"
|
||||
#include "ast/ast_lt.h"
|
||||
#include "ast/for_each_expr.h"
|
||||
#include <algorithm>
|
||||
|
||||
void bool_rewriter::updt_params(params_ref const & _p) {
|
||||
|
@ -32,6 +33,7 @@ void bool_rewriter::updt_params(params_ref const & _p) {
|
|||
m_blast_distinct = p.blast_distinct();
|
||||
m_blast_distinct_threshold = p.blast_distinct_threshold();
|
||||
m_ite_extra_rules = p.ite_extra_rules();
|
||||
m_hoist.set_elim_and(m_elim_and);
|
||||
}
|
||||
|
||||
void bool_rewriter::get_param_descrs(param_descrs & r) {
|
||||
|
@ -269,13 +271,26 @@ br_status bool_rewriter::mk_nflat_or_core(unsigned num_args, expr * const * args
|
|||
|
||||
#if 1
|
||||
br_status st;
|
||||
st = m_hoist.mk_or(buffer.size(), buffer.data(), result);
|
||||
expr_ref r(m());
|
||||
st = m_hoist.mk_or(buffer.size(), buffer.data(), r);
|
||||
if (st != BR_FAILED) {
|
||||
m_counts1.reserve(m().get_num_asts() + 1);
|
||||
m_counts2.reserve(m().get_num_asts() + 1);
|
||||
get_num_internal_exprs(m_counts1, m_todo1, r);
|
||||
for (unsigned i = 0; i < num_args; ++i)
|
||||
get_num_internal_exprs(m_counts2, m_todo2, args[i]);
|
||||
unsigned count1 = count_internal_nodes(m_counts1, m_todo1);
|
||||
unsigned count2 = count_internal_nodes(m_counts2, m_todo2);
|
||||
if (count1 > count2)
|
||||
st = BR_FAILED;
|
||||
}
|
||||
if (st != BR_FAILED)
|
||||
result = r;
|
||||
if (st == BR_DONE)
|
||||
return BR_REWRITE1;
|
||||
if (st != BR_FAILED)
|
||||
return st;
|
||||
#endif
|
||||
|
||||
if (s) {
|
||||
ast_lt lt;
|
||||
std::sort(buffer.begin(), buffer.end(), lt);
|
||||
|
|
|
@ -62,6 +62,8 @@ class bool_rewriter {
|
|||
unsigned m_local_ctx_limit;
|
||||
unsigned m_local_ctx_cost;
|
||||
bool m_elim_ite;
|
||||
ptr_vector<expr> m_todo1, m_todo2;
|
||||
unsigned_vector m_counts1, m_counts2;
|
||||
|
||||
br_status mk_flat_and_core(unsigned num_args, expr * const * args, expr_ref & result);
|
||||
br_status mk_flat_or_core(unsigned num_args, expr * const * args, expr_ref & result);
|
||||
|
@ -81,7 +83,9 @@ class bool_rewriter {
|
|||
void push_new_arg(expr* arg, expr_ref_vector& new_args, expr_fast_mark1& neg_lits, expr_fast_mark2& pos_lits);
|
||||
|
||||
public:
|
||||
bool_rewriter(ast_manager & m, params_ref const & p = params_ref()):m_manager(m), m_hoist(m), m_local_ctx_cost(0) { updt_params(p); }
|
||||
bool_rewriter(ast_manager & m, params_ref const & p = params_ref()):m_manager(m), m_hoist(m), m_local_ctx_cost(0) {
|
||||
updt_params(p);
|
||||
}
|
||||
ast_manager & m() const { return m_manager; }
|
||||
family_id get_fid() const { return m().get_basic_family_id(); }
|
||||
bool is_eq(expr * t) const { return m().is_eq(t); }
|
||||
|
|
|
@ -185,7 +185,7 @@ namespace bv {
|
|||
m_args.push_back(arg);
|
||||
continue;
|
||||
}
|
||||
if (!m_bv.is_extract(arg) && m_bound.find(arg, b)) {
|
||||
if (!m_bv.is_extract(arg) && m_bound.find(arg, b) && b.lo() <= b.hi()) {
|
||||
unsigned num_bits = b.hi().get_num_bits();
|
||||
unsigned bv_size = m_bv.get_bv_size(arg);
|
||||
if (0 < num_bits && num_bits < bv_size) {
|
||||
|
@ -202,6 +202,7 @@ namespace bv {
|
|||
|
||||
if (simplified) {
|
||||
result = m.mk_app(to_app(t)->get_decl(), m_args);
|
||||
TRACE("bv", tout << mk_pp(t, m) << " -> " << result << "\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -94,6 +94,10 @@ br_status bv_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons
|
|||
case OP_BNEG:
|
||||
SASSERT(num_args == 1);
|
||||
return mk_uminus(args[0], result);
|
||||
case OP_BNEG_OVFL:
|
||||
SASSERT(num_args == 1);
|
||||
return mk_bvneg_overflow(args[0], result);
|
||||
|
||||
case OP_BSHL:
|
||||
SASSERT(num_args == 2);
|
||||
return mk_bv_shl(args[0], args[1], result);
|
||||
|
@ -200,6 +204,20 @@ br_status bv_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons
|
|||
return mk_bvsmul_no_overflow(num_args, args, false, result);
|
||||
case OP_BUMUL_NO_OVFL:
|
||||
return mk_bvumul_no_overflow(num_args, args, result);
|
||||
case OP_BSMUL_OVFL:
|
||||
return mk_bvsmul_overflow(num_args, args, result);
|
||||
case OP_BUMUL_OVFL:
|
||||
return mk_bvumul_overflow(num_args, args, result);
|
||||
case OP_BSDIV_OVFL:
|
||||
return mk_bvsdiv_overflow(num_args, args, result);
|
||||
case OP_BUADD_OVFL:
|
||||
return mk_bvuadd_overflow(num_args, args, result);
|
||||
case OP_BSADD_OVFL:
|
||||
return mk_bvsadd_over_underflow(num_args, args, result);
|
||||
case OP_BUSUB_OVFL:
|
||||
return mk_bvusub_underflow(num_args, args, result);
|
||||
case OP_BSSUB_OVFL:
|
||||
return mk_bvssub_overflow(num_args, args, result);
|
||||
default:
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
@ -1555,7 +1573,7 @@ br_status bv_rewriter::mk_concat(unsigned num_args, expr * const * args, expr_re
|
|||
if (eq_args) {
|
||||
if (m.is_ite(new_args.back(), x, y, z)) {
|
||||
ptr_buffer<expr> args1, args2;
|
||||
for (expr* arg : new_args)
|
||||
for (unsigned i = 0; i < new_args.size(); ++i)
|
||||
args1.push_back(y), args2.push_back(z);
|
||||
result = m.mk_ite(x, m_util.mk_concat(args1), m_util.mk_concat(args2));
|
||||
return BR_REWRITE2;
|
||||
|
@ -2925,6 +2943,21 @@ br_status bv_rewriter::mk_distinct(unsigned num_args, expr * const * args, expr_
|
|||
return BR_DONE;
|
||||
}
|
||||
|
||||
br_status bv_rewriter::mk_bvsmul_overflow(unsigned num, expr * const * args, expr_ref & result) {
|
||||
SASSERT(num == 2);
|
||||
result = m.mk_or(
|
||||
m.mk_not(m_util.mk_bvsmul_no_ovfl(args[0], args[1])),
|
||||
m.mk_not(m_util.mk_bvsmul_no_udfl(args[0], args[1]))
|
||||
);
|
||||
return BR_REWRITE_FULL;
|
||||
}
|
||||
|
||||
br_status bv_rewriter::mk_bvumul_overflow(unsigned num, expr * const * args, expr_ref & result) {
|
||||
SASSERT(num == 2);
|
||||
result = m.mk_not(m_util.mk_bvumul_no_ovfl(args[0], args[1]));
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
|
||||
br_status bv_rewriter::mk_bvsmul_no_overflow(unsigned num, expr * const * args, bool is_overflow, expr_ref & result) {
|
||||
SASSERT(num == 2);
|
||||
unsigned bv_sz;
|
||||
|
@ -2984,5 +3017,95 @@ br_status bv_rewriter::mk_bvumul_no_overflow(unsigned num, expr * const * args,
|
|||
return BR_FAILED;
|
||||
}
|
||||
|
||||
br_status bv_rewriter::mk_bvneg_overflow(expr * const arg, expr_ref & result) {
|
||||
unsigned int sz = get_bv_size(arg);
|
||||
auto maxUnsigned = mk_numeral(rational::power_of_two(sz)-1, sz);
|
||||
result = m.mk_eq(arg, maxUnsigned);
|
||||
return BR_REWRITE3;
|
||||
}
|
||||
|
||||
br_status bv_rewriter::mk_bvuadd_overflow(unsigned num, expr * const * args, expr_ref & result) {
|
||||
SASSERT(num == 2);
|
||||
SASSERT(get_bv_size(args[0]) == get_bv_size(args[1]));
|
||||
unsigned sz = get_bv_size(args[0]);
|
||||
auto a1 = mk_zero_extend(1, args[0]);
|
||||
auto a2 = mk_zero_extend(1, args[1]);
|
||||
auto r = mk_bv_add(a1, a2);
|
||||
auto extract = m_mk_extract(sz, sz, r);
|
||||
result = m.mk_eq(extract, mk_one(1));
|
||||
return BR_REWRITE_FULL;
|
||||
}
|
||||
|
||||
br_status bv_rewriter::mk_bvsadd_overflow(unsigned num, expr * const * args, expr_ref & result) {
|
||||
SASSERT(num == 2);
|
||||
SASSERT(get_bv_size(args[0]) == get_bv_size(args[1]));
|
||||
unsigned sz = get_bv_size(args[0]);
|
||||
auto zero = mk_zero(sz);
|
||||
auto r = mk_bv_add(args[0], args[1]);
|
||||
auto l1 = m_util.mk_slt(zero, args[0]);
|
||||
auto l2 = m_util.mk_slt(zero, args[1]);
|
||||
auto args_pos = m.mk_and(l1, l2);
|
||||
auto non_pos_sum = m_util.mk_sle(r, zero);
|
||||
result = m.mk_and(args_pos, non_pos_sum);
|
||||
return BR_REWRITE_FULL;
|
||||
}
|
||||
|
||||
br_status bv_rewriter::mk_bvsadd_underflow(unsigned num, expr * const * args, expr_ref & result) {
|
||||
SASSERT(num == 2);
|
||||
SASSERT(get_bv_size(args[0]) == get_bv_size(args[1]));
|
||||
unsigned sz = get_bv_size(args[0]);
|
||||
auto zero = mk_zero(sz);
|
||||
auto r = mk_bv_add(args[0], args[1]);
|
||||
auto l1 = m_util.mk_slt(args[0], zero);
|
||||
auto l2 = m_util.mk_slt(args[1], zero);
|
||||
auto args_neg = m.mk_and(l1, l2);
|
||||
expr_ref non_neg_sum{m};
|
||||
auto res_rewrite = mk_sge(r, zero, non_neg_sum);
|
||||
SASSERT(res_rewrite != BR_FAILED); (void)res_rewrite;
|
||||
result = m.mk_and(args_neg, non_neg_sum);
|
||||
return BR_REWRITE_FULL;
|
||||
}
|
||||
|
||||
br_status bv_rewriter::mk_bvsadd_over_underflow(unsigned num, expr * const * args, expr_ref & result) {
|
||||
SASSERT(num == 2);
|
||||
SASSERT(get_bv_size(args[0]) == get_bv_size(args[1]));
|
||||
expr_ref l1{m};
|
||||
expr_ref l2{m};
|
||||
(void)mk_bvsadd_overflow(2, args, l1);
|
||||
(void)mk_bvsadd_underflow(2, args, l2);
|
||||
result = m.mk_or(l1, l2);
|
||||
return BR_REWRITE_FULL;
|
||||
}
|
||||
|
||||
br_status bv_rewriter::mk_bvusub_underflow(unsigned num, expr * const * args, expr_ref & result) {
|
||||
SASSERT(num == 2);
|
||||
SASSERT(get_bv_size(args[0]) == get_bv_size(args[1]));
|
||||
br_status status = mk_ult(args[0], args[1], result);
|
||||
SASSERT(status != BR_FAILED);
|
||||
return status;
|
||||
}
|
||||
|
||||
br_status bv_rewriter::mk_bvssub_overflow(unsigned num, expr * const * args, expr_ref & result) {
|
||||
SASSERT(num == 2);
|
||||
SASSERT(get_bv_size(args[0]) == get_bv_size(args[1]));
|
||||
auto sz = get_bv_size(args[0]);
|
||||
auto minSigned = mk_numeral(-rational::power_of_two(sz-1), sz);
|
||||
expr_ref bvsaddo {m};
|
||||
expr * args2[2] = { args[0], m_util.mk_bv_neg(args[1]) };
|
||||
auto bvsaddo_stat = mk_bvsadd_overflow(2, args2, bvsaddo);
|
||||
SASSERT(bvsaddo_stat != BR_FAILED); (void)bvsaddo_stat;
|
||||
auto first_arg_ge_zero = m_util.mk_sle(mk_zero(sz), args[0]);
|
||||
result = m.mk_ite(m.mk_eq(args[1], minSigned), first_arg_ge_zero, bvsaddo);
|
||||
return BR_REWRITE_FULL;
|
||||
}
|
||||
br_status bv_rewriter::mk_bvsdiv_overflow(unsigned num, expr * const * args, expr_ref & result) {
|
||||
SASSERT(num == 2);
|
||||
SASSERT(get_bv_size(args[0]) == get_bv_size(args[1]));
|
||||
auto sz = get_bv_size(args[1]);
|
||||
auto minSigned = mk_numeral(-rational::power_of_two(sz-1), sz);
|
||||
auto minusOne = mk_numeral(rational::power_of_two(sz) - 1, sz);
|
||||
result = m.mk_and(m.mk_eq(args[0], minSigned), m.mk_eq(args[1], minusOne));
|
||||
return BR_REWRITE_FULL;
|
||||
}
|
||||
|
||||
template class poly_rewriter<bv_rewriter_core>;
|
||||
|
|
|
@ -139,6 +139,22 @@ class bv_rewriter : public poly_rewriter<bv_rewriter_core> {
|
|||
br_status mk_mkbv(unsigned num, expr * const * args, expr_ref & result);
|
||||
br_status mk_bvsmul_no_overflow(unsigned num, expr * const * args, bool is_overflow, expr_ref & result);
|
||||
br_status mk_bvumul_no_overflow(unsigned num, expr * const * args, expr_ref & result);
|
||||
|
||||
br_status mk_bvsmul_overflow(unsigned num, expr * const * args, expr_ref & result);
|
||||
br_status mk_bvumul_overflow(unsigned num, expr * const * args, expr_ref & result);
|
||||
|
||||
br_status mk_bvsdiv_overflow(unsigned num, expr * const * args, expr_ref & result);
|
||||
|
||||
br_status mk_bvneg_overflow(expr * const arg, expr_ref & result);
|
||||
|
||||
br_status mk_bvuadd_overflow(unsigned num, expr * const * args, expr_ref & result);
|
||||
br_status mk_bvsadd_overflow(unsigned num, expr * const * args, expr_ref & result);
|
||||
br_status mk_bvsadd_underflow(unsigned num, expr * const * args, expr_ref & result);
|
||||
br_status mk_bvsadd_over_underflow(unsigned num, expr * const * args, expr_ref & result);
|
||||
|
||||
br_status mk_bvusub_underflow(unsigned num, expr * const * args, expr_ref & result);
|
||||
br_status mk_bvssub_overflow(unsigned num, expr * const * args, expr_ref & result);
|
||||
|
||||
bool is_minus_one_times_t(expr * arg);
|
||||
void mk_t1_add_t2_eq_c(expr * t1, expr * t2, expr * c, expr_ref & result);
|
||||
|
||||
|
|
|
@ -197,9 +197,10 @@ void der::reduce1(quantifier * q, expr_ref & r, proof_ref & pr) {
|
|||
|
||||
m_pos2var.reserve(num_args, -1);
|
||||
|
||||
// Find all disequalities
|
||||
// Find all equalities/disequalities
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
is_eq = is_forall(q) ? is_var_diseq(literals.get(i), num_decls, v, t) : is_var_eq(literals.get(i), num_decls, v, t);
|
||||
expr* arg = literals.get(i);
|
||||
is_eq = is_forall(q) ? is_var_diseq(arg, num_decls, v, t) : is_var_eq(arg, num_decls, v, t);
|
||||
if (is_eq) {
|
||||
unsigned idx = v->get_idx();
|
||||
if (m_map.get(idx, nullptr) == nullptr) {
|
||||
|
|
|
@ -22,6 +22,7 @@ Revision History:
|
|||
|
||||
#include "ast/used_vars.h"
|
||||
#include "util/obj_hashtable.h"
|
||||
#include "ast/rewriter/rewriter_def.h"
|
||||
#include "ast/rewriter/var_subst.h"
|
||||
#include "ast/rewriter/elim_bounds.h"
|
||||
#include "ast/ast_pp.h"
|
||||
|
|
|
@ -17,16 +17,36 @@ Author:
|
|||
|
||||
|
||||
#include "ast/rewriter/hoist_rewriter.h"
|
||||
#include "ast/rewriter/bool_rewriter.h"
|
||||
#include "ast/ast_util.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "ast/ast_ll_pp.h"
|
||||
|
||||
|
||||
hoist_rewriter::hoist_rewriter(ast_manager & m, params_ref const & p):
|
||||
m(m), m_args1(m), m_args2(m), m_subst(m) {
|
||||
m(m), m_args1(m), m_args2(m), m_refs(m), m_subst(m) {
|
||||
updt_params(p);
|
||||
}
|
||||
|
||||
expr_ref hoist_rewriter::mk_and(expr_ref_vector const& args) {
|
||||
if (m_elim_and) {
|
||||
expr_ref_vector negs(m);
|
||||
for (expr* a : args)
|
||||
if (m.is_false(a))
|
||||
return expr_ref(m.mk_false(), m);
|
||||
else if (m.is_true(a))
|
||||
continue;
|
||||
else
|
||||
negs.push_back(::mk_not(m, a));
|
||||
return ::mk_not(mk_or(negs));
|
||||
}
|
||||
else
|
||||
return ::mk_and(args);
|
||||
}
|
||||
|
||||
expr_ref hoist_rewriter::mk_or(expr_ref_vector const& args) {
|
||||
return ::mk_or(args);
|
||||
}
|
||||
|
||||
br_status hoist_rewriter::mk_or(unsigned num_args, expr * const * es, expr_ref & result) {
|
||||
if (num_args < 2)
|
||||
return BR_FAILED;
|
||||
|
@ -144,28 +164,26 @@ unsigned hoist_rewriter::mk_var(expr* e) {
|
|||
}
|
||||
|
||||
expr_ref hoist_rewriter::hoist_predicates(obj_hashtable<expr> const& preds, unsigned num_args, expr* const* es) {
|
||||
expr_ref result(m);
|
||||
expr_ref_vector args(m), fmls(m);
|
||||
expr_ref_vector args(m), args1(m), fmls(m);
|
||||
for (unsigned i = 0; i < num_args; ++i) {
|
||||
VERIFY(is_and(es[i], &m_args1));
|
||||
VERIFY(is_and(es[i], &args1));
|
||||
fmls.reset();
|
||||
for (expr* e : m_args1)
|
||||
for (expr* e : args1)
|
||||
if (!preds.contains(e))
|
||||
fmls.push_back(e);
|
||||
args.push_back(::mk_and(fmls));
|
||||
args.push_back(mk_and(fmls));
|
||||
}
|
||||
fmls.reset();
|
||||
fmls.push_back(::mk_or(args));
|
||||
fmls.push_back(mk_or(args));
|
||||
for (auto* p : preds)
|
||||
fmls.push_back(p);
|
||||
result = ::mk_and(fmls);
|
||||
return result;
|
||||
return mk_and(fmls);
|
||||
}
|
||||
|
||||
|
||||
br_status hoist_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
|
||||
switch (f->get_decl_kind()) {
|
||||
case OP_OR:
|
||||
case OP_OR:
|
||||
return mk_or(num_args, args, result);
|
||||
default:
|
||||
return BR_FAILED;
|
||||
|
@ -173,6 +191,33 @@ br_status hoist_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * c
|
|||
}
|
||||
|
||||
bool hoist_rewriter::is_and(expr * e, expr_ref_vector* args) {
|
||||
#if 0
|
||||
if (!args)
|
||||
return m.is_and(e) || (m.is_not(e, e) && m.is_or(e));
|
||||
expr_fast_mark1 visited;
|
||||
args->reset();
|
||||
args->push_back(e);
|
||||
m_refs.reset();
|
||||
for (unsigned i = 0; i < args->size(); ++i) {
|
||||
e = args->get(i);
|
||||
if (visited.is_marked(e))
|
||||
goto drop;
|
||||
m_refs.push_back(e);
|
||||
visited.mark(e, true);
|
||||
if (m.is_and(e))
|
||||
args->append(to_app(e)->get_num_args(), to_app(e)->get_args());
|
||||
else if (m.is_not(e, e) && m.is_or(e))
|
||||
for (expr* arg : *to_app(e))
|
||||
args->push_back(::mk_not(m, arg));
|
||||
else
|
||||
continue;
|
||||
drop:
|
||||
(*args)[i] = args->back();
|
||||
args->pop_back();
|
||||
--i;
|
||||
}
|
||||
return args->size() > 1;
|
||||
#else
|
||||
if (m.is_and(e)) {
|
||||
if (args) {
|
||||
args->reset();
|
||||
|
@ -185,9 +230,11 @@ bool hoist_rewriter::is_and(expr * e, expr_ref_vector* args) {
|
|||
args->reset();
|
||||
for (expr* arg : *to_app(e))
|
||||
args->push_back(::mk_not(m, arg));
|
||||
TRACE("hoist", tout << args << " " << * args << "\n");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,9 +25,11 @@ Notes:
|
|||
#include "util/union_find.h"
|
||||
#include "util/obj_hashtable.h"
|
||||
|
||||
class bool_rewriter;
|
||||
|
||||
class hoist_rewriter {
|
||||
ast_manager & m;
|
||||
expr_ref_vector m_args1, m_args2;
|
||||
expr_ref_vector m_args1, m_args2, m_refs;
|
||||
obj_hashtable<expr> m_preds1, m_preds2;
|
||||
basic_union_find m_uf1, m_uf2, m_uf0;
|
||||
ptr_vector<expr> m_es;
|
||||
|
@ -37,8 +39,11 @@ class hoist_rewriter {
|
|||
obj_map<expr, unsigned> m_expr2var;
|
||||
ptr_vector<expr> m_var2expr;
|
||||
expr_mark m_mark;
|
||||
bool m_elim_and = false;
|
||||
|
||||
bool is_and(expr* e, expr_ref_vector* args);
|
||||
expr_ref mk_and(expr_ref_vector const& args);
|
||||
expr_ref mk_or(expr_ref_vector const& args);
|
||||
|
||||
bool is_var(expr* e) { return m_expr2var.contains(e); }
|
||||
expr* mk_expr(unsigned v) { return m_var2expr[v]; }
|
||||
|
@ -48,6 +53,7 @@ class hoist_rewriter {
|
|||
|
||||
expr_ref hoist_predicates(obj_hashtable<expr> const& p, unsigned num_args, expr* const* args);
|
||||
|
||||
|
||||
public:
|
||||
hoist_rewriter(ast_manager & m, params_ref const & p = params_ref());
|
||||
family_id get_fid() const { return m.get_basic_family_id(); }
|
||||
|
@ -56,6 +62,7 @@ public:
|
|||
static void get_param_descrs(param_descrs & r) {}
|
||||
br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
|
||||
br_status mk_or(unsigned num_args, expr * const * args, expr_ref & result);
|
||||
void set_elim_and(bool b) { m_elim_and = b; }
|
||||
};
|
||||
|
||||
struct hoist_rewriter_cfg : public default_rewriter_cfg {
|
||||
|
|
|
@ -92,7 +92,7 @@ br_status maximize_ac_sharing::reduce_app(func_decl * f, unsigned num_args, expr
|
|||
else {
|
||||
result = m.mk_app(f, numeral, _args[0]);
|
||||
}
|
||||
TRACE("ac_sharing_detail", tout << "result: " << mk_pp(result, m) << "\n";);
|
||||
TRACE("ac_sharing_detail", tout << "result: " << result << "\n";);
|
||||
return BR_DONE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -825,16 +825,17 @@ struct pb2bv_rewriter::imp {
|
|||
if (a->get_family_id() == au.get_family_id()) {
|
||||
switch (a->get_decl_kind()) {
|
||||
case OP_ADD:
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
if (!is_pb(a->get_arg(i), mul)) return false;
|
||||
}
|
||||
for (unsigned i = 0; i < sz; ++i)
|
||||
if (!is_pb(a->get_arg(i), mul))
|
||||
return false;
|
||||
return true;
|
||||
case OP_SUB: {
|
||||
if (!is_pb(a->get_arg(0), mul)) return false;
|
||||
if (!is_pb(a->get_arg(0), mul))
|
||||
return false;
|
||||
r = -mul;
|
||||
for (unsigned i = 1; i < sz; ++i) {
|
||||
if (!is_pb(a->get_arg(1), r)) return false;
|
||||
}
|
||||
for (unsigned i = 1; i < sz; ++i)
|
||||
if (!is_pb(a->get_arg(i), r))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
case OP_UMINUS:
|
||||
|
|
|
@ -18,6 +18,7 @@ Revision History:
|
|||
|
||||
--*/
|
||||
#include "ast/rewriter/push_app_ite.h"
|
||||
#include "ast/rewriter/rewriter_def.h"
|
||||
#include "ast/ast_pp.h"
|
||||
|
||||
|
||||
|
|
|
@ -347,7 +347,7 @@ public:
|
|||
Config & cfg() { return m_cfg; }
|
||||
Config const & cfg() const { return m_cfg; }
|
||||
|
||||
~rewriter_tpl() override;
|
||||
~rewriter_tpl() override {};
|
||||
|
||||
void reset();
|
||||
void cleanup();
|
||||
|
|
|
@ -640,10 +640,6 @@ rewriter_tpl<Config>::rewriter_tpl(ast_manager & m, bool proof_gen, Config & cfg
|
|||
m_pr2(m) {
|
||||
}
|
||||
|
||||
template<typename Config>
|
||||
rewriter_tpl<Config>::~rewriter_tpl() {
|
||||
}
|
||||
|
||||
template<typename Config>
|
||||
void rewriter_tpl<Config>::reset() {
|
||||
m_cfg.reset();
|
||||
|
|
|
@ -513,8 +513,8 @@ namespace seq {
|
|||
|
||||
!contains(t, s) => i = -1
|
||||
|t| = 0 => |s| = 0 or i = -1
|
||||
|t| = 0 & |s| = 0 => i = 0
|
||||
|t| != 0 & contains(t, s) => t = xsy & i = len(x)
|
||||
|s| = 0 => i = len(t)
|
||||
|s| = 0 or s = s_head*s_tail
|
||||
|s| = 0 or !contains(s_tail*y, s)
|
||||
|
||||
|
@ -540,7 +540,7 @@ namespace seq {
|
|||
|
||||
add_clause(cnt, i_eq_m1);
|
||||
add_clause(~t_eq_empty, s_eq_empty, i_eq_m1);
|
||||
add_clause(~t_eq_empty, ~s_eq_empty, i_eq_0);
|
||||
add_clause(~s_eq_empty, mk_eq(i, mk_len(t)));
|
||||
add_clause(t_eq_empty, ~cnt, mk_seq_eq(t, xsy));
|
||||
add_clause(t_eq_empty, ~cnt, mk_eq(i, mk_len(x)));
|
||||
add_clause(s_eq_empty, mk_eq(s, mk_concat(s_head, s_tail)));
|
||||
|
@ -928,7 +928,6 @@ namespace seq {
|
|||
e1 < e2 => prefix(e1, e2) or e1 = xcy
|
||||
e1 < e2 => prefix(e1, e2) or c < d
|
||||
e1 < e2 => prefix(e1, e2) or e2 = xdz
|
||||
e1 < e2 => e1 != e2
|
||||
!(e1 < e2) => prefix(e2, e1) or e2 = xdz
|
||||
!(e1 < e2) => prefix(e2, e1) or d < c
|
||||
!(e1 < e2) => prefix(e2, e1) or e1 = xcy
|
||||
|
@ -938,6 +937,7 @@ namespace seq {
|
|||
e1 < e2 or e1 = e2 or e2 < e1
|
||||
!(e1 = e2) or !(e2 < e1)
|
||||
!(e1 < e2) or !(e2 < e1)
|
||||
|
||||
*/
|
||||
void axioms::lt_axiom(expr* n) {
|
||||
expr* _e1 = nullptr, *_e2 = nullptr;
|
||||
|
@ -948,6 +948,7 @@ namespace seq {
|
|||
sort* char_sort = nullptr;
|
||||
VERIFY(seq.is_seq(s, char_sort));
|
||||
expr_ref lt = expr_ref(n, m);
|
||||
expr_ref gt = expr_ref(seq.str.mk_lex_lt(e2, e1), m);
|
||||
expr_ref x = m_sk.mk("str.<.x", e1, e2);
|
||||
expr_ref y = m_sk.mk("str.<.y", e1, e2);
|
||||
expr_ref z = m_sk.mk("str.<.z", e1, e2);
|
||||
|
@ -969,6 +970,7 @@ namespace seq {
|
|||
add_clause(lt, pref21, ltdc);
|
||||
add_clause(lt, pref21, e2xdz);
|
||||
add_clause(~eq, ~lt);
|
||||
add_clause(eq, lt, gt);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1235,7 +1237,7 @@ namespace seq {
|
|||
seq.str.is_string(x)) {
|
||||
expr_ref len(n, m);
|
||||
m_rewrite(len);
|
||||
SASSERT(n != len);
|
||||
SASSERT(m.limit().is_canceled() || n != len);
|
||||
add_clause(mk_eq(len, n));
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -190,8 +190,8 @@ namespace seq {
|
|||
expr_ref digit = m_ax.sk().mk_digit2int(u);
|
||||
add_consequence(m_ax.mk_ge(digit, 1));
|
||||
}
|
||||
expr_ref y(seq.str.mk_concat(es, es[0]->get_sort()), m);
|
||||
ctx.add_solution(seq.str.mk_itos(n), y);
|
||||
expr_ref y(seq.str.mk_concat(es, es[0]->get_sort()), m);
|
||||
ctx.add_solution(seq.str.mk_itos(n), y);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -5024,12 +5024,14 @@ br_status seq_rewriter::mk_re_star(expr* a, expr_ref& result) {
|
|||
* (re.range c_1 c_n)
|
||||
*/
|
||||
br_status seq_rewriter::mk_re_range(expr* lo, expr* hi, expr_ref& result) {
|
||||
zstring s;
|
||||
zstring slo, shi;
|
||||
unsigned len = 0;
|
||||
bool is_empty = false;
|
||||
if (str().is_string(lo, s) && s.length() != 1)
|
||||
if (str().is_string(lo, slo) && slo.length() != 1)
|
||||
is_empty = true;
|
||||
if (str().is_string(hi, s) && s.length() != 1)
|
||||
if (str().is_string(hi, shi) && shi.length() != 1)
|
||||
is_empty = true;
|
||||
if (slo.length() == 1 && shi.length() == 1 && slo[0] > shi[0])
|
||||
is_empty = true;
|
||||
len = min_length(lo).second;
|
||||
if (len > 1)
|
||||
|
@ -5246,7 +5248,17 @@ br_status seq_rewriter::reduce_re_is_empty(expr* r, expr_ref& result) {
|
|||
else if (re().is_range(r, r1, r2) &&
|
||||
str().is_string(r1, s1) && str().is_string(r2, s2) &&
|
||||
s1.length() == 1 && s2.length() == 1) {
|
||||
result = m().mk_bool_val(s1[0] <= s2[0]);
|
||||
result = m().mk_bool_val(s1[0] > s2[0]);
|
||||
return BR_DONE;
|
||||
}
|
||||
else if (re().is_range(r, r1, r2) &&
|
||||
str().is_string(r1, s1) && s1.length() != 1) {
|
||||
result = m().mk_true();
|
||||
return BR_DONE;
|
||||
}
|
||||
else if (re().is_range(r, r1, r2) &&
|
||||
str().is_string(r2, s2) && s2.length() != 1) {
|
||||
result = m().mk_true();
|
||||
return BR_DONE;
|
||||
}
|
||||
else if ((re().is_loop(r, r1, lo) ||
|
||||
|
@ -5307,6 +5319,7 @@ br_status seq_rewriter::mk_le_core(expr * l, expr * r, expr_ref & result) {
|
|||
}
|
||||
|
||||
br_status seq_rewriter::mk_eq_core(expr * l, expr * r, expr_ref & result) {
|
||||
TRACE("seq", tout << mk_pp(l, m()) << " == " << mk_pp(r, m()) << "\n");
|
||||
expr_ref_vector res(m());
|
||||
expr_ref_pair_vector new_eqs(m());
|
||||
if (m_util.is_re(l)) {
|
||||
|
@ -5518,6 +5531,7 @@ bool seq_rewriter::reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_
|
|||
reduce_front(ls, rs, eqs) &&
|
||||
reduce_itos(ls, rs, eqs) &&
|
||||
reduce_itos(rs, ls, eqs) &&
|
||||
reduce_value_clash(ls, rs, eqs) &&
|
||||
reduce_by_length(ls, rs, eqs) &&
|
||||
reduce_subsequence(ls, rs, eqs) &&
|
||||
reduce_non_overlap(ls, rs, eqs) &&
|
||||
|
@ -5943,6 +5957,47 @@ bool seq_rewriter::reduce_non_overlap(expr_ref_vector& ls, expr_ref_vector& rs,
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* partial check for value clash.
|
||||
* checks that elements that do not occur in
|
||||
* other sequence are non-values.
|
||||
* The check could be extended to take non-value
|
||||
* characters (units) into account.
|
||||
*/
|
||||
bool seq_rewriter::reduce_value_clash(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& eqs) {
|
||||
ptr_buffer<expr> es;
|
||||
|
||||
if (ls.empty() || rs.empty())
|
||||
return true;
|
||||
es.append(ls.size(), ls.data());
|
||||
auto remove = [&](expr* r) {
|
||||
for (unsigned i = 0; i < es.size(); ++i) {
|
||||
if (r == es[i]) {
|
||||
es[i] = es.back();
|
||||
es.pop_back();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
auto is_unit_value = [&](expr* r) {
|
||||
return m().is_value(r) && str().is_unit(r);
|
||||
};
|
||||
for (expr* r : rs) {
|
||||
if (remove(r))
|
||||
continue;
|
||||
if (!is_unit_value(r))
|
||||
return true;
|
||||
}
|
||||
if (es.empty())
|
||||
return true;
|
||||
for (expr* e : es)
|
||||
if (!is_unit_value(e))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool seq_rewriter::reduce_subsequence(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& eqs) {
|
||||
|
||||
if (ls.size() > rs.size())
|
||||
|
|
|
@ -340,6 +340,7 @@ class seq_rewriter {
|
|||
bool is_sequence(expr* e, expr_ref_vector& seq);
|
||||
bool is_sequence(eautomaton& aut, expr_ref_vector& seq);
|
||||
bool get_lengths(expr* e, expr_ref_vector& lens, rational& pos);
|
||||
bool reduce_value_clash(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& new_eqs);
|
||||
bool reduce_back(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& new_eqs);
|
||||
bool reduce_front(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& new_eqs);
|
||||
void remove_empty_and_concats(expr_ref_vector& es);
|
||||
|
|
|
@ -31,6 +31,7 @@ Notes:
|
|||
#include "ast/rewriter/seq_rewriter.h"
|
||||
#include "ast/rewriter/rewriter_def.h"
|
||||
#include "ast/rewriter/var_subst.h"
|
||||
#include "ast/rewriter/der.h"
|
||||
#include "ast/rewriter/expr_safe_replace.h"
|
||||
#include "ast/expr_substitution.h"
|
||||
#include "ast/ast_smt2_pp.h"
|
||||
|
@ -54,6 +55,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
|
|||
recfun_rewriter m_rec_rw;
|
||||
arith_util m_a_util;
|
||||
bv_util m_bv_util;
|
||||
der m_der;
|
||||
expr_safe_replace m_rep;
|
||||
expr_ref_vector m_pinned;
|
||||
// substitution support
|
||||
|
@ -821,6 +823,26 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
|
|||
|
||||
TRACE("reduce_quantifier", tout << "after elim_unused_vars:\n" << result << " " << result_pr << "\n" ;);
|
||||
|
||||
proof_ref p2(m());
|
||||
expr_ref r(m());
|
||||
|
||||
bool der_change = false;
|
||||
if (is_quantifier(result) && to_quantifier(result)->get_num_patterns() == 0) {
|
||||
m_der(to_quantifier(result), r, p2);
|
||||
der_change = result.get() != r.get();
|
||||
if (m().proofs_enabled() && der_change)
|
||||
result_pr = m().mk_transitivity(result_pr, p2);
|
||||
result = r;
|
||||
}
|
||||
|
||||
if (der_change) {
|
||||
th_rewriter rw(m());
|
||||
rw(result, r, p2);
|
||||
if (m().proofs_enabled() && result.get() != r.get())
|
||||
result_pr = m().mk_transitivity(result_pr, p2);
|
||||
result = r;
|
||||
}
|
||||
|
||||
SASSERT(old_q->get_sort() == result->get_sort());
|
||||
return true;
|
||||
}
|
||||
|
@ -839,6 +861,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
|
|||
m_rec_rw(m),
|
||||
m_a_util(m),
|
||||
m_bv_util(m),
|
||||
m_der(m),
|
||||
m_rep(m),
|
||||
m_pinned(m),
|
||||
m_used_dependencies(m) {
|
||||
|
@ -944,17 +967,41 @@ void th_rewriter::reset() {
|
|||
}
|
||||
|
||||
void th_rewriter::operator()(expr_ref & term) {
|
||||
expr_ref result(term.get_manager());
|
||||
m_imp->operator()(term, result);
|
||||
term = std::move(result);
|
||||
expr_ref result(term.get_manager());
|
||||
try {
|
||||
m_imp->operator()(term, result);
|
||||
term = std::move(result);
|
||||
}
|
||||
catch (...) {
|
||||
if (!term.get_manager().inc())
|
||||
return;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void th_rewriter::operator()(expr * t, expr_ref & result) {
|
||||
m_imp->operator()(t, result);
|
||||
try {
|
||||
m_imp->operator()(t, result);
|
||||
}
|
||||
catch (...) {
|
||||
result = t;
|
||||
if (!result.get_manager().inc())
|
||||
return;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void th_rewriter::operator()(expr * t, expr_ref & result, proof_ref & result_pr) {
|
||||
m_imp->operator()(t, result, result_pr);
|
||||
try {
|
||||
m_imp->operator()(t, result, result_pr);
|
||||
}
|
||||
catch (...) {
|
||||
result = t;
|
||||
result_pr = nullptr;
|
||||
if (!result.get_manager().inc())
|
||||
return;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
expr_ref th_rewriter::operator()(expr * n, unsigned num_bindings, expr * const * bindings) {
|
||||
|
|
|
@ -663,19 +663,21 @@ void seq_decl_plugin::add_map_sig() {
|
|||
m_sigs[OP_SEQ_MAP] = alloc(psig, m, "seq.map", 2, 2, arrABseqA, seqB);
|
||||
m_sigs[OP_SEQ_MAPI] = alloc(psig, m, "seq.mapi", 2, 3, arrIABintTseqA, seqB);
|
||||
m_sigs[OP_SEQ_FOLDL] = alloc(psig, m, "seq.fold_left", 2, 3, arrBAB_BseqA, B);
|
||||
m_sigs[OP_SEQ_FOLDLI] = alloc(psig, m, "seq.fold_leftli", 2, 4, arrIBABintTBseqA, B);
|
||||
m_sigs[OP_SEQ_FOLDLI] = alloc(psig, m, "seq.fold_lefti", 2, 4, arrIBABintTBseqA, B);
|
||||
}
|
||||
|
||||
void seq_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol const & logic) {
|
||||
init();
|
||||
for (unsigned i = 0; i < m_sigs.size(); ++i) {
|
||||
if (m_sigs[i])
|
||||
op_names.push_back(builtin_name(m_sigs[i]->m_name.str(), i));
|
||||
if (m_sigs[i])
|
||||
op_names.push_back(builtin_name(m_sigs[i]->m_name.str(), i));
|
||||
}
|
||||
op_names.push_back(builtin_name("seq.map", OP_SEQ_MAP));
|
||||
op_names.push_back(builtin_name("seq.mapi", OP_SEQ_MAPI));
|
||||
op_names.push_back(builtin_name("seq.foldl", OP_SEQ_FOLDL));
|
||||
op_names.push_back(builtin_name("seq.foldli", OP_SEQ_FOLDLI));
|
||||
op_names.push_back(builtin_name("seq.fold_lefti", OP_SEQ_FOLDLI));
|
||||
op_names.push_back(builtin_name("seq.fold_left", OP_SEQ_FOLDL));
|
||||
op_names.push_back(builtin_name("str.in.re", _OP_STRING_IN_REGEXP));
|
||||
op_names.push_back(builtin_name("str.in-re", _OP_STRING_IN_REGEXP));
|
||||
op_names.push_back(builtin_name("str.to.re", _OP_STRING_TO_REGEXP));
|
||||
|
|
|
@ -81,7 +81,7 @@ void dependent_expr_state::freeze_recfun() {
|
|||
ast_mark visited;
|
||||
for (func_decl* f : rec.get_rec_funs()) {
|
||||
auto& d = rec.get_def(f);
|
||||
if (!d.is_macro())
|
||||
if (!d.is_macro() && d.get_rhs())
|
||||
freeze_terms(d.get_rhs(), false, visited);
|
||||
}
|
||||
m_trail.push(value_trail(m_num_recfun));
|
||||
|
|
|
@ -41,7 +41,7 @@ class dominator_simplifier : public dependent_expr_simplifier {
|
|||
bool is_subexpr(expr * a, expr * b);
|
||||
|
||||
expr_ref get_cached(expr* t) { expr* r = nullptr; if (!m_result.find(t, r)) r = t; return expr_ref(r, m); }
|
||||
void cache(expr *t, expr* r) { m_result.insert(t, r); m_trail.push_back(r); }
|
||||
void cache(expr *t, expr* r) { m_result.insert(t, r); m_trail.push_back(r); m_trail.push_back(t); }
|
||||
void reset_cache() { m_result.reset(); }
|
||||
|
||||
ptr_vector<expr> const & tree(expr * e);
|
||||
|
|
|
@ -52,9 +52,9 @@ monotonicity or reflexivity rules.
|
|||
#include "ast/simplifiers/elim_unconstrained.h"
|
||||
|
||||
elim_unconstrained::elim_unconstrained(ast_manager& m, dependent_expr_state& fmls) :
|
||||
dependent_expr_simplifier(m, fmls), m_inverter(m), m_lt(*this), m_heap(1024, m_lt), m_trail(m) {
|
||||
dependent_expr_simplifier(m, fmls), m_inverter(m), m_lt(*this), m_heap(1024, m_lt), m_trail(m), m_args(m) {
|
||||
std::function<bool(expr*)> is_var = [&](expr* e) {
|
||||
return is_uninterp_const(e) && !m_fmls.frozen(e) && get_node(e).m_refcount <= 1;
|
||||
return is_uninterp_const(e) && !m_fmls.frozen(e) && is_node(e) && get_node(e).m_refcount <= 1;
|
||||
};
|
||||
m_inverter.set_is_var(is_var);
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ void elim_unconstrained::eliminate() {
|
|||
node& n = get_node(v);
|
||||
if (n.m_refcount == 0)
|
||||
continue;
|
||||
if (n.m_refcount > 1)
|
||||
if (n.m_refcount > 1)
|
||||
return;
|
||||
|
||||
if (n.m_parents.empty()) {
|
||||
|
@ -90,10 +90,10 @@ void elim_unconstrained::eliminate() {
|
|||
unsigned sz = m_args.size();
|
||||
for (expr* arg : *to_app(t))
|
||||
m_args.push_back(reconstruct_term(get_node(arg)));
|
||||
bool inverted = m_inverter(t->get_decl(), to_app(t)->get_num_args(), m_args.data() + sz, r);
|
||||
bool inverted = m_inverter(t->get_decl(), t->get_num_args(), m_args.data() + sz, r);
|
||||
proof_ref pr(m);
|
||||
if (inverted && m_enable_proofs) {
|
||||
expr * s = m.mk_app(t->get_decl(), to_app(t)->get_num_args(), m_args.data() + sz);
|
||||
expr * s = m.mk_app(t->get_decl(), t->get_num_args(), m_args.data() + sz);
|
||||
expr * eq = m.mk_eq(s, r);
|
||||
proof * pr1 = m.mk_def_intro(eq);
|
||||
proof * pr = m.mk_apply_def(s, r, pr1);
|
||||
|
@ -114,7 +114,7 @@ void elim_unconstrained::eliminate() {
|
|||
gc(e);
|
||||
invalidate_parents(e);
|
||||
freeze_rec(r);
|
||||
|
||||
|
||||
m_root.setx(r->get_id(), e->get_id(), UINT_MAX);
|
||||
get_node(e).m_term = r;
|
||||
get_node(e).m_proof = pr;
|
||||
|
@ -291,7 +291,7 @@ expr_ref elim_unconstrained::reconstruct_term(node& n0) {
|
|||
unsigned sz0 = todo.size();
|
||||
if (is_app(t)) {
|
||||
for (expr* arg : *to_app(t))
|
||||
if (get_node(arg).m_dirty)
|
||||
if (get_node(arg).m_dirty || !get_node(arg).m_term)
|
||||
todo.push_back(arg);
|
||||
if (todo.size() != sz0)
|
||||
continue;
|
||||
|
@ -300,18 +300,20 @@ expr_ref elim_unconstrained::reconstruct_term(node& n0) {
|
|||
for (expr* arg : *to_app(t))
|
||||
m_args.push_back(get_node(arg).m_term);
|
||||
n.m_term = m.mk_app(to_app(t)->get_decl(), to_app(t)->get_num_args(), m_args.data() + sz);
|
||||
|
||||
m_args.shrink(sz);
|
||||
}
|
||||
else if (is_quantifier(t)) {
|
||||
expr* body = to_quantifier(t)->get_expr();
|
||||
node& n2 = get_node(body);
|
||||
if (n2.m_dirty) {
|
||||
if (n2.m_dirty || !n2.m_term) {
|
||||
todo.push_back(body);
|
||||
continue;
|
||||
}
|
||||
n.m_term = m.update_quantifier(to_quantifier(t), n2.m_term);
|
||||
}
|
||||
m_trail.push_back(n.m_term);
|
||||
m_root.setx(n.m_term->get_id(), n.m_term->get_id(), UINT_MAX);
|
||||
todo.pop_back();
|
||||
n.m_dirty = false;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,8 @@ Author:
|
|||
|
||||
class elim_unconstrained : public dependent_expr_simplifier {
|
||||
|
||||
friend class seq_simplifier;
|
||||
|
||||
struct node {
|
||||
unsigned m_refcount = 0;
|
||||
expr* m_term = nullptr;
|
||||
|
@ -46,13 +48,15 @@ class elim_unconstrained : public dependent_expr_simplifier {
|
|||
var_lt m_lt;
|
||||
heap<var_lt> m_heap;
|
||||
expr_ref_vector m_trail;
|
||||
ptr_vector<expr> m_args;
|
||||
expr_ref_vector m_args;
|
||||
stats m_stats;
|
||||
unsigned_vector m_root;
|
||||
bool m_created_compound = false;
|
||||
bool m_enable_proofs = false;
|
||||
|
||||
bool is_var_lt(int v1, int v2) const;
|
||||
bool is_node(unsigned n) const { return m_nodes.size() > n; }
|
||||
bool is_node(expr* t) const { return is_node(t->get_id()); }
|
||||
node& get_node(unsigned n) { return m_nodes[n]; }
|
||||
node const& get_node(unsigned n) const { return m_nodes[n]; }
|
||||
node& get_node(expr* t) { return m_nodes[root(t)]; }
|
||||
|
|
|
@ -174,7 +174,7 @@ bool eliminate_predicates::can_be_quasi_macro_head(expr* _head, unsigned num_bou
|
|||
// then replace (f x y z) by (if (= z (+ x y)) s (f' x y z))
|
||||
//
|
||||
|
||||
void eliminate_predicates::insert_quasi_macro(app* head, expr* body, clause const& cl) {
|
||||
void eliminate_predicates::insert_quasi_macro(app* head, expr* body, clause& cl) {
|
||||
expr_ref _body(body, m);
|
||||
uint_set indices;
|
||||
expr_ref_vector args(m), eqs(m);
|
||||
|
@ -205,9 +205,10 @@ void eliminate_predicates::insert_quasi_macro(app* head, expr* body, clause cons
|
|||
|
||||
// forall vars . f(args) = if eqs then body else f'(args)
|
||||
f1 = m.mk_fresh_func_decl(f->get_name(), symbol::null, sorts.size(), sorts.data(), f->get_range());
|
||||
|
||||
lhs = m.mk_app(f, args);
|
||||
rhs = m.mk_ite(mk_and(eqs), body, m.mk_app(f1, args));
|
||||
insert_macro(lhs, rhs, cl.m_dep);
|
||||
insert_macro(lhs, rhs, cl);
|
||||
}
|
||||
|
||||
|
||||
|
@ -310,6 +311,12 @@ bool eliminate_predicates::is_macro_safe(expr* e) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void eliminate_predicates::insert_macro(app* head, expr* def, clause& cl) {
|
||||
insert_macro(head, def, cl.m_dep);
|
||||
TRACE("elim_predicates", tout << "remove " << cl << "\n");
|
||||
cl.m_alive = false;
|
||||
}
|
||||
|
||||
void eliminate_predicates::insert_macro(app* head, expr* def, expr_dependency* dep) {
|
||||
unsigned num = head->get_num_args();
|
||||
ptr_buffer<expr> vars, subst_args;
|
||||
|
@ -334,7 +341,7 @@ void eliminate_predicates::insert_macro(app* head, expr* def, expr_dependency* d
|
|||
auto* info = alloc(macro_def, _head, _def, _dep);
|
||||
m_macros.insert(head->get_decl(), info);
|
||||
m_fmls.model_trail().push(head->get_decl(), _def, _dep, {}); // augment with definition for head
|
||||
m_is_macro.mark(head->get_decl(), true);
|
||||
m_is_macro.mark(head->get_decl(), true);
|
||||
TRACE("elim_predicates", tout << "insert " << _head << " " << _def << "\n");
|
||||
++m_stats.m_num_macros;
|
||||
}
|
||||
|
@ -367,26 +374,22 @@ void eliminate_predicates::try_find_macro(clause& cl) {
|
|||
// (= (f x) t)
|
||||
if (cl.is_unit() && !cl.sign(0) && m.is_eq(cl.atom(0), x, y)) {
|
||||
if (can_be_def(x, y)) {
|
||||
insert_macro(to_app(x), y, cl.m_dep);
|
||||
cl.m_alive = false;
|
||||
insert_macro(to_app(x), y, cl);
|
||||
return;
|
||||
}
|
||||
if (can_be_def(y, x)) {
|
||||
insert_macro(to_app(y), x, cl.m_dep);
|
||||
cl.m_alive = false;
|
||||
insert_macro(to_app(y), x, cl);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// not (= (p x) t) -> (p x) = (not t)
|
||||
if (cl.is_unit() && cl.sign(0) && m.is_iff(cl.atom(0), x, y)) {
|
||||
if (can_be_def(x, y)) {
|
||||
insert_macro(to_app(x), m.mk_not(y), cl.m_dep);
|
||||
cl.m_alive = false;
|
||||
insert_macro(to_app(x), m.mk_not(y), cl);
|
||||
return;
|
||||
}
|
||||
if (can_be_def(y, x)) {
|
||||
insert_macro(to_app(y), m.mk_not(x), cl.m_dep);
|
||||
cl.m_alive = false;
|
||||
insert_macro(to_app(y), m.mk_not(x), cl);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -413,8 +416,7 @@ void eliminate_predicates::try_find_macro(clause& cl) {
|
|||
m_fmls.model_trail().hide(fn); // hide definition of fn
|
||||
k = m.mk_app(fn, f->get_num_args(), f->get_args());
|
||||
def = m.mk_ite(cond, t, k);
|
||||
insert_macro(f, def, cl.m_dep);
|
||||
cl.m_alive = false;
|
||||
insert_macro(f, def, cl);
|
||||
fml = m.mk_not(m.mk_eq(k, t));
|
||||
clause* new_cl = init_clause(fml, cl.m_dep, UINT_MAX);
|
||||
add_use_list(*new_cl);
|
||||
|
@ -531,8 +533,7 @@ void eliminate_predicates::try_find_macro(clause& cl) {
|
|||
expr_ref y1 = subtract(y, to_app(x), i);
|
||||
if (inv)
|
||||
y1 = uminus(y1);
|
||||
insert_macro(to_app(arg), y1, cl.m_dep);
|
||||
cl.m_alive = false;
|
||||
insert_macro(to_app(arg), y1, cl);
|
||||
return true;
|
||||
}
|
||||
next:
|
||||
|
@ -572,7 +573,7 @@ void eliminate_predicates::try_find_macro(clause& cl) {
|
|||
!occurs(x->get_decl(), y);
|
||||
};
|
||||
|
||||
if (cl.is_unit() && m.is_eq(cl.atom(0), x, y)) {
|
||||
if (cl.is_unit() && m.is_eq(cl.atom(0), x, y) && !cl.m_bound.empty()) {
|
||||
if (!cl.sign(0) && can_be_qdef(x, y)) {
|
||||
insert_quasi_macro(to_app(x), y, cl);
|
||||
return;
|
||||
|
@ -590,7 +591,7 @@ void eliminate_predicates::try_find_macro(clause& cl) {
|
|||
return;
|
||||
}
|
||||
}
|
||||
if (cl.is_unit()) {
|
||||
if (cl.is_unit() && !cl.m_bound.empty()) {
|
||||
expr* body = cl.sign(0) ? m.mk_false() : m.mk_true();
|
||||
expr* x = cl.atom(0);
|
||||
if (can_be_qdef(x, body)) {
|
||||
|
@ -736,6 +737,7 @@ void eliminate_predicates::update_model(func_decl* p) {
|
|||
}
|
||||
|
||||
rewrite(def);
|
||||
TRACE("elim_predicates", tout << "insert " << p->get_name() << " " << def << "\n");
|
||||
m_fmls.model_trail().push(p, def, dep, deleted);
|
||||
}
|
||||
|
||||
|
@ -1008,8 +1010,6 @@ void eliminate_predicates::reset() {
|
|||
|
||||
|
||||
void eliminate_predicates::reduce() {
|
||||
if (!m_fmls.has_quantifiers())
|
||||
return;
|
||||
reset();
|
||||
init_clauses();
|
||||
find_definitions();
|
||||
|
|
|
@ -111,9 +111,10 @@ private:
|
|||
bool try_find_binary_definition(func_decl* p, app_ref& head, expr_ref& def, expr_dependency_ref& dep);
|
||||
void try_resolve_definition(func_decl* p);
|
||||
void insert_macro(app* head, expr* def, expr_dependency* dep);
|
||||
void insert_macro(app* head, expr* def, clause& cl);
|
||||
expr_ref bind_free_variables_in_def(clause& cl, app* head, expr* def);
|
||||
bool can_be_macro_head(expr* head, unsigned num_bound);
|
||||
void insert_quasi_macro(app* head, expr* body, clause const& cl);
|
||||
void insert_quasi_macro(app* head, expr* body, clause& cl);
|
||||
bool can_be_quasi_macro_head(expr* head, unsigned num_bound);
|
||||
bool is_macro_safe(expr* e);
|
||||
void try_find_macro(clause& cl);
|
||||
|
|
|
@ -262,6 +262,47 @@ namespace euf {
|
|||
}
|
||||
}
|
||||
|
||||
void solve_eqs::collect_num_occs(expr * t, expr_fast_mark1 & visited) {
|
||||
ptr_buffer<app, 128> stack;
|
||||
|
||||
auto visit = [&](expr* arg) {
|
||||
if (is_uninterp_const(arg))
|
||||
m_num_occs.insert_if_not_there(arg, 0)++;
|
||||
if (!visited.is_marked(arg) && is_app(arg)) {
|
||||
visited.mark(arg, true);
|
||||
stack.push_back(to_app(arg));
|
||||
}
|
||||
};
|
||||
|
||||
visit(t);
|
||||
|
||||
while (!stack.empty()) {
|
||||
app * t = stack.back();
|
||||
stack.pop_back();
|
||||
for (expr* arg : *t)
|
||||
visit(arg);
|
||||
}
|
||||
}
|
||||
|
||||
void solve_eqs::collect_num_occs() {
|
||||
if (m_config.m_max_occs == UINT_MAX)
|
||||
return; // no need to compute num occs
|
||||
m_num_occs.reset();
|
||||
expr_fast_mark1 visited;
|
||||
for (unsigned i : indices())
|
||||
collect_num_occs(m_fmls[i].fml(), visited);
|
||||
}
|
||||
|
||||
// Check if the number of occurrences of t is below the specified threshold :solve-eqs-max-occs
|
||||
bool solve_eqs::check_occs(expr * t) const {
|
||||
if (m_config.m_max_occs == UINT_MAX)
|
||||
return true;
|
||||
unsigned num = 0;
|
||||
m_num_occs.find(t, num);
|
||||
TRACE("solve_eqs_check_occs", tout << mk_ismt2_pp(t, m) << " num_occs: " << num << " max: " << m_config.m_max_occs << "\n";);
|
||||
return num <= m_config.m_max_occs;
|
||||
}
|
||||
|
||||
void solve_eqs::save_subst(vector<dependent_expr> const& old_fmls) {
|
||||
if (!m_subst->empty())
|
||||
m_fmls.model_trail().push(m_subst.detach(), old_fmls);
|
||||
|
|
|
@ -56,10 +56,12 @@ namespace euf {
|
|||
expr_mark m_unsafe_vars; // expressions that cannot be replaced
|
||||
ptr_vector<expr> m_todo;
|
||||
expr_mark m_visited;
|
||||
obj_map<expr, unsigned> m_num_occs;
|
||||
|
||||
|
||||
bool is_var(expr* e) const { return e->get_id() < m_var2id.size() && m_var2id[e->get_id()] != UINT_MAX; }
|
||||
unsigned var2id(expr* v) const { return m_var2id[v->get_id()]; }
|
||||
bool can_be_var(expr* e) const { return is_uninterp_const(e) && !m_unsafe_vars.is_marked(e); }
|
||||
bool can_be_var(expr* e) const { return is_uninterp_const(e) && !m_unsafe_vars.is_marked(e) && check_occs(e); }
|
||||
void get_eqs(dep_eq_vector& eqs);
|
||||
void filter_unsafe_vars();
|
||||
void extract_subst();
|
||||
|
@ -67,6 +69,9 @@ namespace euf {
|
|||
void normalize();
|
||||
void apply_subst(vector<dependent_expr>& old_fmls);
|
||||
void save_subst(vector<dependent_expr> const& old_fmls);
|
||||
void collect_num_occs(expr * t, expr_fast_mark1 & visited);
|
||||
void collect_num_occs();
|
||||
bool check_occs(expr* t) const;
|
||||
|
||||
public:
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ Copyright (c) 2022 Microsoft Corporation
|
|||
|
||||
Module Name:
|
||||
|
||||
seq_simplifier.h
|
||||
then_simplifier.h
|
||||
|
||||
Abstract:
|
||||
|
||||
|
@ -21,7 +21,7 @@ Author:
|
|||
#include "ast/simplifiers/dependent_expr_state.h"
|
||||
|
||||
|
||||
class seq_simplifier : public dependent_expr_simplifier {
|
||||
class then_simplifier : public dependent_expr_simplifier {
|
||||
scoped_ptr_vector<dependent_expr_simplifier> m_simplifiers;
|
||||
|
||||
struct collect_stats {
|
||||
|
@ -53,7 +53,7 @@ class seq_simplifier : public dependent_expr_simplifier {
|
|||
|
||||
public:
|
||||
|
||||
seq_simplifier(ast_manager& m, params_ref const& p, dependent_expr_state& fmls):
|
||||
then_simplifier(ast_manager& m, params_ref const& p, dependent_expr_state& fmls):
|
||||
dependent_expr_simplifier(m, fmls) {
|
||||
}
|
||||
|
|
@ -47,6 +47,7 @@ func_decl * special_relations_decl_plugin::mk_func_decl(
|
|||
if (!m_manager->is_bool(range)) {
|
||||
m_manager->raise_exception("range type is expected to be Boolean for special relations");
|
||||
}
|
||||
m_has_special_relation = true;
|
||||
func_decl_info info(m_family_id, k, num_parameters, parameters);
|
||||
symbol name;
|
||||
switch(k) {
|
||||
|
@ -54,7 +55,11 @@ func_decl * special_relations_decl_plugin::mk_func_decl(
|
|||
case OP_SPECIAL_RELATION_LO: name = m_lo; break;
|
||||
case OP_SPECIAL_RELATION_PLO: name = m_plo; break;
|
||||
case OP_SPECIAL_RELATION_TO: name = m_to; break;
|
||||
case OP_SPECIAL_RELATION_TC: name = m_tc; break;
|
||||
case OP_SPECIAL_RELATION_TC:
|
||||
name = m_tc;
|
||||
if (num_parameters != 1 || !parameters[0].is_ast() || !is_func_decl(parameters[0].get_ast()))
|
||||
m_manager->raise_exception("parameter to transitive closure should be a function declaration");
|
||||
break;
|
||||
}
|
||||
return m_manager->mk_func_decl(name, arity, domain, range, info);
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ class special_relations_decl_plugin : public decl_plugin {
|
|||
symbol m_plo;
|
||||
symbol m_to;
|
||||
symbol m_tc;
|
||||
bool m_has_special_relation = false;
|
||||
public:
|
||||
special_relations_decl_plugin();
|
||||
|
||||
|
@ -50,6 +51,8 @@ public:
|
|||
void get_op_names(svector<builtin_name> & op_names, symbol const & logic) override;
|
||||
|
||||
sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) override { return nullptr; }
|
||||
|
||||
bool has_special_relation() const { return m_has_special_relation; }
|
||||
};
|
||||
|
||||
enum sr_property {
|
||||
|
@ -71,15 +74,19 @@ class special_relations_util {
|
|||
ast_manager& m;
|
||||
mutable family_id m_fid;
|
||||
func_decl* mk_rel_decl(func_decl* f, decl_kind k) {
|
||||
SASSERT(f);
|
||||
parameter p(f); SASSERT(f->get_arity() == 2);
|
||||
return m.mk_func_decl(fid(), k, 1, &p, 2, f->get_domain(), f->get_range());
|
||||
}
|
||||
family_id fid() const {
|
||||
if (null_family_id == m_fid) m_fid = m.get_family_id("specrels");
|
||||
if (null_family_id == m_fid)
|
||||
m_fid = m.get_family_id("specrels");
|
||||
return m_fid;
|
||||
}
|
||||
public:
|
||||
special_relations_util(ast_manager& m) : m(m), m_fid(null_family_id) { }
|
||||
|
||||
bool has_special_relation() const { return static_cast<special_relations_decl_plugin*>(m.get_plugin(m.mk_family_id("specrels")))->has_special_relation(); }
|
||||
|
||||
bool is_special_relation(func_decl* f) const { return f->get_family_id() == fid(); }
|
||||
bool is_special_relation(app* e) const { return is_special_relation(e->get_decl()); }
|
||||
|
@ -99,6 +106,12 @@ public:
|
|||
bool is_to(expr const * e) const { return is_app_of(e, fid(), OP_SPECIAL_RELATION_TO); }
|
||||
bool is_tc(expr const * e) const { return is_app_of(e, fid(), OP_SPECIAL_RELATION_TC); }
|
||||
|
||||
bool is_lo(func_decl const * e) const { return is_decl_of(e, fid(), OP_SPECIAL_RELATION_LO); }
|
||||
bool is_po(func_decl const * e) const { return is_decl_of(e, fid(), OP_SPECIAL_RELATION_PO); }
|
||||
bool is_plo(func_decl const * e) const { return is_decl_of(e, fid(), OP_SPECIAL_RELATION_PLO); }
|
||||
bool is_to(func_decl const * e) const { return is_decl_of(e, fid(), OP_SPECIAL_RELATION_TO); }
|
||||
bool is_tc(func_decl const * e) const { return is_decl_of(e, fid(), OP_SPECIAL_RELATION_TC); }
|
||||
|
||||
app * mk_lo (expr * arg1, expr * arg2) { return m.mk_app( fid(), OP_SPECIAL_RELATION_LO, arg1, arg2); }
|
||||
app * mk_po (expr * arg1, expr * arg2) { return m.mk_app( fid(), OP_SPECIAL_RELATION_PO, arg1, arg2); }
|
||||
app * mk_plo(expr * arg1, expr * arg2) { return m.mk_app( fid(), OP_SPECIAL_RELATION_PLO, arg1, arg2); }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue