diff --git a/src/ast/array_decl_plugin.cpp b/src/ast/array_decl_plugin.cpp index af451f9c5..fa17b591d 100644 --- a/src/ast/array_decl_plugin.cpp +++ b/src/ast/array_decl_plugin.cpp @@ -253,7 +253,10 @@ func_decl* array_decl_plugin::mk_select(unsigned arity, sort * const * domain) { if (!parameters[i].is_ast() || !is_sort(parameters[i].get_ast()) || !m_manager->compatible_sorts(domain[i+1], to_sort(parameters[i].get_ast()))) { - m_manager->raise_exception("domain sort and parameter do not match"); + std::stringstream strm; + strm << "domain sort " << sort_ref(domain[i+1], *m_manager) << " and parameter "; + strm << parameter_pp(parameters[i], *m_manager) << " do not match"; + m_manager->raise_exception(strm.str().c_str()); UNREACHABLE(); return nullptr; } @@ -292,8 +295,12 @@ func_decl * array_decl_plugin::mk_store(unsigned arity, sort * const * domain) { m_manager->raise_exception("expecting sort parameter"); return nullptr; } - if (!m_manager->compatible_sorts(to_sort(parameters[i].get_ast()), domain[i+1])) { - m_manager->raise_exception("domain sort and parameter do not match"); + sort* srt1 = to_sort(parameters[i].get_ast()); + sort* srt2 = domain[i+1]; + if (!m_manager->compatible_sorts(srt1, srt2)) { + std::stringstream strm; + strm << "domain sort " << sort_ref(srt2, *m_manager) << " and parameter sort " << sort_ref(srt2, *m_manager) << " do not match"; + m_manager->raise_exception(strm.str()); UNREACHABLE(); return nullptr; } @@ -326,13 +333,13 @@ bool array_decl_plugin::check_set_arguments(unsigned arity, sort * const * domai if (domain[i] != domain[0]) { std::ostringstream buffer; buffer << "arguments " << 1 << " and " << (i+1) << " have different sorts"; - m_manager->raise_exception(buffer.str().c_str()); + m_manager->raise_exception(buffer.str()); return false; } if (domain[i]->get_family_id() != m_family_id) { std::ostringstream buffer; buffer << "argument " << (i+1) << " is not of array sort"; - m_manager->raise_exception(buffer.str().c_str()); + m_manager->raise_exception(buffer.str()); return false; } } @@ -517,6 +524,7 @@ func_decl * array_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters void array_decl_plugin::get_sort_names(svector& sort_names, symbol const & logic) { sort_names.push_back(builtin_name(ARRAY_SORT_STR, ARRAY_SORT)); + sort_names.push_back(builtin_name("=>", ARRAY_SORT)); // TBD: this could easily break users even though it is already used in CVC4: // sort_names.push_back(builtin_name("Set", _SET_SORT)); } diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 8750425a8..99e861b16 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1542,6 +1542,16 @@ void ast_manager::raise_exception(char const * msg) { } +std::ostream& ast_manager::display(std::ostream& out, parameter const& p) { + switch (p.get_kind()) { + case parameter::PARAM_AST: + return out << mk_pp(p.get_ast(), *this); + default: + return p.display(out); + } + return out; +} + void ast_manager::copy_families_plugins(ast_manager const & from) { TRACE("copy_families_plugins", tout << "target:\n"; diff --git a/src/ast/ast.h b/src/ast/ast.h index c1193dfbd..ee39f4032 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -1558,6 +1558,9 @@ public: // Equivalent to throw ast_exception(msg) Z3_NORETURN void raise_exception(char const * msg); + Z3_NORETURN void raise_exception(std::string const& msg) { raise_exception(msg.c_str()); } + + std::ostream& display(std::ostream& out, parameter const& p); bool is_format_manager() const { return m_format_manager == nullptr; } @@ -2569,6 +2572,16 @@ public: void operator()(AST * n) { m_manager.inc_ref(n); } }; +struct parameter_pp { + parameter const& p; + ast_manager& m; + parameter_pp(parameter const& p, ast_manager& m): p(p), m(m) {} +}; + +inline std::ostream& operator<<(std::ostream& out, parameter_pp const& pp) { + return pp.m.display(out, pp.p); +} + #endif /* AST_H_ */ diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 84c05d53e..e4ad3bb9d 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -859,10 +859,6 @@ br_status seq_rewriter::mk_seq_replace(expr* a, expr* b, expr* c, expr_ref& resu result = m_util.str.mk_concat(c, a); return BR_REWRITE1; } - if (m_util.str.is_string(a, s1) && s1.length() == 0) { - result = a; - return BR_DONE; - } return BR_FAILED; } diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index e9e6c4ee6..29221c0e8 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -86,6 +86,7 @@ namespace sat { m_local_search_mode = local_search_mode::gsat; else m_local_search_mode = local_search_mode::wsat; + m_local_search_dbg_flips = p.local_search_dbg_flips(); m_unit_walk = p.unit_walk(); m_unit_walk_threads = p.unit_walk_threads(); m_lookahead_simplify = p.lookahead_simplify(); diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 63e979394..ba5c9aaf3 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -105,6 +105,7 @@ namespace sat { unsigned m_local_search_threads; bool m_local_search; local_search_mode m_local_search_mode; + bool m_local_search_dbg_flips; unsigned m_unit_walk_threads; bool m_unit_walk; bool m_lookahead_simplify; diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 9b79e2964..b65abfd23 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -553,6 +553,7 @@ namespace sat { PROGRESS(tries, total_flips); for (tries = 1; !m_unsat_stack.empty() && m_limit.inc(); ++tries) { + ++m_stats.m_num_restarts; for (step = 0; step < m_max_steps && !m_unsat_stack.empty(); ++step) { pick_flip_walksat(); if (m_unsat_stack.size() < m_best_unsat) { @@ -622,7 +623,6 @@ namespace sat { break; } - // remove unit clauses from assumptions. m_constraints.shrink(num_constraints() - sz); @@ -779,8 +779,11 @@ namespace sat { } void local_search::flip_walksat(bool_var flipvar) { + ++m_stats.m_num_flips; VERIFY(!is_unit(flipvar)); m_vars[flipvar].m_value = !cur_solution(flipvar); + m_vars[flipvar].m_flips++; + m_vars[flipvar].m_slow_break.update(abs(m_vars[flipvar].m_slack_score)); bool flip_is_true = cur_solution(flipvar); coeff_vector const& truep = m_vars[flipvar].m_watch[flip_is_true]; @@ -1062,6 +1065,19 @@ namespace sat { return out << "v" << v << " := " << (vi.m_value?"true":"false") << " bias: " << vi.m_bias << "\n"; } + void local_search::collect_statistics(statistics& st) const { + if (m_config.dbg_flips()) { + unsigned i = 0; + for (var_info const& vi : m_vars) { + IF_VERBOSE(0, verbose_stream() << "flips: " << i << " " << vi.m_flips << " " << vi.m_slow_break << "\n"); + ++i; + } + } + st.update("local-search-flips", m_stats.m_num_flips); + st.update("local-search-restarts", m_stats.m_num_restarts); + } + + bool local_search::check_goodvar() { unsigned g = 0; for (unsigned v = 0; v < num_vars(); ++v) { diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index baf072419..849b4f26b 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -23,6 +23,8 @@ #include "sat/sat_types.h" #include "sat/sat_config.h" #include "util/rlimit.h" +#include "util/ema.h" +#include "util/statistics.h" namespace sat { @@ -33,18 +35,21 @@ namespace sat { int m_best_known_value; local_search_mode m_mode; bool m_phase_sticky; + bool m_dbg_flips; public: local_search_config() { m_random_seed = 0; m_best_known_value = INT_MAX; m_mode = local_search_mode::wsat; m_phase_sticky = false; + m_dbg_flips = false; } unsigned random_seed() const { return m_random_seed; } unsigned best_known_value() const { return m_best_known_value; } local_search_mode mode() const { return m_mode; } bool phase_sticky() const { return m_phase_sticky; } + bool dbg_flips() const { return m_dbg_flips; } void set_random_seed(unsigned s) { m_random_seed = s; } void set_best_known_value(unsigned v) { m_best_known_value = v; } @@ -53,6 +58,7 @@ namespace sat { m_mode = cfg.m_local_search_mode; m_random_seed = cfg.m_random_seed; m_phase_sticky = cfg.m_phase_sticky; + m_dbg_flips = cfg.m_local_search_dbg_flips; } }; @@ -74,6 +80,13 @@ namespace sat { int coefficient; // non-zero integer ob_term(bool_var v, int c): var_id(v), coefficient(c) {} }; + + struct stats { + unsigned m_num_flips; + unsigned m_num_restarts; + void reset() { memset(this, 0, sizeof(*this)); } + stats() { reset(); } + }; struct var_info { bool m_value; // current solution @@ -89,6 +102,8 @@ namespace sat { bool_var_vector m_neighbors; // neighborhood variables coeff_vector m_watch[2]; literal_vector m_bin[2]; + unsigned m_flips; + ema m_slow_break; var_info(): m_value(true), m_bias(50), @@ -97,7 +112,9 @@ namespace sat { m_in_goodvar_stack(false), m_score(0), m_slack_score(0), - m_cscc(0) + m_cscc(0), + m_flips(0), + m_slow_break(1e-5) {} }; @@ -115,6 +132,8 @@ namespace sat { literal const* end() const { return m_literals.end(); } }; + stats m_stats; + local_search_config m_config; // objective function: maximize @@ -145,7 +164,6 @@ namespace sat { inline void set_best_unsat(); /* TBD: other scores */ - vector m_constraints; @@ -293,6 +311,8 @@ namespace sat { model& get_model() { return m_model; } + void collect_statistics(statistics& st) const; + }; } diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 3f0479707..2aef881ca 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -48,6 +48,7 @@ def_module_params('sat', ('local_search', BOOL, False, 'use local search instead of CDCL'), ('local_search_threads', UINT, 0, 'number of local search threads to find satisfiable solution'), ('local_search_mode', SYMBOL, 'wsat', 'local search algorithm, either default wsat or qsat'), + ('local_search_dbg_flips', BOOL, False, 'write debug information for number of flips'), ('unit_walk', BOOL, False, 'use unit-walk search instead of CDCL'), ('unit_walk_threads', UINT, 0, 'number of unit-walk search threads to find satisfiable solution'), ('lookahead.cube.cutoff', SYMBOL, 'depth', 'cutoff type used to create lookahead cubes: depth, freevars, psat, adaptive_freevars, adaptive_psat'), diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 2032445ed..fea45c07b 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -68,6 +68,7 @@ namespace sat { m_simplifications = 0; m_ext = nullptr; m_cuber = nullptr; + m_local_search = nullptr; m_mc.set_solver(this); } @@ -764,9 +765,9 @@ namespace sat { m_not_l = not_l; } - void solver::assign_core(literal l, justification j) { + void solver::assign_core(literal l, unsigned lvl, justification j) { SASSERT(value(l) == l_undef); - TRACE("sat_assign_core", tout << l << " " << j << " level: " << scope_lvl() << "\n";); + TRACE("sat_assign_core", tout << l << " " << j << " level: " << lvl << "\n";); if (at_base_lvl()) { if (m_config.m_drat) m_drat.add(l, !j.is_none()); j = justification(); // erase justification for level 0 @@ -774,7 +775,7 @@ namespace sat { m_assignment[l.index()] = l_true; m_assignment[(~l).index()] = l_false; bool_var v = l.var(); - m_level[v] = scope_lvl(); + m_level[v] = lvl; m_justification[v] = j; m_phase[v] = static_cast(l.sign()); m_assigned_since_gc[v] = true; @@ -882,7 +883,7 @@ namespace sat { return false; case l_undef: m_stats.m_bin_propagate++; - assign_core(l1, justification(not_l)); + assign_core(l1, scope_lvl(), justification(not_l)); break; case l_true: break; // skip @@ -897,11 +898,11 @@ namespace sat { val2 = value(l2); if (val1 == l_false && val2 == l_undef) { m_stats.m_ter_propagate++; - assign_core(l2, justification(l1, not_l)); + assign_core(l2, scope_lvl(), justification(l1, not_l)); } else if (val1 == l_undef && val2 == l_false) { m_stats.m_ter_propagate++; - assign_core(l1, justification(l2, not_l)); + assign_core(l1, scope_lvl(), justification(l2, not_l)); } else if (val1 == l_false && val2 == l_false) { CONFLICT_CLEANUP(); @@ -964,7 +965,7 @@ namespace sat { it2++; m_stats.m_propagate++; c.mark_used(); - assign_core(c[0], justification(cls_off)); + assign_core(c[0], scope_lvl(), justification(cls_off)); #ifdef UPDATE_GLUE if (update && c.is_learned() && c.glue() > 2) { unsigned glue; @@ -1042,7 +1043,7 @@ namespace sat { literal l(v, false); if (mdl[v] != l_true) l.neg(); push(); - assign_core(l, justification()); + assign_core(l, scope_lvl(), justification()); } mk_model(); break; @@ -1160,13 +1161,16 @@ namespace sat { lbool solver::do_local_search(unsigned num_lits, literal const* lits) { scoped_limits scoped_rl(rlimit()); - local_search srch; + SASSERT(!m_local_search); + m_local_search = alloc(local_search); + local_search& srch = *m_local_search; srch.config().set_config(m_config); srch.import(*this, false); scoped_rl.push_child(&srch.rlimit()); lbool r = srch.check(num_lits, lits, nullptr); m_model = srch.get_model(); - // srch.collect_statistics(m_aux_stats); + m_local_search = nullptr; + dealloc(&srch); return r; } @@ -3379,6 +3383,7 @@ namespace sat { m_asymm_branch.collect_statistics(st); m_probing.collect_statistics(st); if (m_ext) m_ext->collect_statistics(st); + if (m_local_search) m_local_search->collect_statistics(st); st.copy(m_aux_stats); } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index a9a9fcee0..27c2e123c 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -163,6 +163,7 @@ namespace sat { bool m_par_syncing_clauses; class lookahead* m_cuber; + class local_search* m_local_search; statistics m_aux_stats; @@ -305,11 +306,11 @@ namespace sat { TRACE("sat_assign", tout << l << " previous value: " << value(l) << "\n";); switch (value(l)) { case l_false: set_conflict(j, ~l); break; - case l_undef: assign_core(l, j); break; + case l_undef: assign_core(l, scope_lvl(), j); break; case l_true: return; } } - void assign_core(literal l, justification jst); + void assign_core(literal l, unsigned lvl, justification jst); void set_conflict(justification c, literal not_l); void set_conflict(justification c) { set_conflict(c, null_literal); } lbool status(clause const & c) const; diff --git a/src/shell/dimacs_frontend.cpp b/src/shell/dimacs_frontend.cpp index 3a2af72cf..d0fce359f 100644 --- a/src/shell/dimacs_frontend.cpp +++ b/src/shell/dimacs_frontend.cpp @@ -178,21 +178,21 @@ unsigned read_dimacs(char const * file_name) { std::cerr << "(error \"failed to open file '" << file_name << "'\")" << std::endl; exit(ERR_OPEN_FILE); } - parse_dimacs(in, solver); + parse_dimacs(in, *g_solver); } else { - parse_dimacs(std::cin, solver); + parse_dimacs(std::cin, *g_solver); } - IF_VERBOSE(20, solver.display_status(verbose_stream());); + IF_VERBOSE(20, g_solver->display_status(verbose_stream());); lbool r; vector tracking_clauses; - sat::solver solver2(p, limit); - if (p.get_bool("dimacs.core", false)) { - g_solver = &solver2; + sat::solver solver2( p, limit); + if (p.get_bool("dimacs.core", false)) { sat::literal_vector assumptions; track_clauses(solver, solver2, assumptions, tracking_clauses); - r = g_solver->check(assumptions.size(), assumptions.c_ptr()); + g_solver = &solver2; + r = solver2.check(assumptions.size(), assumptions.c_ptr()); } else { r = g_solver->check();