mirror of
https://github.com/Z3Prover/z3
synced 2025-07-29 07:27:57 +00:00
seq
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
24de0a9b90
commit
94bd2fdbe4
7 changed files with 285 additions and 78 deletions
|
@ -636,7 +636,12 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve
|
|||
}
|
||||
change = true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
lhs.push_back(l);
|
||||
rhs.push_back(r);
|
||||
}
|
||||
|
@ -649,7 +654,13 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve
|
|||
else if (head2 == m_rhs.size()) {
|
||||
return set_empty(m_lhs.size() - head1, m_lhs.c_ptr() + head1, lhs, rhs);
|
||||
}
|
||||
else { // head1 < m_lhs.size() && head2 < m_rhs.size() // could solve if either side is fixed size.
|
||||
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;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
@ -674,3 +685,39 @@ bool seq_rewriter::set_empty(unsigned sz, expr* const* es, expr_ref_vector& lhs,
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
if (szl == szr) return false;
|
||||
if (szr < szl) {
|
||||
std::swap(szl, szr);
|
||||
std::swap(l, r);
|
||||
}
|
||||
|
||||
for (unsigned i = 1; i + szl <= szr; ++i) {
|
||||
bool eq = true;
|
||||
for (unsigned j = 0; eq && j < szl; ++j) {
|
||||
eq = l[j] == r[i+j];
|
||||
}
|
||||
if (eq) {
|
||||
SASSERT(szr >= i + szl);
|
||||
is_sat = set_empty(i, r, lhs, rhs);
|
||||
is_sat &= set_empty(szr - (i + szl), r + i + szl, lhs, rhs);
|
||||
|
||||
TRACE("seq",
|
||||
for (unsigned k = 0; k < szl; ++k) {
|
||||
tout << mk_pp(l[k], m()) << " ";
|
||||
}
|
||||
tout << "\n";
|
||||
for (unsigned k = 0; k < szr; ++k) {
|
||||
tout << mk_pp(r[k], m()) << " ";
|
||||
}
|
||||
tout << "\n";
|
||||
tout << lhs << "; " << rhs << "\n";);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -54,6 +54,8 @@ class seq_rewriter {
|
|||
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 is_subsequence(unsigned n, expr* const* l, unsigned m, expr* const* r,
|
||||
expr_ref_vector& lhs, expr_ref_vector& rhs, bool& is_sat);
|
||||
public:
|
||||
seq_rewriter(ast_manager & m, params_ref const & p = params_ref()):
|
||||
m_util(m), m_autil(m) {
|
||||
|
|
|
@ -47,7 +47,7 @@ bool seq_decl_plugin::match(ptr_vector<sort>& binding, sort* s, sort* sP) {
|
|||
if (is_sort_param(sP, i)) {
|
||||
if (binding.size() <= i) binding.resize(i+1);
|
||||
if (binding[i] && (binding[i] != s)) return false;
|
||||
TRACE("seq", tout << "setting binding @ " << i << " to " << mk_pp(s, m) << "\n";);
|
||||
TRACE("seq_verbose", tout << "setting binding @ " << i << " to " << mk_pp(s, m) << "\n";);
|
||||
binding[i] = s;
|
||||
return true;
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ bool seq_decl_plugin::match(ptr_vector<sort>& binding, sort* s, sort* sP) {
|
|||
void seq_decl_plugin::match_left_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",
|
||||
TRACE("seq_verbose",
|
||||
tout << sig.m_name << ": ";
|
||||
for (unsigned i = 0; i < dsz; ++i) tout << mk_pp(dom[i], m) << " ";
|
||||
if (range) tout << " range: " << mk_pp(range, m);
|
||||
|
@ -102,7 +102,7 @@ void seq_decl_plugin::match_left_assoc(psig& sig, unsigned dsz, sort *const* dom
|
|||
m.raise_exception(strm.str().c_str());
|
||||
}
|
||||
range_out = apply_binding(binding, sig.m_range);
|
||||
TRACE("seq", tout << mk_pp(range_out, m) << "\n";);
|
||||
TRACE("seq_verbose", tout << mk_pp(range_out, m) << "\n";);
|
||||
}
|
||||
|
||||
void seq_decl_plugin::match(psig& sig, unsigned dsz, sort *const* dom, sort* range, sort_ref& range_out) {
|
||||
|
@ -321,18 +321,27 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
|
|||
func_decl_info(m_family_id, OP_STRING_CONST, num_parameters, parameters));
|
||||
|
||||
case OP_SEQ_CONCAT: {
|
||||
if (arity < 2) {
|
||||
m.raise_exception("invalid concatenation. At least two arguments 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 < 2) {
|
||||
m.raise_exception("invalid concatenation. At least two arguments 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 < 2) {
|
||||
m.raise_exception("invalid string concatenation. At least two arguments 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();
|
||||
|
@ -386,6 +395,8 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
|
|||
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, rng, func_decl_info(m_family_id, k));
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
|
@ -419,6 +430,13 @@ bool seq_decl_plugin::is_value(app* e) const {
|
|||
return is_app_of(e, m_family_id, OP_STRING_CONST);
|
||||
}
|
||||
|
||||
app* seq_util::mk_skolem(symbol const& name, unsigned n, expr* const* args, sort* range) {
|
||||
parameter param(name);
|
||||
func_decl* f = m.mk_func_decl(get_family_id(), _OP_SEQ_SKOLEM, 1, ¶m, n, args, range);
|
||||
return m.mk_app(f, n, args);
|
||||
}
|
||||
|
||||
|
||||
app* seq_util::str::mk_string(symbol const& s) {
|
||||
return u.seq.mk_string(s);
|
||||
}
|
||||
|
|
|
@ -74,6 +74,7 @@ enum seq_op_kind {
|
|||
_OP_STRING_TO_REGEXP,
|
||||
_OP_STRING_CHARAT,
|
||||
_OP_STRING_SUBSTR,
|
||||
_OP_SEQ_SKOLEM,
|
||||
LAST_SEQ_OP
|
||||
};
|
||||
|
||||
|
@ -155,6 +156,11 @@ 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_seq(expr* e) const { return is_seq(m.get_sort(e)); }
|
||||
bool is_re(expr* e) const { return is_re(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); }
|
||||
|
||||
class str {
|
||||
seq_util& u;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue