From 67958efed25de9e39e3e2919331cbb289dd023d6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 17 Feb 2016 21:20:39 -0800 Subject: [PATCH] add fixed length heuristic Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 55 ++++++++++++++++++++++++++++++++++++++++++ src/smt/theory_seq.h | 16 ++++++++++++ 2 files changed, 71 insertions(+) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index e11ca806a..11bf2b678 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(); + bool found = false; + for (; it != end; ++it) { + if (fixed_length(*it)) { + found = true; + } + } + return found; +} + +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 (is_skolem(m_tail, e) || is_skolem(m_seq_first, e) || + is_skolem(m_indexof_left, e) || is_skolem(m_indexof_right, e) || + is_skolem(m_contains_left, e) || is_skolem(m_contains_right, e) || + m_fixed.contains(e)) { + return false; + } + + context& ctx = get_context(); + + m_trail_stack.push(insert_obj_trail(m_fixed, e)); + m_fixed.insert(e); + + + 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()); + 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();