diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 33f70c98d..fc0d3b5e0 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -71,6 +71,7 @@ VERBOSE=True DEBUG_MODE=False SHOW_CPPS = True VS_X64 = False +VS_ARM = False LINUX_X64 = True ONLY_MAKEFILES = False Z3PY_SRC_DIR=None @@ -99,6 +100,7 @@ USE_OMP=True FPMATH="Default" FPMATH_FLAGS="-mfpmath=sse -msse -msse2" + def check_output(cmd): out = subprocess.Popen(cmd, stdout=subprocess.PIPE).communicate()[0] if out != None: @@ -1557,6 +1559,8 @@ class DotNetDLLComponent(Component): if IS_WINDOWS: if VS_X64: cscCmdLine.extend(['/platform:x64']) + elif VS_ARM: + cscCmdLine.extend(['/platform:arm']) else: cscCmdLine.extend(['/platform:x86']) else: @@ -1997,6 +2001,8 @@ class DotNetExampleComponent(ExampleComponent): out.write('\t%s /out:%s /reference:%s /debug:full /reference:System.Numerics.dll' % (CSC, exefile, dll)) if VS_X64: out.write(' /platform:x64') + elif VS_ARM: + out.write(' /platform:arm') else: out.write(' /platform:x86') for csfile in get_cs_files(self.ex_dir): @@ -2186,18 +2192,21 @@ def mk_config(): 'AR_FLAGS=/nologo\n' 'LINK_FLAGS=/nologo /MDd\n' 'SLINK_FLAGS=/nologo /LDd\n') - if not VS_X64: - config.write( - 'CXXFLAGS=/c /Zi /nologo /W3 /WX- /Od /Oy- /D WIN32 /D _DEBUG /D Z3DEBUG %s /D _CONSOLE /D _TRACE /D _WINDOWS /Gm- /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /analyze- /arch:SSE2\n' % extra_opt) - config.write( - 'LINK_EXTRA_FLAGS=/link /DEBUG /MACHINE:X86 /SUBSYSTEM:CONSOLE /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE /NXCOMPAT\n' - 'SLINK_EXTRA_FLAGS=/link /DEBUG /MACHINE:X86 /SUBSYSTEM:WINDOWS /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE:NO\n') - else: + if VS_X64: config.write( 'CXXFLAGS=/c /Zi /nologo /W3 /WX- /Od /Oy- /D WIN32 /D _AMD64_ /D _DEBUG /D Z3DEBUG %s /D _CONSOLE /D _TRACE /D _WINDOWS /Gm- /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /analyze-\n' % extra_opt) config.write( 'LINK_EXTRA_FLAGS=/link /DEBUG /MACHINE:X64 /SUBSYSTEM:CONSOLE /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE /NXCOMPAT\n' 'SLINK_EXTRA_FLAGS=/link /DEBUG /MACHINE:X64 /SUBSYSTEM:WINDOWS /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE:NO\n') + elif VS_ARM: + print "ARM on VS is unsupported" + exit(1) + else: + config.write( + 'CXXFLAGS=/c /Zi /nologo /W3 /WX- /Od /Oy- /D WIN32 /D _DEBUG /D Z3DEBUG %s /D _CONSOLE /D _TRACE /D _WINDOWS /Gm- /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /analyze- /arch:SSE2\n' % extra_opt) + config.write( + 'LINK_EXTRA_FLAGS=/link /DEBUG /MACHINE:X86 /SUBSYSTEM:CONSOLE /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE /NXCOMPAT\n' + 'SLINK_EXTRA_FLAGS=/link /DEBUG /MACHINE:X86 /SUBSYSTEM:WINDOWS /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE:NO\n') else: # Windows Release mode LTCG=' /LTCG' if SLOW_OPTIMIZE else '' @@ -2209,18 +2218,23 @@ def mk_config(): % LTCG) if TRACE: extra_opt = '%s /D _TRACE ' % extra_opt - if not VS_X64: - config.write( - 'CXXFLAGS=/nologo /c%s /Zi /W3 /WX- /O2 /Oy- /D _EXTERNAL_RELEASE /D WIN32 /D NDEBUG %s /D _CONSOLE /D _WINDOWS /D ASYNC_COMMANDS /Gm- /EHsc /MD /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /analyze- /arch:SSE2\n' % (GL, extra_opt)) - config.write( - 'LINK_EXTRA_FLAGS=/link%s /DEBUG /MACHINE:X86 /SUBSYSTEM:CONSOLE /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE /NXCOMPAT\n' - 'SLINK_EXTRA_FLAGS=/link%s /DEBUG /MACHINE:X86 /SUBSYSTEM:WINDOWS /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE:NO\n' % (LTCG, LTCG)) - else: + if VS_X64: config.write( 'CXXFLAGS=/c%s /Zi /nologo /W3 /WX- /O2 /D _EXTERNAL_RELEASE /D WIN32 /D NDEBUG %s /D _LIB /D _WINDOWS /D _AMD64_ /D _UNICODE /D UNICODE /Gm- /EHsc /MD /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /TP\n' % (GL, extra_opt)) config.write( 'LINK_EXTRA_FLAGS=/link%s /MACHINE:X64 /SUBSYSTEM:CONSOLE /INCREMENTAL:NO /STACK:8388608\n' 'SLINK_EXTRA_FLAGS=/link%s /MACHINE:X64 /SUBSYSTEM:WINDOWS /INCREMENTAL:NO /STACK:8388608\n' % (LTCG, LTCG)) + elif VS_ARM: + print "ARM on VS is unsupported" + exit(1) + else: + config.write( + 'CXXFLAGS=/nologo /c%s /Zi /W3 /WX- /O2 /Oy- /D _EXTERNAL_RELEASE /D WIN32 /D NDEBUG %s /D _CONSOLE /D _WINDOWS /D ASYNC_COMMANDS /Gm- /EHsc /MD /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /analyze- /arch:SSE2\n' % (GL, extra_opt)) + config.write( + 'LINK_EXTRA_FLAGS=/link%s /DEBUG /MACHINE:X86 /SUBSYSTEM:CONSOLE /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE /NXCOMPAT\n' + 'SLINK_EXTRA_FLAGS=/link%s /DEBUG /MACHINE:X86 /SUBSYSTEM:WINDOWS /INCREMENTAL:NO /STACK:8388608 /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE:NO\n' % (LTCG, LTCG)) + + # End of Windows VS config.mk if is_verbose(): @@ -2446,6 +2460,9 @@ def mk_makefile(): if VS_X64: print(" platform: x64\n") print("To build Z3, open a [Visual Studio x64 Command Prompt], then") + elif VS_ARM: + print(" platform: ARM\n") + print("To build Z3, open a [Visual Studio ARM Command Prompt], then") else: print(" platform: x86") print("To build Z3, open a [Visual Studio Command Prompt], then") diff --git a/src/ast/ast_smt_pp.cpp b/src/ast/ast_smt_pp.cpp index 9279f50fe..82137483a 100644 --- a/src/ast/ast_smt_pp.cpp +++ b/src/ast/ast_smt_pp.cpp @@ -30,6 +30,7 @@ Revision History: #include"for_each_ast.h" #include"decl_collector.h" #include"smt2_util.h" +#include"seq_decl_plugin.h" // --------------------------------------- // smt_renaming @@ -160,6 +161,7 @@ class smt_printer { unsigned m_num_lets; arith_util m_autil; bv_util m_bvutil; + seq_util m_sutil; family_id m_basic_fid; family_id m_bv_fid; family_id m_arith_fid; @@ -247,6 +249,10 @@ class smt_printer { } if (m_is_smt2) { + if (is_sort_symbol && sym == symbol("String")) { + m_out << "String"; + return; + } if (is_sort_symbol && sym != symbol("BitVec")) { m_out << "(" << sym << " "; } @@ -397,6 +403,7 @@ class smt_printer { bool is_int, pos; buffer names; unsigned bv_size; + zstring s; unsigned num_args = n->get_num_args(); func_decl* decl = n->get_decl(); if (m_autil.is_numeral(n, val, is_int)) { @@ -415,6 +422,19 @@ class smt_printer { display_rational(val, is_int); } } + else if (m_sutil.str.is_string(n, s)) { + std::string encs = s.encode(); + m_out << "\""; + for (unsigned i = 0; i < encs.length(); ++i) { + if (encs[i] == '\"') { + m_out << "\"\""; + } + else { + m_out << encs[i]; + } + } + m_out << "\""; + } else if (m_bvutil.is_numeral(n, val, bv_size)) { if (m_is_smt2) { m_out << "(_ bv" << val << " " << bv_size << ")"; @@ -797,6 +817,7 @@ public: m_num_lets(0), m_autil(m), m_bvutil(m), + m_sutil(m), m_logic(logic), m_AUFLIRA("AUFLIRA"), // It's much easier to read those testcases with that. diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 13ba7d67d..a26fcfe2c 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -437,7 +437,12 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) { m_util.str.get_concat(a, as); m_util.str.get_concat(b, bs); bool all_values = true; - + + if (bs.empty()) { + result = m().mk_true(); + return BR_DONE; + } + for (unsigned i = 0; all_values && i < bs.size(); ++i) { all_values = m().is_value(bs[i].get()); } @@ -459,6 +464,39 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) { result = m().mk_false(); return BR_DONE; } + + unsigned lenA = 0, lenB = 0; + bool lA = min_length(as.size(), as.c_ptr(), lenA); + if (lA) { + bool lB = min_length(bs.size(), bs.c_ptr(), lenB); + if (lenB > lenA) { + result = m().mk_false(); + return BR_DONE; + } + } + + + if (as.empty()) { + result = m().mk_eq(b, m_util.str.mk_empty(m().get_sort(b))); + return BR_REWRITE2; + } + + unsigned offs = 0; + unsigned sz = as.size(); + expr* b0 = bs[0].get(); + expr* bL = bs[bs.size()-1].get(); + for (; offs < as.size() && m().are_distinct(b0, as[offs].get()); ++offs) {}; + for (; sz > offs && m().are_distinct(bL, as[sz-1].get()); --sz) {} + if (offs == sz) { + result = m().mk_eq(b, m_util.str.mk_empty(m().get_sort(b))); + return BR_REWRITE2; + } + if (offs > 0 || sz < as.size()) { + SASSERT(sz > offs); + result = m_util.str.mk_contains(m_util.str.mk_concat(sz-offs, as.c_ptr()+offs), b); + return BR_REWRITE2; + } + return BR_FAILED; } diff --git a/src/ast/seq_decl_plugin.h b/src/ast/seq_decl_plugin.h index 4100fe6cc..6200d910f 100644 --- a/src/ast/seq_decl_plugin.h +++ b/src/ast/seq_decl_plugin.h @@ -222,16 +222,16 @@ public: str(seq_util& u): u(u), m(u.m), m_fid(u.m_fid) {} sort* mk_seq(sort* s) { parameter param(s); return m.mk_sort(m_fid, SEQ_SORT, 1, ¶m); } - sort* mk_string_sort() { return m.mk_sort(m_fid, _STRING_SORT, 0, 0); } - app* mk_empty(sort* s) { return m.mk_const(m.mk_func_decl(m_fid, OP_SEQ_EMPTY, 0, 0, 0, (expr*const*)0, s)); } + sort* mk_string_sort() const { return m.mk_sort(m_fid, _STRING_SORT, 0, 0); } + app* mk_empty(sort* s) const { return m.mk_const(m.mk_func_decl(m_fid, OP_SEQ_EMPTY, 0, 0, 0, (expr*const*)0, s)); } app* mk_string(zstring const& s); app* mk_string(symbol const& s) { return u.seq.mk_string(s); } app* mk_char(char ch); - app* mk_concat(expr* a, expr* b) { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_SEQ_CONCAT, 2, es); } + app* mk_concat(expr* a, expr* b) const { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_SEQ_CONCAT, 2, es); } app* mk_concat(expr* a, expr* b, expr* c) { return mk_concat(a, mk_concat(b, c)); } - expr* mk_concat(unsigned n, expr* const* es) { 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) { return mk_concat(es.size(), es.c_ptr()); } - app* mk_length(expr* a) { return m.mk_app(m_fid, OP_SEQ_LENGTH, 1, &a); } + 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_substr(expr* a, expr* b, expr* c) { expr* es[3] = { a, b, c }; return m.mk_app(m_fid, OP_SEQ_EXTRACT, 3, es); } app* mk_contains(expr* a, expr* b) { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_SEQ_CONTAINS, 2, es); } app* mk_prefix(expr* a, expr* b) { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_SEQ_PREFIX, 2, es); } diff --git a/src/smt/smt_conflict_resolution.cpp b/src/smt/smt_conflict_resolution.cpp index 3aa02c0b6..86593b0f2 100644 --- a/src/smt/smt_conflict_resolution.cpp +++ b/src/smt/smt_conflict_resolution.cpp @@ -99,22 +99,29 @@ namespace smt { This method may update m_antecedents, m_todo_js and m_todo_eqs. */ void conflict_resolution::eq_justification2literals(enode * lhs, enode * rhs, eq_justification js) { + ast_manager& m = get_manager(); SASSERT(m_antecedents); + TRACE("conflict_detail", tout << mk_pp(lhs->get_owner(), m) << " = " << mk_pp(rhs->get_owner(), m); + switch (js.get_kind()) { + case eq_justification::AXIOM: tout << " axiom\n"; break; + case eq_justification::EQUATION: + tout << " was asserted\nliteral: "; m_ctx.display_literal(tout, js.get_literal()); tout << "\n"; + break; + case eq_justification::JUSTIFICATION: tout << " justification\n"; break; + case eq_justification::CONGRUENCE: tout << " congruence\n"; break; + default: break; + }); + switch(js.get_kind()) { case eq_justification::AXIOM: - TRACE("conflict_detail", tout << "#" << lhs->get_owner_id() << " = " << rhs->get_owner_id() << " axiom\n";); break; case eq_justification::EQUATION: - TRACE("conflict_detail", tout << "#" << lhs->get_owner_id() << " = " << rhs->get_owner_id() << " was asserted\n" - << "literal: "; m_ctx.display_literal(tout, js.get_literal()); tout << "\n";); m_antecedents->push_back(js.get_literal()); break; case eq_justification::JUSTIFICATION: - TRACE("conflict_detail", tout << "#" << lhs->get_owner_id() << " = " << rhs->get_owner_id() << " justification\n";); mark_justification(js.get_justification()); break; case eq_justification::CONGRUENCE: { - TRACE("conflict_detail", tout << "#" << lhs->get_owner_id() << " = " << rhs->get_owner_id() << " congruence\n";); CTRACE("dyn_ack_target", !lhs->is_eq(), tout << "dyn_ack_target2: " << lhs->get_owner_id() << " " << rhs->get_owner_id() << "\n";); m_dyn_ack_manager.used_cg_eh(lhs->get_owner(), rhs->get_owner()); unsigned num_args = lhs->get_num_args(); @@ -206,7 +213,6 @@ namespace smt { justification_vector::iterator it = m_todo_js.begin() + old_js_qhead; justification_vector::iterator end = m_todo_js.end(); for (; it != end; ++it) { - TRACE("conflict_detail", tout << "unmarking: " << *it << "\n";); (*it)->unset_mark(); } m_todo_js.shrink(old_js_qhead); @@ -371,11 +377,9 @@ namespace smt { tout << "conflict_lvl: " << m_conflict_lvl << " scope_lvl: " << m_ctx.get_scope_level() << " base_lvl: " << m_ctx.get_base_level() << " search_lvl: " << m_ctx.get_search_level() << "\n"; tout << "js.kind: " << js.get_kind() << "\n"; - tout << "consequent: " << consequent << "\n"; - for (unsigned i = 0; i < m_assigned_literals.size(); ++i) { - tout << m_assigned_literals[i] << " "; - } - tout << "\n"; + tout << "consequent: " << consequent << ": "; + m_ctx.display_literal_verbose(tout, consequent); tout << "\n"; + m_ctx.display(tout, js); tout << "\n"; ); // m_conflict_lvl can be smaller than m_ctx.get_search_level() when: @@ -416,12 +420,12 @@ namespace smt { TRACE("conflict", tout << "before minimization:\n"; - m_ctx.display_literals(tout, m_lemma.size(), m_lemma.c_ptr()); + m_ctx.display_literals(tout, m_lemma); tout << "\n";); TRACE("conflict_verbose", tout << "before minimization:\n"; - m_ctx.display_literals_verbose(tout, m_lemma.size(), m_lemma.c_ptr()); + m_ctx.display_literals_verbose(tout, m_lemma); tout << "\n";); if (m_params.m_minimize_lemmas) @@ -429,12 +433,16 @@ namespace smt { TRACE("conflict", tout << "after minimization:\n"; - m_ctx.display_literals(tout, m_lemma.size(), m_lemma.c_ptr()); + m_ctx.display_literals(tout, m_lemma); tout << "\n";); TRACE("conflict_verbose", tout << "after minimization:\n"; - m_ctx.display_literals_verbose(tout, m_lemma.size(), m_lemma.c_ptr()); + m_ctx.display_literals_verbose(tout, m_lemma); + tout << "\n";); + + TRACE("conflict_bug", + m_ctx.display_literals_verbose(tout, m_lemma); tout << "\n";); literal_vector::iterator it = m_lemma.begin(); @@ -1423,7 +1431,7 @@ namespace smt { } end_unsat_core: - TRACE("unsat_core", tout << "assumptions:\n"; m_ctx.display_literals(tout, m_assumptions.size(), m_assumptions.c_ptr()); tout << "\n";); + TRACE("unsat_core", tout << "assumptions:\n"; m_ctx.display_literals(tout, m_assumptions); tout << "\n";); reset_unmark_and_justifications(0, 0); } diff --git a/src/smt/smt_conflict_resolution.h b/src/smt/smt_conflict_resolution.h index 6d8abbf23..daccadbb7 100644 --- a/src/smt/smt_conflict_resolution.h +++ b/src/smt/smt_conflict_resolution.h @@ -114,7 +114,6 @@ namespace smt { void mark_justification(justification * js) { if (!js->is_marked()) { - TRACE("conflict_detail", tout << "marking: " << js << "\n";); js->set_mark(); m_todo_js.push_back(js); } @@ -126,7 +125,7 @@ namespace smt { std::swap(n1, n2); enode_pair p(n1, n2); if (m_already_processed_eqs.insert_if_not_there(p)) { - TRACE("conflict_detail", tout << "marking eq #" << p.first->get_owner_id() << " = #" << + TRACE("conflict_detail_verbose", tout << "marking eq #" << p.first->get_owner_id() << " = #" << p.second->get_owner_id() << "\n";); m_todo_eqs.push_back(p); SASSERT(m_already_processed_eqs.contains(p)); @@ -168,9 +167,8 @@ namespace smt { void eq_justification2literals(enode * lhs, enode * rhs, eq_justification js); void eq_branch2literals(enode * n1, enode * n2); void eq2literals(enode * n1, enode * n2); - void justification2literals_core(justification * js, literal_vector & result); + void justification2literals_core(justification * js, literal_vector & result) ; void unmark_justifications(unsigned old_js_qhead); - void justification2literals(justification * js, literal_vector & result); literal_vector m_tmp_literal_vector; @@ -256,6 +254,9 @@ namespace smt { literal_vector::const_iterator end_unsat_core() const { return m_assumptions.end(); } + + void justification2literals(justification * js, literal_vector & result); + }; inline void mark_literals(conflict_resolution & cr, unsigned sz, literal const * ls) { diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 1a8658c99..7d07f3997 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -295,7 +295,7 @@ namespace smt { void context::assign_core(literal l, b_justification j, bool decision) { TRACE("assign_core", tout << (decision?"decision: ":"propagating: ") << l << " "; - display_literal(tout, l); tout << " level: " << m_scope_lvl << "\n"; + display_literal_verbose(tout, l); tout << " level: " << m_scope_lvl << "\n"; display(tout, j);); SASSERT(l.var() < static_cast(m_b_internalized_stack.size())); m_assigned_literals.push_back(l); diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 85fd63033..b918be2cf 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1176,8 +1176,18 @@ namespace smt { void display_literals(std::ostream & out, unsigned num_lits, literal const * lits) const; + void display_literals(std::ostream & out, literal_vector const& lits) const { + display_literals(out, lits.size(), lits.c_ptr()); + } + + void display_literal_verbose(std::ostream & out, literal lit) const; + void display_literals_verbose(std::ostream & out, unsigned num_lits, literal const * lits) const; + void display_literals_verbose(std::ostream & out, literal_vector const& lits) const { + display_literals_verbose(out, lits.size(), lits.c_ptr()); + } + void display_watch_list(std::ostream & out, literal l) const; void display_watch_lists(std::ostream & out) const; diff --git a/src/smt/smt_context_pp.cpp b/src/smt/smt_context_pp.cpp index d04165c5b..1f5566a03 100644 --- a/src/smt/smt_context_pp.cpp +++ b/src/smt/smt_context_pp.cpp @@ -96,6 +96,10 @@ namespace smt { display_compact(out, num_lits, lits, m_bool_var2expr.c_ptr()); } + void context::display_literal_verbose(std::ostream & out, literal lit) const { + display_literals_verbose(out, 1, &lit); + } + void context::display_literals_verbose(std::ostream & out, unsigned num_lits, literal const * lits) const { display_verbose(out, m_manager, num_lits, lits, m_bool_var2expr.c_ptr(), "\n"); } @@ -599,12 +603,16 @@ namespace smt { case b_justification::CLAUSE: { clause * cls = j.get_clause(); out << "clause "; - display_literals(out, cls->get_num_literals(), cls->begin_literals()); + if (cls) display_literals_verbose(out, cls->get_num_literals(), cls->begin_literals()); break; } - case b_justification::JUSTIFICATION: - out << "justification"; + case b_justification::JUSTIFICATION: { + out << "justification "; + literal_vector lits; + const_cast(*m_conflict_resolution).justification2literals(j.get_justification(), lits); + display_literals_verbose(out, lits.size(), lits.c_ptr()); break; + } default: UNREACHABLE(); break; diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 40b9fa04b..cfd043895 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -258,6 +258,11 @@ final_check_status theory_seq::final_check_eh() { TRACE("seq", tout << ">>propagate_automata\n";); return FC_CONTINUE; } + if (check_contains()) { + ++m_stats.m_propagate_contains; + TRACE("seq", tout << ">>propagate_contains\n";); + return FC_CONTINUE; + } if (is_solved()) { TRACE("seq", tout << ">>is_solved\n";); return FC_DONE; @@ -288,7 +293,7 @@ bool theory_seq::branch_variable() { unsigned id = e.id(); s = find_branch_start(2*id); - TRACE("seq", tout << s << " " << 2*id << ": " << e.ls() << " = " << e.rs() << "\n";); + TRACE("seq", tout << s << " " << id << ": " << e.ls() << " = " << e.rs() << "\n";); bool found = find_branch_candidate(s, e.dep(), e.ls(), e.rs()); insert_branch_start(2*id, s); if (found) { @@ -337,15 +342,15 @@ bool theory_seq::find_branch_candidate(unsigned& start, dependency* dep, expr_re return false; } + TRACE("seq", tout << mk_pp(l, m) << ": " << get_context().get_scope_level() << " - start:" << start << "\n";); + expr_ref v0(m); v0 = m_util.str.mk_empty(m.get_sort(l)); - literal_vector lits; if (can_be_equal(ls.size() - 1, ls.c_ptr() + 1, rs.size(), rs.c_ptr())) { if (l_false != assume_equality(l, v0)) { TRACE("seq", tout << mk_pp(l, m) << " " << v0 << "\n";); return true; } - lits.push_back(~mk_eq_empty(l)); } for (; start < rs.size(); ++start) { unsigned j = start; @@ -370,14 +375,31 @@ bool theory_seq::find_branch_candidate(unsigned& start, dependency* dep, expr_re all_units &= m_util.str.is_unit(rs[j]); } if (all_units) { + context& ctx = get_context(); + literal_vector lits; + lits.push_back(~mk_eq_empty(l)); for (unsigned i = 0; i < rs.size(); ++i) { if (can_be_equal(ls.size() - 1, ls.c_ptr() + 1, rs.size() - i - 1, rs.c_ptr() + i + 1)) { v0 = mk_concat(i + 1, rs.c_ptr()); lits.push_back(~mk_eq(l, v0, false)); } } + for (unsigned i = 0; i < lits.size(); ++i) { + switch (ctx.get_assignment(lits[i])) { + case l_true: break; + case l_false: start = 0; return true; + case l_undef: ctx.force_phase(~lits[i]); start = 0; return true; + } + } set_conflict(dep, lits); - TRACE("seq", tout << mk_pp(l, m) << " " << v0 << "\n";); + TRACE("seq", + tout << "start: " << start << "\n"; + for (unsigned i = 0; i < lits.size(); ++i) { + ctx.display_literal_verbose(tout << lits[i] << ": ", lits[i]); + tout << "\n"; + ctx.display(tout, ctx.get_justification(lits[i].var())); + tout << "\n"; + }); return true; } return false; @@ -429,10 +451,19 @@ lbool theory_seq::assume_equality(expr* l, expr* r) { if (n1->get_root() == n2->get_root()) { return l_true; } + if (ctx.is_diseq(n1, n2)) { + return l_false; + } + if (false && ctx.is_diseq_slow(n1, n2)) { + return l_false; + } ctx.mark_as_relevant(n1); ctx.mark_as_relevant(n2); - ctx.assume_eq(n1, n2); - return l_undef; + if (!ctx.assume_eq(n1, n2)) { + return l_false; + } + return ctx.get_assignment(mk_eq(l, r, false)); + //return l_undef; } @@ -483,29 +514,50 @@ bool theory_seq::propagate_length_coherence(expr* e) { return true; } + bool theory_seq::check_length_coherence(expr* e) { if (is_var(e) && m_rep.is_root(e)) { - expr_ref emp(m_util.str.mk_empty(m.get_sort(e)), m); - expr_ref head(m), tail(m); - if (!propagate_length_coherence(e) && - l_false == assume_equality(e, emp)) { + if (!check_length_coherence0(e)) { + expr_ref emp(m_util.str.mk_empty(m.get_sort(e)), m); + expr_ref head(m), tail(m); // e = emp \/ e = unit(head.elem(e))*tail(e) mk_decompose(e, head, tail); expr_ref conc = mk_concat(head, tail); - propagate_is_conc(e, conc); - assume_equality(tail, emp); - } - else if (!get_context().at_base_level()) { - m_trail_stack.push(push_replay(alloc(replay_length_coherence, m, e))); + if (propagate_is_conc(e, conc)) { + assume_equality(tail, emp); + } } return true; } return false; } +bool theory_seq::check_length_coherence0(expr* e) { + if (is_var(e) && m_rep.is_root(e)) { + expr_ref emp(m_util.str.mk_empty(m.get_sort(e)), m); + if (propagate_length_coherence(e) || + l_false != assume_equality(e, emp)) { + if (!get_context().at_base_level()) { + m_trail_stack.push(push_replay(alloc(replay_length_coherence, m, e))); + } + return true; + } + } + return false; +} + bool theory_seq::check_length_coherence() { obj_hashtable::iterator it = m_length.begin(), end = m_length.end(); +#if 1 + for (; it != end; ++it) { + expr* e = *it; + if (check_length_coherence0(e)) { + return true; + } + } + it = m_length.begin(); +#endif for (; it != end; ++it) { expr* e = *it; if (check_length_coherence(e)) { @@ -570,14 +622,19 @@ void theory_seq::propagate_non_empty(literal lit, expr* s) { propagate_lit(0, 1, &lit, ~mk_eq_empty(s)); } -void theory_seq::propagate_is_conc(expr* e, expr* conc) { +bool theory_seq::propagate_is_conc(expr* e, expr* conc) { TRACE("seq", tout << mk_pp(conc, m) << " is non-empty\n";); context& ctx = get_context(); literal lit = ~mk_eq_empty(e); - SASSERT(ctx.get_assignment(lit) == l_true); - propagate_lit(0, 1, &lit, mk_eq(e, conc, false)); - expr_ref e1(e, m), e2(conc, m); - new_eq_eh(m_dm.mk_leaf(assumption(lit)), ctx.get_enode(e1), ctx.get_enode(e2)); + if (ctx.get_assignment(lit) == l_true) { + propagate_lit(0, 1, &lit, mk_eq(e, conc, false)); + expr_ref e1(e, m), e2(conc, m); + new_eq_eh(m_dm.mk_leaf(assumption(lit)), ctx.get_enode(e1), ctx.get_enode(e2)); + return true; + } + else { + return false; + } } bool theory_seq::is_nth(expr* e) const { @@ -717,6 +774,23 @@ bool theory_seq::check_extensionality() { return true; } +/* + \brief check negated contains constriants. + */ +bool theory_seq::check_contains() { + context & ctx = get_context(); + for (unsigned i = 0; !ctx.inconsistent() && i < m_ncs.size(); ++i) { + if (solve_nc(i)) { + if (i + 1 != m_ncs.size()) { + nc n = m_ncs[m_ncs.size()-1]; + m_ncs.set(i, n); + --i; + } + m_ncs.pop_back(); + } + } + return m_new_propagation || ctx.inconsistent(); +} /* - Eqs = 0 - Diseqs evaluate to false @@ -762,20 +836,31 @@ void theory_seq::linearize(dependency* dep, enode_pair_vector& eqs, literal_vect void theory_seq::propagate_lit(dependency* dep, unsigned n, literal const* _lits, literal lit) { + if (lit == true_literal) return; + context& ctx = get_context(); - ctx.mark_as_relevant(lit); literal_vector lits(n, _lits); + + if (lit == false_literal) { + set_conflict(dep, lits); + return; + } + + ctx.mark_as_relevant(lit); enode_pair_vector eqs; linearize(dep, eqs, lits); - TRACE("seq", ctx.display_detailed_literal(tout, lit); - tout << " <- "; ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); if (!lits.empty()) tout << "\n"; display_deps(tout, dep);); + TRACE("seq", + tout << "assert:"; + ctx.display_detailed_literal(tout, lit); + tout << " <- "; ctx.display_literals_verbose(tout, lits); + if (!lits.empty()) tout << "\n"; display_deps(tout, dep);); justification* js = ctx.mk_justification( ext_theory_propagation_justification( get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), eqs.size(), eqs.c_ptr(), lit)); m_new_propagation = true; - ctx.assign(lit, js); + ctx.assign(lit, js); } void theory_seq::set_conflict(dependency* dep, literal_vector const& _lits) { @@ -783,7 +868,7 @@ void theory_seq::set_conflict(dependency* dep, literal_vector const& _lits) { enode_pair_vector eqs; literal_vector lits(_lits); linearize(dep, eqs, lits); - TRACE("seq", display_deps(tout, lits, eqs);); + TRACE("seq", display_deps(tout << "assert conflict:", lits, eqs);); m_new_propagation = true; ctx.set_conflict( ctx.mk_justification( @@ -800,7 +885,7 @@ void theory_seq::propagate_eq(dependency* dep, enode* n1, enode* n2) { enode_pair_vector eqs; linearize(dep, eqs, lits); TRACE("seq", - tout << mk_pp(n1->get_owner(), m) << " = " << mk_pp(n2->get_owner(), m) << " <- \n"; + tout << "assert:" << mk_pp(n1->get_owner(), m) << " = " << mk_pp(n2->get_owner(), m) << " <- \n"; display_deps(tout, dep); ); @@ -1484,6 +1569,30 @@ bool theory_seq::solve_ne(unsigned idx) { return updated; } +bool theory_seq::solve_nc(unsigned idx) { + context& ctx = get_context(); + nc const& n = m_ncs[idx]; + + dependency* deps = n.deps(); + expr_ref c = canonize(n.contains(), deps); + + CTRACE("seq", c != n.contains(), tout << n.contains() << " => " << c << "\n";); + + if (m.is_true(c)) { + literal_vector lits; + set_conflict(deps, lits); + return true; + } + if (m.is_false(c)) { + return true; + } + if (c != n.contains()) { + m_ncs.push_back(nc(c, deps)); + return true; + } + return false; +} + theory_seq::cell* theory_seq::mk_cell(cell* p, expr* e, dependency* d) { cell* c = alloc(cell, p, e, d); m_all_cells.push_back(c); @@ -1747,6 +1856,20 @@ void theory_seq::display(std::ostream & out) const { out << "Exclusions:\n"; m_exclude.display(out); } + + if (!m_length.empty()) { + obj_hashtable::iterator it = m_length.begin(), end = m_length.end(); + for (; it != end; ++it) { + expr* e = *it; + rational lo(-1), hi(-1); + lower_bound(e, lo); + upper_bound(e, hi); + if (lo.is_pos() || !hi.is_minus_one()) { + out << mk_pp(e, m) << " [" << lo << ":" << hi << "]\n"; + } + } + } + } void theory_seq::display_equations(std::ostream& out) const { @@ -2360,7 +2483,7 @@ void theory_seq::propagate_in_re(expr* n, bool is_true) { propagate_lit(0, 1, &lit, lits[1]); } else { - TRACE("seq", ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";); + TRACE("seq", ctx.display_literals_verbose(tout, lits); tout << "\n";); ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); } } @@ -2393,7 +2516,7 @@ static theory_mi_arith* get_th_arith(context& ctx, theory_id afid, expr* e) { } } -bool theory_seq::lower_bound(expr* _e, rational& lo) { +bool theory_seq::lower_bound(expr* _e, rational& lo) const { context& ctx = get_context(); expr_ref e(m_util.str.mk_length(_e), m); theory_mi_arith* tha = get_th_arith(ctx, m_autil.get_family_id(), e); @@ -2402,7 +2525,7 @@ bool theory_seq::lower_bound(expr* _e, rational& lo) { return m_autil.is_numeral(_lo, lo) && lo.is_int(); } -bool theory_seq::upper_bound(expr* _e, rational& hi) { +bool theory_seq::upper_bound(expr* _e, rational& hi) const { context& ctx = get_context(); expr_ref e(m_util.str.mk_length(_e), m); theory_mi_arith* tha = get_th_arith(ctx, m_autil.get_family_id(), e); @@ -2411,7 +2534,7 @@ bool theory_seq::upper_bound(expr* _e, rational& hi) { return m_autil.is_numeral(_hi, hi) && hi.is_int(); } -bool theory_seq::get_length(expr* e, rational& val) { +bool theory_seq::get_length(expr* e, rational& val) const { context& ctx = get_context(); theory* th = ctx.get_theory(m_autil.get_family_id()); if (!th) return false; @@ -2705,7 +2828,6 @@ literal theory_seq::mk_eq_empty(expr* _e, bool phase) { literal lit = mk_eq(e, emp, false); ctx.force_phase(phase?lit:~lit); ctx.mark_as_relevant(lit); - TRACE("seq", tout << mk_pp(e, m) << " = empty\n";); return lit; } @@ -2718,7 +2840,7 @@ void theory_seq::add_axiom(literal l1, literal l2, literal l3, literal l4, liter if (l3 != null_literal && l3 != false_literal) { ctx.mark_as_relevant(l3); lits.push_back(l3); } if (l4 != null_literal && l4 != false_literal) { ctx.mark_as_relevant(l4); lits.push_back(l4); } if (l5 != null_literal && l5 != false_literal) { ctx.mark_as_relevant(l5); lits.push_back(l5); } - TRACE("seq", ctx.display_literals_verbose(tout << "axiom: ", lits.size(), lits.c_ptr()); tout << "\n";); + TRACE("seq", ctx.display_literals_verbose(tout << "assert: ", lits); tout << "\n";); m_new_propagation = true; ++m_stats.m_add_axiom; ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); @@ -2775,8 +2897,8 @@ void theory_seq::propagate_eq(dependency* deps, literal_vector const& _lits, exp new_eq_eh(deps, n1, n2); } TRACE("seq", - ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); - tout << " => " << mk_pp(e1, m) << " = " << mk_pp(e2, m) << "\n";); + tout << "assert: " << mk_pp(e1, m) << " = " << mk_pp(e2, m) << "<- \n"; + ctx.display_literals_verbose(tout, lits);); justification* js = ctx.mk_justification( ext_theory_eq_propagation_justification( @@ -2848,10 +2970,15 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { } else if (!canonizes(false, e)) { propagate_non_empty(lit, e2); +#if 0 + dependency* dep = m_dm.mk_leaf(assumption(lit)); + m_ncs.push_back(nc(expr_ref(e, m), dep)); +#else propagate_lit(0, 1, &lit, ~mk_literal(m_util.str.mk_prefix(e2, e1))); if (add_contains2contains(e, change)) { add_atom(e); } +#endif } } else if (is_accept(e)) { @@ -2921,7 +3048,7 @@ void theory_seq::new_diseq_eh(theory_var v1, theory_var v2) { expr_ref eq(m.mk_eq(e1, e2), m); m_rewrite(eq); if (!m.is_false(eq)) { - TRACE("seq", tout << "new disequality: " << eq << "\n";); + TRACE("seq", tout << "new disequality " << get_context().get_scope_level() << ": " << eq << "\n";); literal lit = mk_eq(e1, e2, false); @@ -2980,6 +3107,7 @@ void theory_seq::push_scope_eh() { m_trail_stack.push(value_trail(m_axioms_head)); m_eqs.push_scope(); m_nqs.push_scope(); + m_ncs.push_scope(); m_atoms_lim.push_back(m_atoms.size()); } @@ -2992,6 +3120,7 @@ void theory_seq::pop_scope_eh(unsigned num_scopes) { m_exclude.pop_scope(num_scopes); m_eqs.pop_scope(num_scopes); m_nqs.pop_scope(num_scopes); + m_ncs.pop_scope(num_scopes); m_atoms.resize(m_atoms_lim[m_atoms_lim.size()-num_scopes]); m_atoms_lim.shrink(m_atoms_lim.size()-num_scopes); m_rewrite.reset(); @@ -3196,7 +3325,7 @@ bool theory_seq::add_accept2step(expr* acc, bool& change) { if (has_undef) { return true; } - TRACE("seq", ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";); + TRACE("seq", ctx.display_literals_verbose(tout, lits); tout << "\n";); for (unsigned i = 0; i < lits.size(); ++i) { SASSERT(ctx.get_assignment(lits[i]) == l_false); lits[i].neg(); @@ -3353,7 +3482,6 @@ void theory_seq::propagate_not_prefix(expr* e) { void theory_seq::propagate_not_prefix2(expr* e) { context& ctx = get_context(); - //std::cout << mk_pp(e, m) << " " << ctx.get_scope_level() << "\n"; expr* e1, *e2; VERIFY(m_util.str.is_prefix(e, e1, e2)); literal lit = ctx.get_literal(e); @@ -3423,7 +3551,7 @@ bool theory_seq::add_prefix2prefix(expr* e, bool& change) { switch (ctx.get_assignment(e2_is_emp)) { case l_true: TRACE("seq", tout << mk_pp(e, m) << ": " << mk_pp(e2, m) << " = empty\n"; - ctx.display_literals_verbose(tout, 1, &e2_is_emp); tout << "\n"; ); + ctx.display_literal_verbose(tout, e2_is_emp); tout << "\n"; ); return false; // done case l_undef: // ctx.force_phase(e2_is_emp); diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 23ab25905..c600e443f 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -191,6 +191,27 @@ namespace smt { expr_ref const& r() const { return m_r; } }; + class nc { + expr_ref m_contains; + dependency* m_dep; + public: + nc(expr_ref const& c, dependency* dep): + m_contains(c), + m_dep(dep) {} + nc(nc const& other): + m_contains(other.m_contains), + m_dep(other.m_dep) {} + nc& operator=(nc const& other) { + if (this != &other) { + m_contains = other.m_contains; + m_dep = other.m_dep; + } + return *this; + } + dependency* deps() const { return m_dep; } + expr_ref const& contains() const { return m_contains; } + }; + class apply { public: virtual ~apply() {} @@ -263,12 +284,14 @@ namespace smt { unsigned m_add_axiom; unsigned m_extensionality; unsigned m_fixed_length; + unsigned m_propagate_contains; }; ast_manager& m; dependency_manager m_dm; solution_map m_rep; // unification representative. scoped_vector m_eqs; // set of current equations. scoped_vector m_nqs; // set of current disequalities. + scoped_vector m_ncs; // set of non-contains constraints. unsigned m_eq_id; seq_factory* m_factory; // value factory @@ -335,12 +358,14 @@ namespace smt { bool split_variable(); // split a variable bool is_solved(); bool check_length_coherence(); + bool check_length_coherence0(expr* e); bool check_length_coherence(expr* e); bool fixed_length(); bool fixed_length(expr* e); bool propagate_length_coherence(expr* e); bool check_extensionality(); + bool check_contains(); bool solve_eqs(unsigned start); bool solve_eq(expr_ref_vector const& l, expr_ref_vector const& r, dependency* dep); bool simplify_eq(expr_ref_vector& l, expr_ref_vector& r, dependency* dep); @@ -362,6 +387,7 @@ namespace smt { expr_ref mk_concat(expr* e1, expr* e2, expr* e3) { return expr_ref(m_util.str.mk_concat(e1, e2, e3), m); } bool solve_nqs(unsigned i); bool solve_ne(unsigned i); + bool solve_nc(unsigned i); struct cell { cell* m_parent; @@ -452,9 +478,9 @@ namespace smt { // arithmetic integration - bool lower_bound(expr* s, rational& lo); - bool upper_bound(expr* s, rational& hi); - bool get_length(expr* s, rational& val); + bool lower_bound(expr* s, rational& lo) const; + bool upper_bound(expr* s, rational& hi) const; + bool get_length(expr* s, rational& val) const; void mk_decompose(expr* e, expr_ref& head, expr_ref& tail); expr_ref mk_skolem(symbol const& s, expr* e1, expr* e2 = 0, expr* e3 = 0, sort* range = 0); @@ -494,7 +520,7 @@ namespace smt { void ensure_nth(literal lit, expr* s, expr* idx); bool canonizes(bool sign, expr* e); void propagate_non_empty(literal lit, expr* s); - void propagate_is_conc(expr* e, expr* conc); + bool propagate_is_conc(expr* e, expr* conc); void propagate_acc_rej_length(literal lit, expr* acc_rej); bool propagate_automata(); void add_atom(expr* e);