mirror of
https://github.com/Z3Prover/z3
synced 2025-04-23 17:15:31 +00:00
Merge branch 'master' of https://github.com/Z3Prover/z3 into jan4
This commit is contained in:
commit
8b47a84598
56 changed files with 5500 additions and 887 deletions
|
@ -1656,6 +1656,7 @@ ast * ast_manager::register_node_core(ast * n) {
|
|||
|
||||
n->m_id = is_decl(n) ? m_decl_id_gen.mk() : m_expr_id_gen.mk();
|
||||
|
||||
|
||||
TRACE("ast", tout << "Object " << n->m_id << " was created.\n";);
|
||||
TRACE("mk_var_bug", tout << "mk_ast: " << n->m_id << "\n";);
|
||||
// increment reference counters
|
||||
|
|
|
@ -121,8 +121,11 @@ public:
|
|||
void mk_comp(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits);
|
||||
|
||||
void mk_carry_save_adder(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr * const * c_bits, expr_ref_vector & sum_bits, expr_ref_vector & carry_bits);
|
||||
void mk_const_multiplier(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits);
|
||||
bool mk_const_multiplier(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits);
|
||||
bool mk_const_case_multiplier(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits);
|
||||
void mk_const_case_multiplier(bool is_a, unsigned i, unsigned sz, ptr_buffer<expr, 128>& a_bits, ptr_buffer<expr, 128>& b_bits, expr_ref_vector & out_bits);
|
||||
|
||||
bool is_bool_const(expr* e) const { return m().is_true(e) || m().is_false(e); }
|
||||
void mk_abs(unsigned sz, expr * const * a_bits, expr_ref_vector & out_bits);
|
||||
};
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ void bit_blaster_tpl<Cfg>::checkpoint() {
|
|||
template<typename Cfg>
|
||||
bool bit_blaster_tpl<Cfg>::is_numeral(unsigned sz, expr * const * bits) const {
|
||||
for (unsigned i = 0; i < sz; i++)
|
||||
if (!m().is_true(bits[i]) && !m().is_false(bits[i]))
|
||||
if (!is_bool_const(bits[i]))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
@ -158,30 +158,24 @@ void bit_blaster_tpl<Cfg>::mk_subtracter(unsigned sz, expr * const * a_bits, exp
|
|||
template<typename Cfg>
|
||||
void bit_blaster_tpl<Cfg>::mk_multiplier(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits) {
|
||||
SASSERT(sz > 0);
|
||||
|
||||
if (!m_use_bcm) {
|
||||
numeral n_a, n_b;
|
||||
if (is_numeral(sz, a_bits, n_b))
|
||||
std::swap(a_bits, b_bits);
|
||||
if (is_minus_one(sz, b_bits)) {
|
||||
mk_neg(sz, a_bits, out_bits);
|
||||
return;
|
||||
}
|
||||
if (is_numeral(sz, a_bits, n_a)) {
|
||||
n_a *= n_b;
|
||||
num2bits(n_a, sz, out_bits);
|
||||
return;
|
||||
}
|
||||
numeral n_a, n_b;
|
||||
if (is_numeral(sz, a_bits, n_b))
|
||||
std::swap(a_bits, b_bits);
|
||||
if (is_minus_one(sz, b_bits)) {
|
||||
mk_neg(sz, a_bits, out_bits);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
numeral n_a, n_b;
|
||||
if (is_numeral(sz, a_bits, n_a)) {
|
||||
mk_const_multiplier(sz, a_bits, b_bits, out_bits);
|
||||
return;
|
||||
} else if (is_numeral(sz, b_bits, n_b)) {
|
||||
mk_const_multiplier(sz, b_bits, a_bits, out_bits);
|
||||
return;
|
||||
}
|
||||
if (is_numeral(sz, a_bits, n_a)) {
|
||||
n_a *= n_b;
|
||||
num2bits(n_a, sz, out_bits);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mk_const_multiplier(sz, a_bits, b_bits, out_bits)) {
|
||||
return;
|
||||
}
|
||||
if (mk_const_multiplier(sz, b_bits, a_bits, out_bits)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_use_wtm) {
|
||||
|
@ -1171,13 +1165,74 @@ void bit_blaster_tpl<Cfg>::mk_carry_save_adder(unsigned sz, expr * const * a_bit
|
|||
}
|
||||
|
||||
template<typename Cfg>
|
||||
void bit_blaster_tpl<Cfg>::mk_const_multiplier(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits) {
|
||||
DEBUG_CODE({
|
||||
numeral x;
|
||||
SASSERT(is_numeral(sz, a_bits, x));
|
||||
SASSERT(out_bits.empty());
|
||||
});
|
||||
bool bit_blaster_tpl<Cfg>::mk_const_case_multiplier(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits) {
|
||||
unsigned nb = 0;
|
||||
unsigned case_size = 1;
|
||||
unsigned circuit_size = sz*sz*5;
|
||||
for (unsigned i = 0; case_size < circuit_size && i < sz; ++i) {
|
||||
if (!is_bool_const(a_bits[i])) {
|
||||
case_size *= 2;
|
||||
}
|
||||
if (!is_bool_const(b_bits[i])) {
|
||||
case_size *= 2;
|
||||
}
|
||||
}
|
||||
if (case_size >= circuit_size) {
|
||||
return false;
|
||||
}
|
||||
SASSERT(out_bits.empty());
|
||||
|
||||
ptr_buffer<expr, 128> na_bits;
|
||||
na_bits.append(sz, a_bits);
|
||||
ptr_buffer<expr, 128> nb_bits;
|
||||
nb_bits.append(sz, b_bits);
|
||||
mk_const_case_multiplier(true, 0, sz, na_bits, nb_bits, out_bits);
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename Cfg>
|
||||
void bit_blaster_tpl<Cfg>::mk_const_case_multiplier(bool is_a, unsigned i, unsigned sz, ptr_buffer<expr, 128>& a_bits, ptr_buffer<expr, 128>& b_bits, expr_ref_vector & out_bits) {
|
||||
while (is_a && i < sz && is_bool_const(a_bits[i])) ++i;
|
||||
if (is_a && i == sz) { is_a = false; i = 0; }
|
||||
while (!is_a && i < sz && is_bool_const(b_bits[i])) ++i;
|
||||
if (i < sz) {
|
||||
expr_ref_vector out1(m()), out2(m());
|
||||
expr_ref x(m());
|
||||
x = is_a?a_bits[i]:b_bits[i];
|
||||
if (is_a) a_bits[i] = m().mk_true(); else b_bits[i] = m().mk_true();
|
||||
mk_const_case_multiplier(is_a, i+1, sz, a_bits, b_bits, out1);
|
||||
if (is_a) a_bits[i] = m().mk_false(); else b_bits[i] = m().mk_false();
|
||||
mk_const_case_multiplier(is_a, i+1, sz, a_bits, b_bits, out2);
|
||||
if (is_a) a_bits[i] = x; else b_bits[i] = x;
|
||||
SASSERT(out_bits.empty());
|
||||
for (unsigned j = 0; j < sz; ++j) {
|
||||
out_bits.push_back(m().mk_ite(x, out1[j].get(), out2[j].get()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
numeral n_a, n_b;
|
||||
SASSERT(i == sz && !is_a);
|
||||
VERIFY(is_numeral(sz, a_bits.c_ptr(), n_a));
|
||||
VERIFY(is_numeral(sz, b_bits.c_ptr(), n_b));
|
||||
n_a *= n_b;
|
||||
num2bits(n_a, sz, out_bits);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Cfg>
|
||||
bool bit_blaster_tpl<Cfg>::mk_const_multiplier(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits) {
|
||||
numeral n_a;
|
||||
if (!is_numeral(sz, a_bits, n_a)) {
|
||||
return false;
|
||||
}
|
||||
SASSERT(out_bits.empty());
|
||||
|
||||
if (mk_const_case_multiplier(sz, a_bits, b_bits, out_bits)) {
|
||||
return true;
|
||||
}
|
||||
if (!m_use_bcm) {
|
||||
return false;
|
||||
}
|
||||
expr_ref_vector minus_b_bits(m()), tmp(m());
|
||||
mk_neg(sz, b_bits, minus_b_bits);
|
||||
|
||||
|
@ -1255,4 +1310,6 @@ void bit_blaster_tpl<Cfg>::mk_const_multiplier(unsigned sz, expr * const * a_bit
|
|||
|
||||
TRACE("bit_blaster_tpl_booth", for (unsigned i=0; i<out_bits.size(); i++)
|
||||
tout << "Booth encoding: " << mk_pp(out_bits[i].get(), m()) << "\n"; );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1968,7 +1968,63 @@ void bv_rewriter::mk_t1_add_t2_eq_c(expr * t1, expr * t2, expr * c, expr_ref & r
|
|||
result = m().mk_eq(t1, m_util.mk_bv_sub(c, t2));
|
||||
}
|
||||
|
||||
#include "ast_pp.h"
|
||||
|
||||
bool bv_rewriter::isolate_term(expr* lhs, expr* rhs, expr_ref& result) {
|
||||
if (!m_util.is_numeral(lhs) || !is_add(rhs)) {
|
||||
std::swap(lhs, rhs);
|
||||
}
|
||||
if (!m_util.is_numeral(lhs) || !is_add(rhs)) {
|
||||
return false;
|
||||
}
|
||||
unsigned sz = to_app(rhs)->get_num_args();
|
||||
expr_ref t1(m()), t2(m());
|
||||
t1 = to_app(rhs)->get_arg(0);
|
||||
if (sz > 2) {
|
||||
t2 = m().mk_app(get_fid(), OP_BADD, sz-1, to_app(rhs)->get_args()+1);
|
||||
}
|
||||
else {
|
||||
SASSERT(sz == 2);
|
||||
t2 = to_app(rhs)->get_arg(1);
|
||||
}
|
||||
mk_t1_add_t2_eq_c(t1, t2, lhs, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bv_rewriter::is_add_mul_const(expr* e) const {
|
||||
if (!m_util.is_bv_add(e)) {
|
||||
return false;
|
||||
}
|
||||
unsigned num = to_app(e)->get_num_args();
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
expr * arg = to_app(e)->get_arg(i);
|
||||
expr * c2, * x2;
|
||||
if (m_util.is_numeral(arg))
|
||||
continue;
|
||||
if (m_util.is_bv_mul(arg, c2, x2) && m_util.is_numeral(c2))
|
||||
continue;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bv_rewriter::is_concat_target(expr* lhs, expr* rhs) const {
|
||||
return
|
||||
m_util.is_concat(lhs) && (is_concat_split_target(rhs) || has_numeral(to_app(lhs))) ||
|
||||
m_util.is_concat(rhs) && (is_concat_split_target(lhs) || has_numeral(to_app(rhs)));
|
||||
}
|
||||
|
||||
bool bv_rewriter::has_numeral(app* a) const {
|
||||
for (unsigned i = 0; i < a->get_num_args(); ++i) {
|
||||
if (is_numeral(a->get_arg(i))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
br_status bv_rewriter::mk_mul_eq(expr * lhs, expr * rhs, expr_ref & result) {
|
||||
|
||||
expr * c, * x;
|
||||
numeral c_val, c_inv_val;
|
||||
unsigned sz;
|
||||
|
@ -2001,24 +2057,30 @@ br_status bv_rewriter::mk_mul_eq(expr * lhs, expr * rhs, expr_ref & result) {
|
|||
|
||||
// c * x = t_1 + ... + t_n
|
||||
// and t_i's have non-unary coefficients (this condition is used to make sure we are actually reducing the number of multipliers).
|
||||
if (m_util.is_bv_add(rhs)) {
|
||||
if (is_add_mul_const(rhs)) {
|
||||
// Potential problem: this simplification may increase the number of adders by reducing the amount of sharing.
|
||||
unsigned num = to_app(rhs)->get_num_args();
|
||||
unsigned i;
|
||||
for (i = 0; i < num; i++) {
|
||||
expr * arg = to_app(rhs)->get_arg(i);
|
||||
expr * c2, * x2;
|
||||
if (m_util.is_numeral(arg))
|
||||
continue;
|
||||
if (m_util.is_bv_mul(arg, c2, x2) && m_util.is_numeral(c2))
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
if (i == num) {
|
||||
result = m().mk_eq(x, m_util.mk_bv_mul(m_util.mk_numeral(c_inv_val, sz), rhs));
|
||||
return BR_REWRITE2;
|
||||
result = m().mk_eq(x, m_util.mk_bv_mul(m_util.mk_numeral(c_inv_val, sz), rhs));
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
}
|
||||
if (m_util.is_numeral(lhs, c_val, sz) && is_add_mul_const(rhs)) {
|
||||
unsigned sz = to_app(rhs)->get_num_args();
|
||||
unsigned i = 0;
|
||||
expr* c2, *x2;
|
||||
numeral c2_val, c2_inv_val;
|
||||
bool found = false;
|
||||
for (; !found && i < sz; ++i) {
|
||||
expr* arg = to_app(rhs)->get_arg(i);
|
||||
if (m_util.is_bv_mul(arg, c2, x2) && m_util.is_numeral(c2, c2_val, sz) &&
|
||||
m_util.mult_inverse(c2_val, sz, c2_inv_val)) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
result = m().mk_eq(m_util.mk_numeral(c2_inv_val*c_val, sz),
|
||||
m_util.mk_bv_mul(m_util.mk_numeral(c2_inv_val, sz), rhs));
|
||||
return BR_REWRITE3;
|
||||
}
|
||||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
@ -2065,9 +2127,10 @@ br_status bv_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) {
|
|||
return st;
|
||||
}
|
||||
|
||||
expr_ref new_lhs(m());
|
||||
expr_ref new_rhs(m());
|
||||
|
||||
if (m_util.is_bv_add(lhs) || m_util.is_bv_mul(lhs) || m_util.is_bv_add(rhs) || m_util.is_bv_mul(rhs)) {
|
||||
expr_ref new_lhs(m());
|
||||
expr_ref new_rhs(m());
|
||||
st = cancel_monomials(lhs, rhs, false, new_lhs, new_rhs);
|
||||
if (st != BR_FAILED) {
|
||||
if (is_numeral(new_lhs) && is_numeral(new_rhs)) {
|
||||
|
@ -2080,28 +2143,27 @@ br_status bv_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) {
|
|||
new_rhs = rhs;
|
||||
}
|
||||
|
||||
lhs = new_lhs;
|
||||
rhs = new_rhs;
|
||||
// Try to rewrite t1 + t2 = c --> t1 = c - t2
|
||||
// Reason: it is much cheaper to bit-blast.
|
||||
expr * t1, * t2;
|
||||
if (m_util.is_bv_add(new_lhs, t1, t2) && is_numeral(new_rhs)) {
|
||||
mk_t1_add_t2_eq_c(t1, t2, new_rhs, result);
|
||||
if (isolate_term(lhs, rhs, result)) {
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
if (m_util.is_bv_add(new_rhs, t1, t2) && is_numeral(new_lhs)) {
|
||||
mk_t1_add_t2_eq_c(t1, t2, new_lhs, result);
|
||||
return BR_REWRITE2;
|
||||
if (is_concat_target(lhs, rhs)) {
|
||||
return mk_eq_concat(lhs, rhs, result);
|
||||
}
|
||||
|
||||
|
||||
if (st != BR_FAILED) {
|
||||
result = m().mk_eq(new_lhs, new_rhs);
|
||||
result = m().mk_eq(lhs, rhs);
|
||||
return BR_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_util.is_concat(lhs) && is_concat_split_target(rhs)) ||
|
||||
(m_util.is_concat(rhs) && is_concat_split_target(lhs)))
|
||||
if (is_concat_target(lhs, rhs)) {
|
||||
return mk_eq_concat(lhs, rhs, result);
|
||||
|
||||
}
|
||||
|
||||
if (swapped) {
|
||||
result = m().mk_eq(lhs, rhs);
|
||||
return BR_DONE;
|
||||
|
|
|
@ -137,6 +137,10 @@ class bv_rewriter : public poly_rewriter<bv_rewriter_core> {
|
|||
bool is_concat_split_target(expr * t) const;
|
||||
|
||||
br_status mk_mul_eq(expr * lhs, expr * rhs, expr_ref & result);
|
||||
bool is_add_mul_const(expr* e) const;
|
||||
bool isolate_term(expr* lhs, expr* rhs, expr_ref & result);
|
||||
bool has_numeral(app* e) const;
|
||||
bool is_concat_target(expr* lhs, expr* rhs) const;
|
||||
|
||||
void updt_local_params(params_ref const & p);
|
||||
|
||||
|
|
|
@ -20,9 +20,11 @@ Revision History:
|
|||
|
||||
#include "expr_safe_replace.h"
|
||||
#include "rewriter.h"
|
||||
#include "ast_pp.h"
|
||||
|
||||
|
||||
void expr_safe_replace::insert(expr* src, expr* dst) {
|
||||
SASSERT(m.get_sort(src) == m.get_sort(dst));
|
||||
m_src.push_back(src);
|
||||
m_dst.push_back(dst);
|
||||
m_subst.insert(src, dst);
|
||||
|
@ -30,7 +32,7 @@ void expr_safe_replace::insert(expr* src, expr* dst) {
|
|||
|
||||
void expr_safe_replace::operator()(expr* e, expr_ref& res) {
|
||||
m_todo.push_back(e);
|
||||
expr* a, *b, *d;
|
||||
expr* a, *b;
|
||||
|
||||
while (!m_todo.empty()) {
|
||||
a = m_todo.back();
|
||||
|
@ -39,7 +41,7 @@ void expr_safe_replace::operator()(expr* e, expr_ref& res) {
|
|||
}
|
||||
else if (m_subst.find(a, b)) {
|
||||
m_cache.insert(a, b);
|
||||
m_todo.pop_back();
|
||||
m_todo.pop_back();
|
||||
}
|
||||
else if (is_var(a)) {
|
||||
m_cache.insert(a, a);
|
||||
|
@ -51,18 +53,21 @@ void expr_safe_replace::operator()(expr* e, expr_ref& res) {
|
|||
m_args.reset();
|
||||
bool arg_differs = false;
|
||||
for (unsigned i = 0; i < n; ++i) {
|
||||
if (m_cache.find(c->get_arg(i), d)) {
|
||||
expr* d = 0, *arg = c->get_arg(i);
|
||||
if (m_cache.find(arg, d)) {
|
||||
m_args.push_back(d);
|
||||
arg_differs |= c->get_arg(i) != d;
|
||||
arg_differs |= arg != d;
|
||||
SASSERT(m.get_sort(arg) == m.get_sort(d));
|
||||
}
|
||||
else {
|
||||
m_todo.push_back(c->get_arg(i));
|
||||
m_todo.push_back(arg);
|
||||
}
|
||||
}
|
||||
if (m_args.size() == n) {
|
||||
if (arg_differs) {
|
||||
b = m.mk_app(c->get_decl(), m_args.size(), m_args.c_ptr());
|
||||
m_refs.push_back(b);
|
||||
SASSERT(m.get_sort(a) == m.get_sort(b));
|
||||
} else {
|
||||
b = a;
|
||||
}
|
||||
|
|
|
@ -22,30 +22,144 @@ Notes:
|
|||
#include"ast_pp.h"
|
||||
#include"ast_util.h"
|
||||
#include"uint_set.h"
|
||||
#include"automaton.h"
|
||||
#include"well_sorted.h"
|
||||
|
||||
|
||||
struct display_expr1 {
|
||||
ast_manager& m;
|
||||
display_expr1(ast_manager& m): m(m) {}
|
||||
std::ostream& display(std::ostream& out, expr* e) const {
|
||||
return out << mk_pp(e, m);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
re2automaton::re2automaton(ast_manager& m): m(m), u(m) {}
|
||||
|
||||
eautomaton* re2automaton::operator()(expr* e) {
|
||||
eautomaton* r = re2aut(e);
|
||||
if (r) {
|
||||
//display_expr1 disp(m);
|
||||
//r->display(std::cout, disp);
|
||||
r->compress();
|
||||
//r->display(std::cout, disp);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
eautomaton* re2automaton::re2aut(expr* e) {
|
||||
SASSERT(u.is_re(e));
|
||||
expr* e1, *e2;
|
||||
scoped_ptr<eautomaton> a, b;
|
||||
if (u.re.is_to_re(e, e1)) {
|
||||
return seq2aut(e1);
|
||||
}
|
||||
else if (u.re.is_concat(e, e1, e2) && (a = re2aut(e1)) && (b = re2aut(e2))) {
|
||||
return eautomaton::mk_concat(*a, *b);
|
||||
}
|
||||
else if (u.re.is_union(e, e1, e2) && (a = re2aut(e1)) && (b = re2aut(e2))) {
|
||||
return eautomaton::mk_union(*a, *b);
|
||||
}
|
||||
else if (u.re.is_star(e, e1) && (a = re2aut(e1))) {
|
||||
a->add_final_to_init_moves();
|
||||
a->add_init_to_final_states();
|
||||
|
||||
return a.detach();
|
||||
}
|
||||
else if (u.re.is_plus(e, e1) && (a = re2aut(e1))) {
|
||||
a->add_final_to_init_moves();
|
||||
return a.detach();
|
||||
}
|
||||
else if (u.re.is_opt(e, e1) && (a = re2aut(e1))) {
|
||||
a = eautomaton::mk_opt(*a);
|
||||
return a.detach();
|
||||
}
|
||||
else if (u.re.is_range(e)) {
|
||||
|
||||
}
|
||||
else if (u.re.is_loop(e)) {
|
||||
|
||||
}
|
||||
#if 0
|
||||
else if (u.re.is_intersect(e, e1, e2)) {
|
||||
|
||||
}
|
||||
else if (u.re.is_empty(e)) {
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
eautomaton* re2automaton::seq2aut(expr* e) {
|
||||
SASSERT(u.is_seq(e));
|
||||
zstring s;
|
||||
expr* e1, *e2;
|
||||
scoped_ptr<eautomaton> a, b;
|
||||
if (u.str.is_concat(e, e1, e2) && (a = seq2aut(e1)) && (b = seq2aut(e2))) {
|
||||
return eautomaton::mk_concat(*a, *b);
|
||||
}
|
||||
else if (u.str.is_unit(e, e1)) {
|
||||
return alloc(eautomaton, m, e1);
|
||||
}
|
||||
else if (u.str.is_empty(e)) {
|
||||
return eautomaton::mk_epsilon(m);
|
||||
}
|
||||
else if (u.str.is_string(e, s)) {
|
||||
unsigned init = 0;
|
||||
eautomaton::moves mvs;
|
||||
unsigned_vector final;
|
||||
final.push_back(s.length());
|
||||
for (unsigned k = 0; k < s.length(); ++k) {
|
||||
// reference count?
|
||||
mvs.push_back(eautomaton::move(m, k, k+1, u.str.mk_char(s, k)));
|
||||
}
|
||||
return alloc(eautomaton, m, init, final, mvs);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
switch(f->get_decl_kind()) {
|
||||
|
||||
case OP_SEQ_UNIT:
|
||||
case OP_SEQ_EMPTY:
|
||||
|
||||
case OP_RE_PLUS:
|
||||
case OP_RE_STAR:
|
||||
case OP_RE_OPTION:
|
||||
case OP_RE_RANGE:
|
||||
case OP_RE_CONCAT:
|
||||
case OP_RE_UNION:
|
||||
case OP_RE_INTERSECT:
|
||||
case OP_RE_LOOP:
|
||||
case OP_RE_EMPTY_SET:
|
||||
case OP_RE_FULL_SET:
|
||||
case OP_RE_OF_PRED:
|
||||
case _OP_SEQ_SKOLEM:
|
||||
return BR_FAILED;
|
||||
|
||||
case OP_SEQ_EMPTY:
|
||||
return BR_FAILED;
|
||||
case OP_RE_PLUS:
|
||||
SASSERT(num_args == 1);
|
||||
return mk_re_plus(args[0], result);
|
||||
case OP_RE_STAR:
|
||||
SASSERT(num_args == 1);
|
||||
return mk_re_star(args[0], result);
|
||||
case OP_RE_OPTION:
|
||||
SASSERT(num_args == 1);
|
||||
return mk_re_opt(args[0], result);
|
||||
case OP_RE_CONCAT:
|
||||
SASSERT(num_args == 2);
|
||||
return mk_re_concat(args[0], args[1], result);
|
||||
case OP_RE_UNION:
|
||||
SASSERT(num_args == 2);
|
||||
return mk_re_union(args[0], args[1], result);
|
||||
case OP_RE_RANGE:
|
||||
return BR_FAILED;
|
||||
case OP_RE_INTERSECT:
|
||||
return BR_FAILED;
|
||||
case OP_RE_LOOP:
|
||||
return BR_FAILED;
|
||||
case OP_RE_EMPTY_SET:
|
||||
return BR_FAILED;
|
||||
case OP_RE_FULL_SET:
|
||||
return BR_FAILED;
|
||||
case OP_RE_OF_PRED:
|
||||
return BR_FAILED;
|
||||
case _OP_SEQ_SKOLEM:
|
||||
return BR_FAILED;
|
||||
case OP_SEQ_CONCAT:
|
||||
if (num_args == 1) {
|
||||
result = args[0];
|
||||
|
@ -83,10 +197,11 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
|
|||
SASSERT(num_args == 3);
|
||||
return mk_seq_replace(args[0], args[1], args[2], result);
|
||||
case OP_SEQ_TO_RE:
|
||||
return BR_FAILED;
|
||||
SASSERT(num_args == 1);
|
||||
return mk_str_to_regexp(args[0], result);
|
||||
case OP_SEQ_IN_RE:
|
||||
return BR_FAILED;
|
||||
|
||||
SASSERT(num_args == 2);
|
||||
return mk_str_in_regexp(args[0], args[1], result);
|
||||
case OP_STRING_CONST:
|
||||
return BR_FAILED;
|
||||
case OP_STRING_ITOS:
|
||||
|
@ -129,8 +244,8 @@ br_status seq_rewriter::mk_seq_concat(expr* a, expr* b, expr_ref& result) {
|
|||
result = m_util.str.mk_string(s1 + s2);
|
||||
return BR_DONE;
|
||||
}
|
||||
if (m_util.str.is_concat(b, c, d)) {
|
||||
result = m_util.str.mk_concat(m_util.str.mk_concat(a, c), d);
|
||||
if (m_util.str.is_concat(a, c, d)) {
|
||||
result = m_util.str.mk_concat(c, m_util.str.mk_concat(d, b));
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
if (m_util.str.is_empty(a)) {
|
||||
|
@ -141,11 +256,15 @@ br_status seq_rewriter::mk_seq_concat(expr* a, expr* b, expr_ref& result) {
|
|||
result = a;
|
||||
return BR_DONE;
|
||||
}
|
||||
if (m_util.str.is_concat(a, c, d) &&
|
||||
m_util.str.is_string(d, s1) && isc2) {
|
||||
// TBD concatenation is right-associative
|
||||
if (isc2 && m_util.str.is_concat(a, c, d) && m_util.str.is_string(d, s1)) {
|
||||
result = m_util.str.mk_concat(c, m_util.str.mk_string(s1 + s2));
|
||||
return BR_DONE;
|
||||
}
|
||||
if (isc1 && m_util.str.is_concat(b, c, d) && m_util.str.is_string(c, s2)) {
|
||||
result = m_util.str.mk_concat(m_util.str.mk_string(s1 + s2), d);
|
||||
return BR_DONE;
|
||||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
|
@ -156,17 +275,17 @@ br_status seq_rewriter::mk_seq_length(expr* a, expr_ref& result) {
|
|||
unsigned len = 0;
|
||||
unsigned j = 0;
|
||||
for (unsigned i = 0; i < m_es.size(); ++i) {
|
||||
if (m_util.str.is_string(m_es[i], b)) {
|
||||
if (m_util.str.is_string(m_es[i].get(), b)) {
|
||||
len += b.length();
|
||||
}
|
||||
else if (m_util.str.is_unit(m_es[i])) {
|
||||
else if (m_util.str.is_unit(m_es[i].get())) {
|
||||
len += 1;
|
||||
}
|
||||
else if (m_util.str.is_empty(m_es[i])) {
|
||||
else if (m_util.str.is_empty(m_es[i].get())) {
|
||||
// skip
|
||||
}
|
||||
else {
|
||||
m_es[j] = m_es[i];
|
||||
m_es[j] = m_es[i].get();
|
||||
++j;
|
||||
}
|
||||
}
|
||||
|
@ -177,7 +296,7 @@ br_status seq_rewriter::mk_seq_length(expr* a, expr_ref& result) {
|
|||
if (j != m_es.size() || j != 1) {
|
||||
expr_ref_vector es(m());
|
||||
for (unsigned i = 0; i < j; ++i) {
|
||||
es.push_back(m_util.str.mk_length(m_es[i]));
|
||||
es.push_back(m_util.str.mk_length(m_es[i].get()));
|
||||
}
|
||||
if (len != 0) {
|
||||
es.push_back(m_autil.mk_numeral(rational(len, rational::ui64()), true));
|
||||
|
@ -207,20 +326,31 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) {
|
|||
return BR_DONE;
|
||||
}
|
||||
// check if subsequence of b is in a.
|
||||
ptr_vector<expr> as, bs;
|
||||
expr_ref_vector as(m()), bs(m());
|
||||
m_util.str.get_concat(a, as);
|
||||
m_util.str.get_concat(b, bs);
|
||||
bool all_values = true;
|
||||
|
||||
for (unsigned i = 0; all_values && i < bs.size(); ++i) {
|
||||
all_values = m().is_value(bs[i].get());
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
for (unsigned i = 0; !found && i < as.size(); ++i) {
|
||||
if (bs.size() > as.size() - i) break;
|
||||
all_values &= m().is_value(as[i].get());
|
||||
unsigned j = 0;
|
||||
for (; j < bs.size() && as[j+i] == bs[j]; ++j) {};
|
||||
for (; j < bs.size() && as[j+i].get() == bs[j].get(); ++j) {};
|
||||
found = j == bs.size();
|
||||
}
|
||||
if (found) {
|
||||
result = m().mk_true();
|
||||
return BR_DONE;
|
||||
}
|
||||
if (all_values) {
|
||||
result = m().mk_false();
|
||||
return BR_DONE;
|
||||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
|
@ -292,7 +422,7 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) {
|
|||
expr* b1 = m_util.str.get_leftmost_concat(b);
|
||||
isc1 = m_util.str.is_string(a1, s1);
|
||||
isc2 = m_util.str.is_string(b1, s2);
|
||||
ptr_vector<expr> as, bs;
|
||||
expr_ref_vector as(m()), bs(m());
|
||||
|
||||
if (a1 != b1 && isc1 && isc2) {
|
||||
if (s1.length() <= s2.length()) {
|
||||
|
@ -342,15 +472,26 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) {
|
|||
m_util.str.get_concat(a, as);
|
||||
m_util.str.get_concat(b, bs);
|
||||
unsigned i = 0;
|
||||
for (; i < as.size() && i < bs.size() && as[i] == bs[i]; ++i) {};
|
||||
bool all_values = true;
|
||||
for (; i < as.size() && i < bs.size(); ++i) {
|
||||
all_values &= m().is_value(as[i].get()) && m().is_value(bs[i].get());
|
||||
if (as[i].get() != bs[i].get()) {
|
||||
if (all_values) {
|
||||
result = m().mk_false();
|
||||
return BR_DONE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
if (i == as.size()) {
|
||||
result = m().mk_true();
|
||||
return BR_DONE;
|
||||
}
|
||||
SASSERT(i < as.size());
|
||||
if (i == bs.size()) {
|
||||
expr_ref_vector es(m());
|
||||
for (unsigned j = i; j < as.size(); ++j) {
|
||||
es.push_back(m().mk_eq(m_util.str.mk_empty(m().get_sort(a)), as[j]));
|
||||
es.push_back(m().mk_eq(m_util.str.mk_empty(m().get_sort(a)), as[j].get()));
|
||||
}
|
||||
result = mk_and(es);
|
||||
return BR_REWRITE3;
|
||||
|
@ -380,20 +521,10 @@ br_status seq_rewriter::mk_seq_suffix(expr* a, expr* b, expr_ref& result) {
|
|||
result = m().mk_eq(m_util.str.mk_empty(m().get_sort(a)), a);
|
||||
return BR_REWRITE3;
|
||||
}
|
||||
// concatenation is left-associative, so a2, b2 are not concatenations
|
||||
expr* a1, *a2, *b1, *b2;
|
||||
if (m_util.str.is_concat(a, a1, a2) &&
|
||||
m_util.str.is_concat(b, b1, b2) && a2 == b2) {
|
||||
result = m_util.str.mk_suffix(a1, b1);
|
||||
return BR_REWRITE1;
|
||||
}
|
||||
if (m_util.str.is_concat(b, b1, b2) && b2 == a) {
|
||||
result = m().mk_true();
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
bool isc1 = false;
|
||||
bool isc2 = false;
|
||||
|
||||
expr* a1, *a2, *b1, *b2;
|
||||
if (m_util.str.is_concat(a, a1, a2) && m_util.str.is_string(a2, s1)) {
|
||||
isc1 = true;
|
||||
}
|
||||
|
@ -453,6 +584,37 @@ br_status seq_rewriter::mk_seq_suffix(expr* a, expr* b, expr_ref& result) {
|
|||
}
|
||||
}
|
||||
}
|
||||
expr_ref_vector as(m()), bs(m());
|
||||
m_util.str.get_concat(a, as);
|
||||
m_util.str.get_concat(b, bs);
|
||||
bool change = false;
|
||||
while (as.size() > 0 && bs.size() > 0 && as.back() == bs.back()) {
|
||||
as.pop_back();
|
||||
bs.pop_back();
|
||||
change = true;
|
||||
}
|
||||
if (as.size() > 0 && bs.size() > 0 && m().is_value(as.back()) && m().is_value(bs.back())) {
|
||||
result = m().mk_false();
|
||||
return BR_DONE;
|
||||
}
|
||||
if (change) {
|
||||
// suffix("", bs) <- true
|
||||
if (as.empty()) {
|
||||
result = m().mk_true();
|
||||
return BR_DONE;
|
||||
}
|
||||
// suffix(as, "") iff as = ""
|
||||
if (bs.empty()) {
|
||||
for (unsigned j = 0; j < as.size(); ++j) {
|
||||
bs.push_back(m().mk_eq(m_util.str.mk_empty(m().get_sort(a)), as[j].get()));
|
||||
}
|
||||
result = mk_and(bs);
|
||||
return BR_REWRITE3;
|
||||
}
|
||||
result = m_util.str.mk_suffix(m_util.str.mk_concat(as.size(), as.c_ptr()),
|
||||
m_util.str.mk_concat(bs.size(), bs.c_ptr()));
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
@ -480,26 +642,190 @@ br_status seq_rewriter::mk_str_stoi(expr* a, expr_ref& result) {
|
|||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
void seq_rewriter::add_next(u_map<expr*>& next, unsigned idx, expr* cond) {
|
||||
expr* acc;
|
||||
if (m().is_true(cond) || !next.find(idx, acc)) {
|
||||
next.insert(idx, cond);
|
||||
}
|
||||
else {
|
||||
next.insert(idx, m().mk_or(cond, acc));
|
||||
}
|
||||
}
|
||||
|
||||
bool seq_rewriter::is_sequence(expr* e, expr_ref_vector& seq) {
|
||||
zstring s;
|
||||
ptr_vector<expr> todo;
|
||||
expr *e1, *e2;
|
||||
todo.push_back(e);
|
||||
while (!todo.empty()) {
|
||||
e = todo.back();
|
||||
todo.pop_back();
|
||||
if (m_util.str.is_string(e, s)) {
|
||||
for (unsigned i = s.length(); i > 0; ) {
|
||||
--i;
|
||||
seq.push_back(m_util.str.mk_char(s, i));
|
||||
}
|
||||
}
|
||||
else if (m_util.str.is_empty(e)) {
|
||||
continue;
|
||||
}
|
||||
else if (m_util.str.is_unit(e)) {
|
||||
seq.push_back(e);
|
||||
}
|
||||
else if (m_util.str.is_concat(e, e1, e2)) {
|
||||
todo.push_back(e1);
|
||||
todo.push_back(e2);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
seq.reverse();
|
||||
return true;
|
||||
}
|
||||
|
||||
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 (is_sequence(a, seq) && (aut = re2automaton(m())(b))) {
|
||||
expr_ref_vector trail(m());
|
||||
u_map<expr*> maps[2];
|
||||
bool select_map = false;
|
||||
expr_ref ch(m()), cond(m());
|
||||
eautomaton::moves mvs;
|
||||
maps[0].insert(aut->init(), m().mk_true());
|
||||
// is_accepted(a, aut) & some state in frontier is final.
|
||||
|
||||
for (unsigned i = 0; i < seq.size(); ++i) {
|
||||
u_map<expr*>& frontier = maps[select_map];
|
||||
u_map<expr*>& next = maps[!select_map];
|
||||
select_map = !select_map;
|
||||
ch = seq[i].get();
|
||||
next.reset();
|
||||
u_map<expr*>::iterator it = frontier.begin(), end = frontier.end();
|
||||
for (; it != end; ++it) {
|
||||
mvs.reset();
|
||||
unsigned state = it->m_key;
|
||||
expr* acc = it->m_value;
|
||||
aut->get_moves_from(state, mvs, false);
|
||||
for (unsigned j = 0; j < mvs.size(); ++j) {
|
||||
eautomaton::move const& mv = mvs[j];
|
||||
if (m().is_value(mv.t()) && m().is_value(ch)) {
|
||||
if (mv.t() == ch) {
|
||||
add_next(next, mv.dst(), acc);
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
cond = m().mk_eq(mv.t(), ch);
|
||||
if (!m().is_true(acc)) cond = m().mk_and(acc, cond);
|
||||
add_next(next, mv.dst(), cond);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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) {
|
||||
unsigned_vector states;
|
||||
bool has_final = false;
|
||||
aut->get_epsilon_closure(it->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);
|
||||
}
|
||||
}
|
||||
result = mk_or(ors);
|
||||
return BR_REWRITE_FULL;
|
||||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
br_status seq_rewriter::mk_str_to_regexp(expr* a, expr_ref& result) {
|
||||
return BR_FAILED;
|
||||
}
|
||||
br_status seq_rewriter::mk_re_concat(expr* a, expr* b, expr_ref& result) {
|
||||
if (is_epsilon(a)) {
|
||||
result = b;
|
||||
return BR_DONE;
|
||||
}
|
||||
if (is_epsilon(b)) {
|
||||
result = a;
|
||||
return BR_DONE;
|
||||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
/*
|
||||
(a + a) = a
|
||||
(a + eps) = a
|
||||
(eps + a) = a
|
||||
*/
|
||||
br_status seq_rewriter::mk_re_union(expr* a, expr* b, expr_ref& result) {
|
||||
if (a == b) {
|
||||
result = a;
|
||||
return BR_DONE;
|
||||
}
|
||||
if (m_util.re.is_star(a) && is_epsilon(b)) {
|
||||
result = a;
|
||||
return BR_DONE;
|
||||
}
|
||||
if (m_util.re.is_star(b) && is_epsilon(a)) {
|
||||
result = b;
|
||||
return BR_DONE;
|
||||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
/*
|
||||
a** = a*
|
||||
(a* + b)* = (a + b)*
|
||||
(a + b*)* = (a + b)*
|
||||
(a*b*)* = (a + b)*
|
||||
*/
|
||||
br_status seq_rewriter::mk_re_star(expr* a, expr_ref& result) {
|
||||
expr* b, *c, *b1, *c1;
|
||||
if (m_util.re.is_star(a)) {
|
||||
result = a;
|
||||
return BR_DONE;
|
||||
}
|
||||
if (m_util.re.is_union(a, b, c)) {
|
||||
if (m_util.re.is_star(b, b1)) {
|
||||
result = m_util.re.mk_star(m_util.re.mk_union(b1, c));
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
if (m_util.re.is_star(c, c1)) {
|
||||
result = m_util.re.mk_star(m_util.re.mk_union(b, c1));
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
}
|
||||
if (m_util.re.is_concat(a, b, c) &&
|
||||
m_util.re.is_star(b, b1) && m_util.re.is_star(c, c1)) {
|
||||
result = m_util.re.mk_star(m_util.re.mk_union(b1, c1));
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
/*
|
||||
a+ = aa*
|
||||
*/
|
||||
br_status seq_rewriter::mk_re_plus(expr* a, expr_ref& result) {
|
||||
return BR_FAILED;
|
||||
// result = m_util.re.mk_concat(a, m_util.re.mk_star(a));
|
||||
// return BR_REWRITE2;
|
||||
}
|
||||
|
||||
br_status seq_rewriter::mk_re_opt(expr* a, expr_ref& result) {
|
||||
return BR_FAILED;
|
||||
sort* s;
|
||||
VERIFY(m_util.is_re(a, s));
|
||||
sort_ref seq(m_util.str.mk_seq(s), m());
|
||||
result = m_util.re.mk_union(m_util.re.mk_to_re(m_util.str.mk_empty(seq)), a);
|
||||
return BR_REWRITE1;
|
||||
}
|
||||
|
||||
br_status seq_rewriter::mk_eq_core(expr * l, expr * r, expr_ref & result) {
|
||||
|
@ -518,38 +844,33 @@ br_status seq_rewriter::mk_eq_core(expr * l, expr * r, expr_ref & result) {
|
|||
return BR_REWRITE3;
|
||||
}
|
||||
|
||||
bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_vector& rhs) {
|
||||
bool seq_rewriter::reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_vector& lhs, expr_ref_vector& rhs) {
|
||||
expr* a, *b;
|
||||
zstring s;
|
||||
bool change = false;
|
||||
expr_ref_vector trail(m());
|
||||
m_lhs.reset();
|
||||
m_rhs.reset();
|
||||
m_util.str.get_concat(l, m_lhs);
|
||||
m_util.str.get_concat(r, m_rhs);
|
||||
|
||||
// solve from back
|
||||
while (true) {
|
||||
while (!m_rhs.empty() && m_util.str.is_empty(m_rhs.back())) {
|
||||
m_rhs.pop_back();
|
||||
while (!rs.empty() && m_util.str.is_empty(rs.back())) {
|
||||
rs.pop_back();
|
||||
change = true;
|
||||
}
|
||||
while (!m_lhs.empty() && m_util.str.is_empty(m_lhs.back())) {
|
||||
m_lhs.pop_back();
|
||||
while (!ls.empty() && m_util.str.is_empty(ls.back())) {
|
||||
ls.pop_back();
|
||||
change = true;
|
||||
}
|
||||
if (m_lhs.empty() || m_rhs.empty()) {
|
||||
if (ls.empty() || rs.empty()) {
|
||||
break;
|
||||
}
|
||||
expr* l = m_lhs.back();
|
||||
expr* r = m_rhs.back();
|
||||
expr* l = ls.back();
|
||||
expr* r = rs.back();
|
||||
if (m_util.str.is_unit(r) && m_util.str.is_string(l)) {
|
||||
std::swap(l, r);
|
||||
std::swap(m_lhs, m_rhs);
|
||||
ls.swap(rs);
|
||||
}
|
||||
if (l == r) {
|
||||
m_lhs.pop_back();
|
||||
m_rhs.pop_back();
|
||||
ls.pop_back();
|
||||
rs.pop_back();
|
||||
}
|
||||
else if(m_util.str.is_unit(l, a) &&
|
||||
m_util.str.is_unit(r, b)) {
|
||||
|
@ -558,8 +879,8 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve
|
|||
}
|
||||
lhs.push_back(a);
|
||||
rhs.push_back(b);
|
||||
m_lhs.pop_back();
|
||||
m_rhs.pop_back();
|
||||
ls.pop_back();
|
||||
rs.pop_back();
|
||||
}
|
||||
else if (m_util.str.is_unit(l, a) && m_util.str.is_string(r, s)) {
|
||||
SASSERT(s.length() > 0);
|
||||
|
@ -568,14 +889,13 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve
|
|||
SASSERT(m().get_sort(ch) == m().get_sort(a));
|
||||
lhs.push_back(ch);
|
||||
rhs.push_back(a);
|
||||
m_lhs.pop_back();
|
||||
ls.pop_back();
|
||||
if (s.length() == 1) {
|
||||
m_rhs.pop_back();
|
||||
rs.pop_back();
|
||||
}
|
||||
else {
|
||||
expr_ref s2(m_util.str.mk_string(s.extract(0, s.length()-2)), m());
|
||||
m_rhs[m_rhs.size()-1] = s2;
|
||||
trail.push_back(s2);
|
||||
rs[rs.size()-1] = s2;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -587,22 +907,22 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve
|
|||
// solve from front
|
||||
unsigned head1 = 0, head2 = 0;
|
||||
while (true) {
|
||||
while (head1 < m_lhs.size() && m_util.str.is_empty(m_lhs[head1])) {
|
||||
while (head1 < ls.size() && m_util.str.is_empty(ls[head1].get())) {
|
||||
++head1;
|
||||
}
|
||||
while (head2 < m_rhs.size() && m_util.str.is_empty(m_rhs[head2])) {
|
||||
while (head2 < rs.size() && m_util.str.is_empty(rs[head2].get())) {
|
||||
++head2;
|
||||
}
|
||||
if (head1 == m_lhs.size() || head2 == m_rhs.size()) {
|
||||
if (head1 == ls.size() || head2 == rs.size()) {
|
||||
break;
|
||||
}
|
||||
SASSERT(head1 < m_lhs.size() && head2 < m_rhs.size());
|
||||
SASSERT(head1 < ls.size() && head2 < rs.size());
|
||||
|
||||
expr* l = m_lhs[head1];
|
||||
expr* r = m_rhs[head2];
|
||||
expr* l = ls[head1].get();
|
||||
expr* r = rs[head2].get();
|
||||
if (m_util.str.is_unit(r) && m_util.str.is_string(l)) {
|
||||
std::swap(l, r);
|
||||
std::swap(m_lhs, m_rhs);
|
||||
ls.swap(rs);
|
||||
}
|
||||
if (l == r) {
|
||||
++head1;
|
||||
|
@ -624,14 +944,13 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve
|
|||
SASSERT(m().get_sort(ch) == m().get_sort(a));
|
||||
lhs.push_back(ch);
|
||||
rhs.push_back(a);
|
||||
m_lhs.pop_back();
|
||||
ls.pop_back();
|
||||
if (s.length() == 1) {
|
||||
m_rhs.pop_back();
|
||||
rs.pop_back();
|
||||
}
|
||||
else {
|
||||
expr_ref s2(m_util.str.mk_string(s.extract(1, s.length()-1)), m());
|
||||
m_rhs[m_rhs.size()-1] = s2;
|
||||
trail.push_back(s2);
|
||||
rs[rs.size()-1] = s2;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -641,10 +960,10 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve
|
|||
}
|
||||
// reduce strings
|
||||
zstring s1, s2;
|
||||
while (head1 < m_lhs.size() &&
|
||||
head2 < m_rhs.size() &&
|
||||
m_util.str.is_string(m_lhs[head1], s1) &&
|
||||
m_util.str.is_string(m_rhs[head2], s2)) {
|
||||
while (head1 < ls.size() &&
|
||||
head2 < rs.size() &&
|
||||
m_util.str.is_string(ls[head1].get(), s1) &&
|
||||
m_util.str.is_string(rs[head2].get(), s2)) {
|
||||
unsigned l = std::min(s1.length(), s2.length());
|
||||
for (unsigned i = 0; i < l; ++i) {
|
||||
if (s1[i] != s2[i]) {
|
||||
|
@ -655,68 +974,88 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve
|
|||
++head1;
|
||||
}
|
||||
else {
|
||||
m_lhs[head1] = m_util.str.mk_string(s1.extract(l, s1.length()-l));
|
||||
trail.push_back(m_lhs[head1]);
|
||||
ls[head1] = m_util.str.mk_string(s1.extract(l, s1.length()-l));
|
||||
}
|
||||
if (l == s2.length()) {
|
||||
++head2;
|
||||
}
|
||||
else {
|
||||
m_rhs[head2] = m_util.str.mk_string(s2.extract(l, s2.length()-l));
|
||||
trail.push_back(m_rhs[head2]);
|
||||
rs[head2] = m_util.str.mk_string(s2.extract(l, s2.length()-l));
|
||||
}
|
||||
change = true;
|
||||
}
|
||||
while (head1 < m_lhs.size() &&
|
||||
head2 < m_rhs.size() &&
|
||||
m_util.str.is_string(m_lhs.back(), s1) &&
|
||||
m_util.str.is_string(m_rhs.back(), s2)) {
|
||||
while (head1 < ls.size() &&
|
||||
head2 < rs.size() &&
|
||||
m_util.str.is_string(ls.back(), s1) &&
|
||||
m_util.str.is_string(rs.back(), s2)) {
|
||||
unsigned l = std::min(s1.length(), s2.length());
|
||||
for (unsigned i = 0; i < l; ++i) {
|
||||
if (s1[s1.length()-i-1] != s2[s2.length()-i-1]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
m_lhs.pop_back();
|
||||
m_rhs.pop_back();
|
||||
ls.pop_back();
|
||||
rs.pop_back();
|
||||
if (l < s1.length()) {
|
||||
m_lhs.push_back(m_util.str.mk_string(s1.extract(0, s1.length()-l)));
|
||||
trail.push_back(m_lhs.back());
|
||||
ls.push_back(m_util.str.mk_string(s1.extract(0, s1.length()-l)));
|
||||
}
|
||||
if (l < s2.length()) {
|
||||
m_rhs.push_back(m_util.str.mk_string(s2.extract(0, s2.length()-l)));
|
||||
trail.push_back(m_rhs.back());
|
||||
}
|
||||
rs.push_back(m_util.str.mk_string(s2.extract(0, s2.length()-l)));
|
||||
}
|
||||
change = true;
|
||||
}
|
||||
|
||||
bool is_sat;
|
||||
unsigned szl = m_lhs.size() - head1, szr = m_rhs.size() - head2;
|
||||
expr* const* ls = m_lhs.c_ptr() + head1, * const*rs = m_rhs.c_ptr() + head2;
|
||||
if (length_constrained(szl, ls, szr, rs, lhs, rhs, is_sat)) {
|
||||
unsigned szl = ls.size() - head1, szr = rs.size() - head2;
|
||||
expr* const* _ls = ls.c_ptr() + head1, * const* _rs = rs.c_ptr() + head2;
|
||||
if (length_constrained(szl, _ls, szr, _rs, lhs, rhs, is_sat)) {
|
||||
ls.reset(); rs.reset();
|
||||
return is_sat;
|
||||
}
|
||||
if (is_subsequence(szl, ls, szr, rs, lhs, rhs, is_sat)) {
|
||||
if (is_subsequence(szl, _ls, szr, _rs, lhs, rhs, is_sat)) {
|
||||
ls.reset(); rs.reset();
|
||||
return is_sat;
|
||||
}
|
||||
|
||||
if (szl == 0 && szr == 0) {
|
||||
return true;
|
||||
}
|
||||
if (szl == 0 && szr == 0) {
|
||||
ls.reset(); rs.reset();
|
||||
return true;
|
||||
}
|
||||
else if (!change) {
|
||||
lhs.push_back(l);
|
||||
rhs.push_back(r);
|
||||
// skip
|
||||
SASSERT(lhs.empty());
|
||||
}
|
||||
else {
|
||||
// could solve if either side is fixed size.
|
||||
SASSERT(szl > 0 && szr > 0);
|
||||
|
||||
lhs.push_back(m_util.str.mk_concat(szl, ls));
|
||||
rhs.push_back(m_util.str.mk_concat(szr, rs));
|
||||
lhs.push_back(m_util.str.mk_concat(szl, ls.c_ptr() + head1));
|
||||
rhs.push_back(m_util.str.mk_concat(szr, rs.c_ptr() + head2));
|
||||
ls.reset();
|
||||
rs.reset();
|
||||
}
|
||||
SASSERT(lhs.empty() || ls.empty());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_vector& rhs) {
|
||||
m_lhs.reset();
|
||||
m_rhs.reset();
|
||||
m_util.str.get_concat(l, m_lhs);
|
||||
m_util.str.get_concat(r, m_rhs);
|
||||
if (reduce_eq(m_lhs, m_rhs, lhs, rhs)) {
|
||||
SASSERT(lhs.size() == rhs.size());
|
||||
if (lhs.empty()) {
|
||||
lhs.push_back(l);
|
||||
rhs.push_back(r);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
TRACE("seq", tout << mk_pp(l, m()) << " != " << mk_pp(r, m()) << "\n";);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
expr* seq_rewriter::concat_non_empty(unsigned n, expr* const* as) {
|
||||
SASSERT(n > 0);
|
||||
ptr_vector<expr> bs;
|
||||
|
@ -812,6 +1151,11 @@ bool seq_rewriter::length_constrained(unsigned szl, expr* const* l, unsigned szr
|
|||
return false;
|
||||
}
|
||||
|
||||
bool seq_rewriter::is_epsilon(expr* e) const {
|
||||
expr* e1;
|
||||
return m_util.re.is_to_re(e, e1) && m_util.str.is_empty(e1);
|
||||
}
|
||||
|
||||
bool seq_rewriter::is_subsequence(unsigned szl, expr* const* l, unsigned szr, expr* const* r,
|
||||
expr_ref_vector& lhs, expr_ref_vector& rhs, bool& is_sat) {
|
||||
is_sat = true;
|
||||
|
|
|
@ -24,15 +24,27 @@ Notes:
|
|||
#include"rewriter_types.h"
|
||||
#include"params.h"
|
||||
#include"lbool.h"
|
||||
#include"automaton.h"
|
||||
|
||||
|
||||
typedef automaton<expr, ast_manager> eautomaton;
|
||||
class re2automaton {
|
||||
ast_manager& m;
|
||||
seq_util u;
|
||||
eautomaton* re2aut(expr* e);
|
||||
eautomaton* seq2aut(expr* e);
|
||||
public:
|
||||
re2automaton(ast_manager& m);
|
||||
eautomaton* operator()(expr* e);
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Cheap rewrite rules for seq constraints
|
||||
*/
|
||||
class seq_rewriter {
|
||||
seq_util m_util;
|
||||
arith_util m_autil;
|
||||
ptr_vector<expr> m_es, m_lhs, m_rhs;
|
||||
expr_ref_vector m_es, m_lhs, m_rhs;
|
||||
|
||||
br_status mk_seq_concat(expr* a, expr* b, expr_ref& result);
|
||||
br_status mk_seq_length(expr* a, expr_ref& result);
|
||||
|
@ -61,9 +73,13 @@ class seq_rewriter {
|
|||
bool min_length(unsigned n, expr* const* es, unsigned& len);
|
||||
expr* concat_non_empty(unsigned n, expr* const* es);
|
||||
|
||||
void add_next(u_map<expr*>& next, unsigned idx, expr* cond);
|
||||
bool is_sequence(expr* e, expr_ref_vector& seq);
|
||||
bool is_epsilon(expr* e) const;
|
||||
|
||||
public:
|
||||
seq_rewriter(ast_manager & m, params_ref const & p = params_ref()):
|
||||
m_util(m), m_autil(m) {
|
||||
m_util(m), m_autil(m), m_es(m), m_lhs(m), m_rhs(m) {
|
||||
}
|
||||
ast_manager & m() const { return m_util.get_manager(); }
|
||||
family_id get_fid() const { return m_util.get_family_id(); }
|
||||
|
@ -76,6 +92,8 @@ public:
|
|||
|
||||
bool reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_vector& rhs);
|
||||
|
||||
bool reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_vector& lhs, expr_ref_vector& rhs);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -25,7 +25,6 @@ Revision History:
|
|||
zstring::zstring(encoding enc): m_encoding(enc) {}
|
||||
|
||||
zstring::zstring(char const* s, encoding enc): m_encoding(enc) {
|
||||
// TBD: epply decoding
|
||||
while (*s) {
|
||||
m_buffer.push_back(*s);
|
||||
++s;
|
||||
|
@ -42,7 +41,7 @@ zstring::zstring(unsigned num_bits, bool const* ch) {
|
|||
m_encoding = (num_bits == 8)?ascii:unicode;
|
||||
unsigned n = 0;
|
||||
for (unsigned i = 0; i < num_bits; ++i) {
|
||||
n |= (((unsigned)ch[i]) << num_bits);
|
||||
n |= (((unsigned)ch[i]) << i);
|
||||
}
|
||||
m_buffer.push_back(n);
|
||||
}
|
||||
|
@ -81,12 +80,23 @@ zstring zstring::replace(zstring const& src, zstring const& dst) const {
|
|||
return result;
|
||||
}
|
||||
|
||||
static char* esc_table[32] = { "\\0", "^A", "^B", "^C", "^D", "^E", "^F", "\\a", "\\b", "\\t", "\\n", "\\v", "\\f", "\\r", "^N",
|
||||
"^O", "^P", "^Q", "^R", "^S", "^T", "^U", "^V","^W","^X","^Y","^Z","\\e","^\\","^]","^^","^_"};
|
||||
|
||||
std::string zstring::encode() const {
|
||||
// TBD apply encodings.
|
||||
SASSERT(m_encoding == ascii);
|
||||
std::ostringstream strm;
|
||||
for (unsigned i = 0; i < m_buffer.size(); ++i) {
|
||||
strm << (char)(m_buffer[i]);
|
||||
unsigned char ch = m_buffer[i];
|
||||
if (0 <= ch && ch < 32) {
|
||||
strm << esc_table[ch];
|
||||
}
|
||||
else if (ch == 127) {
|
||||
strm << "^?";
|
||||
}
|
||||
else {
|
||||
strm << (char)(ch);
|
||||
}
|
||||
}
|
||||
return strm.str();
|
||||
}
|
||||
|
@ -163,6 +173,7 @@ std::ostream& zstring::operator<<(std::ostream& out) const {
|
|||
|
||||
seq_decl_plugin::seq_decl_plugin(): m_init(false),
|
||||
m_stringc_sym("String"),
|
||||
m_charc_sym("Char"),
|
||||
m_string(0),
|
||||
m_char(0) {}
|
||||
|
||||
|
@ -211,9 +222,9 @@ bool seq_decl_plugin::match(ptr_vector<sort>& binding, sort* s, sort* sP) {
|
|||
}
|
||||
|
||||
/*
|
||||
\brief match left associative operator.
|
||||
\brief match right associative operator.
|
||||
*/
|
||||
void seq_decl_plugin::match_left_assoc(psig& sig, unsigned dsz, sort *const* dom, sort* range, sort_ref& range_out) {
|
||||
void seq_decl_plugin::match_right_assoc(psig& sig, unsigned dsz, sort *const* dom, sort* range, sort_ref& range_out) {
|
||||
ptr_vector<sort> binding;
|
||||
ast_manager& m = *m_manager;
|
||||
TRACE("seq_verbose",
|
||||
|
@ -369,7 +380,8 @@ void seq_decl_plugin::init() {
|
|||
|
||||
void seq_decl_plugin::set_manager(ast_manager* m, family_id id) {
|
||||
decl_plugin::set_manager(m, id);
|
||||
m_char = m->mk_sort(symbol("Char"), sort_info(m_family_id, _CHAR_SORT, 0, (parameter const*)0));
|
||||
bv_util bv(*m);
|
||||
m_char = bv.mk_sort(8);
|
||||
m->inc_ref(m_char);
|
||||
parameter param(m_char);
|
||||
m_string = m->mk_sort(symbol("String"), sort_info(m_family_id, SEQ_SORT, 1, ¶m));
|
||||
|
@ -391,18 +403,18 @@ sort * seq_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter
|
|||
return m_string;
|
||||
}
|
||||
return m.mk_sort(symbol("Seq"), sort_info(m_family_id, SEQ_SORT, num_parameters, parameters));
|
||||
case RE_SORT:
|
||||
case RE_SORT: {
|
||||
if (num_parameters != 1) {
|
||||
m.raise_exception("Invalid regex sort, expecting one parameter");
|
||||
}
|
||||
if (!parameters[0].is_ast() || !is_sort(parameters[0].get_ast())) {
|
||||
m.raise_exception("invalid regex sort, parameter is not a sort");
|
||||
}
|
||||
sort * s = to_sort(parameters[0].get_ast());
|
||||
return m.mk_sort(symbol("RegEx"), sort_info(m_family_id, RE_SORT, num_parameters, parameters));
|
||||
}
|
||||
case _STRING_SORT:
|
||||
return m_string;
|
||||
case _CHAR_SORT:
|
||||
return m_char;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
|
@ -430,9 +442,9 @@ func_decl* seq_decl_plugin::mk_assoc_fun(decl_kind k, unsigned arity, sort* cons
|
|||
if (arity == 0) {
|
||||
m.raise_exception("Invalid function application. At least one argument expected");
|
||||
}
|
||||
match_left_assoc(*m_sigs[k], arity, domain, range, rng);
|
||||
match_right_assoc(*m_sigs[k], arity, domain, range, rng);
|
||||
func_decl_info info(m_family_id, k_seq);
|
||||
info.set_left_associative();
|
||||
info.set_right_associative();
|
||||
return m.mk_func_decl(m_sigs[(rng == m_string)?k_string:k_seq]->m_name, rng, rng, rng, info);
|
||||
}
|
||||
|
||||
|
@ -470,6 +482,8 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
|
|||
}
|
||||
return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k, num_parameters, parameters));
|
||||
|
||||
|
||||
|
||||
case OP_STRING_CONST:
|
||||
if (!(num_parameters == 1 && arity == 0 && parameters[0].is_symbol())) {
|
||||
m.raise_exception("invalid string declaration");
|
||||
|
@ -583,7 +597,7 @@ void seq_decl_plugin::get_sort_names(svector<builtin_name> & sort_names, symbol
|
|||
app* seq_decl_plugin::mk_string(symbol const& s) {
|
||||
parameter param(s);
|
||||
func_decl* f = m_manager->mk_const_decl(m_stringc_sym, m_string,
|
||||
func_decl_info(m_family_id, OP_STRING_CONST, 1, ¶m));
|
||||
func_decl_info(m_family_id, OP_STRING_CONST, 1, ¶m));
|
||||
return m_manager->mk_const(f);
|
||||
}
|
||||
|
||||
|
@ -591,12 +605,16 @@ app* seq_decl_plugin::mk_string(zstring const& s) {
|
|||
symbol sym(s.encode().c_str());
|
||||
parameter param(sym);
|
||||
func_decl* f = m_manager->mk_const_decl(m_stringc_sym, m_string,
|
||||
func_decl_info(m_family_id, OP_STRING_CONST, 1, ¶m));
|
||||
func_decl_info(m_family_id, OP_STRING_CONST, 1, ¶m));
|
||||
return m_manager->mk_const(f);
|
||||
}
|
||||
|
||||
|
||||
bool seq_decl_plugin::is_value(app* e) const {
|
||||
return is_app_of(e, m_family_id, OP_STRING_CONST);
|
||||
return
|
||||
is_app_of(e, m_family_id, OP_SEQ_EMPTY) ||
|
||||
(is_app_of(e, m_family_id, OP_SEQ_UNIT) &&
|
||||
m_manager->is_value(e->get_arg(0)));
|
||||
}
|
||||
|
||||
app* seq_util::mk_skolem(symbol const& name, unsigned n, expr* const* args, sort* range) {
|
||||
|
@ -609,11 +627,26 @@ app* seq_util::mk_skolem(symbol const& name, unsigned n, expr* const* args, sort
|
|||
app* seq_util::str::mk_string(zstring const& s) { return u.seq.mk_string(s); }
|
||||
|
||||
|
||||
|
||||
app* seq_util::str::mk_char(zstring const& s, unsigned idx) {
|
||||
bv_util bvu(m);
|
||||
return bvu.mk_numeral(s[idx], s.num_bits());
|
||||
}
|
||||
|
||||
app* seq_util::str::mk_char(char ch) {
|
||||
zstring s(ch, zstring::ascii);
|
||||
return mk_char(s, 0);
|
||||
}
|
||||
|
||||
bool seq_util::str::is_char(expr* n, zstring& c) const {
|
||||
if (u.is_char(n)) {
|
||||
c = zstring(to_app(n)->get_decl()->get_parameter(0).get_symbol().bare_str());
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool seq_util::str::is_string(expr const* n, zstring& s) const {
|
||||
if (is_string(n)) {
|
||||
|
@ -626,7 +659,7 @@ bool seq_util::str::is_string(expr const* n, zstring& s) const {
|
|||
}
|
||||
|
||||
|
||||
void seq_util::str::get_concat(expr* e, ptr_vector<expr>& es) const {
|
||||
void seq_util::str::get_concat(expr* e, expr_ref_vector& es) const {
|
||||
expr* e1, *e2;
|
||||
while (is_concat(e, e1, e2)) {
|
||||
get_concat(e1, es);
|
||||
|
|
|
@ -22,13 +22,13 @@ Revision History:
|
|||
#define SEQ_DECL_PLUGIN_H_
|
||||
|
||||
#include "ast.h"
|
||||
#include "bv_decl_plugin.h"
|
||||
|
||||
|
||||
enum seq_sort_kind {
|
||||
SEQ_SORT,
|
||||
RE_SORT,
|
||||
_STRING_SORT, // internal only
|
||||
_CHAR_SORT // internal only
|
||||
_STRING_SORT // internal only
|
||||
};
|
||||
|
||||
enum seq_op_kind {
|
||||
|
@ -131,12 +131,13 @@ class seq_decl_plugin : public decl_plugin {
|
|||
ptr_vector<psig> m_sigs;
|
||||
bool m_init;
|
||||
symbol m_stringc_sym;
|
||||
symbol m_charc_sym;
|
||||
sort* m_string;
|
||||
sort* m_char;
|
||||
|
||||
void match(psig& sig, unsigned dsz, sort* const* dom, sort* range, sort_ref& rng);
|
||||
|
||||
void match_left_assoc(psig& sig, unsigned dsz, sort* const* dom, sort* range, sort_ref& rng);
|
||||
void match_right_assoc(psig& sig, unsigned dsz, sort* const* dom, sort* range, sort_ref& rng);
|
||||
|
||||
bool match(ptr_vector<sort>& binding, sort* s, sort* sP);
|
||||
|
||||
|
@ -187,6 +188,7 @@ public:
|
|||
|
||||
ast_manager& get_manager() const { return m; }
|
||||
|
||||
bool is_char(sort* s) const { return seq.is_char(s); }
|
||||
bool is_string(sort* s) const { return is_seq(s) && seq.is_char(s->get_parameter(0).get_ast()); }
|
||||
bool is_seq(sort* s) const { return is_sort_of(s, m_fid, SEQ_SORT); }
|
||||
bool is_re(sort* s) const { return is_sort_of(s, m_fid, RE_SORT); }
|
||||
|
@ -195,6 +197,7 @@ public:
|
|||
bool is_seq(sort* s, sort*& seq) { return is_seq(s) && (seq = to_sort(s->get_parameter(0).get_ast()), true); }
|
||||
bool is_re(expr* e) const { return is_re(m.get_sort(e)); }
|
||||
bool is_re(expr* e, sort*& seq) const { return is_re(m.get_sort(e), seq); }
|
||||
bool is_char(expr* e) const { return is_char(m.get_sort(e)); }
|
||||
|
||||
app* mk_skolem(symbol const& name, unsigned n, expr* const* args, sort* range);
|
||||
bool is_skolem(expr const* e) const { return is_app_of(e, m_fid, _OP_SEQ_SKOLEM); }
|
||||
|
@ -212,13 +215,13 @@ public:
|
|||
str(seq_util& u): u(u), m(u.m), m_fid(u.m_fid) {}
|
||||
|
||||
sort* mk_seq(sort* s) { parameter param(s); return m.mk_sort(m_fid, SEQ_SORT, 1, ¶m); }
|
||||
sort* mk_string_sort() { return m.mk_sort(m_fid, _STRING_SORT, 0, 0); }
|
||||
app* mk_empty(sort* s) { return m.mk_const(m.mk_func_decl(m_fid, OP_SEQ_EMPTY, 0, 0, 0, (expr*const*)0, s)); }
|
||||
app* mk_string(zstring const& s);
|
||||
app* mk_string(symbol const& s) { return u.seq.mk_string(s); }
|
||||
app* mk_char(char ch);
|
||||
app* mk_concat(expr* a, expr* b) { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_SEQ_CONCAT, 2, es); }
|
||||
app* mk_concat(expr* a, expr* b, expr* c) {
|
||||
return mk_concat(mk_concat(a, b), c);
|
||||
}
|
||||
app* mk_concat(expr* a, expr* b, expr* c) { return mk_concat(a, mk_concat(b, c)); }
|
||||
expr* mk_concat(unsigned n, expr* const* es) { if (n == 1) return es[0]; SASSERT(n > 1); return m.mk_app(m_fid, OP_SEQ_CONCAT, n, es); }
|
||||
app* mk_length(expr* a) { return m.mk_app(m_fid, OP_SEQ_LENGTH, 1, &a); }
|
||||
app* mk_substr(expr* a, expr* b, expr* c) { expr* es[3] = { a, b, c }; return m.mk_app(m_fid, OP_SEQ_EXTRACT, 3, es); }
|
||||
|
@ -229,8 +232,6 @@ public:
|
|||
app* mk_unit(expr* u) { return m.mk_app(m_fid, OP_SEQ_UNIT, 1, &u); }
|
||||
app* mk_char(zstring const& s, unsigned idx);
|
||||
|
||||
|
||||
|
||||
bool is_string(expr const * n) const { return is_app_of(n, m_fid, OP_STRING_CONST); }
|
||||
|
||||
bool is_string(expr const* n, symbol& s) const {
|
||||
|
@ -238,6 +239,7 @@ public:
|
|||
}
|
||||
|
||||
bool is_string(expr const* n, zstring& s) const;
|
||||
bool is_char(expr* n, zstring& s) const;
|
||||
|
||||
bool is_empty(expr const* n) const { symbol s;
|
||||
return is_app_of(n, m_fid, OP_SEQ_EMPTY) || (is_string(n, s) && !s.is_numerical() && *s.bare_str() == 0);
|
||||
|
@ -271,8 +273,9 @@ public:
|
|||
MATCH_BINARY(is_in_re);
|
||||
MATCH_UNARY(is_unit);
|
||||
|
||||
void get_concat(expr* e, ptr_vector<expr>& es) const;
|
||||
void get_concat(expr* e, expr_ref_vector& es) const;
|
||||
expr* get_leftmost_concat(expr* e) const { expr* e1, *e2; while (is_concat(e, e1, e2)) e = e1; return e; }
|
||||
expr* get_rightmost_concat(expr* e) const { expr* e1, *e2; while (is_concat(e, e1, e2)) e = e2; return e; }
|
||||
};
|
||||
|
||||
class re {
|
||||
|
@ -281,6 +284,8 @@ public:
|
|||
public:
|
||||
re(seq_util& u): m(u.m), m_fid(u.m_fid) {}
|
||||
|
||||
sort* mk_re(sort* seq) { parameter param(seq); return m.mk_sort(m_fid, RE_SORT, 1, ¶m); }
|
||||
|
||||
app* mk_to_re(expr* s) { return m.mk_app(m_fid, OP_SEQ_TO_RE, 1, &s); }
|
||||
app* mk_in_re(expr* s, expr* r) { return m.mk_app(m_fid, OP_SEQ_IN_RE, s, r); }
|
||||
app* mk_concat(expr* r1, expr* r2) { return m.mk_app(m_fid, OP_RE_CONCAT, r1, r2); }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue