diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index fc0e5a807..29b892029 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -320,6 +320,17 @@ br_status bv_rewriter::mk_leq_core(bool is_signed, expr * a, expr * b, expr_ref } } + expr* a1, *a2, *a3, *a4, *a5, *a6; + // (bvsle (- x (rem x c1)) c2) -> (bvsle x (+ c1 c2 - 1)) + if (is_signed && is_num2 && m_util.is_bv_add(a, a1, a2) && + m_util.is_bv_mul(a2, a3, a4) && is_numeral(a3, r3, sz) && + (r3 = m_util.norm(r3, sz, is_signed), r3.is_minus_one()) && + m_util.is_bv_sremi(a4, a5, a6) && is_numeral(a6, r3, sz) && + a1 == a5 /* && r1 + r3 - rational::one() < power(rational(2), sz) */) { + result = m_util.mk_sle(a1, m_util.mk_numeral(r3 + r1 - rational::one(), sz)); + return BR_REWRITE2; + } + #if 0 if (!is_signed && m_util.is_concat(b) && to_app(b)->get_num_args() == 2 && m_util.is_zero(to_app(b)->get_arg(0))) { // diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index e11ca806a..2fab37969 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -233,6 +233,11 @@ final_check_status theory_seq::final_check_eh() { TRACE("seq", tout << ">>solve_nqs\n";); return FC_CONTINUE; } + if (fixed_length()) { + ++m_stats.m_fixed_length; + TRACE("seq", tout << ">>fixed_length\n";); + return FC_CONTINUE; + } if (branch_variable()) { ++m_stats.m_branch_variable; TRACE("seq", tout << ">>branch_variable\n";); @@ -430,6 +435,7 @@ lbool theory_seq::assume_equality(expr* l, expr* r) { return l_undef; } + bool theory_seq::propagate_length_coherence(expr* e) { expr_ref head(m), tail(m); rational lo, hi; @@ -509,6 +515,54 @@ bool theory_seq::check_length_coherence() { return false; } +bool theory_seq::fixed_length() { + obj_hashtable::iterator it = m_length.begin(), end = m_length.end(); + for (; it != end; ++it) { + if (fixed_length(*it)) { + return true; + } + } + return false; +} + +bool theory_seq::fixed_length(expr* e) { + rational lo, hi; + if (!(is_var(e) && lower_bound(e, lo) && upper_bound(e, hi) && lo == hi && lo.is_unsigned() && lo.is_pos())) { + return false; + } + if (m_fixed.contains(e)) { + return false; + } + + context& ctx = get_context(); + + m_trail_stack.push(insert_obj_trail(m_fixed, e)); + m_fixed.insert(e); + + if (is_skolem(m_tail, e) || is_skolem(m_pre, e) || is_skolem(m_post, e) || is_skolem(m_seq_first, e)) { + return false; + } + + unsigned _lo = lo.get_unsigned(); + expr_ref seq(e, m), head(m), tail(m); + expr_ref_vector elems(m); + + for (unsigned j = 0; j < _lo; ++j) { + mk_decompose(seq, head, tail); + elems.push_back(head); + seq = tail; + } + seq = mk_concat(elems.size(), elems.c_ptr()); + std::cout << "Fixed " << mk_pp(e, m) << " " << lo << " " << get_context().get_scope_level() << "\n"; + TRACE("seq", tout << "Fixed: " << mk_pp(e, m) << " " << lo << "\n";); + add_axiom(~mk_eq(m_util.str.mk_length(e), m_autil.mk_numeral(lo, true), false), mk_seq_eq(seq, e)); + if (!ctx.at_base_level()) { + m_trail_stack.push(push_replay(alloc(replay_fixed_length, m, e))); + } + return true; +} + + /* lit => s != "" */ @@ -1778,6 +1832,7 @@ void theory_seq::collect_statistics(::statistics & st) const { st.update("seq solve =", m_stats.m_solve_eqs); st.update("seq add axiom", m_stats.m_add_axiom); st.update("seq extensionality", m_stats.m_extensionality); + st.update("seq fixed length", m_stats.m_fixed_length); } void theory_seq::init_model(expr_ref_vector const& es) { diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index a28458e02..3aedac835 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -208,6 +208,17 @@ namespace smt { } }; + class replay_fixed_length : public apply { + expr_ref m_e; + public: + replay_fixed_length(ast_manager& m, expr* e) : m_e(e, m) {} + virtual ~replay_fixed_length() {} + virtual void operator()(theory_seq& th) { + th.fixed_length(m_e); + m_e.reset(); + } + }; + class replay_axiom : public apply { expr_ref m_e; public: @@ -251,6 +262,7 @@ namespace smt { unsigned m_solve_eqs; unsigned m_add_axiom; unsigned m_extensionality; + unsigned m_fixed_length; }; ast_manager& m; dependency_manager m_dm; @@ -292,6 +304,8 @@ namespace smt { bool m_new_propagation; // new propagation to core re2automaton m_mk_aut; + obj_hashtable m_fixed; // string variables that are fixed length. + virtual final_check_status final_check_eh(); virtual bool internalize_atom(app* atom, bool) { return internalize_term(atom); } virtual bool internalize_term(app*); @@ -322,6 +336,8 @@ namespace smt { bool is_solved(); bool check_length_coherence(); bool check_length_coherence(expr* e); + bool fixed_length(); + bool fixed_length(expr* e); bool propagate_length_coherence(expr* e); bool check_extensionality();