3
0
Fork 0
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:
nilsbecker 2019-02-22 00:19:43 +01:00
commit ec76efedbe
386 changed files with 10027 additions and 8346 deletions

View file

@ -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

View file

@ -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) {

View file

@ -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());

View file

@ -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) {

View file

@ -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)

View file

@ -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);

View file

@ -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";);

View file

@ -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(),

View file

@ -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,

View 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();
}
}

View 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

View file

@ -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";

View file

@ -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 ++;

View file

@ -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)); }

View file

@ -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)) {

View file

@ -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;

View file

@ -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);

View file

@ -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(),