mirror of
https://github.com/Z3Prover/z3
synced 2025-06-23 06:13:40 +00:00
synchronizing with main repository
This commit is contained in:
commit
ec76efedbe
386 changed files with 10027 additions and 8346 deletions
|
@ -19,6 +19,7 @@ z3_add_component(rewriter
|
|||
factor_equivs.cpp
|
||||
factor_rewriter.cpp
|
||||
fpa_rewriter.cpp
|
||||
hoist_rewriter.cpp
|
||||
inj_axiom.cpp
|
||||
label_rewriter.cpp
|
||||
maximize_ac_sharing.cpp
|
||||
|
|
|
@ -861,7 +861,8 @@ bool arith_rewriter::divides(expr* num, expr* den, expr_ref& result) {
|
|||
if (m_util.is_numeral(arg, num_r)) num_e = arg;
|
||||
}
|
||||
for (expr* arg : args2) {
|
||||
if (mark.is_marked(arg)) {
|
||||
// dont remove divisor on (div (* -1 x) (* -1 y)) because rewriting would diverge.
|
||||
if (mark.is_marked(arg) && (!m_util.is_numeral(arg, num_r) || !num_r.is_minus_one())) {
|
||||
result = remove_divisor(arg, num, den);
|
||||
return true;
|
||||
}
|
||||
|
@ -900,7 +901,14 @@ expr_ref arith_rewriter::remove_divisor(expr* arg, expr* num, expr* den) {
|
|||
expr_ref zero(m_util.mk_int(0), m());
|
||||
num = args1.empty() ? m_util.mk_int(1) : m_util.mk_mul(args1.size(), args1.c_ptr());
|
||||
den = args2.empty() ? m_util.mk_int(1) : m_util.mk_mul(args2.size(), args2.c_ptr());
|
||||
return expr_ref(m().mk_ite(m().mk_eq(zero, arg), m_util.mk_idiv(zero, zero), m_util.mk_idiv(num, den)), m());
|
||||
expr_ref d(m_util.mk_idiv(num, den), m());
|
||||
expr_ref nd(m_util.mk_idiv(m_util.mk_uminus(num), m_util.mk_uminus(den)), m());
|
||||
return expr_ref(m().mk_ite(m().mk_eq(zero, arg),
|
||||
m_util.mk_idiv(zero, zero),
|
||||
m().mk_ite(m_util.mk_ge(arg, zero),
|
||||
d,
|
||||
nd)),
|
||||
m());
|
||||
}
|
||||
|
||||
void arith_rewriter::flat_mul(expr* e, ptr_buffer<expr>& args) {
|
||||
|
|
|
@ -75,9 +75,23 @@ bool bit_blaster_tpl<Cfg>::is_minus_one(unsigned sz, expr * const * bits) const
|
|||
static void _num2bits(ast_manager & m, rational const & v, unsigned sz, expr_ref_vector & out_bits) {
|
||||
SASSERT(v.is_nonneg());
|
||||
rational aux = v;
|
||||
rational two(2);
|
||||
rational two(2), base32(1ull << 32ull, rational::ui64());
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
if ((aux % two).is_zero())
|
||||
if (i + 32 < sz) {
|
||||
unsigned u = (aux % base32).get_unsigned();
|
||||
for (unsigned j = 0; j < 32; ++j) {
|
||||
if (0 != (u & (1 << j))) {
|
||||
out_bits.push_back(m.mk_true());
|
||||
}
|
||||
else {
|
||||
out_bits.push_back(m.mk_false());
|
||||
}
|
||||
}
|
||||
aux = div(aux, base32);
|
||||
i += 31;
|
||||
continue;
|
||||
}
|
||||
else if ((aux % two).is_zero())
|
||||
out_bits.push_back(m.mk_false());
|
||||
else
|
||||
out_bits.push_back(m.mk_true());
|
||||
|
|
|
@ -628,7 +628,7 @@ bool bv_bounds::is_sat_core(app * v) {
|
|||
numeral new_hi = lower - one;
|
||||
numeral ptr = lower;
|
||||
if (has_neg_intervals) {
|
||||
SASSERT(negative_intervals != NULL);
|
||||
SASSERT(negative_intervals != nullptr);
|
||||
std::sort(negative_intervals->begin(), negative_intervals->end(), interval_comp);
|
||||
intervals::const_iterator e = negative_intervals->end();
|
||||
for (intervals::const_iterator i = negative_intervals->begin(); i != e; ++i) {
|
||||
|
|
|
@ -196,6 +196,9 @@ br_status bv_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons
|
|||
return mk_bv_comp(args[0], args[1], result);
|
||||
case OP_MKBV:
|
||||
return mk_mkbv(num_args, args, result);
|
||||
case OP_BIT2BOOL:
|
||||
SASSERT(num_args == 1);
|
||||
return mk_bit2bool(args[0], f->get_parameter(0).get_int(), result);
|
||||
case OP_BSMUL_NO_OVFL:
|
||||
return mk_bvsmul_no_overflow(num_args, args, result);
|
||||
case OP_BUMUL_NO_OVFL:
|
||||
|
@ -779,10 +782,11 @@ br_status bv_rewriter::mk_extract(unsigned high, unsigned low, expr * arg, expr_
|
|||
}
|
||||
}
|
||||
|
||||
if (m().is_ite(arg)) {
|
||||
result = m().mk_ite(to_app(arg)->get_arg(0),
|
||||
m_mk_extract(high, low, to_app(arg)->get_arg(1)),
|
||||
m_mk_extract(high, low, to_app(arg)->get_arg(2)));
|
||||
expr* c = nullptr, *t = nullptr, *e = nullptr;
|
||||
if (m().is_ite(arg, c, t, e) &&
|
||||
(t->get_ref_count() == 1 || !m().is_ite(t)) &&
|
||||
(e->get_ref_count() == 1 || !m().is_ite(e))) {
|
||||
result = m().mk_ite(c, m_mk_extract(high, low, t), m_mk_extract(high, low, e));
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
|
||||
|
@ -2202,6 +2206,19 @@ br_status bv_rewriter::mk_bv_mul(unsigned num_args, expr * const * args, expr_re
|
|||
return st;
|
||||
}
|
||||
|
||||
br_status bv_rewriter::mk_bit2bool(expr * n, int idx, expr_ref & result) {
|
||||
rational v, bit;
|
||||
unsigned sz = 0;
|
||||
if (!is_numeral(n, v, sz))
|
||||
return BR_FAILED;
|
||||
if (idx < 0 || idx >= static_cast<int>(sz))
|
||||
return BR_FAILED;
|
||||
div(v, rational::power_of_two(idx), bit);
|
||||
mod(bit, rational(2), bit);
|
||||
result = m().mk_bool_val(bit.is_one());
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
br_status bv_rewriter::mk_bit2bool(expr * lhs, expr * rhs, expr_ref & result) {
|
||||
unsigned sz = get_bv_size(lhs);
|
||||
if (sz != 1)
|
||||
|
|
|
@ -134,6 +134,7 @@ class bv_rewriter : public poly_rewriter<bv_rewriter_core> {
|
|||
br_status mk_bv_redand(expr * arg, expr_ref & result);
|
||||
br_status mk_bv_comp(expr * arg1, expr * arg2, expr_ref & result);
|
||||
br_status mk_bit2bool(expr * lhs, expr * rhs, expr_ref & result);
|
||||
br_status mk_bit2bool(expr * lhs, int idx, expr_ref & result);
|
||||
br_status mk_blast_eq_value(expr * lhs, expr * rhs, expr_ref & result);
|
||||
br_status mk_eq_concat(expr * lhs, expr * rhs, expr_ref & result);
|
||||
br_status mk_mkbv(unsigned num, expr * const * args, expr_ref & result);
|
||||
|
|
|
@ -364,7 +364,7 @@ struct bv_trailing::imp {
|
|||
}
|
||||
|
||||
void reset_cache(const unsigned condition) {
|
||||
SASSERT(m_count_cache[0] == NULL);
|
||||
SASSERT(m_count_cache[0] == nullptr);
|
||||
for (unsigned i = 1; i <= TRAILING_DEPTH; ++i) {
|
||||
if (m_count_cache[i] == nullptr) continue;
|
||||
TRACE("bv-trailing", tout << "may reset cache " << i << " " << condition << "\n";);
|
||||
|
|
|
@ -374,13 +374,11 @@ void der::apply_substitution(quantifier * q, expr_ref & r) {
|
|||
expr_ref_buffer new_patterns(m_manager);
|
||||
expr_ref_buffer new_no_patterns(m_manager);
|
||||
for (unsigned j = 0; j < q->get_num_patterns(); j++) {
|
||||
expr_ref new_pat = m_subst(q->get_pattern(j), m_subst_map.size(), m_subst_map.c_ptr());
|
||||
new_patterns.push_back(new_pat);
|
||||
new_patterns.push_back(m_subst(q->get_pattern(j), m_subst_map.size(), m_subst_map.c_ptr()));
|
||||
}
|
||||
|
||||
for (unsigned j = 0; j < q->get_num_no_patterns(); j++) {
|
||||
expr_ref new_nopat = m_subst(q->get_no_pattern(j), m_subst_map.size(), m_subst_map.c_ptr());
|
||||
new_no_patterns.push_back(new_nopat);
|
||||
new_no_patterns.push_back(m_subst(q->get_no_pattern(j), m_subst_map.size(), m_subst_map.c_ptr()));
|
||||
}
|
||||
|
||||
r = m_manager.update_quantifier(q, new_patterns.size(), new_patterns.c_ptr(),
|
||||
|
|
|
@ -126,8 +126,7 @@ void distribute_forall::reduce1_quantifier(quantifier * q) {
|
|||
br.mk_not(arg, not_arg);
|
||||
quantifier_ref tmp_q(m_manager);
|
||||
tmp_q = m_manager.update_quantifier(q, not_arg);
|
||||
expr_ref new_q = elim_unused_vars(m_manager, tmp_q, params_ref());
|
||||
new_args.push_back(new_q);
|
||||
new_args.push_back(elim_unused_vars(m_manager, tmp_q, params_ref()));
|
||||
}
|
||||
expr_ref result(m_manager);
|
||||
// m_bsimp.mk_and actually constructs a (not (or ...)) formula,
|
||||
|
|
201
src/ast/rewriter/hoist_rewriter.cpp
Normal file
201
src/ast/rewriter/hoist_rewriter.cpp
Normal file
|
@ -0,0 +1,201 @@
|
|||
/*++
|
||||
Copyright (c) 2019 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
hoist_rewriter.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Hoist predicates over disjunctions
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2019-2-4
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
#include "ast/rewriter/hoist_rewriter.h"
|
||||
#include "ast/ast_util.h"
|
||||
#include "ast/rewriter/expr_safe_replace.h"
|
||||
#include "ast/ast_pp.h"
|
||||
|
||||
|
||||
hoist_rewriter::hoist_rewriter(ast_manager & m, params_ref const & p):
|
||||
m_manager(m), m_args1(m), m_args2(m) {
|
||||
updt_params(p);
|
||||
}
|
||||
|
||||
br_status hoist_rewriter::mk_or(unsigned num_args, expr * const * es, expr_ref & result) {
|
||||
if (num_args < 2) {
|
||||
return BR_FAILED;
|
||||
}
|
||||
for (unsigned i = 0; i < num_args; ++i) {
|
||||
if (!is_and(es[i], nullptr)) {
|
||||
return BR_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
bool turn = false;
|
||||
m_preds1.reset();
|
||||
m_preds2.reset();
|
||||
m_uf1.reset();
|
||||
m_uf2.reset();
|
||||
m_expr2var.reset();
|
||||
m_var2expr.reset();
|
||||
basic_union_find* uf[2] = { &m_uf1, &m_uf2 };
|
||||
obj_hashtable<expr>* preds[2] = { &m_preds1, &m_preds2 };
|
||||
expr_ref_vector* args[2] = { &m_args1, &m_args2 };
|
||||
VERIFY(is_and(es[0], args[turn]));
|
||||
expr* e1, *e2;
|
||||
for (expr* e : *(args[turn])) {
|
||||
if (m().is_eq(e, e1, e2)) {
|
||||
(*uf)[turn].merge(mk_var(e1), mk_var(e2));
|
||||
}
|
||||
else {
|
||||
(*preds)[turn].insert(e);
|
||||
}
|
||||
}
|
||||
unsigned round = 0;
|
||||
for (unsigned j = 1; j < num_args; ++j) {
|
||||
++round;
|
||||
m_es.reset();
|
||||
m_mark.reset();
|
||||
|
||||
bool last = turn;
|
||||
turn = !turn;
|
||||
(*preds)[turn].reset();
|
||||
reset(m_uf0);
|
||||
VERIFY(is_and(es[j], args[turn]));
|
||||
|
||||
for (expr* e : *args[turn]) {
|
||||
if (m().is_eq(e, e1, e2)) {
|
||||
m_es.push_back(e1);
|
||||
m_uf0.merge(mk_var(e1), mk_var(e2));
|
||||
}
|
||||
else if ((*preds)[last].contains(e)) {
|
||||
(*preds)[turn].insert(e);
|
||||
}
|
||||
}
|
||||
|
||||
if ((*preds)[turn].empty() && m_es.empty()) {
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
m_eqs.reset();
|
||||
for (expr* e : m_es) {
|
||||
if (m_mark.is_marked(e)) {
|
||||
continue;
|
||||
}
|
||||
unsigned u = mk_var(e);
|
||||
unsigned v = u;
|
||||
m_roots.reset();
|
||||
do {
|
||||
m_mark.mark(e);
|
||||
unsigned r = (*uf)[last].find(v);
|
||||
if (m_roots.find(r, e2)) {
|
||||
m_eqs.push_back(std::make_pair(e, e2));
|
||||
}
|
||||
else {
|
||||
m_roots.insert(r, e);
|
||||
}
|
||||
v = m_uf0.next(v);
|
||||
e = mk_expr(v);
|
||||
}
|
||||
while (u != v);
|
||||
}
|
||||
reset((*uf)[turn]);
|
||||
for (auto const& p : m_eqs) {
|
||||
(*uf)[turn].merge(mk_var(p.first), mk_var(p.second));
|
||||
}
|
||||
if ((*preds)[turn].empty() && m_eqs.empty()) {
|
||||
return BR_FAILED;
|
||||
}
|
||||
}
|
||||
// p & eqs & (or fmls)
|
||||
expr_ref_vector fmls(m()), ors(m());
|
||||
expr_safe_replace subst(m());
|
||||
for (expr * p : (*preds)[turn]) {
|
||||
expr* q = nullptr;
|
||||
if (m().is_not(p, q)) {
|
||||
subst.insert(q, m().mk_false());
|
||||
}
|
||||
else {
|
||||
subst.insert(p, m().mk_true());
|
||||
}
|
||||
fmls.push_back(p);
|
||||
}
|
||||
for (auto const& p : m_eqs) {
|
||||
subst.insert(p.first, p.second);
|
||||
fmls.push_back(m().mk_eq(p.first, p.second));
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < num_args; ++i) {
|
||||
expr_ref tmp(m());
|
||||
subst(es[i], tmp);
|
||||
ors.push_back(tmp);
|
||||
}
|
||||
fmls.push_back(m().mk_or(ors.size(), ors.c_ptr()));
|
||||
result = m().mk_and(fmls.size(), fmls.c_ptr());
|
||||
TRACE("hoist",
|
||||
for (unsigned i = 0; i < num_args; ++i) {
|
||||
tout << mk_pp(es[i], m()) << "\n";
|
||||
}
|
||||
tout << "=>\n";
|
||||
tout << result << "\n";);
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
unsigned hoist_rewriter::mk_var(expr* e) {
|
||||
unsigned v = 0;
|
||||
if (m_expr2var.find(e, v)) {
|
||||
return v;
|
||||
}
|
||||
v = m_uf1.mk_var();
|
||||
v = m_uf2.mk_var();
|
||||
SASSERT(v == m_var2expr.size());
|
||||
m_expr2var.insert(e, v);
|
||||
m_var2expr.push_back(e);
|
||||
return v;
|
||||
}
|
||||
|
||||
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:
|
||||
return mk_or(num_args, args, result);
|
||||
default:
|
||||
return BR_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
bool hoist_rewriter::is_and(expr * e, expr_ref_vector* args) {
|
||||
if (m().is_and(e)) {
|
||||
if (args) {
|
||||
args->reset();
|
||||
args->append(to_app(e)->get_num_args(), to_app(e)->get_args());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (m().is_not(e, e) && m().is_or(e)) {
|
||||
if (args) {
|
||||
args->reset();
|
||||
for (expr* arg : *to_app(e)) {
|
||||
args->push_back(::mk_not(m(), arg));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void hoist_rewriter::reset(basic_union_find& uf) {
|
||||
uf.reset();
|
||||
for (expr* e : m_var2expr) {
|
||||
(void)e;
|
||||
uf.mk_var();
|
||||
}
|
||||
}
|
80
src/ast/rewriter/hoist_rewriter.h
Normal file
80
src/ast/rewriter/hoist_rewriter.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*++
|
||||
Copyright (c) 2019 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
hoist_rewriter.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Hoist predicates over disjunctions
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2019-2-4
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef HOIST_REWRITER_H_
|
||||
#define HOIST_REWRITER_H_
|
||||
|
||||
#include "ast/ast.h"
|
||||
#include "ast/rewriter/rewriter.h"
|
||||
#include "util/params.h"
|
||||
#include "util/union_find.h"
|
||||
#include "util/obj_hashtable.h"
|
||||
|
||||
class hoist_rewriter {
|
||||
ast_manager & m_manager;
|
||||
expr_ref_vector m_args1, m_args2;
|
||||
obj_hashtable<expr> m_preds1, m_preds2;
|
||||
basic_union_find m_uf1, m_uf2, m_uf0;
|
||||
ptr_vector<expr> m_es;
|
||||
svector<std::pair<expr*,expr*>> m_eqs;
|
||||
u_map<expr*> m_roots;
|
||||
obj_map<expr, unsigned> m_expr2var;
|
||||
ptr_vector<expr> m_var2expr;
|
||||
expr_mark m_mark;
|
||||
|
||||
br_status mk_or(unsigned num_args, expr * const * args, expr_ref & result);
|
||||
|
||||
bool is_and(expr* e, expr_ref_vector* args);
|
||||
|
||||
bool is_var(expr* e) { return m_expr2var.contains(e); }
|
||||
expr* mk_expr(unsigned v) { return m_var2expr[v]; }
|
||||
unsigned mk_var(expr* e);
|
||||
|
||||
void reset(basic_union_find& uf);
|
||||
|
||||
public:
|
||||
hoist_rewriter(ast_manager & m, params_ref const & p = params_ref());
|
||||
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); }
|
||||
void updt_params(params_ref const & p) {}
|
||||
static void get_param_descrs(param_descrs & r) {}
|
||||
br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
|
||||
};
|
||||
|
||||
struct hoist_rewriter_cfg : public default_rewriter_cfg {
|
||||
hoist_rewriter m_r;
|
||||
bool rewrite_patterns() const { return false; }
|
||||
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
|
||||
result_pr = nullptr;
|
||||
if (f->get_family_id() != m_r.get_fid())
|
||||
return BR_FAILED;
|
||||
return m_r.mk_app_core(f, num, args, result);
|
||||
}
|
||||
hoist_rewriter_cfg(ast_manager & m, params_ref const & p):m_r(m, p) {}
|
||||
};
|
||||
|
||||
class hoist_rewriter_star : public rewriter_tpl<hoist_rewriter_cfg> {
|
||||
hoist_rewriter_cfg m_cfg;
|
||||
public:
|
||||
hoist_rewriter_star(ast_manager & m, params_ref const & p = params_ref()):
|
||||
rewriter_tpl<hoist_rewriter_cfg>(m, false, m_cfg),
|
||||
m_cfg(m, p) {}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -323,7 +323,7 @@ br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons
|
|||
break;
|
||||
}
|
||||
}
|
||||
TRACE("pb",
|
||||
TRACE("pb_verbose",
|
||||
expr_ref tmp(m);
|
||||
tmp = m.mk_app(f, num_args, args);
|
||||
tout << tmp << "\n";
|
||||
|
|
|
@ -42,7 +42,7 @@ void rewriter_core::del_cache_stack() {
|
|||
}
|
||||
}
|
||||
|
||||
void rewriter_core::cache_result(expr * k, expr * v) {
|
||||
void rewriter_core::cache_shifted_result(expr * k, unsigned offset, expr * v) {
|
||||
#if 0
|
||||
// trace for tracking cache usage
|
||||
verbose_stream() << "1 " << k->get_id() << std::endl;
|
||||
|
@ -53,7 +53,7 @@ void rewriter_core::cache_result(expr * k, expr * v) {
|
|||
|
||||
SASSERT(m().get_sort(k) == m().get_sort(v));
|
||||
|
||||
m_cache->insert(k, v);
|
||||
m_cache->insert(k, offset, v);
|
||||
#if 0
|
||||
static unsigned num_cached = 0;
|
||||
num_cached ++;
|
||||
|
|
|
@ -90,8 +90,10 @@ protected:
|
|||
void init_cache_stack();
|
||||
void del_cache_stack();
|
||||
void reset_cache();
|
||||
void cache_result(expr * k, expr * v);
|
||||
void cache_result(expr * k, expr * v) { cache_shifted_result(k, 0, v); }
|
||||
void cache_shifted_result(expr * k, unsigned offset, expr * v);
|
||||
expr * get_cached(expr * k) const { return m_cache->find(k); }
|
||||
expr * get_cached(expr* k, unsigned offset) const { return m_cache->find(k, offset); }
|
||||
|
||||
void cache_result(expr * k, expr * v, proof * pr);
|
||||
proof * get_cached_pr(expr * k) const { return static_cast<proof*>(m_cache_pr->find(k)); }
|
||||
|
|
|
@ -38,9 +38,10 @@ void rewriter_tpl<Config>::process_var(var * v) {
|
|||
if (!ProofGen) {
|
||||
// bindings are only used when Proof Generation is not enabled.
|
||||
unsigned idx = v->get_idx();
|
||||
|
||||
if (idx < m_bindings.size()) {
|
||||
unsigned index = m_bindings.size() - idx - 1;
|
||||
var * r = (var*)(m_bindings[index]);
|
||||
expr * r = m_bindings[index];
|
||||
if (r != nullptr) {
|
||||
CTRACE("rewriter", v->get_sort() != m().get_sort(r),
|
||||
tout << expr_ref(v, m()) << ":" << sort_ref(v->get_sort(), m()) << " != " << expr_ref(r, m()) << ":" << sort_ref(m().get_sort(r), m());
|
||||
|
@ -50,11 +51,18 @@ void rewriter_tpl<Config>::process_var(var * v) {
|
|||
if (!is_ground(r) && m_shifts[index] != m_bindings.size()) {
|
||||
|
||||
unsigned shift_amount = m_bindings.size() - m_shifts[index];
|
||||
expr* c = get_cached(r, shift_amount);
|
||||
if (c) {
|
||||
result_stack().push_back(c);
|
||||
set_new_child_flag(v);
|
||||
return;
|
||||
}
|
||||
expr_ref tmp(m());
|
||||
m_shifter(r, shift_amount, tmp);
|
||||
result_stack().push_back(tmp);
|
||||
TRACE("rewriter", tout << "shift: " << shift_amount << " idx: " << idx << " --> " << tmp << "\n";
|
||||
display_bindings(tout););
|
||||
cache_shifted_result(r, shift_amount, tmp);
|
||||
}
|
||||
else {
|
||||
result_stack().push_back(r);
|
||||
|
@ -380,7 +388,6 @@ void rewriter_tpl<Config>::process_app(app * t, frame & fr) {
|
|||
TRACE("get_macro", display_bindings(tout););
|
||||
begin_scope();
|
||||
m_num_qvars += num_args;
|
||||
//m_num_qvars = 0;
|
||||
m_root = def;
|
||||
push_frame(def, false, RW_UNBOUNDED_DEPTH);
|
||||
return;
|
||||
|
@ -480,7 +487,7 @@ void rewriter_tpl<Config>::process_quantifier(quantifier * q, frame & fr) {
|
|||
m_root = q->get_expr();
|
||||
unsigned sz = m_bindings.size();
|
||||
for (unsigned i = 0; i < num_decls; i++) {
|
||||
m_bindings.push_back(0);
|
||||
m_bindings.push_back(nullptr);
|
||||
m_shifts.push_back(sz);
|
||||
}
|
||||
}
|
||||
|
@ -514,7 +521,12 @@ void rewriter_tpl<Config>::process_quantifier(quantifier * q, frame & fr) {
|
|||
}
|
||||
if (ProofGen) {
|
||||
quantifier_ref new_q(m().update_quantifier(q, num_pats, new_pats.c_ptr(), num_no_pats, new_no_pats.c_ptr(), new_body), m());
|
||||
m_pr = q == new_q ? nullptr : m().mk_quant_intro(q, new_q, result_pr_stack().get(fr.m_spos));
|
||||
m_pr = nullptr;
|
||||
if (q != new_q) {
|
||||
m_pr = result_pr_stack().get(fr.m_spos);
|
||||
m_pr = m().mk_bind_proof(q, m_pr);
|
||||
m_pr = m().mk_quant_intro(q, new_q, m_pr);
|
||||
}
|
||||
m_r = new_q;
|
||||
proof_ref pr2(m());
|
||||
if (m_cfg.reduce_quantifier(new_q, new_body, new_pats.c_ptr(), new_no_pats.c_ptr(), m_r, pr2)) {
|
||||
|
|
|
@ -33,30 +33,32 @@ Notes:
|
|||
expr_ref sym_expr::accept(expr* e) {
|
||||
ast_manager& m = m_t.get_manager();
|
||||
expr_ref result(m);
|
||||
var_subst subst(m);
|
||||
seq_util u(m);
|
||||
unsigned r1, r2, r3;
|
||||
switch (m_ty) {
|
||||
case t_pred: {
|
||||
var_subst subst(m);
|
||||
case t_pred:
|
||||
result = subst(m_t, 1, &e);
|
||||
break;
|
||||
case t_not:
|
||||
result = m_expr->accept(e);
|
||||
result = m.mk_not(result);
|
||||
break;
|
||||
}
|
||||
case t_char:
|
||||
SASSERT(m.get_sort(e) == m.get_sort(m_t));
|
||||
SASSERT(m.get_sort(e) == m_sort);
|
||||
result = m.mk_eq(e, m_t);
|
||||
break;
|
||||
case t_range: {
|
||||
bv_util bv(m);
|
||||
rational r1, r2, r3;
|
||||
unsigned sz;
|
||||
if (bv.is_numeral(m_t, r1, sz) && bv.is_numeral(e, r2, sz) && bv.is_numeral(m_s, r3, sz)) {
|
||||
case t_range:
|
||||
if (u.is_const_char(m_t, r1) && u.is_const_char(e, r2) && u.is_const_char(m_s, r3)) {
|
||||
result = m.mk_bool_val((r1 <= r2) && (r2 <= r3));
|
||||
}
|
||||
else {
|
||||
result = m.mk_and(bv.mk_ule(m_t, e), bv.mk_ule(e, m_s));
|
||||
result = m.mk_and(u.mk_le(m_t, e), u.mk_le(e, m_s));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -65,6 +67,7 @@ std::ostream& sym_expr::display(std::ostream& out) const {
|
|||
case t_char: return out << m_t;
|
||||
case t_range: return out << m_t << ":" << m_s;
|
||||
case t_pred: return out << m_t;
|
||||
case t_not: return m_expr->display(out << "not ");
|
||||
}
|
||||
return out << "expression type not recognized";
|
||||
}
|
||||
|
@ -80,10 +83,11 @@ struct display_expr1 {
|
|||
class sym_expr_boolean_algebra : public boolean_algebra<sym_expr*> {
|
||||
ast_manager& m;
|
||||
expr_solver& m_solver;
|
||||
expr_ref m_var;
|
||||
typedef sym_expr* T;
|
||||
public:
|
||||
sym_expr_boolean_algebra(ast_manager& m, expr_solver& s):
|
||||
m(m), m_solver(s) {}
|
||||
m(m), m_solver(s), m_var(m) {}
|
||||
|
||||
T mk_false() override {
|
||||
expr_ref fml(m.mk_false(), m);
|
||||
|
@ -94,6 +98,7 @@ public:
|
|||
return sym_expr::mk_pred(fml, m.mk_bool_sort());
|
||||
}
|
||||
T mk_and(T x, T y) override {
|
||||
seq_util u(m);
|
||||
if (x->is_char() && y->is_char()) {
|
||||
if (x->get_char() == y->get_char()) {
|
||||
return x;
|
||||
|
@ -103,6 +108,21 @@ public:
|
|||
return sym_expr::mk_pred(fml, x->get_sort());
|
||||
}
|
||||
}
|
||||
unsigned lo1, hi1, lo2, hi2;
|
||||
if (x->is_range() && y->is_range() &&
|
||||
u.is_const_char(x->get_lo(), lo1) && u.is_const_char(x->get_hi(), hi1) &&
|
||||
u.is_const_char(y->get_lo(), lo2) && u.is_const_char(y->get_hi(), hi2)) {
|
||||
lo1 = std::max(lo1, lo2);
|
||||
hi1 = std::min(hi1, hi2);
|
||||
if (lo1 > hi1) {
|
||||
expr_ref fml(m.mk_false(), m);
|
||||
return sym_expr::mk_pred(fml, x->get_sort());
|
||||
}
|
||||
expr_ref _start(u.mk_char(lo1), m);
|
||||
expr_ref _stop(u.mk_char(hi1), m);
|
||||
return sym_expr::mk_range(_start, _stop);
|
||||
}
|
||||
|
||||
sort* s = x->get_sort();
|
||||
if (m.is_bool(s)) s = y->get_sort();
|
||||
var_ref v(m.mk_var(0, s), m);
|
||||
|
@ -111,13 +131,29 @@ public:
|
|||
if (m.is_true(fml1)) {
|
||||
return y;
|
||||
}
|
||||
if (m.is_true(fml2)) return x;
|
||||
if (fml1 == fml2) return x;
|
||||
if (m.is_true(fml2)) {
|
||||
return x;
|
||||
}
|
||||
if (fml1 == fml2) {
|
||||
return x;
|
||||
}
|
||||
if (is_complement(fml1, fml2)) {
|
||||
expr_ref ff(m.mk_false(), m);
|
||||
return sym_expr::mk_pred(ff, x->get_sort());
|
||||
}
|
||||
bool_rewriter br(m);
|
||||
expr_ref fml(m);
|
||||
br.mk_and(fml1, fml2, fml);
|
||||
return sym_expr::mk_pred(fml, x->get_sort());
|
||||
}
|
||||
|
||||
bool is_complement(expr* f1, expr* f2) {
|
||||
expr* f = nullptr;
|
||||
return
|
||||
(m.is_not(f1, f) && f == f2) ||
|
||||
(m.is_not(f2, f) && f == f1);
|
||||
}
|
||||
|
||||
T mk_or(T x, T y) override {
|
||||
if (x->is_char() && y->is_char() &&
|
||||
x->get_char() == y->get_char()) {
|
||||
|
@ -148,6 +184,7 @@ public:
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
T mk_or(unsigned sz, T const* ts) override {
|
||||
switch (sz) {
|
||||
case 0: return mk_false();
|
||||
|
@ -161,15 +198,24 @@ public:
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
lbool is_sat(T x) override {
|
||||
unsigned lo, hi;
|
||||
seq_util u(m);
|
||||
|
||||
if (x->is_char()) {
|
||||
return l_true;
|
||||
}
|
||||
if (x->is_range()) {
|
||||
// TBD check lower is below upper.
|
||||
if (x->is_range() && u.is_const_char(x->get_lo(), lo) && u.is_const_char(x->get_hi(), hi)) {
|
||||
return (lo <= hi) ? l_true : l_false;
|
||||
}
|
||||
expr_ref v(m.mk_fresh_const("x", x->get_sort()), m);
|
||||
expr_ref fml = x->accept(v);
|
||||
if (x->is_not() && x->get_arg()->is_range() && u.is_const_char(x->get_arg()->get_lo(), lo) && 0 < lo) {
|
||||
return l_true;
|
||||
}
|
||||
if (!m_var || m.get_sort(m_var) != x->get_sort()) {
|
||||
m_var = m.mk_fresh_const("x", x->get_sort());
|
||||
}
|
||||
expr_ref fml = x->accept(m_var);
|
||||
if (m.is_true(fml)) {
|
||||
return l_true;
|
||||
}
|
||||
|
@ -178,19 +224,14 @@ public:
|
|||
}
|
||||
return m_solver.check_sat(fml);
|
||||
}
|
||||
|
||||
T mk_not(T x) override {
|
||||
var_ref v(m.mk_var(0, x->get_sort()), m);
|
||||
expr_ref fml(m.mk_not(x->accept(v)), m);
|
||||
return sym_expr::mk_pred(fml, x->get_sort());
|
||||
return sym_expr::mk_not(m, x);
|
||||
}
|
||||
|
||||
/*virtual vector<std::pair<vector<bool>, T>> generate_min_terms(vector<T> constraints){
|
||||
|
||||
return 0;
|
||||
}*/
|
||||
};
|
||||
|
||||
re2automaton::re2automaton(ast_manager& m): m(m), u(m), bv(m), m_ba(nullptr), m_sa(nullptr) {}
|
||||
re2automaton::re2automaton(ast_manager& m): m(m), u(m), m_ba(nullptr), m_sa(nullptr) {}
|
||||
|
||||
re2automaton::~re2automaton() {}
|
||||
|
||||
|
@ -248,9 +289,8 @@ eautomaton* re2automaton::re2aut(expr* e) {
|
|||
s1.length() == 1 && s2.length() == 1) {
|
||||
unsigned start = s1[0];
|
||||
unsigned stop = s2[0];
|
||||
unsigned nb = s1.num_bits();
|
||||
expr_ref _start(bv.mk_numeral(start, nb), m);
|
||||
expr_ref _stop(bv.mk_numeral(stop, nb), m);
|
||||
expr_ref _start(u.mk_char(start), m);
|
||||
expr_ref _stop(u.mk_char(stop), m);
|
||||
TRACE("seq", tout << "Range: " << start << " " << stop << "\n";);
|
||||
a = alloc(eautomaton, sm, sym_expr::mk_range(_start, _stop));
|
||||
return a.detach();
|
||||
|
@ -309,6 +349,9 @@ eautomaton* re2automaton::re2aut(expr* e) {
|
|||
else if (u.re.is_intersection(e, e1, e2) && m_sa && (a = re2aut(e1)) && (b = re2aut(e2))) {
|
||||
return m_sa->mk_product(*a, *b);
|
||||
}
|
||||
else {
|
||||
TRACE("seq", tout << "not handled " << mk_pp(e, m) << "\n";);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -343,9 +386,9 @@ eautomaton* re2automaton::seq2aut(expr* e) {
|
|||
|
||||
br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
|
||||
SASSERT(f->get_family_id() == get_fid());
|
||||
|
||||
br_status st = BR_FAILED;
|
||||
switch(f->get_decl_kind()) {
|
||||
|
||||
|
||||
case OP_SEQ_UNIT:
|
||||
SASSERT(num_args == 1);
|
||||
return mk_seq_unit(args[0], result);
|
||||
|
@ -356,16 +399,19 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
|
|||
return mk_re_plus(args[0], result);
|
||||
case OP_RE_STAR:
|
||||
SASSERT(num_args == 1);
|
||||
return mk_re_star(args[0], result);
|
||||
st = mk_re_star(args[0], result);
|
||||
break;
|
||||
case OP_RE_OPTION:
|
||||
SASSERT(num_args == 1);
|
||||
return mk_re_opt(args[0], result);
|
||||
case OP_RE_CONCAT:
|
||||
if (num_args == 1) {
|
||||
result = args[0]; return BR_DONE;
|
||||
result = args[0];
|
||||
return BR_DONE;
|
||||
}
|
||||
SASSERT(num_args == 2);
|
||||
return mk_re_concat(args[0], args[1], result);
|
||||
st = mk_re_concat(args[0], args[1], result);
|
||||
break;
|
||||
case OP_RE_UNION:
|
||||
if (num_args == 1) {
|
||||
result = args[0]; return BR_DONE;
|
||||
|
@ -405,13 +451,19 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
|
|||
return mk_seq_length(args[0], result);
|
||||
case OP_SEQ_EXTRACT:
|
||||
SASSERT(num_args == 3);
|
||||
return mk_seq_extract(args[0], args[1], args[2], result);
|
||||
st = mk_seq_extract(args[0], args[1], args[2], result);
|
||||
break;
|
||||
case OP_SEQ_CONTAINS:
|
||||
SASSERT(num_args == 2);
|
||||
return mk_seq_contains(args[0], args[1], result);
|
||||
case OP_SEQ_AT:
|
||||
SASSERT(num_args == 2);
|
||||
return mk_seq_at(args[0], args[1], result);
|
||||
#if 0
|
||||
case OP_SEQ_NTH:
|
||||
SASSERT(num_args == 2);
|
||||
return mk_seq_nth(args[0], args[1], result);
|
||||
#endif
|
||||
case OP_SEQ_PREFIX:
|
||||
SASSERT(num_args == 2);
|
||||
return mk_seq_prefix(args[0], args[1], result);
|
||||
|
@ -456,21 +508,20 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
|
|||
case _OP_STRING_STRIDOF:
|
||||
UNREACHABLE();
|
||||
}
|
||||
return BR_FAILED;
|
||||
CTRACE("seq", st != BR_FAILED, tout << result << "\n";);
|
||||
return st;
|
||||
}
|
||||
|
||||
/*
|
||||
* (seq.unit (_ BitVector 8)) ==> String constant
|
||||
*/
|
||||
br_status seq_rewriter::mk_seq_unit(expr* e, expr_ref& result) {
|
||||
bv_util bvu(m());
|
||||
rational n_val;
|
||||
unsigned int n_size;
|
||||
unsigned ch;
|
||||
// specifically we want (_ BitVector 8)
|
||||
if (bvu.is_bv(e) && bvu.is_numeral(e, n_val, n_size) && n_size == 8) {
|
||||
if (m_util.is_const_char(e, ch)) {
|
||||
// convert to string constant
|
||||
zstring str(n_val.get_unsigned());
|
||||
TRACE("seq_verbose", tout << "rewrite seq.unit of 8-bit value " << n_val.to_string() << " to string constant \"" << str<< "\"" << std::endl;);
|
||||
zstring str(ch);
|
||||
TRACE("seq_verbose", tout << "rewrite seq.unit of 8-bit value " << ch << " to string constant \"" << str<< "\"" << std::endl;);
|
||||
result = m_util.str.mk_string(str);
|
||||
return BR_DONE;
|
||||
}
|
||||
|
@ -566,6 +617,7 @@ br_status seq_rewriter::mk_seq_extract(expr* a, expr* b, expr* c, expr_ref& resu
|
|||
bool constantPos = m_autil.is_numeral(b, pos);
|
||||
bool constantLen = m_autil.is_numeral(c, len);
|
||||
|
||||
|
||||
// case 1: pos<0 or len<=0
|
||||
// rewrite to ""
|
||||
if ( (constantPos && pos.is_neg()) || (constantLen && !len.is_pos()) ) {
|
||||
|
@ -574,7 +626,7 @@ br_status seq_rewriter::mk_seq_extract(expr* a, expr* b, expr* c, expr_ref& resu
|
|||
}
|
||||
// case 1.1: pos >= length(base)
|
||||
// rewrite to ""
|
||||
if (constantBase && constantPos && pos >= rational(s.length())) {
|
||||
if (constantPos && constantBase && pos >= rational(s.length())) {
|
||||
result = m_util.str.mk_empty(m().get_sort(a));
|
||||
return BR_DONE;
|
||||
}
|
||||
|
@ -582,52 +634,73 @@ br_status seq_rewriter::mk_seq_extract(expr* a, expr* b, expr* c, expr_ref& resu
|
|||
constantPos &= pos.is_unsigned();
|
||||
constantLen &= len.is_unsigned();
|
||||
|
||||
if (constantBase && constantPos && constantLen) {
|
||||
if (pos.get_unsigned() + len.get_unsigned() >= s.length()) {
|
||||
// case 2: pos+len goes past the end of the string
|
||||
unsigned _len = s.length() - pos.get_unsigned() + 1;
|
||||
result = m_util.str.mk_string(s.extract(pos.get_unsigned(), _len));
|
||||
} else {
|
||||
// case 3: pos+len still within string
|
||||
result = m_util.str.mk_string(s.extract(pos.get_unsigned(), len.get_unsigned()));
|
||||
}
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
if (constantPos && constantLen) {
|
||||
if (constantPos && constantLen && constantBase) {
|
||||
unsigned _pos = pos.get_unsigned();
|
||||
unsigned _len = len.get_unsigned();
|
||||
SASSERT(_len > 0);
|
||||
expr_ref_vector as(m()), bs(m());
|
||||
m_util.str.get_concat(a, as);
|
||||
if (as.empty()) {
|
||||
result = a;
|
||||
return BR_DONE;
|
||||
}
|
||||
for (unsigned i = 0; i < as.size() && _len > 0; ++i) {
|
||||
if (m_util.str.is_unit(as[i].get())) {
|
||||
if (_pos == 0) {
|
||||
bs.push_back(as[i].get());
|
||||
--_len;
|
||||
}
|
||||
else {
|
||||
--_pos;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return BR_FAILED;
|
||||
}
|
||||
}
|
||||
if (bs.empty()) {
|
||||
result = m_util.str.mk_empty(m().get_sort(a));
|
||||
}
|
||||
else {
|
||||
result = m_util.str.mk_concat(bs);
|
||||
if (_pos + _len >= s.length()) {
|
||||
// case 2: pos+len goes past the end of the string
|
||||
unsigned _len = s.length() - _pos + 1;
|
||||
result = m_util.str.mk_string(s.extract(_pos, _len));
|
||||
} else {
|
||||
// case 3: pos+len still within string
|
||||
result = m_util.str.mk_string(s.extract(_pos, _len));
|
||||
}
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
return BR_FAILED;
|
||||
|
||||
expr_ref_vector as(m()), bs(m());
|
||||
m_util.str.get_concat_units(a, as);
|
||||
if (as.empty()) {
|
||||
result = m_util.str.mk_empty(m().get_sort(a));
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
if (!constantPos) {
|
||||
return BR_FAILED;
|
||||
}
|
||||
unsigned _pos = pos.get_unsigned();
|
||||
|
||||
// (extract s 0 (len s)) = s
|
||||
expr* a2 = nullptr;
|
||||
if (_pos == 0 && m_util.str.is_length(c, a2) && a == a2) {
|
||||
result = a;
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
unsigned offset = 0;
|
||||
for (; offset < as.size() && m_util.str.is_unit(as.get(offset)) && offset < _pos; ++offset) {};
|
||||
if (offset == 0 && _pos > 0) {
|
||||
return BR_FAILED;
|
||||
}
|
||||
if (_pos == 0 && !constantLen) {
|
||||
return BR_FAILED;
|
||||
}
|
||||
// (extract (++ (unit x) (unit y)) 3 c) = empty
|
||||
if (offset == as.size()) {
|
||||
result = m_util.str.mk_empty(m().get_sort(a));
|
||||
return BR_DONE;
|
||||
}
|
||||
SASSERT(offset != 0 || _pos == 0);
|
||||
|
||||
if (constantLen && _pos == offset) {
|
||||
unsigned _len = len.get_unsigned();
|
||||
// (extract (++ (unit a) (unit b) (unit c) x) 1 2) = (++ (unit b) (unit c))
|
||||
unsigned i = offset;
|
||||
for (; i < as.size() && m_util.str.is_unit(as.get(i)) && i - offset < _len; ++i);
|
||||
if (i - offset == _len) {
|
||||
result = m_util.str.mk_concat(_len, as.c_ptr() + offset);
|
||||
return BR_DONE;
|
||||
}
|
||||
}
|
||||
if (offset == 0) {
|
||||
return BR_FAILED;
|
||||
}
|
||||
expr_ref pos1(m());
|
||||
pos1 = m_autil.mk_sub(b, m_autil.mk_int(offset));
|
||||
result = m_util.str.mk_concat(as.size() - offset, as.c_ptr() + offset);
|
||||
result = m_util.str.mk_substr(result, pos1, c);
|
||||
return BR_REWRITE3;
|
||||
}
|
||||
|
||||
bool seq_rewriter::cannot_contain_suffix(expr* a, expr* b) {
|
||||
|
@ -809,6 +882,32 @@ br_status seq_rewriter::mk_seq_at(expr* a, expr* b, expr_ref& result) {
|
|||
return BR_DONE;
|
||||
}
|
||||
|
||||
br_status seq_rewriter::mk_seq_nth(expr* a, expr* b, expr_ref& result) {
|
||||
zstring c;
|
||||
rational r;
|
||||
if (!m_autil.is_numeral(b, r) || !r.is_unsigned()) {
|
||||
return BR_FAILED;
|
||||
}
|
||||
unsigned len = r.get_unsigned();
|
||||
|
||||
expr_ref_vector as(m());
|
||||
m_util.str.get_concat_units(a, as);
|
||||
|
||||
for (unsigned i = 0; i < as.size(); ++i) {
|
||||
expr* a = as.get(i), *u = nullptr;
|
||||
if (m_util.str.is_unit(a, u)) {
|
||||
if (len == i) {
|
||||
result = u;
|
||||
return BR_DONE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return BR_FAILED;
|
||||
}
|
||||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
br_status seq_rewriter::mk_seq_index(expr* a, expr* b, expr* c, expr_ref& result) {
|
||||
zstring s1, s2;
|
||||
rational r;
|
||||
|
@ -1238,6 +1337,7 @@ br_status seq_rewriter::mk_str_in_regexp(expr* a, expr* b, expr_ref& result) {
|
|||
scoped_ptr<eautomaton> aut;
|
||||
expr_ref_vector seq(m());
|
||||
if (!(aut = m_re2aut(b))) {
|
||||
TRACE("seq", tout << "not translated to automaton " << mk_pp(b, m()) << "\n";);
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
|
@ -1254,6 +1354,7 @@ br_status seq_rewriter::mk_str_in_regexp(expr* a, expr* b, expr_ref& result) {
|
|||
}
|
||||
|
||||
if (!is_sequence(a, seq)) {
|
||||
TRACE("seq", tout << "not a sequence " << mk_pp(a, m()) << "\n";);
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
|
@ -1305,17 +1406,16 @@ br_status seq_rewriter::mk_str_in_regexp(expr* a, expr* b, expr_ref& result) {
|
|||
}
|
||||
}
|
||||
u_map<expr*> const& frontier = maps[select_map];
|
||||
u_map<expr*>::iterator it = frontier.begin(), end = frontier.end();
|
||||
expr_ref_vector ors(m());
|
||||
for (; it != end; ++it) {
|
||||
for (auto const& kv : frontier) {
|
||||
unsigned_vector states;
|
||||
bool has_final = false;
|
||||
aut->get_epsilon_closure(it->m_key, states);
|
||||
aut->get_epsilon_closure(kv.m_key, states);
|
||||
for (unsigned i = 0; i < states.size() && !has_final; ++i) {
|
||||
has_final = aut->is_final_state(states[i]);
|
||||
}
|
||||
if (has_final) {
|
||||
ors.push_back(it->m_value);
|
||||
ors.push_back(kv.m_value);
|
||||
}
|
||||
}
|
||||
result = mk_or(ors);
|
||||
|
@ -1434,6 +1534,14 @@ br_status seq_rewriter::mk_re_inter(expr* a, expr* b, expr_ref& result) {
|
|||
result = a;
|
||||
return BR_DONE;
|
||||
}
|
||||
expr* ac = nullptr, *bc = nullptr;
|
||||
if ((m_util.re.is_complement(a, ac) && ac == b) ||
|
||||
(m_util.re.is_complement(b, bc) && bc == a)) {
|
||||
sort* seq_sort = nullptr;
|
||||
VERIFY(m_util.is_re(a, seq_sort));
|
||||
result = m_util.re.mk_empty(seq_sort);
|
||||
return BR_DONE;
|
||||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
|
@ -1977,15 +2085,13 @@ bool seq_rewriter::min_length(unsigned n, expr* const* es, unsigned& len) {
|
|||
bool seq_rewriter::is_string(unsigned n, expr* const* es, zstring& s) const {
|
||||
zstring s1;
|
||||
expr* e;
|
||||
bv_util bv(m());
|
||||
rational val;
|
||||
unsigned sz;
|
||||
unsigned ch;
|
||||
for (unsigned i = 0; i < n; ++i) {
|
||||
if (m_util.str.is_string(es[i], s1)) {
|
||||
s = s + s1;
|
||||
}
|
||||
else if (m_util.str.is_unit(es[i], e) && bv.is_numeral(e, val, sz)) {
|
||||
s = s + zstring(val.get_unsigned());
|
||||
else if (m_util.str.is_unit(es[i], e) && m_util.is_const_char(e, ch)) {
|
||||
s = s + zstring(ch);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
|
|
|
@ -31,31 +31,38 @@ class sym_expr {
|
|||
enum ty {
|
||||
t_char,
|
||||
t_pred,
|
||||
t_not,
|
||||
t_range
|
||||
};
|
||||
ty m_ty;
|
||||
sort* m_sort;
|
||||
expr_ref m_t;
|
||||
expr_ref m_s;
|
||||
unsigned m_ref;
|
||||
sym_expr(ty ty, expr_ref& t, expr_ref& s, sort* srt) : m_ty(ty), m_sort(srt), m_t(t), m_s(s), m_ref(0) {}
|
||||
ty m_ty;
|
||||
sort* m_sort;
|
||||
sym_expr* m_expr;
|
||||
expr_ref m_t;
|
||||
expr_ref m_s;
|
||||
unsigned m_ref;
|
||||
sym_expr(ty ty, expr_ref& t, expr_ref& s, sort* srt, sym_expr* e) :
|
||||
m_ty(ty), m_sort(srt), m_expr(e), m_t(t), m_s(s), m_ref(0) {}
|
||||
public:
|
||||
~sym_expr() { if (m_expr) m_expr->dec_ref(); }
|
||||
expr_ref accept(expr* e);
|
||||
static sym_expr* mk_char(expr_ref& t) { return alloc(sym_expr, t_char, t, t, t.get_manager().get_sort(t)); }
|
||||
static sym_expr* mk_char(expr_ref& t) { return alloc(sym_expr, t_char, t, t, t.get_manager().get_sort(t), nullptr); }
|
||||
static sym_expr* mk_char(ast_manager& m, expr* t) { expr_ref tr(t, m); return mk_char(tr); }
|
||||
static sym_expr* mk_pred(expr_ref& t, sort* s) { return alloc(sym_expr, t_pred, t, t, s); }
|
||||
static sym_expr* mk_range(expr_ref& lo, expr_ref& hi) { return alloc(sym_expr, t_range, lo, hi, lo.get_manager().get_sort(hi)); }
|
||||
static sym_expr* mk_pred(expr_ref& t, sort* s) { return alloc(sym_expr, t_pred, t, t, s, nullptr); }
|
||||
static sym_expr* mk_range(expr_ref& lo, expr_ref& hi) { return alloc(sym_expr, t_range, lo, hi, lo.get_manager().get_sort(hi), nullptr); }
|
||||
static sym_expr* mk_not(ast_manager& m, sym_expr* e) { expr_ref f(m); e->inc_ref(); return alloc(sym_expr, t_not, f, f, e->get_sort(), e); }
|
||||
void inc_ref() { ++m_ref; }
|
||||
void dec_ref() { --m_ref; if (m_ref == 0) dealloc(this); }
|
||||
std::ostream& display(std::ostream& out) const;
|
||||
bool is_char() const { return m_ty == t_char; }
|
||||
bool is_pred() const { return !is_char(); }
|
||||
bool is_range() const { return m_ty == t_range; }
|
||||
bool is_not() const { return m_ty == t_not; }
|
||||
sort* get_sort() const { return m_sort; }
|
||||
expr* get_char() const { SASSERT(is_char()); return m_t; }
|
||||
expr* get_pred() const { SASSERT(is_pred()); return m_t; }
|
||||
expr* get_lo() const { SASSERT(is_range()); return m_t; }
|
||||
expr* get_hi() const { SASSERT(is_range()); return m_s; }
|
||||
sym_expr* get_arg() const { SASSERT(is_not()); return m_expr; }
|
||||
};
|
||||
|
||||
class sym_expr_manager {
|
||||
|
@ -77,7 +84,6 @@ class re2automaton {
|
|||
ast_manager& m;
|
||||
sym_expr_manager sm;
|
||||
seq_util u;
|
||||
bv_util bv;
|
||||
scoped_ptr<expr_solver> m_solver;
|
||||
scoped_ptr<boolean_algebra_t> m_ba;
|
||||
scoped_ptr<symbolic_automata_t> m_sa;
|
||||
|
@ -108,6 +114,7 @@ class seq_rewriter {
|
|||
br_status mk_seq_extract(expr* a, expr* b, expr* c, expr_ref& result);
|
||||
br_status mk_seq_contains(expr* a, expr* b, expr_ref& result);
|
||||
br_status mk_seq_at(expr* a, expr* b, expr_ref& result);
|
||||
br_status mk_seq_nth(expr* a, expr* b, expr_ref& result);
|
||||
br_status mk_seq_index(expr* a, expr* b, expr* c, expr_ref& result);
|
||||
br_status mk_seq_replace(expr* a, expr* b, expr* c, expr_ref& result);
|
||||
br_status mk_seq_prefix(expr* a, expr* b, expr_ref& result);
|
||||
|
|
|
@ -135,17 +135,14 @@ expr_ref unused_vars_eliminator::operator()(quantifier* q) {
|
|||
return result;
|
||||
}
|
||||
|
||||
expr_ref tmp(m);
|
||||
expr_ref_buffer new_patterns(m);
|
||||
expr_ref_buffer new_no_patterns(m);
|
||||
|
||||
for (unsigned i = 0; i < num_patterns; i++) {
|
||||
tmp = m_subst(q->get_pattern(i), var_mapping.size(), var_mapping.c_ptr());
|
||||
new_patterns.push_back(tmp);
|
||||
new_patterns.push_back(m_subst(q->get_pattern(i), var_mapping.size(), var_mapping.c_ptr()));
|
||||
}
|
||||
for (unsigned i = 0; i < num_no_patterns; i++) {
|
||||
tmp = m_subst(q->get_no_pattern(i), var_mapping.size(), var_mapping.c_ptr());
|
||||
new_no_patterns.push_back(tmp);
|
||||
new_no_patterns.push_back(m_subst(q->get_no_pattern(i), var_mapping.size(), var_mapping.c_ptr()));
|
||||
}
|
||||
|
||||
result = m.mk_quantifier(q->get_kind(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue