diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 7342e6a41..8cdf0091e 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -2210,13 +2210,21 @@ br_status seq_rewriter::mk_eq_core(expr * l, expr * r, expr_ref & result) { return BR_REWRITE3; } -void seq_rewriter::remove_empty(expr_ref_vector& es) { +void seq_rewriter::remove_empty_and_concats(expr_ref_vector& es) { unsigned j = 0; + bool has_concat = false; for (expr* e : es) { + has_concat |= m_util.str.is_concat(e); if (!m_util.str.is_empty(e)) es[j++] = e; } es.shrink(j); + if (has_concat) { + expr_ref_vector fs(m()); + for (expr* e : es) + m_util.str.get_concat(e, fs); + es.swap(fs); + } } void seq_rewriter::remove_leading(unsigned n, expr_ref_vector& es) { @@ -2229,7 +2237,7 @@ void seq_rewriter::remove_leading(unsigned n, expr_ref_vector& es) { es.shrink(es.size() - n); } -bool seq_rewriter::reduce_back(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& new_eqs, bool& change) { +bool seq_rewriter::reduce_back(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& new_eqs) { expr* a, *b; zstring s, s1, s2; while (true) { @@ -2237,7 +2245,7 @@ bool seq_rewriter::reduce_back(expr_ref_vector& ls, expr_ref_vector& rs, expr_re break; } expr* l = ls.back(); - expr* r = rs.back(); + expr* r = rs.back(); if (m_util.str.is_unit(r) && m_util.str.is_string(l)) { std::swap(l, r); ls.swap(rs); @@ -2289,12 +2297,11 @@ bool seq_rewriter::reduce_back(expr_ref_vector& ls, expr_ref_vector& rs, expr_re else { break; } - change = true; } return true; } -bool seq_rewriter::reduce_front(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& new_eqs, bool& change) { +bool seq_rewriter::reduce_front(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& new_eqs) { expr* a, *b; zstring s, s1, s2; unsigned head1 = 0, head2 = 0; @@ -2364,7 +2371,6 @@ bool seq_rewriter::reduce_front(expr_ref_vector& ls, expr_ref_vector& rs, expr_r else { break; } - change = true; } remove_leading(head1, ls); remove_leading(head2, rs); @@ -2376,17 +2382,24 @@ bool seq_rewriter::reduce_front(expr_ref_vector& ls, expr_ref_vector& rs, expr_r - New equalities are inserted into eqs. - Last remaining equalities that cannot be simplified further are kept in ls, rs - returns false if equality is unsatisfiable + - sets change to true if some simplification occurred */ bool seq_rewriter::reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& eqs, bool& change) { TRACE("seq_verbose", tout << ls << "\n"; tout << rs << "\n";); - remove_empty(ls); - remove_empty(rs); + unsigned hash_l = ls.hash(); + unsigned hash_r = rs.hash(); + unsigned sz_eqs = eqs.size(); + remove_empty_and_concats(ls); + remove_empty_and_concats(rs); return - reduce_back(ls, rs, eqs, change) && - reduce_front(ls, rs, eqs, change) && - reduce_itos(ls, rs, eqs, change) && - reduce_by_length(ls, rs, eqs, change) && - reduce_subsequence(ls, rs, eqs, change); + reduce_back(ls, rs, eqs) && + reduce_front(ls, rs, eqs) && + reduce_itos(ls, rs, eqs) && + reduce_itos(rs, ls, eqs) && + reduce_by_length(ls, rs, eqs) && + reduce_subsequence(ls, rs, eqs) && + (change = (hash_l != ls.hash() || hash_r != rs.hash() || eqs.size() != sz_eqs), + true); } bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_pair_vector& new_eqs, bool& changed) { @@ -2552,41 +2565,31 @@ bool seq_rewriter::is_string(unsigned n, expr* const* es, zstring& s) const { return true; } -bool seq_rewriter::reduce_itos(expr_ref_vector& ls, expr_ref_vector& rs, - expr_ref_pair_vector& eqs, bool& change) { - expr* n = nullptr; - if (ls.size() == 1 && m_util.str.is_itos(ls.get(0), n) && - solve_itos(n, rs, eqs)) { - ls.reset(); rs.reset(); - change = true; - } - else if (rs.size() == 1 && m_util.str.is_itos(rs.get(0), n) && - solve_itos(n, ls, eqs)) { - ls.reset(); rs.reset(); - change = true; - } - return true; -} - /** * itos(n) = -> n = numeric */ -bool seq_rewriter::solve_itos(expr* n, expr_ref_vector const& es, expr_ref_pair_vector& eqs) { +bool seq_rewriter::reduce_itos(expr_ref_vector& ls, expr_ref_vector& rs, + expr_ref_pair_vector& eqs) { + expr* n = nullptr; zstring s; - if (is_string(es.size(), es.c_ptr(), s)) { + if (ls.size() == 1 && + m_util.str.is_itos(ls.get(0), n) && + is_string(rs.size(), rs.c_ptr(), s)) { std::string s1 = s.encode(); rational r(s1.c_str()); if (s1 == r.to_string()) { eqs.push_back(n, m_autil.mk_numeral(r, true)); + ls.reset(); + rs.reset(); return true; } - } - return false; + } + return true; } bool seq_rewriter::reduce_by_length(expr_ref_vector& ls, expr_ref_vector& rs, - expr_ref_pair_vector& eqs, bool& change) { + expr_ref_pair_vector& eqs) { if (ls.empty() && rs.empty()) return true; @@ -2599,7 +2602,6 @@ bool seq_rewriter::reduce_by_length(expr_ref_vector& ls, expr_ref_vector& rs, if (bounded2 && len2 < len1) return false; if (bounded1 && len1 == len2 && len1 > 0) { - change = true; if (!set_empty(rs.size(), rs.c_ptr(), false, eqs)) return false; eqs.push_back(concat_non_empty(ls), concat_non_empty(rs)); @@ -2607,7 +2609,6 @@ bool seq_rewriter::reduce_by_length(expr_ref_vector& ls, expr_ref_vector& rs, rs.reset(); } else if (bounded2 && len1 == len2 && len1 > 0) { - change = true; if (!set_empty(ls.size(), ls.c_ptr(), false, eqs)) return false; eqs.push_back(concat_non_empty(ls), concat_non_empty(rs)); @@ -2623,7 +2624,7 @@ bool seq_rewriter::is_epsilon(expr* e) const { return m_util.re.is_to_re(e, e1) && m_util.str.is_empty(e1); } -bool seq_rewriter::reduce_subsequence(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& eqs, bool& change) { +bool seq_rewriter::reduce_subsequence(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& eqs) { if (ls.size() > rs.size()) ls.swap(rs); @@ -2663,7 +2664,6 @@ bool seq_rewriter::reduce_subsequence(expr_ref_vector& ls, expr_ref_vector& rs, if (j == rs.size()) { return true; } - change = true; rs.shrink(j); SASSERT(ls.size() == rs.size()); if (!ls.empty()) { diff --git a/src/ast/rewriter/seq_rewriter.h b/src/ast/rewriter/seq_rewriter.h index 2e8b275d6..eaa788458 100644 --- a/src/ast/rewriter/seq_rewriter.h +++ b/src/ast/rewriter/seq_rewriter.h @@ -174,10 +174,9 @@ class seq_rewriter { bool sign_is_determined(expr* len, sign& s); bool set_empty(unsigned sz, expr* const* es, bool all, expr_ref_pair_vector& eqs); - bool reduce_subsequence(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& eqs, bool& change); - bool reduce_by_length(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& eqs, bool& change); - bool reduce_itos(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& eqs, bool& change); - bool solve_itos(expr* n, expr_ref_vector const& es, expr_ref_pair_vector& eqs); + bool reduce_subsequence(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& eqs); + bool reduce_by_length(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& eqs); + bool reduce_itos(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& eqs); bool min_length(expr_ref_vector const& es, unsigned& len); expr* concat_non_empty(expr_ref_vector& es); @@ -188,9 +187,9 @@ class seq_rewriter { bool is_sequence(eautomaton& aut, expr_ref_vector& seq); bool is_epsilon(expr* e) const; bool get_lengths(expr* e, expr_ref_vector& lens, rational& pos); - bool reduce_back(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& new_eqs, bool& change); - bool reduce_front(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& new_eqs, bool& change); - void remove_empty(expr_ref_vector& es); + bool reduce_back(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& new_eqs); + bool reduce_front(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_pair_vector& new_eqs); + void remove_empty_and_concats(expr_ref_vector& es); void remove_leading(unsigned n, expr_ref_vector& es); public: diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 123033089..ae55f38de 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2288,7 +2288,6 @@ void theory_seq::validate_fmls(enode_pair_vector const& eqs, literal_vector cons for (expr* f : fmls) { k.assert_expr(f); } - IF_VERBOSE(0, verbose_stream() << "validate: " << fmls << "\n";); lbool r = k.check(); if (r != l_false && !m.limit().get_cancel_flag()) { model_ref mdl; diff --git a/src/util/ref_vector.h b/src/util/ref_vector.h index 0c1c3594d..5b5d9ac34 100644 --- a/src/util/ref_vector.h +++ b/src/util/ref_vector.h @@ -41,6 +41,11 @@ protected: dec_ref(*it); } + struct hash_proc { + unsigned operator()(ref_vector_core const* v, unsigned idx) const { + return (*v)[idx]->get_id(); + } + }; public: typedef T * data; @@ -129,6 +134,14 @@ public: T ** c_ptr() { return m_nodes.begin(); } + unsigned hash() const { + unsigned sz = size(); + if (sz == 0) { + return 0; + } + return get_composite_hash(this, sz, default_kind_hash_proc(), hash_proc()); + } + iterator begin() const { return m_nodes.begin(); } iterator end() const { return begin() + size(); } @@ -400,21 +413,8 @@ struct ref_vector_ptr_hash { typedef ref_vector RefV; - struct hash_proc { - unsigned operator()(RefV* v, unsigned idx) const { - return (*v)[idx]->get_id(); - } - }; - unsigned operator()(RefV* v) const { - if (!v) { - return 0; - } - unsigned sz = v->size(); - if (sz == 0) { - return 0; - } - return get_composite_hash(v, sz, default_kind_hash_proc(), hash_proc()); + return v ? v->hash() : 0; } };