diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 8f92d5bb4..330d0f2bc 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -163,12 +163,46 @@ extern "C" { to_solver_ref(s)->set_model_converter(ctx->get_model_converter()); } + static void solver_from_dimacs_stream(Z3_context c, Z3_solver s, std::istream& is) { + init_solver(c, s); + ast_manager& m = to_solver_ref(s)->get_manager(); + std::stringstream err; + sat::solver solver(to_solver_ref(s)->get_params(), m.limit()); + if (!parse_dimacs(is, err, solver)) { + SET_ERROR_CODE(Z3_PARSER_ERROR, err.str().c_str()); + return; + } + sat2goal s2g; + ref mc; + atom2bool_var a2b(m); + for (unsigned v = 0; v < solver.num_vars(); ++v) { + a2b.insert(m.mk_const(symbol(v), m.mk_bool_sort()), v); + } + goal g(m); + s2g(solver, a2b, to_solver_ref(s)->get_params(), g, mc); + for (unsigned i = 0; i < g.size(); ++i) { + to_solver_ref(s)->assert_expr(g.form(i)); + } + } + + // DIMACS files start with "p cnf" and number of variables/clauses. + // This is not legal SMT syntax, so use the DIMACS parser. + static bool is_dimacs_string(Z3_string c_str) { + std::cout << c_str << "\n"; + return c_str[0] == 'p' && c_str[1] == ' ' && c_str[2] == 'c'; + } + void Z3_API Z3_solver_from_string(Z3_context c, Z3_solver s, Z3_string c_str) { Z3_TRY; LOG_Z3_solver_from_string(c, s, c_str); std::string str(c_str); std::istringstream is(str); - solver_from_stream(c, s, is); + if (is_dimacs_string(c_str)) { + solver_from_dimacs_stream(c, s, is); + } + else { + solver_from_stream(c, s, is); + } Z3_CATCH; } @@ -182,24 +216,7 @@ extern "C" { SET_ERROR_CODE(Z3_FILE_ACCESS_ERROR, nullptr); } else if (ext && (std::string("dimacs") == ext || std::string("cnf") == ext)) { - ast_manager& m = to_solver_ref(s)->get_manager(); - std::stringstream err; - sat::solver solver(to_solver_ref(s)->get_params(), m.limit()); - if (!parse_dimacs(is, err, solver)) { - SET_ERROR_CODE(Z3_PARSER_ERROR, err.str().c_str()); - return; - } - sat2goal s2g; - ref mc; - atom2bool_var a2b(m); - for (unsigned v = 0; v < solver.num_vars(); ++v) { - a2b.insert(m.mk_const(symbol(v), m.mk_bool_sort()), v); - } - goal g(m); - s2g(solver, a2b, to_solver_ref(s)->get_params(), g, mc); - for (unsigned i = 0; i < g.size(); ++i) { - to_solver_ref(s)->assert_expr(g.form(i)); - } + solver_from_dimacs_stream(c, s, is); } else { solver_from_stream(c, s, is); @@ -532,6 +549,17 @@ extern "C" { Z3_CATCH_RETURN(""); } + Z3_string Z3_API Z3_solver_to_dimacs_string(Z3_context c, Z3_solver s) { + Z3_TRY; + LOG_Z3_solver_to_string(c, s); + RESET_ERROR_CODE(); + init_solver(c, s); + std::ostringstream buffer; + to_solver_ref(s)->display_dimacs(buffer); + return mk_c(c)->mk_external_string(buffer.str()); + Z3_CATCH_RETURN(""); + } + Z3_lbool Z3_API Z3_get_implied_equalities(Z3_context c, Z3_solver s, diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index e541080c9..9847e4264 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -2240,6 +2240,8 @@ namespace z3 { fml)); } + std::string dimacs() const { return std::string(Z3_solver_to_dimacs_string(ctx(), m_solver)); } + param_descrs get_param_descrs() { return param_descrs(ctx(), Z3_solver_get_param_descrs(ctx(), m_solver)); } diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 65f634b6b..1886bc475 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -6800,6 +6800,10 @@ class Solver(Z3PPObject): """ return Z3_solver_to_string(self.ctx.ref(), self.solver) + def dimacs(self): + """Return a textual representation of the solver in DIMACS format.""" + return Z3_solver_to_dimacs_string(self.ctx.ref(), self.solver) + def to_smt2(self): """return SMTLIB2 formatted benchmark for solver's assertions""" es = self.assertions() diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 5ee7fcb99..cd52d2d86 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -6368,6 +6368,14 @@ extern "C" { */ Z3_string Z3_API Z3_solver_to_string(Z3_context c, Z3_solver s); + /** + \brief Convert a solver into a DIMACS formatted string. + \sa Z3_goal_to_diamcs_string for requirements. + + def_API('Z3_solver_to_dimacs_string', STRING, (_in(CONTEXT), _in(SOLVER))) + */ + Z3_string Z3_API Z3_solver_to_dimacs_string(Z3_context c, Z3_solver s); + /*@}*/ /** @name Statistics */ diff --git a/src/ast/CMakeLists.txt b/src/ast/CMakeLists.txt index ce2817b58..56ab78b8a 100644 --- a/src/ast/CMakeLists.txt +++ b/src/ast/CMakeLists.txt @@ -17,6 +17,7 @@ z3_add_component(ast csp_decl_plugin.cpp datatype_decl_plugin.cpp decl_collector.cpp + display_dimacs.cpp dl_decl_plugin.cpp expr2polynomial.cpp expr2var.cpp diff --git a/src/ast/display_dimacs.cpp b/src/ast/display_dimacs.cpp new file mode 100644 index 000000000..da39538d9 --- /dev/null +++ b/src/ast/display_dimacs.cpp @@ -0,0 +1,81 @@ +/*++ +Copyright (c) 2019 Microsoft Corporation + +Module Name: + + display_dimacs.h + +Abstract: + + Display expressions in DIMACS format. + +Author: + + Nikolaj Bjorner (nbjorner0 2019-01-24 + +Revision History: + +--*/ + +#include "ast.h" +#include "display_dimacs.h" + +std::ostream& display_dimacs(std::ostream& out, expr_ref_vector const& fmls) { + ast_manager& m = fmls.m(); + unsigned_vector expr2var; + ptr_vector exprs; + unsigned num_vars = 0; + unsigned num_cls = fmls.size(); + for (expr * f : fmls) { + unsigned num_lits; + expr * const * lits; + if (m.is_or(f)) { + num_lits = to_app(f)->get_num_args(); + lits = to_app(f)->get_args(); + } + else { + num_lits = 1; + lits = &f; + } + for (unsigned j = 0; j < num_lits; j++) { + expr * l = lits[j]; + if (m.is_not(l)) + l = to_app(l)->get_arg(0); + if (expr2var.get(l->get_id(), UINT_MAX) == UINT_MAX) { + num_vars++; + expr2var.setx(l->get_id(), num_vars, UINT_MAX); + exprs.setx(l->get_id(), l, nullptr); + } + } + } + out << "p cnf " << num_vars << " " << num_cls << "\n"; + for (expr* f : fmls) { + unsigned num_lits; + expr * const * lits; + if (m.is_or(f)) { + num_lits = to_app(f)->get_num_args(); + lits = to_app(f)->get_args(); + } + else { + num_lits = 1; + lits = &f; + } + for (unsigned j = 0; j < num_lits; j++) { + expr * l = lits[j]; + if (m.is_not(l)) { + out << "-"; + l = to_app(l)->get_arg(0); + } + SASSERT(exprs[l->get_id()]); + out << expr2var[l->get_id()] << " "; + } + out << "0\n"; + } + for (expr* e : exprs) { + if (e && is_app(e)) { + symbol const& n = to_app(e)->get_decl()->get_name(); + out << "c " << expr2var[e->get_id()] << " " << n << "\n"; + } + } + return out; +} diff --git a/src/ast/display_dimacs.h b/src/ast/display_dimacs.h new file mode 100644 index 000000000..91c2386be --- /dev/null +++ b/src/ast/display_dimacs.h @@ -0,0 +1,26 @@ +/*++ +Copyright (c) 2019 Microsoft Corporation + +Module Name: + + display_dimacs.h + +Abstract: + + Display expressions in DIMACS format. + +Author: + + Nikolaj Bjorner (nbjorner0 2019-01-24 + +Revision History: + +--*/ +#ifndef DISPLAY_DIMACS_H_ +#define DISPLAY_DIMACS_H_ + +#include "ast.h" + +std::ostream& display_dimacs(std::ostream& out, expr_ref_vector const& fmls); + +#endif /* DISPLAY_DIMACS_H__ */ diff --git a/src/muz/spacer/spacer_iuc_solver.cpp b/src/muz/spacer/spacer_iuc_solver.cpp index 32f33f773..f28864e27 100644 --- a/src/muz/spacer/spacer_iuc_solver.cpp +++ b/src/muz/spacer/spacer_iuc_solver.cpp @@ -27,443 +27,426 @@ Notes: #include "muz/spacer/spacer_iuc_proof.h" namespace spacer { -void iuc_solver::push () -{ - m_defs.push_back (def_manager (*this)); - m_solver.push (); -} - -void iuc_solver::pop (unsigned n) -{ - m_solver.pop (n); - unsigned lvl = m_defs.size (); - SASSERT (n <= lvl); - unsigned new_lvl = lvl-n; - while (m_defs.size() > new_lvl) { - m_num_proxies -= m_defs.back ().m_defs.size (); - m_defs.pop_back (); + void iuc_solver::push () { + m_defs.push_back (def_manager (*this)); + m_solver.push (); } -} - -app* iuc_solver::fresh_proxy () -{ - if (m_num_proxies == m_proxies.size()) { - std::stringstream name; - name << "spacer_proxy!" << m_proxies.size (); - app_ref res(m); - res = m.mk_const (symbol (name.str ().c_str ()), - m.mk_bool_sort ()); - m_proxies.push_back (res); - - // -- add the new proxy to proxy eliminator - proof_ref pr(m); - pr = m.mk_asserted (m.mk_true ()); - m_elim_proxies_sub.insert (res, m.mk_true (), pr); + void iuc_solver::pop (unsigned n) { + m_solver.pop (n); + unsigned lvl = m_defs.size (); + SASSERT (n <= lvl); + unsigned new_lvl = lvl-n; + while (m_defs.size() > new_lvl) { + m_num_proxies -= m_defs.back ().m_defs.size (); + m_defs.pop_back (); + } } - return m_proxies.get (m_num_proxies++); -} -app* iuc_solver::mk_proxy (expr *v) -{ - { + app* iuc_solver::fresh_proxy () { + if (m_num_proxies == m_proxies.size()) { + std::stringstream name; + name << "spacer_proxy!" << m_proxies.size (); + app_ref res(m); + res = m.mk_const (symbol (name.str ().c_str ()), + m.mk_bool_sort ()); + m_proxies.push_back (res); + + // -- add the new proxy to proxy eliminator + proof_ref pr(m); + pr = m.mk_asserted (m.mk_true ()); + m_elim_proxies_sub.insert (res, m.mk_true (), pr); + + } + return m_proxies.get (m_num_proxies++); + } + + app* iuc_solver::mk_proxy (expr *v) { expr *e = v; m.is_not (v, e); - if (is_uninterp_const(e)) { return to_app(v); } + if (is_uninterp_const(e)) { + return to_app(v); + } + + def_manager &def = !m_defs.empty() ? m_defs.back () : m_base_defs; + return def.mk_proxy (v); } - def_manager &def = !m_defs.empty() ? m_defs.back () : m_base_defs; - return def.mk_proxy (v); -} - -bool iuc_solver::mk_proxies (expr_ref_vector &v, unsigned from) -{ - bool dirty = false; - for (unsigned i = from, sz = v.size(); i < sz; ++i) { - app *p = mk_proxy (v.get (i)); - dirty |= (v.get (i) != p); - v[i] = p; + bool iuc_solver::mk_proxies (expr_ref_vector &v, unsigned from) { + bool dirty = false; + for (unsigned i = from, sz = v.size(); i < sz; ++i) { + app *p = mk_proxy (v.get (i)); + dirty |= (v.get (i) != p); + v[i] = p; + } + return dirty; } - return dirty; -} -void iuc_solver::push_bg (expr *e) -{ - if (m_assumptions.size () > m_first_assumption) - { m_assumptions.shrink(m_first_assumption); } - m_assumptions.push_back (e); - m_first_assumption = m_assumptions.size (); -} - -void iuc_solver::pop_bg (unsigned n) -{ - if (n == 0) { return; } - - if (m_assumptions.size () > m_first_assumption) { + void iuc_solver::push_bg (expr *e) { + if (m_assumptions.size () > m_first_assumption) { + m_assumptions.shrink(m_first_assumption); + } + m_assumptions.push_back (e); + m_first_assumption = m_assumptions.size (); + } + + void iuc_solver::pop_bg (unsigned n) { + if (n == 0) return; + + if (m_assumptions.size () > m_first_assumption) { + m_assumptions.shrink(m_first_assumption); + } + m_first_assumption = m_first_assumption > n ? m_first_assumption - n : 0; + m_assumptions.shrink (m_first_assumption); + } + + unsigned iuc_solver::get_num_bg () { + return m_first_assumption; + } + + lbool iuc_solver::check_sat_core (unsigned num_assumptions, expr * const *assumptions) { + // -- remove any old assumptions m_assumptions.shrink(m_first_assumption); + + // -- replace theory literals in background assumptions with proxies + mk_proxies (m_assumptions); + // -- in case mk_proxies added new literals, they are all background + m_first_assumption = m_assumptions.size (); + + m_assumptions.append (num_assumptions, assumptions); + m_is_proxied = mk_proxies (m_assumptions, m_first_assumption); + + return set_status (m_solver.check_sat (m_assumptions)); } - m_first_assumption = m_first_assumption > n ? m_first_assumption - n : 0; - m_assumptions.shrink (m_first_assumption); -} + + lbool iuc_solver::check_sat_cc(const expr_ref_vector &cube, + vector const & clauses) { + if (clauses.empty()) + return check_sat(cube.size(), cube.c_ptr()); + + // -- remove any old assumptions + m_assumptions.shrink(m_first_assumption); + + // -- replace theory literals in background assumptions with proxies + mk_proxies(m_assumptions); + // -- in case mk_proxies added new literals, they are all background + m_first_assumption = m_assumptions.size(); + + m_assumptions.append(cube); + m_is_proxied = mk_proxies(m_assumptions, m_first_assumption); + + return set_status (m_solver.check_sat_cc(m_assumptions, clauses)); + } + -unsigned iuc_solver::get_num_bg () {return m_first_assumption;} - -lbool iuc_solver::check_sat (unsigned num_assumptions, expr * const *assumptions) -{ - // -- remove any old assumptions - m_assumptions.shrink(m_first_assumption); - - // -- replace theory literals in background assumptions with proxies - mk_proxies (m_assumptions); - // -- in case mk_proxies added new literals, they are all background - m_first_assumption = m_assumptions.size (); - - m_assumptions.append (num_assumptions, assumptions); - m_is_proxied = mk_proxies (m_assumptions, m_first_assumption); - - return set_status (m_solver.check_sat (m_assumptions)); -} - -lbool iuc_solver::check_sat_cc(const expr_ref_vector &cube, - vector const & clauses) { - if (clauses.empty()) - return check_sat(cube.size(), cube.c_ptr()); - - // -- remove any old assumptions - m_assumptions.shrink(m_first_assumption); - - // -- replace theory literals in background assumptions with proxies - mk_proxies(m_assumptions); - // -- in case mk_proxies added new literals, they are all background - m_first_assumption = m_assumptions.size(); - - m_assumptions.append(cube); - m_is_proxied = mk_proxies(m_assumptions, m_first_assumption); - - return set_status (m_solver.check_sat_cc(m_assumptions, clauses)); -} - - -app* iuc_solver::def_manager::mk_proxy (expr *v) -{ - app* r; - if (m_expr2proxy.find(v, r)) - return r; - - ast_manager &m = m_parent.m; - app* proxy = m_parent.fresh_proxy (); - app* def = m.mk_or (m.mk_not (proxy), v); - m_defs.push_back (def); - m_expr2proxy.insert (v, proxy); - m_proxy2def.insert (proxy, def); - - m_parent.assert_expr (def); - return proxy; -} - -bool iuc_solver::def_manager::is_proxy (app *k, app_ref &def) -{ - app *r = nullptr; - bool found = m_proxy2def.find (k, r); - def = r; - return found; -} - -void iuc_solver::def_manager::reset () -{ - m_expr2proxy.reset (); - m_proxy2def.reset (); - m_defs.reset (); -} - -bool iuc_solver::def_manager::is_proxy_def (expr *v) -{ - // XXX This might not be the most robust way to check - return m_defs.contains (v); -} - -bool iuc_solver::is_proxy(expr *e, app_ref &def) -{ - if (!is_uninterp_const(e)) - return false; - - app* a = to_app (e); - - for (int i = m_defs.size (); i-- > 0; ) - if (m_defs[i].is_proxy (a, def)) - return true; - - return m_base_defs.is_proxy (a, def); -} - -void iuc_solver::collect_statistics (statistics &st) const -{ - m_solver.collect_statistics (st); - st.update ("time.iuc_solver.get_iuc", m_iuc_sw.get_seconds()); - st.update ("time.iuc_solver.get_iuc.hyp_reduce1", m_hyp_reduce1_sw.get_seconds()); - st.update ("time.iuc_solver.get_iuc.hyp_reduce2", m_hyp_reduce2_sw.get_seconds()); - st.update ("time.iuc_solver.get_iuc.learn_core", m_learn_core_sw.get_seconds()); - - st.update("iuc_solver.num_proxies", m_proxies.size()); -} - -void iuc_solver::reset_statistics () -{ - m_iuc_sw.reset(); - m_hyp_reduce1_sw.reset(); - m_hyp_reduce2_sw.reset(); - m_learn_core_sw.reset(); -} - -void iuc_solver::get_unsat_core (expr_ref_vector &core) { - m_solver.get_unsat_core (core); - undo_proxies_in_core (core); -} - -void iuc_solver::undo_proxies_in_core (expr_ref_vector &r) -{ - app_ref e(m); - expr_fast_mark1 bg; - for (unsigned i = 0; i < m_first_assumption; ++i) { - bg.mark(m_assumptions.get(i)); + app* iuc_solver::def_manager::mk_proxy (expr *v) { + app* r; + if (m_expr2proxy.find(v, r)) + return r; + + ast_manager &m = m_parent.m; + app* proxy = m_parent.fresh_proxy (); + app* def = m.mk_or (m.mk_not (proxy), v); + m_defs.push_back (def); + m_expr2proxy.insert (v, proxy); + m_proxy2def.insert (proxy, def); + + m_parent.assert_expr (def); + return proxy; } - // expand proxies - unsigned j = 0; - for (expr* rr : r) { - // skip background assumptions - if (bg.is_marked(rr)) - continue; + bool iuc_solver::def_manager::is_proxy (app *k, app_ref &def) { + app *r = nullptr; + bool found = m_proxy2def.find (k, r); + def = r; + return found; + } + + void iuc_solver::def_manager::reset () { + m_expr2proxy.reset (); + m_proxy2def.reset (); + m_defs.reset (); + } - // -- undo proxies, but only if they were introduced in check_sat - if (m_is_proxied && is_proxy(rr, e)) { - SASSERT (m.is_or (e)); - r[j++] = e->get_arg (1); + bool iuc_solver::def_manager::is_proxy_def (expr *v) { + // XXX This might not be the most robust way to check + return m_defs.contains (v); + } + + bool iuc_solver::is_proxy(expr *e, app_ref &def) { + if (!is_uninterp_const(e)) + return false; + + app* a = to_app (e); + + for (int i = m_defs.size (); i-- > 0; ) + if (m_defs[i].is_proxy (a, def)) + return true; + + return m_base_defs.is_proxy (a, def); + } + + void iuc_solver::collect_statistics (statistics &st) const { + m_solver.collect_statistics (st); + st.update ("time.iuc_solver.get_iuc", m_iuc_sw.get_seconds()); + st.update ("time.iuc_solver.get_iuc.hyp_reduce1", m_hyp_reduce1_sw.get_seconds()); + st.update ("time.iuc_solver.get_iuc.hyp_reduce2", m_hyp_reduce2_sw.get_seconds()); + st.update ("time.iuc_solver.get_iuc.learn_core", m_learn_core_sw.get_seconds()); + + st.update("iuc_solver.num_proxies", m_proxies.size()); + } + + void iuc_solver::reset_statistics () { + m_iuc_sw.reset(); + m_hyp_reduce1_sw.reset(); + m_hyp_reduce2_sw.reset(); + m_learn_core_sw.reset(); + } + + void iuc_solver::get_unsat_core (expr_ref_vector &core) { + m_solver.get_unsat_core (core); + undo_proxies_in_core (core); + } + + void iuc_solver::undo_proxies_in_core (expr_ref_vector &r) { + app_ref e(m); + expr_fast_mark1 bg; + for (unsigned i = 0; i < m_first_assumption; ++i) { + bg.mark(m_assumptions.get(i)); + } + + // expand proxies + unsigned j = 0; + for (expr* rr : r) { + // skip background assumptions + if (bg.is_marked(rr)) + continue; + + // -- undo proxies, but only if they were introduced in check_sat + if (m_is_proxied && is_proxy(rr, e)) { + SASSERT (m.is_or (e)); + r[j++] = e->get_arg (1); + } + else { + r[j++] = rr; + } + } + r.shrink (j); + } + + void iuc_solver::undo_proxies (expr_ref_vector &r) { + app_ref e(m); + // expand proxies + for (unsigned i = 0, sz = r.size (); i < sz; ++i) + if (is_proxy(r.get(i), e)) { + SASSERT (m.is_or (e)); + r[i] = e->get_arg (1); + } + } + + void iuc_solver::elim_proxies (expr_ref_vector &v) { + expr_ref f = mk_and (v); + scoped_ptr rep = mk_expr_simp_replacer (m); + rep->set_substitution (&m_elim_proxies_sub); + (*rep)(f); + v.reset(); + flatten_and(f, v); + } + + void iuc_solver::get_iuc(expr_ref_vector &core) { + scoped_watch _t_ (m_iuc_sw); + + typedef obj_hashtable expr_set; + expr_set core_lits; + for (unsigned i = m_first_assumption, sz = m_assumptions.size(); i < sz; ++i) { + expr *a = m_assumptions.get (i); + app_ref def(m); + if (is_proxy(a, def)) { core_lits.insert(def.get()); } + core_lits.insert (a); + } + + if (m_iuc == 0) { + // ORIGINAL PDR CODE + // AG: deprecated + proof_ref pr(m); + pr = get_proof (); + + farkas_learner learner_old; + learner_old.set_split_literals(m_split_literals); + + learner_old.get_lemmas (pr, core_lits, core); + elim_proxies (core); + simplify_bounds (core); // XXX potentially redundant } else { - r[j++] = rr; - } - } - r.shrink (j); -} - -void iuc_solver::undo_proxies (expr_ref_vector &r) -{ - app_ref e(m); - // expand proxies - for (unsigned i = 0, sz = r.size (); i < sz; ++i) - if (is_proxy(r.get(i), e)) { - SASSERT (m.is_or (e)); - r[i] = e->get_arg (1); - } -} - -void iuc_solver::elim_proxies (expr_ref_vector &v) -{ - expr_ref f = mk_and (v); - scoped_ptr rep = mk_expr_simp_replacer (m); - rep->set_substitution (&m_elim_proxies_sub); - (*rep)(f); - v.reset(); - flatten_and(f, v); -} - -void iuc_solver::get_iuc(expr_ref_vector &core) -{ - scoped_watch _t_ (m_iuc_sw); - - typedef obj_hashtable expr_set; - expr_set core_lits; - for (unsigned i = m_first_assumption, sz = m_assumptions.size(); i < sz; ++i) { - expr *a = m_assumptions.get (i); - app_ref def(m); - if (is_proxy(a, def)) { core_lits.insert(def.get()); } - core_lits.insert (a); - } - - if (m_iuc == 0) { - // ORIGINAL PDR CODE - // AG: deprecated - proof_ref pr(m); - pr = get_proof (); - - farkas_learner learner_old; - learner_old.set_split_literals(m_split_literals); - - learner_old.get_lemmas (pr, core_lits, core); - elim_proxies (core); - simplify_bounds (core); // XXX potentially redundant - } - else { - // NEW IUC - proof_ref res(get_proof(), m); - - // -- old hypothesis reducer while the new one is broken - if (m_old_hyp_reducer) { - scoped_watch _t_ (m_hyp_reduce1_sw); - // AG: deprecated - // pre-process proof in order to get a proof which is - // better suited for unsat-core-extraction - if (m_print_farkas_stats) { - iuc_proof iuc_before(m, res.get(), core_lits); - verbose_stream() << "\nOld reduce_hypotheses. Before:"; - iuc_before.dump_farkas_stats(); + // NEW IUC + proof_ref res(get_proof(), m); + + // -- old hypothesis reducer while the new one is broken + if (m_old_hyp_reducer) { + scoped_watch _t_ (m_hyp_reduce1_sw); + // AG: deprecated + // pre-process proof in order to get a proof which is + // better suited for unsat-core-extraction + if (m_print_farkas_stats) { + iuc_proof iuc_before(m, res.get(), core_lits); + verbose_stream() << "\nOld reduce_hypotheses. Before:"; + iuc_before.dump_farkas_stats(); + } + + proof_utils::reduce_hypotheses(res); + proof_utils::permute_unit_resolution(res); + + if (m_print_farkas_stats) { + iuc_proof iuc_after(m, res.get(), core_lits); + verbose_stream() << "Old reduce_hypothesis. After:"; + iuc_after.dump_farkas_stats(); + } } - - proof_utils::reduce_hypotheses(res); - proof_utils::permute_unit_resolution(res); - - if (m_print_farkas_stats) { - iuc_proof iuc_after(m, res.get(), core_lits); - verbose_stream() << "Old reduce_hypothesis. After:"; - iuc_after.dump_farkas_stats(); - } - } - // -- new hypothesis reducer - else - { + // -- new hypothesis reducer + else + { #if 0 - static unsigned bcnt = 0; + static unsigned bcnt = 0; + { + bcnt++; + TRACE("spacer", tout << "Dumping pf bcnt: " << bcnt << "\n";); + if (bcnt == 123) { + std::ofstream ofs; + ofs.open("/tmp/bpf_" + std::to_string(bcnt) + ".dot"); + iuc_proof iuc_pf_before(m, res.get(), core_lits); + iuc_pf_before.display_dot(ofs); + ofs.close(); + + proof_checker pc(m); + expr_ref_vector side(m); + ENSURE(pc.check(res, side)); + } + } +#endif + scoped_watch _t_ (m_hyp_reduce2_sw); + + // pre-process proof for better iuc extraction + if (m_print_farkas_stats) { + iuc_proof iuc_before(m, res.get(), core_lits); + verbose_stream() << "\n New hypothesis_reducer. Before:"; + iuc_before.dump_farkas_stats(); + } + + proof_ref pr1(m); + { + scoped_watch _t_ (m_hyp_reduce1_sw); + theory_axiom_reducer ta_reducer(m); + pr1 = ta_reducer.reduce (res.get()); + } + + proof_ref pr2(m); + { + scoped_watch _t_ (m_hyp_reduce2_sw); + hypothesis_reducer hyp_reducer(m); + pr2 = hyp_reducer.reduce(pr1); + } + + res = pr2; + + if (m_print_farkas_stats) { + iuc_proof iuc_after(m, res.get(), core_lits); + verbose_stream() << "New hypothesis_reducer. After:"; + iuc_after.dump_farkas_stats(); + } + } + + iuc_proof iuc_pf(m, res, core_lits); + +#if 0 + static unsigned cnt = 0; { - bcnt++; - TRACE("spacer", tout << "Dumping pf bcnt: " << bcnt << "\n";); - if (bcnt == 123) { + cnt++; + TRACE("spacer", tout << "Dumping pf cnt: " << cnt << "\n";); + if (cnt == 123) { std::ofstream ofs; - ofs.open("/tmp/bpf_" + std::to_string(bcnt) + ".dot"); - iuc_proof iuc_pf_before(m, res.get(), core_lits); - iuc_pf_before.display_dot(ofs); + ofs.open("/tmp/pf_" + std::to_string(cnt) + ".dot"); + iuc_pf.display_dot(ofs); ofs.close(); - proof_checker pc(m); expr_ref_vector side(m); ENSURE(pc.check(res, side)); } } #endif - scoped_watch _t_ (m_hyp_reduce2_sw); - - // pre-process proof for better iuc extraction - if (m_print_farkas_stats) { - iuc_proof iuc_before(m, res.get(), core_lits); - verbose_stream() << "\n New hypothesis_reducer. Before:"; - iuc_before.dump_farkas_stats(); + unsat_core_learner learner(m, iuc_pf); + + unsat_core_plugin* plugin; + // -- register iuc plugins + switch (m_iuc_arith) { + case 0: + case 1: + plugin = + alloc(unsat_core_plugin_farkas_lemma, + learner, m_split_literals, + (m_iuc_arith == 1) /* use constants from A */); + learner.register_plugin(plugin); + break; + case 2: + SASSERT(false && "Broken"); + plugin = alloc(unsat_core_plugin_farkas_lemma_optimized, learner, m); + learner.register_plugin(plugin); + break; + case 3: + plugin = alloc(unsat_core_plugin_farkas_lemma_bounded, learner, m); + learner.register_plugin(plugin); + break; + default: + UNREACHABLE(); + break; } - - proof_ref pr1(m); + + switch (m_iuc) { + case 1: + // -- iuc based on the lowest cut in the proof + plugin = alloc(unsat_core_plugin_lemma, learner); + learner.register_plugin(plugin); + break; + case 2: + // -- iuc based on the smallest cut in the proof + plugin = alloc(unsat_core_plugin_min_cut, learner, m); + learner.register_plugin(plugin); + break; + default: + UNREACHABLE(); + break; + } + { - scoped_watch _t_ (m_hyp_reduce1_sw); - theory_axiom_reducer ta_reducer(m); - pr1 = ta_reducer.reduce (res.get()); - } - - proof_ref pr2(m); - { - scoped_watch _t_ (m_hyp_reduce2_sw); - hypothesis_reducer hyp_reducer(m); - pr2 = hyp_reducer.reduce(pr1); - } - - res = pr2; - - if (m_print_farkas_stats) { - iuc_proof iuc_after(m, res.get(), core_lits); - verbose_stream() << "New hypothesis_reducer. After:"; - iuc_after.dump_farkas_stats(); + scoped_watch _t_ (m_learn_core_sw); + // compute interpolating unsat core + learner.compute_unsat_core(core); } + + elim_proxies (core); + // AG: this should be taken care of by minimizing the iuc cut + simplify_bounds (core); } - - iuc_proof iuc_pf(m, res, core_lits); - -#if 0 - static unsigned cnt = 0; - { - cnt++; - TRACE("spacer", tout << "Dumping pf cnt: " << cnt << "\n";); - if (cnt == 123) { - std::ofstream ofs; - ofs.open("/tmp/pf_" + std::to_string(cnt) + ".dot"); - iuc_pf.display_dot(ofs); - ofs.close(); - proof_checker pc(m); - expr_ref_vector side(m); - ENSURE(pc.check(res, side)); - } - } -#endif - unsat_core_learner learner(m, iuc_pf); - - unsat_core_plugin* plugin; - // -- register iuc plugins - switch (m_iuc_arith) { - case 0: - case 1: - plugin = - alloc(unsat_core_plugin_farkas_lemma, - learner, m_split_literals, - (m_iuc_arith == 1) /* use constants from A */); - learner.register_plugin(plugin); - break; - case 2: - SASSERT(false && "Broken"); - plugin = alloc(unsat_core_plugin_farkas_lemma_optimized, learner, m); - learner.register_plugin(plugin); - break; - case 3: - plugin = alloc(unsat_core_plugin_farkas_lemma_bounded, learner, m); - learner.register_plugin(plugin); - break; - default: - UNREACHABLE(); - break; - } - - switch (m_iuc) { - case 1: - // -- iuc based on the lowest cut in the proof - plugin = alloc(unsat_core_plugin_lemma, learner); - learner.register_plugin(plugin); - break; - case 2: - // -- iuc based on the smallest cut in the proof - plugin = alloc(unsat_core_plugin_min_cut, learner, m); - learner.register_plugin(plugin); - break; - default: - UNREACHABLE(); - break; - } - - { - scoped_watch _t_ (m_learn_core_sw); - // compute interpolating unsat core - learner.compute_unsat_core(core); - } - - elim_proxies (core); - // AG: this should be taken care of by minimizing the iuc cut - simplify_bounds (core); + + IF_VERBOSE(2, + verbose_stream () << "IUC Core:\n" << core << "\n";); } - - IF_VERBOSE(2, - verbose_stream () << "IUC Core:\n" << core << "\n";); -} - -void iuc_solver::refresh () -{ - // only refresh in non-pushed state - SASSERT (m_defs.empty()); - expr_ref_vector assertions (m); - for (unsigned i = 0, e = m_solver.get_num_assertions(); i < e; ++i) { - expr* a = m_solver.get_assertion (i); - if (!m_base_defs.is_proxy_def(a)) { assertions.push_back(a); } - + + void iuc_solver::refresh () { + // only refresh in non-pushed state + SASSERT (m_defs.empty()); + expr_ref_vector assertions (m); + for (unsigned i = 0, e = m_solver.get_num_assertions(); i < e; ++i) { + expr* a = m_solver.get_assertion (i); + if (!m_base_defs.is_proxy_def(a)) { assertions.push_back(a); } + + } + m_base_defs.reset (); + NOT_IMPLEMENTED_YET (); + // solver interface does not have a reset method. need to introduce it somewhere. + // m_solver.reset (); + for (unsigned i = 0, e = assertions.size (); i < e; ++i) + { m_solver.assert_expr(assertions.get(i)); } } - m_base_defs.reset (); - NOT_IMPLEMENTED_YET (); - // solver interface does not have a reset method. need to introduce it somewhere. - // m_solver.reset (); - for (unsigned i = 0, e = assertions.size (); i < e; ++i) - { m_solver.assert_expr(assertions.get(i)); } -} - + } diff --git a/src/muz/spacer/spacer_iuc_solver.h b/src/muz/spacer/spacer_iuc_solver.h index c0a0072ed..a51bfbef9 100644 --- a/src/muz/spacer/spacer_iuc_solver.h +++ b/src/muz/spacer/spacer_iuc_solver.h @@ -127,7 +127,7 @@ public: void pop(unsigned n) override; unsigned get_scope_level() const override { return m_solver.get_scope_level(); } - lbool check_sat(unsigned num_assumptions, expr * const *assumptions) override; + lbool check_sat_core(unsigned num_assumptions, expr * const *assumptions) override; lbool check_sat_cc(const expr_ref_vector &cube, vector const & clauses) override; void set_progress_callback(progress_callback *callback) override { m_solver.set_progress_callback(callback); diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index e61a02d80..78851f5cb 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -158,7 +158,7 @@ namespace opt { return m_dump_benchmarks; } - lbool opt_solver::check_sat_core(unsigned num_assumptions, expr * const * assumptions) { + lbool opt_solver::check_sat_core2(unsigned num_assumptions, expr * const * assumptions) { TRACE("opt_verbose", { tout << "context size: " << m_context.size() << "\n"; for (unsigned i = 0; i < m_context.size(); ++i) { diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 39562ec54..8d2abdb93 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -95,7 +95,7 @@ namespace opt { void assert_expr_core(expr * t) override; void push_core() override; void pop_core(unsigned n) override; - lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) override; + lbool check_sat_core2(unsigned num_assumptions, expr * const * assumptions) override; void get_unsat_core(expr_ref_vector & r) override; void get_model_core(model_ref & _m) override; proof * get_proof() override; diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 8823c40c5..34348f0fc 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -166,7 +166,7 @@ public: (m.is_not(e, e) && is_uninterp_const(e)); } - lbool check_sat(unsigned sz, expr * const * assumptions) override { + lbool check_sat_core(unsigned sz, expr * const * assumptions) override { m_solver.pop_to_base_level(); m_core.reset(); if (m_solver.inconsistent()) return l_false; diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 48f6053fc..5d32d1bed 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -185,7 +185,7 @@ namespace smt { m_context.pop(n); } - lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) override { + lbool check_sat_core2(unsigned num_assumptions, expr * const * assumptions) override { TRACE("solver_na2as", tout << "smt_solver::check_sat_core: " << num_assumptions << "\n";); return m_context.check(num_assumptions, assumptions); } diff --git a/src/solver/CMakeLists.txt b/src/solver/CMakeLists.txt index c8e206f7f..281a34018 100644 --- a/src/solver/CMakeLists.txt +++ b/src/solver/CMakeLists.txt @@ -16,5 +16,7 @@ z3_add_component(solver PYG_FILES combined_solver_params.pyg parallel_params.pyg + PYG_FILES + solver_params.pyg ) diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index e8fb34815..813b2be18 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -218,7 +218,7 @@ public: return l_undef; } - lbool check_sat(unsigned num_assumptions, expr * const * assumptions) override { + lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) override { m_check_sat_executed = true; m_use_solver1_results = false; @@ -227,13 +227,13 @@ public: m_ignore_solver1) { // must use incremental solver switch_inc_mode(); - return m_solver2->check_sat(num_assumptions, assumptions); + return m_solver2->check_sat_core(num_assumptions, assumptions); } if (m_inc_mode) { if (m_inc_timeout == UINT_MAX) { IF_VERBOSE(PS_VB_LVL, verbose_stream() << "(combined-solver \"using solver 2 (without a timeout)\")\n";); - lbool r = m_solver2->check_sat(num_assumptions, assumptions); + lbool r = m_solver2->check_sat_core(num_assumptions, assumptions); if (r != l_undef || !use_solver1_when_undef() || get_manager().canceled()) { return r; } @@ -244,7 +244,7 @@ public: lbool r = l_undef; try { scoped_timer timer(m_inc_timeout, &eh); - r = m_solver2->check_sat(num_assumptions, assumptions); + r = m_solver2->check_sat_core(num_assumptions, assumptions); } catch (z3_exception&) { if (!eh.m_canceled) { @@ -260,7 +260,7 @@ public: IF_VERBOSE(PS_VB_LVL, verbose_stream() << "(combined-solver \"using solver 1\")\n";); m_use_solver1_results = true; - return m_solver1->check_sat(num_assumptions, assumptions); + return m_solver1->check_sat_core(num_assumptions, assumptions); } void set_progress_callback(progress_callback * callback) override { diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index f3c533704..6f4880d38 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -3,7 +3,7 @@ Copyright (c) 2011 Microsoft Corporation Module Name: - solver.h + solver.cpp Abstract: @@ -21,25 +21,25 @@ Notes: #include "ast/ast_util.h" #include "ast/ast_pp.h" #include "ast/ast_pp_util.h" +#include "ast/display_dimacs.h" #include "tactic/model_converter.h" #include "solver/solver.h" +#include "solver/solver_params.hpp" #include "model/model_evaluator.h" unsigned solver::get_num_assertions() const { - NOT_IMPLEMENTED_YET(); + UNREACHABLE(); return 0; } expr * solver::get_assertion(unsigned idx) const { - NOT_IMPLEMENTED_YET(); + UNREACHABLE(); return nullptr; } std::ostream& solver::display(std::ostream & out, unsigned n, expr* const* assumptions) const { expr_ref_vector fmls(get_manager()); - stopwatch sw; - sw.start(); get_assertions(fmls); ast_pp_util visitor(get_manager()); model_converter_ref mc = get_model_converter(); @@ -57,6 +57,12 @@ std::ostream& solver::display(std::ostream & out, unsigned n, expr* const* assum return out; } +std::ostream& solver::display_dimacs(std::ostream& out) const { + expr_ref_vector fmls(get_manager()); + get_assertions(fmls); + return ::display_dimacs(out, fmls); +} + void solver::get_assertions(expr_ref_vector& fmls) const { unsigned sz = get_num_assertions(); for (unsigned i = 0; i < sz; ++i) { @@ -232,12 +238,16 @@ void solver::collect_param_descrs(param_descrs & r) { void solver::reset_params(params_ref const & p) { m_params = p; - m_enforce_model_conversion = m_params.get_bool("solver.enforce_model_conversion", false); + solver_params sp(m_params); + m_enforce_model_conversion = sp.enforce_model_conversion(); + m_cancel_backup_file = sp.cancel_backup_file(); } void solver::updt_params(params_ref const & p) { m_params.copy(p); - m_enforce_model_conversion = m_params.get_bool("solver.enforce_model_conversion", false); + solver_params sp(m_params); + m_enforce_model_conversion = sp.enforce_model_conversion(); + m_cancel_backup_file = sp.cancel_backup_file(); } @@ -309,3 +319,28 @@ expr_ref_vector solver::get_non_units(ast_manager& m) { } return result; } + +lbool solver::check_sat(unsigned num_assumptions, expr * const * assumptions) { + lbool r = l_undef; + try { + r = check_sat_core(num_assumptions, assumptions); + } + catch (...) { + if (get_manager().canceled()) { + dump_state(num_assumptions, assumptions); + } + throw; + } + if (r == l_undef && get_manager().canceled()) { + dump_state(num_assumptions, assumptions); + } + return r; +} + +void solver::dump_state(unsigned sz, expr* const* assumptions) { + std::string file = m_cancel_backup_file.str(); + if (file != "") { + std::ofstream ous(file); + display(ous, sz, assumptions); + } +} diff --git a/src/solver/solver.h b/src/solver/solver.h index 7437a5a08..161677cb5 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -44,8 +44,9 @@ public: - results based on check_sat_result API */ class solver : public check_sat_result { - params_ref m_params; - bool m_enforce_model_conversion; + params_ref m_params; + bool m_enforce_model_conversion; + symbol m_cancel_backup_file; public: solver(): m_enforce_model_conversion(false) {} ~solver() override {} @@ -140,7 +141,8 @@ public: If it is unsatisfiable, and unsat-core generation is enabled. Then, the unsat-core is a subset of these assumptions. */ - virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions) = 0; + + lbool check_sat(unsigned num_assumptions, expr * const * assumptions); lbool check_sat(expr_ref_vector const& asms) { return check_sat(asms.size(), asms.c_ptr()); } @@ -227,6 +229,11 @@ public: */ virtual std::ostream& display(std::ostream & out, unsigned n = 0, expr* const* assumptions = nullptr) const; + /** + \brief Display the content of this solver in DIMACS format + */ + std::ostream& display_dimacs(std::ostream & out) const; + /** \brief expose model converter when solver produces partially reduced set of assertions. */ @@ -249,14 +256,17 @@ public: void disable_pop() { m_nopop = true; } }; + virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) = 0; protected: virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences); + void dump_state(unsigned sz, expr* const* assumptions); bool is_literal(ast_manager& m, expr* e); + }; typedef ref solver_ref; diff --git a/src/solver/solver_na2as.cpp b/src/solver/solver_na2as.cpp index a3fcd0e0b..6173dfddf 100644 --- a/src/solver/solver_na2as.cpp +++ b/src/solver/solver_na2as.cpp @@ -61,10 +61,10 @@ struct append_assumptions { } }; -lbool solver_na2as::check_sat(unsigned num_assumptions, expr * const * assumptions) { +lbool solver_na2as::check_sat_core(unsigned num_assumptions, expr * const * assumptions) { append_assumptions app(m_assumptions, num_assumptions, assumptions); TRACE("solver_na2as", display(tout);); - return check_sat_core(m_assumptions.size(), m_assumptions.c_ptr()); + return check_sat_core2(m_assumptions.size(), m_assumptions.c_ptr()); } lbool solver_na2as::check_sat_cc(const expr_ref_vector &assumptions, vector const &clauses) { diff --git a/src/solver/solver_na2as.h b/src/solver/solver_na2as.h index d1515a206..67ec004cc 100644 --- a/src/solver/solver_na2as.h +++ b/src/solver/solver_na2as.h @@ -35,10 +35,9 @@ public: ~solver_na2as() override; void assert_expr_core2(expr * t, expr * a) override; - // virtual void assert_expr_core(expr * t) = 0; // Subclasses of solver_na2as should redefine the following *_core methods instead of these ones. - lbool check_sat(unsigned num_assumptions, expr * const * assumptions) override; + lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) override; lbool check_sat_cc(const expr_ref_vector &assumptions, vector const &clauses) override; void push() override; void pop(unsigned n) override; @@ -49,7 +48,7 @@ public: lbool get_consequences(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) override; lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) override; protected: - virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) = 0; + virtual lbool check_sat_core2(unsigned num_assumptions, expr * const * assumptions) = 0; virtual lbool check_sat_cc_core(const expr_ref_vector &assumptions, vector const &clauses) { NOT_IMPLEMENTED_YET(); } virtual void push_core() = 0; virtual void pop_core(unsigned n) = 0; diff --git a/src/solver/solver_params.pyg b/src/solver/solver_params.pyg new file mode 100644 index 000000000..29690a164 --- /dev/null +++ b/src/solver/solver_params.pyg @@ -0,0 +1,8 @@ + +def_module_params('solver', + description='solver parameters', + export=True, + params=(('enforce_model_conversion', BOOL, False, "apply model transformation on new assertions"), + ('cancel_backup_file', SYMBOL, '', "file to save partial search state if search is canceled"), + )) + diff --git a/src/solver/solver_pool.cpp b/src/solver/solver_pool.cpp index 598bb6c02..0495e8a3d 100644 --- a/src/solver/solver_pool.cpp +++ b/src/solver/solver_pool.cpp @@ -119,7 +119,7 @@ public: } } - lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) override { + lbool check_sat_core2(unsigned num_assumptions, expr * const * assumptions) override { SASSERT(!m_pushed || get_scope_level() > 0); m_proof.reset(); scoped_watch _t_(m_pool.m_check_watch); diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index 492ddd443..298ed9bc5 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -62,7 +62,7 @@ public: void push_core() override; void pop_core(unsigned n) override; - lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) override; + lbool check_sat_core2(unsigned num_assumptions, expr * const * assumptions) override; void collect_statistics(statistics & st) const override; void get_unsat_core(expr_ref_vector & r) override; @@ -136,7 +136,7 @@ void tactic2solver::pop_core(unsigned n) { m_result = nullptr; } -lbool tactic2solver::check_sat_core(unsigned num_assumptions, expr * const * assumptions) { +lbool tactic2solver::check_sat_core2(unsigned num_assumptions, expr * const * assumptions) { if (m_tactic.get() == nullptr) return l_false; ast_manager & m = m_assertions.m(); diff --git a/src/tactic/fd_solver/bounded_int2bv_solver.cpp b/src/tactic/fd_solver/bounded_int2bv_solver.cpp index 8791a6282..45d1344ba 100644 --- a/src/tactic/fd_solver/bounded_int2bv_solver.cpp +++ b/src/tactic/fd_solver/bounded_int2bv_solver.cpp @@ -137,9 +137,9 @@ public: } } - lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) override { + lbool check_sat_core2(unsigned num_assumptions, expr * const * assumptions) override { flush_assertions(); - return m_solver->check_sat(num_assumptions, assumptions); + return m_solver->check_sat_core(num_assumptions, assumptions); } void updt_params(params_ref const & p) override { solver::updt_params(p); m_solver->updt_params(p); } diff --git a/src/tactic/fd_solver/enum2bv_solver.cpp b/src/tactic/fd_solver/enum2bv_solver.cpp index 185f23d13..b9a564542 100644 --- a/src/tactic/fd_solver/enum2bv_solver.cpp +++ b/src/tactic/fd_solver/enum2bv_solver.cpp @@ -78,9 +78,9 @@ public: m_rewriter.pop(n); } - lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) override { + lbool check_sat_core2(unsigned num_assumptions, expr * const * assumptions) override { m_solver->updt_params(get_params()); - return m_solver->check_sat(num_assumptions, assumptions); + return m_solver->check_sat_core(num_assumptions, assumptions); } void updt_params(params_ref const & p) override { solver::updt_params(p); m_solver->updt_params(p); } diff --git a/src/tactic/fd_solver/pb2bv_solver.cpp b/src/tactic/fd_solver/pb2bv_solver.cpp index fd4fb8e73..b3620c8ec 100644 --- a/src/tactic/fd_solver/pb2bv_solver.cpp +++ b/src/tactic/fd_solver/pb2bv_solver.cpp @@ -75,9 +75,9 @@ public: m_rewriter.pop(n); } - lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) override { + lbool check_sat_core2(unsigned num_assumptions, expr * const * assumptions) override { flush_assertions(); - return m_solver->check_sat(num_assumptions, assumptions); + return m_solver->check_sat_core(num_assumptions, assumptions); } void updt_params(params_ref const & p) override { solver::updt_params(p); m_rewriter.updt_params(p); m_solver->updt_params(p); } diff --git a/src/tactic/goal.cpp b/src/tactic/goal.cpp index 8f8b86a65..c2d93fa2a 100644 --- a/src/tactic/goal.cpp +++ b/src/tactic/goal.cpp @@ -20,6 +20,7 @@ Revision History: #include "ast/ast_smt2_pp.h" #include "ast/for_each_expr.h" #include "ast/well_sorted.h" +#include "ast/display_dimacs.h" #include "tactic/goal.h" goal::precision goal::mk_union(precision p1, precision p2) { @@ -262,14 +263,14 @@ void goal::assert_expr(expr * f, expr_dependency * d) { assert_expr(f, proofs_enabled() ? m().mk_asserted(f) : nullptr, d); } -void goal::get_formulas(ptr_vector & result) { +void goal::get_formulas(ptr_vector & result) const { unsigned sz = size(); for (unsigned i = 0; i < sz; i++) { result.push_back(form(i)); } } -void goal::get_formulas(expr_ref_vector & result) { +void goal::get_formulas(expr_ref_vector & result) const { unsigned sz = size(); for (unsigned i = 0; i < sz; i++) { result.push_back(form(i)); @@ -434,63 +435,9 @@ void goal::display_ll(std::ostream & out) const { \brief Assumes that the formula is already in CNF. */ void goal::display_dimacs(std::ostream & out) const { - unsigned_vector expr2var; - ptr_vector exprs; - unsigned num_vars = 0; - unsigned num_cls = size(); - for (unsigned i = 0; i < num_cls; i++) { - expr * f = form(i); - unsigned num_lits; - expr * const * lits; - if (m().is_or(f)) { - num_lits = to_app(f)->get_num_args(); - lits = to_app(f)->get_args(); - } - else { - num_lits = 1; - lits = &f; - } - for (unsigned j = 0; j < num_lits; j++) { - expr * l = lits[j]; - if (m().is_not(l)) - l = to_app(l)->get_arg(0); - if (expr2var.get(l->get_id(), UINT_MAX) == UINT_MAX) { - num_vars++; - expr2var.setx(l->get_id(), num_vars, UINT_MAX); - exprs.setx(l->get_id(), l, nullptr); - } - } - } - out << "p cnf " << num_vars << " " << num_cls << "\n"; - for (unsigned i = 0; i < num_cls; i++) { - expr * f = form(i); - unsigned num_lits; - expr * const * lits; - if (m().is_or(f)) { - num_lits = to_app(f)->get_num_args(); - lits = to_app(f)->get_args(); - } - else { - num_lits = 1; - lits = &f; - } - for (unsigned j = 0; j < num_lits; j++) { - expr * l = lits[j]; - if (m().is_not(l)) { - out << "-"; - l = to_app(l)->get_arg(0); - } - SASSERT(exprs[l->get_id()]); - out << expr2var[l->get_id()] << " "; - } - out << "0\n"; - } - for (expr* e : exprs) { - if (e && is_app(e)) { - symbol const& n = to_app(e)->get_decl()->get_name(); - out << "c " << expr2var[e->get_id()] << " " << n << "\n"; - } - } + expr_ref_vector fmls(m()); + get_formulas(fmls); + ::display_dimacs(out, fmls); } unsigned goal::num_exprs() const { diff --git a/src/tactic/goal.h b/src/tactic/goal.h index fa2f16eb6..33f9298ab 100644 --- a/src/tactic/goal.h +++ b/src/tactic/goal.h @@ -126,8 +126,8 @@ public: void update(unsigned i, expr * f, proof * pr = nullptr, expr_dependency * dep = nullptr); - void get_formulas(ptr_vector & result); - void get_formulas(expr_ref_vector & result); + void get_formulas(ptr_vector & result) const; + void get_formulas(expr_ref_vector & result) const; void elim_true(); void elim_redundancies(); diff --git a/src/util/chashtable.h b/src/util/chashtable.h index e49ac3bd4..19ff1ef51 100644 --- a/src/util/chashtable.h +++ b/src/util/chashtable.h @@ -32,6 +32,7 @@ Revision History: #include "util/debug.h" #include "util/trace.h" #include "util/tptr.h" +#include "util/util.h" #ifdef Z3DEBUG #include "util/hashtable.h" #endif