mirror of
https://github.com/Z3Prover/z3
synced 2025-08-19 17:50:23 +00:00
parent
7bc3b4e381
commit
f591e0948a
8 changed files with 209 additions and 210 deletions
|
@ -231,6 +231,11 @@ public:
|
|||
|
||||
bool is_arith_expr(expr const * n) const { return is_app(n) && to_app(n)->get_family_id() == m_afid; }
|
||||
bool is_irrational_algebraic_numeral(expr const * n) const;
|
||||
bool is_unsigned(expr const * n, unsigned& u) const {
|
||||
rational val;
|
||||
bool is_int = true;
|
||||
return is_numeral(n, val, is_int) && is_int && val.is_unsigned(), u = val.get_unsigned(), true;
|
||||
}
|
||||
bool is_numeral(expr const * n, rational & val, bool & is_int) const;
|
||||
bool is_numeral(expr const * n, rational & val) const { bool is_int; return is_numeral(n, val, is_int); }
|
||||
bool is_numeral(expr const * n) const { return is_app_of(n, m_afid, OP_NUM); }
|
||||
|
|
|
@ -738,7 +738,6 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) {
|
|||
return BR_REWRITE2;
|
||||
}
|
||||
|
||||
|
||||
std::function<bool(expr*)> is_unit = [&](expr *e) { return m_util.str.is_unit(e); };
|
||||
|
||||
if (bs.forall(is_unit) && as.forall(is_unit)) {
|
||||
|
@ -754,6 +753,16 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) {
|
|||
return BR_REWRITE_FULL;
|
||||
}
|
||||
|
||||
if (bs.size() == 1 && bs.forall(is_unit) && as.size() > 1) {
|
||||
expr_ref_vector ors(m());
|
||||
for (expr* ai : as) {
|
||||
ors.push_back(m_util.str.mk_contains(ai, bs.get(0)));
|
||||
}
|
||||
result = ::mk_or(ors);
|
||||
return BR_REWRITE_FULL;
|
||||
}
|
||||
|
||||
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
|
@ -1575,6 +1584,34 @@ br_status seq_rewriter::mk_eq_core(expr * l, expr * r, expr_ref & result) {
|
|||
return BR_REWRITE3;
|
||||
}
|
||||
|
||||
/**
|
||||
* t = (concat (unit (nth t 0)) (unit (nth t 1)) (unit (nth t 2)) .. (unit (nth t k-1)))
|
||||
* ->
|
||||
* (length t) = k
|
||||
*/
|
||||
bool seq_rewriter::reduce_nth_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_vector& lhs, expr_ref_vector& rhs) {
|
||||
if (ls.size() == 1 && !rs.empty()) {
|
||||
expr* l = ls.get(0);
|
||||
for (unsigned i = 0; i < rs.size(); ++i) {
|
||||
unsigned k = 0;
|
||||
expr* ru = nullptr, *r = nullptr;
|
||||
if (m_util.str.is_unit(rs.get(i), ru) && m_util.str.is_nth(ru, r, k) && k == i && r == l) {
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
arith_util a(m());
|
||||
lhs.push_back(m_util.str.mk_length(l));
|
||||
rhs.push_back(a.mk_int(rs.size()));
|
||||
ls.reset();
|
||||
rs.reset();
|
||||
return true;
|
||||
}
|
||||
else if (rs.size() == 1 && !ls.empty()) {
|
||||
return reduce_nth_eq(rs, ls, rhs, lhs);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool seq_rewriter::reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_vector& lhs, expr_ref_vector& rhs, bool& change) {
|
||||
expr* a, *b;
|
||||
|
@ -1582,6 +1619,10 @@ bool seq_rewriter::reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_
|
|||
bool lchange = false;
|
||||
SASSERT(lhs.empty());
|
||||
TRACE("seq", tout << ls << "\n"; tout << rs << "\n";);
|
||||
if (reduce_nth_eq(ls, rs, lhs, rhs)) {
|
||||
change = true;
|
||||
return true;
|
||||
}
|
||||
// solve from back
|
||||
while (true) {
|
||||
while (!rs.empty() && m_util.str.is_empty(rs.back())) {
|
||||
|
|
|
@ -170,6 +170,8 @@ public:
|
|||
|
||||
bool reduce_contains(expr* a, expr* b, expr_ref_vector& disj);
|
||||
|
||||
bool reduce_nth_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_vector& lhs, expr_ref_vector& rhs);
|
||||
|
||||
void add_seqs(expr_ref_vector const& ls, expr_ref_vector const& rs, expr_ref_vector& lhs, expr_ref_vector& rhs);
|
||||
|
||||
|
||||
|
|
|
@ -537,6 +537,7 @@ void seq_decl_plugin::init() {
|
|||
m_sigs[OP_SEQ_REPLACE] = alloc(psig, m, "seq.replace", 1, 3, seq3A, seqA);
|
||||
m_sigs[OP_SEQ_INDEX] = alloc(psig, m, "seq.indexof", 1, 3, seq2AintT, intT);
|
||||
m_sigs[OP_SEQ_AT] = alloc(psig, m, "seq.at", 1, 2, seqAintT, seqA);
|
||||
m_sigs[OP_SEQ_NTH] = alloc(psig, m, "seq.nth", 1, 2, seqAintT, A);
|
||||
m_sigs[OP_SEQ_LENGTH] = alloc(psig, m, "seq.len", 1, 1, &seqA, intT);
|
||||
m_sigs[OP_RE_PLUS] = alloc(psig, m, "re.+", 1, 1, &reA, reA);
|
||||
m_sigs[OP_RE_STAR] = alloc(psig, m, "re.*", 1, 1, &reA, reA);
|
||||
|
@ -805,6 +806,10 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
|
|||
case _OP_STRING_CHARAT:
|
||||
return mk_str_fun(k, arity, domain, range, OP_SEQ_AT);
|
||||
|
||||
case OP_SEQ_NTH:
|
||||
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_EXTRACT:
|
||||
return mk_seq_fun(k, arity, domain, range, _OP_STRING_SUBSTR);
|
||||
case _OP_STRING_SUBSTR:
|
||||
|
@ -957,6 +962,16 @@ bool seq_util::str::is_string(expr const* n, zstring& s) const {
|
|||
}
|
||||
}
|
||||
|
||||
bool seq_util::str::is_nth(expr const* n, expr*& s, unsigned& idx) const {
|
||||
expr* i = nullptr;
|
||||
if (!is_nth(n, s, i)) return false;
|
||||
return arith_util(m).is_unsigned(i, idx);
|
||||
}
|
||||
|
||||
app* seq_util::str::mk_nth(expr* s, unsigned i) const {
|
||||
return mk_nth(s, arith_util(m).mk_int(i));
|
||||
}
|
||||
|
||||
|
||||
void seq_util::str::get_concat(expr* e, expr_ref_vector& es) const {
|
||||
expr* e1, *e2;
|
||||
|
|
|
@ -41,6 +41,7 @@ enum seq_op_kind {
|
|||
OP_SEQ_EXTRACT,
|
||||
OP_SEQ_REPLACE,
|
||||
OP_SEQ_AT,
|
||||
OP_SEQ_NTH,
|
||||
OP_SEQ_LENGTH,
|
||||
OP_SEQ_INDEX,
|
||||
OP_SEQ_TO_RE,
|
||||
|
@ -243,6 +244,9 @@ public:
|
|||
expr* mk_concat(unsigned n, expr* const* es) const { if (n == 1) return es[0]; SASSERT(n > 1); return m.mk_app(m_fid, OP_SEQ_CONCAT, n, es); }
|
||||
expr* mk_concat(expr_ref_vector const& es) const { return mk_concat(es.size(), es.c_ptr()); }
|
||||
app* mk_length(expr* a) const { return m.mk_app(m_fid, OP_SEQ_LENGTH, 1, &a); }
|
||||
app* mk_nth(expr* s, expr* i) const { expr* es[2] = { s, i }; return m.mk_app(m_fid, OP_SEQ_NTH, 2, es); }
|
||||
app* mk_nth(expr* s, unsigned i) const;
|
||||
|
||||
app* mk_substr(expr* a, expr* b, expr* c) const { expr* es[3] = { a, b, c }; return m.mk_app(m_fid, OP_SEQ_EXTRACT, 3, es); }
|
||||
app* mk_contains(expr* a, expr* b) const { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_SEQ_CONTAINS, 2, es); }
|
||||
app* mk_prefix(expr* a, expr* b) const { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_SEQ_PREFIX, 2, es); }
|
||||
|
@ -270,6 +274,8 @@ public:
|
|||
bool is_extract(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_EXTRACT); }
|
||||
bool is_contains(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_CONTAINS); }
|
||||
bool is_at(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_AT); }
|
||||
bool is_nth(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_NTH); }
|
||||
bool is_nth(expr const* n, expr*& s, unsigned& idx) const;
|
||||
bool is_index(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_INDEX); }
|
||||
bool is_replace(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_REPLACE); }
|
||||
bool is_prefix(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_PREFIX); }
|
||||
|
@ -294,6 +300,7 @@ public:
|
|||
MATCH_TERNARY(is_extract);
|
||||
MATCH_BINARY(is_contains);
|
||||
MATCH_BINARY(is_at);
|
||||
MATCH_BINARY(is_nth);
|
||||
MATCH_BINARY(is_index);
|
||||
MATCH_TERNARY(is_index);
|
||||
MATCH_TERNARY(is_replace);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue