3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-10-01 13:39:28 +00:00
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2015-12-10 19:20:16 -08:00
parent 30580a012a
commit 5eb23e1e7a
17 changed files with 287 additions and 141 deletions

View file

@ -74,7 +74,8 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
case OP_SEQ_INDEX:
if (num_args == 2) {
expr_ref arg3(m_autil.mk_int(0), m());
return mk_seq_index(args[0], args[1], arg3, result);
result = m_util.str.mk_index(args[0], args[1], arg3);
return BR_REWRITE1;
}
SASSERT(num_args == 3);
return mk_seq_index(args[0], args[1], args[2], result);
@ -202,19 +203,19 @@ br_status seq_rewriter::mk_seq_extract(expr* a, expr* b, expr* c, expr_ref& resu
br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) {
std::string c, d;
if (m_util.str.is_string(a, c) && m_util.str.is_string(b, d)) {
result = m().mk_bool_val(0 != strstr(d.c_str(), c.c_str()));
result = m().mk_bool_val(0 != strstr(c.c_str(), d.c_str()));
return BR_DONE;
}
// check if subsequence of a is in b.
// check if subsequence of b is in a.
ptr_vector<expr> as, bs;
m_util.str.get_concat(a, as);
m_util.str.get_concat(b, bs);
bool found = false;
for (unsigned i = 0; !found && i < bs.size(); ++i) {
if (as.size() > bs.size() - i) break;
for (unsigned i = 0; !found && i < as.size(); ++i) {
if (bs.size() > as.size() - i) break;
unsigned j = 0;
for (; j < as.size() && as[j] == bs[i+j]; ++j) {};
found = j == as.size();
for (; j < bs.size() && as[j] == bs[i+j]; ++j) {};
found = j == bs.size();
}
if (found) {
result = m().mk_true();
@ -260,7 +261,7 @@ br_status seq_rewriter::mk_seq_index(expr* a, expr* b, expr* c, expr_ref& result
return BR_DONE;
}
if (m_util.str.is_empty(b)) {
if (m_util.str.is_empty(b) && m_autil.is_numeral(c, r) && r.is_zero()) {
result = c;
return BR_DONE;
}
@ -380,6 +381,7 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) {
return BR_REWRITE3;
}
if (i > 0) {
SASSERT(i < as.size() && i < bs.size());
a = m_util.str.mk_concat(as.size() - i, as.c_ptr() + i);
b = m_util.str.mk_concat(bs.size() - i, bs.c_ptr() + i);
result = m_util.str.mk_prefix(a, b);
@ -657,54 +659,127 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve
}
bool is_sat;
if (!change) {
if (is_subsequence(m_lhs.size(), m_lhs.c_ptr(), m_rhs.size(), m_rhs.c_ptr(), lhs, rhs, is_sat)) {
return 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)) {
return is_sat;
}
if (is_subsequence(szl, ls, szr, rs, lhs, rhs, is_sat)) {
return is_sat;
}
if (szl == 0 && szr == 0) {
return true;
}
else if (!change) {
lhs.push_back(l);
rhs.push_back(r);
}
else if (head1 == m_lhs.size() && head2 == m_rhs.size()) {
// skip
}
else if (head1 == m_lhs.size()) {
return set_empty(m_rhs.size() - head2, m_rhs.c_ptr() + head2, lhs, rhs);
}
else if (head2 == m_rhs.size()) {
return set_empty(m_lhs.size() - head1, m_lhs.c_ptr() + head1, lhs, rhs);
}
else { // could solve if either side is fixed size.
SASSERT(head1 < m_lhs.size() && head2 < m_rhs.size());
if (is_subsequence(m_lhs.size() - head1, m_lhs.c_ptr() + head1,
m_rhs.size() - head2, m_rhs.c_ptr() + head2, lhs, rhs, is_sat)) {
return is_sat;
}
else {
// could solve if either side is fixed size.
SASSERT(szl > 0 && szr > 0);
lhs.push_back(m_util.str.mk_concat(m_lhs.size() - head1, m_lhs.c_ptr() + head1));
rhs.push_back(m_util.str.mk_concat(m_rhs.size() - head2, m_rhs.c_ptr() + head2));
lhs.push_back(m_util.str.mk_concat(szl, ls));
rhs.push_back(m_util.str.mk_concat(szr, rs));
}
return true;
}
bool seq_rewriter::set_empty(unsigned sz, expr* const* es, expr_ref_vector& lhs, expr_ref_vector& rhs) {
expr* seq_rewriter::concat_non_empty(unsigned n, expr* const* as) {
SASSERT(n > 0);
ptr_vector<expr> bs;
for (unsigned i = 0; i < n; ++i) {
if (m_util.str.is_unit(as[i]) ||
m_util.str.is_string(as[i])) {
bs.push_back(as[i]);
}
}
if (bs.empty()) {
return m_util.str.mk_empty(m().get_sort(as[0]));
}
else {
return m_util.str.mk_concat(bs.size(), bs.c_ptr());
}
}
bool seq_rewriter::set_empty(unsigned sz, expr* const* es, bool all, expr_ref_vector& lhs, expr_ref_vector& rhs) {
std::string s;
for (unsigned i = 0; i < sz; ++i) {
if (m_util.str.is_unit(es[i])) {
return false;
if (all) return false;
}
if (m_util.str.is_empty(es[i])) {
else if (m_util.str.is_empty(es[i])) {
continue;
}
if (m_util.str.is_string(es[i], s)) {
SASSERT(s.length() > 0);
return false;
else if (m_util.str.is_string(es[i], s)) {
if (all) {
SASSERT(s.length() > 0);
return false;
}
}
else {
lhs.push_back(m_util.str.mk_empty(m().get_sort(es[i])));
rhs.push_back(es[i]);
}
lhs.push_back(m_util.str.mk_empty(m().get_sort(es[i])));
rhs.push_back(es[i]);
}
return true;
}
bool seq_rewriter::min_length(unsigned n, expr* const* es, size_t& len) {
std::string s;
bool bounded = true;
len = 0;
for (unsigned i = 0; i < n; ++i) {
if (m_util.str.is_unit(es[i])) {
++len;
}
else if (m_util.str.is_empty(es[i])) {
continue;
}
else if (m_util.str.is_string(es[i], s)) {
len += s.length();
}
else {
bounded = false;
}
}
return bounded;
}
bool seq_rewriter::length_constrained(unsigned szl, expr* const* l, unsigned szr, expr* const* r,
expr_ref_vector& lhs, expr_ref_vector& rhs, bool& is_sat) {
is_sat = true;
size_t len1 = 0, len2 = 0;
bool bounded1 = min_length(szl, l, len1);
bool bounded2 = min_length(szr, r, len2);
if (bounded1 && len1 < len2) {
is_sat = false;
return true;
}
if (bounded2 && len2 < len1) {
is_sat = false;
return true;
}
if (bounded1 && len1 == len2 && len1 > 0) {
is_sat = set_empty(szr, r, false, lhs, rhs);
if (is_sat) {
lhs.push_back(concat_non_empty(szl, l));
rhs.push_back(concat_non_empty(szr, r));
}
return true;
}
if (bounded2 && len1 == len2 && len1 > 0) {
is_sat = set_empty(szl, l, false, lhs, rhs);
if (is_sat) {
lhs.push_back(concat_non_empty(szl, l));
rhs.push_back(concat_non_empty(szr, r));
}
return true;
}
return false;
}
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;
@ -733,13 +808,15 @@ bool seq_rewriter::is_subsequence(unsigned szl, expr* const* l, unsigned szr, ex
if (rpos.contains(j)) {
rs.push_back(r[j]);
}
else if (!set_empty(1, r + j, lhs, rhs)) {
else if (!set_empty(1, r + j, true, lhs, rhs)) {
is_sat = false;
return true;
}
}
SASSERT(szl == rs.size());
lhs.push_back(m_util.str.mk_concat(szl, l));
rhs.push_back(m_util.str.mk_concat(szl, rs.c_ptr()));
if (szl > 0) {
lhs.push_back(m_util.str.mk_concat(szl, l));
rhs.push_back(m_util.str.mk_concat(szl, rs.c_ptr()));
}
return true;
}

View file

@ -53,9 +53,14 @@ class seq_rewriter {
br_status mk_re_plus(expr* a, expr_ref& result);
br_status mk_re_opt(expr* a, expr_ref& result);
bool set_empty(unsigned sz, expr* const* es, expr_ref_vector& lhs, expr_ref_vector& rhs);
bool set_empty(unsigned sz, expr* const* es, bool all, expr_ref_vector& lhs, expr_ref_vector& rhs);
bool is_subsequence(unsigned n, expr* const* l, unsigned m, expr* const* r,
expr_ref_vector& lhs, expr_ref_vector& rhs, bool& is_sat);
bool length_constrained(unsigned n, expr* const* l, unsigned m, expr* const* r,
expr_ref_vector& lhs, expr_ref_vector& rhs, bool& is_sat);
bool min_length(unsigned n, expr* const* es, size_t& len);
expr* concat_non_empty(unsigned n, expr* const* es);
public:
seq_rewriter(ast_manager & m, params_ref const & p = params_ref()):
m_util(m), m_autil(m) {

View file

@ -289,6 +289,18 @@ func_decl* seq_decl_plugin::mk_str_fun(decl_kind k, unsigned arity, sort* const*
return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k_seq));
}
func_decl* seq_decl_plugin::mk_assoc_fun(decl_kind k, unsigned arity, sort* const* domain, sort* range, decl_kind k_seq, decl_kind k_string) {
ast_manager& m = *m_manager;
sort_ref rng(m);
if (arity == 0) {
m.raise_exception("Invalid function application. At least one argument expected");
}
match_left_assoc(*m_sigs[k], arity, domain, range, rng);
func_decl_info info(m_family_id, k_seq);
info.set_left_associative();
return m.mk_func_decl(m_sigs[(rng == m_string)?k_string:k_seq]->m_name, rng, rng, rng, info);
}
func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
init();
@ -308,18 +320,21 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
case OP_RE_STAR:
case OP_RE_OPTION:
case OP_RE_RANGE:
case OP_RE_UNION:
case OP_RE_EMPTY_SET:
case OP_RE_OF_PRED:
case OP_STRING_ITOS:
case OP_STRING_STOI:
case OP_REGEXP_LOOP:
match(*m_sigs[k], arity, domain, range, rng);
return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k));
case OP_RE_LOOP:
match(*m_sigs[k], arity, domain, range, rng);
if (num_parameters != 2 || !parameters[0].is_int() || !parameters[1].is_int()) {
m.raise_exception("Expecting two numeral parameters to function re-loop");
}
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");
@ -327,33 +342,17 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
return m.mk_const_decl(m_stringc_sym, m_string,
func_decl_info(m_family_id, OP_STRING_CONST, num_parameters, parameters));
case OP_SEQ_CONCAT: {
if (arity == 0) {
m.raise_exception("invalid concatenation. At least one argument expected");
}
match_left_assoc(*m_sigs[k], arity, domain, range, rng);
func_decl_info info(m_family_id, k);
info.set_left_associative();
return m.mk_func_decl(m_sigs[(rng == m_string)?_OP_STRING_CONCAT:k]->m_name, rng, rng, rng, info);
}
case OP_RE_CONCAT: {
if (arity == 0) {
m.raise_exception("invalid concatenation. At least one argument expected");
}
match_left_assoc(*m_sigs[k], arity, domain, range, rng);
func_decl_info info(m_family_id, k);
info.set_left_associative();
return m.mk_func_decl(m_sigs[k]->m_name, rng, rng, rng, info);
}
case _OP_STRING_CONCAT: {
if (arity == 0) {
m.raise_exception("invalid concatenation. At least one argument expected");
}
match_left_assoc(*m_sigs[k], arity, domain, range, rng);
func_decl_info info(m_family_id, OP_SEQ_CONCAT);
info.set_left_associative();
return m.mk_func_decl(m_sigs[k]->m_name, rng, rng, rng, info);
}
case OP_RE_UNION:
return mk_assoc_fun(k, arity, domain, range, k, k);
case OP_RE_CONCAT:
return mk_assoc_fun(k, arity, domain, range, k, k);
case OP_SEQ_CONCAT:
return mk_assoc_fun(k, arity, domain, range, k, _OP_STRING_CONCAT);
case _OP_STRING_CONCAT:
return mk_assoc_fun(k, arity, domain, range, OP_SEQ_CONCAT, k);
case OP_SEQ_REPLACE:
return mk_seq_fun(k, arity, domain, range, _OP_STRING_STRREPL);
@ -361,8 +360,20 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
return mk_str_fun(k, arity, domain, range, OP_SEQ_REPLACE);
case OP_SEQ_INDEX:
if (arity == 2) {
sort* dom[3] = { domain[0], domain[1], arith_util(m).mk_int() };
sort_ref rng(m);
match(*m_sigs[k], 3, dom, range, rng);
return m.mk_func_decl(m_sigs[(dom[0] == m_string)?_OP_STRING_STRIDOF:k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k));
}
return mk_seq_fun(k, arity, domain, range, _OP_STRING_STRIDOF);
case _OP_STRING_STRIDOF:
if (arity == 2) {
sort* dom[3] = { domain[0], domain[1], arith_util(m).mk_int() };
sort_ref rng(m);
match(*m_sigs[k], 3, dom, range, rng);
return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, OP_SEQ_INDEX));
}
return mk_str_fun(k, arity, domain, range, OP_SEQ_INDEX);
case OP_SEQ_PREFIX:
@ -405,14 +416,13 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
case _OP_STRING_SUBSTR:
return mk_str_fun(k, arity, domain, range, OP_SEQ_EXTRACT);
case OP_STRING_ITOS:
case OP_STRING_STOI:
case OP_REGEXP_LOOP:
match(*m_sigs[k], arity, domain, range, rng);
return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k));
case _OP_SEQ_SKOLEM:
return m.mk_func_decl(symbol("seq.skolem"), arity, domain, range, func_decl_info(m_family_id, k));
case _OP_SEQ_SKOLEM: {
if (num_parameters != 1 || !parameters[0].is_symbol()) {
m.raise_exception("one symbol parameter expected to skolem symbol");
}
symbol s = parameters[0].get_symbol();
return m.mk_func_decl(s, arity, domain, range, func_decl_info(m_family_id, k, num_parameters, parameters));
}
default:
UNREACHABLE();
return 0;

View file

@ -116,6 +116,7 @@ class seq_decl_plugin : public decl_plugin {
func_decl* mk_seq_fun(decl_kind k, unsigned arity, sort* const* domain, sort* range, decl_kind k_string);
func_decl* mk_str_fun(decl_kind k, unsigned arity, sort* const* domain, sort* range, decl_kind k_seq);
func_decl* mk_assoc_fun(decl_kind k, unsigned arity, sort* const* domain, sort* range, decl_kind k_string, decl_kind k_seq);
void init();
@ -158,8 +159,10 @@ public:
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); }
bool is_re(sort* s, sort*& seq) const { return is_sort_of(s, m_fid, RE_SORT) && (seq = to_sort(s->get_parameter(0).get_ast()), true); }
bool is_seq(expr* e) const { return is_seq(m.get_sort(e)); }
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); }
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); }
@ -186,6 +189,7 @@ public:
app* mk_contains(expr* a, expr* b) { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_SEQ_CONTAINS, 2, es); }
app* mk_prefix(expr* a, expr* b) { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_SEQ_PREFIX, 2, es); }
app* mk_suffix(expr* a, expr* b) { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_SEQ_SUFFIX, 2, es); }
app* mk_index(expr* a, expr* b, expr* i) { expr* es[3] = { a, b, i}; return m.mk_app(m_fid, OP_SEQ_INDEX, 3, es); }
bool is_string(expr const * n) const { return is_app_of(n, m_fid, OP_STRING_CONST); }
@ -239,6 +243,15 @@ public:
public:
re(seq_util& u): m(u.m), m_fid(u.m_fid) {}
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); }
app* mk_union(expr* r1, expr* r2) { return m.mk_app(m_fid, OP_RE_UNION, r1, r2); }
app* mk_inter(expr* r1, expr* r2) { return m.mk_app(m_fid, OP_RE_INTERSECT, r1, r2); }
app* mk_star(expr* r) { return m.mk_app(m_fid, OP_RE_STAR, r); }
app* mk_plus(expr* r) { return m.mk_app(m_fid, OP_RE_PLUS, r); }
app* mk_opt(expr* r) { return m.mk_app(m_fid, OP_RE_OPTION, r); }
bool is_to_re(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_TO_RE); }
bool is_concat(expr const* n) const { return is_app_of(n, m_fid, OP_RE_CONCAT); }
bool is_union(expr const* n) const { return is_app_of(n, m_fid, OP_RE_UNION); }