diff --git a/src/api/api_parsers.cpp b/src/api/api_parsers.cpp index 2d5c3d0c4..b6d18096f 100644 --- a/src/api/api_parsers.cpp +++ b/src/api/api_parsers.cpp @@ -23,6 +23,7 @@ Revision History: #include"cmd_context.h" #include"smt2parser.h" #include"smtparser.h" +#include"solver_na2as.h" extern "C" { @@ -251,20 +252,19 @@ extern "C" { // --------------- // Support for SMTLIB2 - class z3_context_solver : public solver { + class z3_context_solver : public solver_na2as { api::context & m_ctx; smt::kernel & ctx() const { return m_ctx.get_smt_kernel(); } public: virtual ~z3_context_solver() {} z3_context_solver(api::context& c) : m_ctx(c) {} - virtual void init(ast_manager & m, symbol const & logic) {} + virtual void init_core(ast_manager & m, symbol const & logic) {} virtual void collect_statistics(statistics & st) const {} - virtual void reset() { ctx().reset(); } + virtual void reset_core() { ctx().reset(); } virtual void assert_expr(expr * t) { ctx().assert_expr(t); } - virtual void push() { ctx().push(); } - virtual void pop(unsigned n) { ctx().pop(n); } - virtual unsigned get_scope_level() const { return ctx().get_scope_level(); } - virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions) { + virtual void push_core() { ctx().push(); } + virtual void pop_core(unsigned n) { ctx().pop(n); } + virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) { return ctx().check(num_assumptions, assumptions); } virtual void get_unsat_core(ptr_vector & r) { diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 8aecc0a3a..6d1becb4d 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -33,14 +33,29 @@ Revision History: extern "C" { + static void init_solver_core(Z3_context c, Z3_solver _s) { + ast_manager & m = mk_c(c)->m(); + Z3_solver_ref * s = to_solver(_s); + s->m_solver->set_produce_proofs(m.proofs_enabled()); + s->m_solver->set_produce_unsat_cores(s->m_params.get_bool(":unsat-core", false)); + s->m_solver->set_produce_models(s->m_params.get_bool(":model", true)); + s->m_solver->set_front_end_params(mk_c(c)->fparams()); + s->m_solver->updt_params(s->m_params); + s->m_solver->init(m, s->m_logic); + s->m_initialized = true; + } + + static void init_solver(Z3_context c, Z3_solver s) { + if (!to_solver(s)->m_initialized) + init_solver_core(c, s); + } + Z3_solver Z3_API Z3_mk_simple_solver(Z3_context c) { Z3_TRY; LOG_Z3_mk_simple_solver(c); RESET_ERROR_CODE(); Z3_solver_ref * s = alloc(Z3_solver_ref); s->m_solver = mk_smt_solver(); - s->m_solver->set_front_end_params(mk_c(c)->fparams()); - s->m_solver->init(mk_c(c)->m(), symbol::null); mk_c(c)->save_object(s); Z3_solver r = of_solver(s); RETURN_Z3(r); @@ -53,8 +68,6 @@ extern "C" { RESET_ERROR_CODE(); Z3_solver_ref * s = alloc(Z3_solver_ref); s->m_solver = mk_smt_strategic_solver(); - s->m_solver->set_front_end_params(mk_c(c)->fparams()); - s->m_solver->init(mk_c(c)->m(), symbol::null); mk_c(c)->save_object(s); Z3_solver r = of_solver(s); RETURN_Z3(r); @@ -65,10 +78,8 @@ extern "C" { Z3_TRY; LOG_Z3_mk_solver_for_logic(c, logic); RESET_ERROR_CODE(); - Z3_solver_ref * s = alloc(Z3_solver_ref); + Z3_solver_ref * s = alloc(Z3_solver_ref, to_symbol(logic)); s->m_solver = mk_smt_strategic_solver(true /* force solver to use tactics even when auto_config is disabled */); - s->m_solver->set_front_end_params(mk_c(c)->fparams()); - s->m_solver->init(mk_c(c)->m(), to_symbol(logic)); mk_c(c)->save_object(s); Z3_solver r = of_solver(s); RETURN_Z3(r); @@ -81,8 +92,6 @@ extern "C" { RESET_ERROR_CODE(); Z3_solver_ref * s = alloc(Z3_solver_ref); s->m_solver = alloc(tactic2solver, to_tactic_ref(t)); - s->m_solver->set_front_end_params(mk_c(c)->fparams()); - s->m_solver->init(mk_c(c)->m(), symbol::null); mk_c(c)->save_object(s); Z3_solver r = of_solver(s); RETURN_Z3(r); @@ -117,7 +126,13 @@ extern "C" { Z3_TRY; LOG_Z3_solver_set_params(c, s, p); RESET_ERROR_CODE(); - to_solver_ref(s)->updt_params(to_param_ref(p)); + if (to_solver(s)->m_initialized) { + bool old_model = to_solver(s)->m_params.get_bool(":model", true); + bool new_model = to_param_ref(p).get_bool(":model", true); + if (old_model != new_model) + to_solver_ref(s)->set_produce_models(new_model); + to_solver_ref(s)->updt_params(to_param_ref(p)); + } to_solver(s)->m_params = to_param_ref(p); Z3_CATCH; } @@ -142,6 +157,7 @@ extern "C" { Z3_TRY; LOG_Z3_solver_push(c, s); RESET_ERROR_CODE(); + init_solver(c, s); to_solver_ref(s)->push(); Z3_CATCH; } @@ -150,6 +166,7 @@ extern "C" { Z3_TRY; LOG_Z3_solver_pop(c, s, n); RESET_ERROR_CODE(); + init_solver(c, s); if (n > to_solver_ref(s)->get_scope_level()) { SET_ERROR_CODE(Z3_IOB); return; @@ -164,7 +181,7 @@ extern "C" { LOG_Z3_solver_reset(c, s); RESET_ERROR_CODE(); to_solver_ref(s)->reset(); - to_solver_ref(s)->init(mk_c(c)->m(), symbol::null); + to_solver(s)->m_initialized = false; Z3_CATCH; } @@ -172,6 +189,7 @@ extern "C" { Z3_TRY; LOG_Z3_solver_get_num_scopes(c, s); RESET_ERROR_CODE(); + init_solver(c, s); return to_solver_ref(s)->get_scope_level(); Z3_CATCH_RETURN(0); } @@ -180,7 +198,8 @@ extern "C" { Z3_TRY; LOG_Z3_solver_assert(c, s, a); RESET_ERROR_CODE(); - CHECK_FORMULA(a,); + init_solver(c, s); + CHECK_FORMULA(a,); to_solver_ref(s)->assert_expr(to_expr(a)); Z3_CATCH; } @@ -189,6 +208,7 @@ extern "C" { Z3_TRY; LOG_Z3_solver_get_assertions(c, s); RESET_ERROR_CODE(); + init_solver(c, s); Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, mk_c(c)->m()); mk_c(c)->save_object(v); unsigned sz = to_solver_ref(s)->get_num_assertions(); @@ -207,9 +227,6 @@ extern "C" { } } expr * const * _assumptions = to_exprs(assumptions); - to_solver_ref(s)->set_produce_models(to_solver(s)->m_params.get_bool(":model", true)); - to_solver_ref(s)->set_produce_proofs(mk_c(c)->m().proofs_enabled()); - to_solver_ref(s)->set_produce_unsat_cores(num_assumptions > 0); unsigned timeout = to_solver(s)->m_params.get_uint(":timeout", UINT_MAX); bool use_ctrl_c = to_solver(s)->m_params.get_bool(":ctrl-c", false); cancel_eh eh(*to_solver_ref(s)); @@ -233,6 +250,7 @@ extern "C" { Z3_TRY; LOG_Z3_solver_check(c, s); RESET_ERROR_CODE(); + init_solver(c, s); return _solver_check(c, s, 0, 0); Z3_CATCH_RETURN(Z3_L_UNDEF); } @@ -241,6 +259,7 @@ extern "C" { Z3_TRY; LOG_Z3_solver_check_assumptions(c, s, num_assumptions, assumptions); RESET_ERROR_CODE(); + init_solver(c, s); return _solver_check(c, s, num_assumptions, assumptions); Z3_CATCH_RETURN(Z3_L_UNDEF); } @@ -249,6 +268,7 @@ extern "C" { Z3_TRY; LOG_Z3_solver_get_model(c, s); RESET_ERROR_CODE(); + init_solver(c, s); model_ref _m; to_solver_ref(s)->get_model(_m); if (!_m) { @@ -266,6 +286,7 @@ extern "C" { Z3_TRY; LOG_Z3_solver_get_proof(c, s); RESET_ERROR_CODE(); + init_solver(c, s); proof * p = to_solver_ref(s)->get_proof(); if (!p) { SET_ERROR_CODE(Z3_INVALID_USAGE); @@ -280,6 +301,7 @@ extern "C" { Z3_TRY; LOG_Z3_solver_get_unsat_core(c, s); RESET_ERROR_CODE(); + init_solver(c, s); ptr_vector core; to_solver_ref(s)->get_unsat_core(core); Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, mk_c(c)->m()); @@ -295,6 +317,7 @@ extern "C" { Z3_TRY; LOG_Z3_solver_get_reason_unknown(c, s); RESET_ERROR_CODE(); + init_solver(c, s); return mk_c(c)->mk_external_string(to_solver_ref(s)->reason_unknown()); Z3_CATCH_RETURN(""); } @@ -303,6 +326,7 @@ extern "C" { Z3_TRY; LOG_Z3_solver_get_statistics(c, s); RESET_ERROR_CODE(); + init_solver(c, s); Z3_stats_ref * st = alloc(Z3_stats_ref); to_solver_ref(s)->collect_statistics(st->m_stats); mk_c(c)->save_object(st); @@ -315,6 +339,7 @@ extern "C" { Z3_TRY; LOG_Z3_solver_to_string(c, s); RESET_ERROR_CODE(); + init_solver(c, s); std::ostringstream buffer; to_solver_ref(s)->display(buffer); return mk_c(c)->mk_external_string(buffer.str()); diff --git a/src/api/api_solver.h b/src/api/api_solver.h index a39475bac..1569ef0da 100644 --- a/src/api/api_solver.h +++ b/src/api/api_solver.h @@ -24,7 +24,10 @@ Revision History: struct Z3_solver_ref : public api::object { solver * m_solver; params_ref m_params; - Z3_solver_ref():m_solver(0) {} + bool m_initialized; + symbol m_logic; + Z3_solver_ref():m_solver(0), m_initialized(false), m_logic(symbol::null) {} + Z3_solver_ref(symbol const & logic):m_solver(0), m_initialized(false), m_logic(logic) {} virtual ~Z3_solver_ref() { dealloc(m_solver); } }; diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index c6fa7718c..4c24b5ae6 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -359,14 +359,14 @@ class set_option_cmd : public set_get_option_cmd { } else if (m_option == m_produce_proofs) { check_not_initialized(ctx, m_produce_proofs); - ctx.params().m_proof_mode = to_bool(value) ? PGM_FINE : PGM_DISABLED; + ctx.set_produce_proofs(to_bool(value)); } else if (m_option == m_produce_unsat_cores) { check_not_initialized(ctx, m_produce_unsat_cores); ctx.set_produce_unsat_cores(to_bool(value)); } else if (m_option == m_produce_models) { - ctx.params().m_model = to_bool(value); + ctx.set_produce_models(to_bool(value)); } else if (m_option == m_produce_assignments) { ctx.set_produce_assignments(to_bool(value)); diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index c56066827..2d0d349d7 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -348,6 +348,24 @@ cmd_context::~cmd_context() { } } +void cmd_context::set_produce_models(bool f) { + params().m_model = f; + if (m_solver) + m_solver->set_produce_models(f); +} + +void cmd_context::set_produce_unsat_cores(bool f) { + // can only be set before initialization + SASSERT(!has_manager()); + m_produce_unsat_cores = f; +} + +void cmd_context::set_produce_proofs(bool f) { + // can only be set before initialization + SASSERT(!has_manager()); + params().m_proof_mode = f ? PGM_FINE : PGM_DISABLED; +} + bool cmd_context::is_smtlib2_compliant() const { return params().m_smtlib2_compliant; } @@ -540,8 +558,12 @@ void cmd_context::init_manager_core(bool new_manager) { // it prevents clashes with builtin types. insert(pm().mk_plist_decl()); } - if (m_solver) + if (m_solver) { + m_solver->set_produce_unsat_cores(m_produce_unsat_cores); + m_solver->set_produce_models(params().m_model); + m_solver->set_produce_proofs(params().m_proof_mode == PGM_FINE); m_solver->init(m(), m_logic); + } m_check_logic.set_logic(m(), m_logic); } @@ -1076,7 +1098,6 @@ void cmd_context::reset(bool finalize) { reset_macros(); reset_func_decls(); restore_assertions(0); - restore_assumptions(0); if (m_solver) m_solver->reset(); m_pp_env = 0; @@ -1108,6 +1129,8 @@ void cmd_context::assert_expr(expr * t) { m_check_sat_result = 0; m().inc_ref(t); m_assertions.push_back(t); + if (m_produce_unsat_cores) + m_assertion_names.push_back(0); if (m_solver) m_solver->assert_expr(t); } @@ -1119,11 +1142,14 @@ void cmd_context::assert_expr(symbol const & name, expr * t) { assert_expr(t); return; } - app * proxy = m().mk_const(name, m().mk_bool_sort()); - expr * new_t = m().mk_implies(proxy, t); - m().inc_ref(proxy); - m_assumptions.push_back(proxy); - assert_expr(new_t); + m_check_sat_result = 0; + m().inc_ref(t); + m_assertions.push_back(t); + expr * ans = m().mk_const(name, m().mk_bool_sort()); + m().inc_ref(ans); + m_assertion_names.push_back(ans); + if (m_solver) + m_solver->assert_expr(t, ans); } void cmd_context::push() { @@ -1137,7 +1163,6 @@ void cmd_context::push() { s.m_macros_stack_lim = m_macros_stack.size(); s.m_aux_pdecls_lim = m_aux_pdecls.size(); s.m_assertions_lim = m_assertions.size(); - s.m_assumptions_lim = m_assumptions.size(); if (m_solver) m_solver->push(); } @@ -1200,29 +1225,25 @@ void cmd_context::restore_aux_pdecls(unsigned old_sz) { m_aux_pdecls.shrink(old_sz); } +static void restore(ast_manager & m, ptr_vector & c, unsigned old_sz) { + ptr_vector::iterator it = c.begin() + old_sz; + ptr_vector::iterator end = c.end(); + for (; it != end; ++it) { + m.dec_ref(*it); + } + c.shrink(old_sz); +} + void cmd_context::restore_assertions(unsigned old_sz) { SASSERT(old_sz <= m_assertions.size()); SASSERT(!m_interactive_mode || m_assertions.size() == m_assertion_strings.size()); - ptr_vector::iterator it = m_assertions.begin() + old_sz; - ptr_vector::iterator end = m_assertions.end(); - for (; it != end; ++it) { - m().dec_ref(*it); - } - m_assertions.shrink(old_sz); + restore(m(), m_assertions, old_sz); + if (m_produce_unsat_cores) + restore(m(), m_assertion_names, old_sz); if (m_interactive_mode) m_assertion_strings.shrink(old_sz); } -void cmd_context::restore_assumptions(unsigned old_sz) { - SASSERT(old_sz <= m_assumptions.size()); - ptr_vector::iterator it = m_assumptions.begin() + old_sz; - ptr_vector::iterator end = m_assumptions.end(); - for (; it != end; ++it) { - m().dec_ref(*it); - } - m_assumptions.shrink(old_sz); -} - void cmd_context::pop(unsigned n) { m_check_sat_result = 0; if (n == 0) @@ -1240,7 +1261,6 @@ void cmd_context::pop(unsigned n) { restore_macros(s.m_macros_stack_lim); restore_aux_pdecls(s.m_aux_pdecls_lim); restore_assertions(s.m_assertions_lim); - restore_assumptions(s.m_assumptions_lim); m_scopes.shrink(new_lvl); } @@ -1260,17 +1280,12 @@ void cmd_context::check_sat(unsigned num_assumptions, expr * const * assumptions m_check_sat_result = m_solver.get(); // solver itself stores the result. m_solver->set_front_end_params(params()); m_solver->set_progress_callback(this); - m_solver->set_produce_proofs(produce_proofs()); - m_solver->set_produce_models(produce_models()); - m_solver->set_produce_unsat_cores(produce_unsat_cores()); scoped_watch sw(*this); cancel_eh eh(*m_solver); scoped_ctrl_c ctrlc(eh); - unsigned old_sz = m_assumptions.size(); - m_assumptions.append(num_assumptions, assumptions); lbool r; try { - r = m_solver->check_sat(m_assumptions.size(), m_assumptions.c_ptr()); + r = m_solver->check_sat(num_assumptions, assumptions); } catch (z3_error & ex) { throw ex; @@ -1278,7 +1293,6 @@ void cmd_context::check_sat(unsigned num_assumptions, expr * const * assumptions catch (z3_exception & ex) { throw cmd_exception(ex.msg()); } - m_assumptions.shrink(old_sz); m_solver->set_status(r); display_sat_result(r); validate_check_sat_result(r); @@ -1410,6 +1424,9 @@ void cmd_context::set_solver(solver * s) { m_solver = s; m_solver->set_front_end_params(params()); if (has_manager() && s != 0) { + m_solver->set_produce_unsat_cores(m_produce_unsat_cores); + m_solver->set_produce_models(params().m_model); + m_solver->set_produce_proofs(params().m_proof_mode == PGM_FINE); m_solver->init(m(), m_logic); // assert formulas and create scopes in the new solver. unsigned lim = 0; diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index 9296f0735..34a3375d7 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -175,16 +175,15 @@ protected: ptr_vector m_aux_pdecls; ptr_vector m_assertions; vector m_assertion_strings; - ptr_vector m_assumptions; // for unsat-core extraction + ptr_vector m_assertion_names; // named assertions are represented using boolean variables. struct scope { unsigned m_func_decls_stack_lim; unsigned m_psort_decls_stack_lim; unsigned m_macros_stack_lim; unsigned m_aux_pdecls_lim; - // only m_assertions_lim and m_assumptions_lim are relevant when m_global_decls = true + // only m_assertions_lim is relevant when m_global_decls = true unsigned m_assertions_lim; - unsigned m_assumptions_lim; }; svector m_scopes; @@ -225,7 +224,6 @@ protected: void restore_macros(unsigned old_sz); void restore_aux_pdecls(unsigned old_sz); void restore_assertions(unsigned old_sz); - void restore_assumptions(unsigned old_sz); void erase_func_decl_core(symbol const & s, func_decl * f); void erase_psort_decl_core(symbol const & s); @@ -272,7 +270,9 @@ public: bool produce_models() const; bool produce_proofs() const; bool produce_unsat_cores() const { return m_produce_unsat_cores; } - void set_produce_unsat_cores(bool flag) { m_produce_unsat_cores = flag; } + void set_produce_models(bool flag); + void set_produce_unsat_cores(bool flag); + void set_produce_proofs(bool flag); bool produce_assignments() const { return m_produce_assignments; } void set_produce_assignments(bool flag) { m_produce_assignments = flag; } void set_status(status st) { m_status = st; } @@ -369,8 +369,8 @@ public: ptr_vector::const_iterator begin_assertions() const { return m_assertions.begin(); } ptr_vector::const_iterator end_assertions() const { return m_assertions.end(); } - ptr_vector::const_iterator begin_assumptions() const { return m_assumptions.begin(); } - ptr_vector::const_iterator end_assumptions() const { return m_assumptions.end(); } + ptr_vector::const_iterator begin_assertion_names() const { return m_assertion_names.begin(); } + ptr_vector::const_iterator end_assertion_names() const { return m_assertion_names.end(); } /** \brief Hack: consume assertions if there are no scopes. @@ -380,7 +380,6 @@ public: if (num_scopes() > 0) return false; restore_assertions(0); - restore_assumptions(0); return true; } diff --git a/src/cmd_context/cmd_context_to_goal.cpp b/src/cmd_context/cmd_context_to_goal.cpp index 21f8445d5..26cb2766b 100644 --- a/src/cmd_context/cmd_context_to_goal.cpp +++ b/src/cmd_context/cmd_context_to_goal.cpp @@ -27,20 +27,22 @@ void assert_exprs_from(cmd_context const & ctx, goal & t) { throw cmd_exception("Frontend does not support simultaneous generation of proofs and unsat cores"); ast_manager & m = t.m(); bool proofs_enabled = t.proofs_enabled(); - ptr_vector::const_iterator it = ctx.begin_assertions(); - ptr_vector::const_iterator end = ctx.end_assertions(); - for (; it != end; ++it) { - t.assert_expr(*it, proofs_enabled ? m.mk_asserted(*it) : 0, 0); - } if (ctx.produce_unsat_cores()) { - SASSERT(!ctx.produce_proofs()); - it = ctx.begin_assumptions(); - end = ctx.end_assumptions(); - for (; it != end; ++it) { - t.assert_expr(*it, 0, m.mk_leaf(*it)); + ptr_vector::const_iterator it = ctx.begin_assertions(); + ptr_vector::const_iterator end = ctx.end_assertions(); + ptr_vector::const_iterator it2 = ctx.begin_assertion_names(); + ptr_vector::const_iterator end2 = ctx.end_assertion_names(); + SASSERT(end - it == end2 - it2); + for (; it != end; ++it, ++it2) { + t.assert_expr(*it, proofs_enabled ? m.mk_asserted(*it) : 0, m.mk_leaf(*it2)); } } else { - SASSERT(ctx.begin_assumptions() == ctx.end_assumptions()); + ptr_vector::const_iterator it = ctx.begin_assertions(); + ptr_vector::const_iterator end = ctx.end_assertions(); + for (; it != end; ++it) { + t.assert_expr(*it, proofs_enabled ? m.mk_asserted(*it) : 0, 0); + } + SASSERT(ctx.begin_assertion_names() == ctx.end_assertion_names()); } } diff --git a/src/cmd_context/strategic_solver_cmd.cpp b/src/cmd_context/strategic_solver_cmd.cpp deleted file mode 100644 index 3bb820e0d..000000000 --- a/src/cmd_context/strategic_solver_cmd.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/*++ -Copyright (c) 2012 Microsoft Corporation - -Module Name: - - strategic_solver_cmd.h - -Abstract: - - Specialization of the strategic solver that - used cmd_context to access the assertion set. - -Author: - - Leonardo (leonardo) 2012-11-01 - -Notes: - ---*/ -#include"strategic_solver_cmd.h" -#include"cmd_context.h" - -strategic_solver_cmd::strategic_solver_cmd(cmd_context & ctx): - m_ctx(ctx) { -} - -unsigned strategic_solver_cmd::get_num_assertions() const { - return static_cast(m_ctx.end_assertions() - m_ctx.begin_assertions()); -} - -expr * strategic_solver_cmd::get_assertion(unsigned idx) const { - SASSERT(idx < get_num_assertions()); - return m_ctx.begin_assertions()[idx]; -} diff --git a/src/cmd_context/strategic_solver_cmd.h b/src/cmd_context/strategic_solver_cmd.h deleted file mode 100644 index 014d2dee6..000000000 --- a/src/cmd_context/strategic_solver_cmd.h +++ /dev/null @@ -1,40 +0,0 @@ -/*++ -Copyright (c) 2012 Microsoft Corporation - -Module Name: - - strategic_solver_cmd.h - -Abstract: - - Specialization of the strategic solver that - used cmd_context to access the assertion set. - -Author: - - Leonardo (leonardo) 2012-11-01 - -Notes: - ---*/ -#ifndef _STRATEGIC_SOLVER_CMD_H_ -#define _STRATEGIC_SOLVER_CMD_H_ - -#include"strategic_solver.h" - -class cmd_context; - -/** - Specialization for the SMT 2.0 command language frontend. - - The strategic solver does not have to maintain a copy of the assertion set in the cmd_context. -*/ -class strategic_solver_cmd : public strategic_solver_core { - cmd_context & m_ctx; -public: - strategic_solver_cmd(cmd_context & ctx); - virtual unsigned get_num_assertions() const; - virtual expr * get_assertion(unsigned idx) const; -}; - -#endif diff --git a/src/parsers/smt/smtlib_solver.cpp b/src/parsers/smt/smtlib_solver.cpp index 77c2455dc..dd54de350 100644 --- a/src/parsers/smt/smtlib_solver.cpp +++ b/src/parsers/smt/smtlib_solver.cpp @@ -83,7 +83,7 @@ namespace smtlib { benchmark.add_formula(m_ast_manager.mk_true()); } m_ctx = alloc(cmd_context, &m_params, true, &m_ast_manager, benchmark.get_logic()); - m_ctx->set_solver(mk_smt_strategic_solver(*m_ctx)); + m_ctx->set_solver(mk_smt_strategic_solver(false)); theory::expr_iterator fit = benchmark.begin_formulas(); theory::expr_iterator fend = benchmark.end_formulas(); for (; fit != fend; ++fit) diff --git a/src/shell/smtlib_frontend.cpp b/src/shell/smtlib_frontend.cpp index 6711158fd..08b070183 100644 --- a/src/shell/smtlib_frontend.cpp +++ b/src/shell/smtlib_frontend.cpp @@ -106,7 +106,7 @@ unsigned read_smtlib2_commands(char const* file_name, front_end_params& front_en ctx.set_solver(s); } else { - solver * s = mk_smt_strategic_solver(ctx); + solver * s = mk_smt_strategic_solver(false); ctx.set_solver(s); } install_dl_cmds(ctx); diff --git a/src/smt/ni_solver.cpp b/src/smt/ni_solver.cpp deleted file mode 100644 index cd0cd503a..000000000 --- a/src/smt/ni_solver.cpp +++ /dev/null @@ -1,236 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - ni_solver.cpp - -Abstract: - Wrappers for smt::kernel that are non-incremental & (quasi-incremental). - -Author: - - Leonardo (leonardo) 2011-03-30 - -Notes: - ---*/ -#include"ni_solver.h" -#include"smt_kernel.h" -#include"cmd_context.h" - -class ni_smt_solver : public solver { -protected: - cmd_context & m_cmd_ctx; - smt::kernel * m_context; - progress_callback * m_callback; -public: - ni_smt_solver(cmd_context & ctx):m_cmd_ctx(ctx), m_context(0), m_callback(0) {} - - virtual ~ni_smt_solver() { - if (m_context != 0) - dealloc(m_context); - } - - virtual void init(ast_manager & m, symbol const & logic) { - // do nothing - } - - virtual void collect_statistics(statistics & st) const { - if (m_context == 0) { - return; - } - else { - m_context->collect_statistics(st); - } - } - - virtual void reset() { - if (m_context != 0) { - #pragma omp critical (ni_solver) - { - dealloc(m_context); - m_context = 0; - } - } - } - - virtual void assert_expr(expr * t) { - // do nothing - } - - virtual void push() { - // do nothing - } - - virtual void pop(unsigned n) { - // do nothing - } - - virtual unsigned get_scope_level() const { - return m_cmd_ctx.num_scopes(); - } - - void assert_exprs() { - ptr_vector::const_iterator it = m_cmd_ctx.begin_assertions(); - ptr_vector::const_iterator end = m_cmd_ctx.end_assertions(); - for (; it != end; ++it) { - m_context->assert_expr(*it); - } - } - - void init_solver() { - reset(); - #pragma omp critical (ni_solver) - { - m_context = alloc(smt::kernel, m_cmd_ctx.m(), m_cmd_ctx.params()); - } - if (m_cmd_ctx.has_logic()) - m_context->set_logic(m_cmd_ctx.get_logic()); - if (m_callback) - m_context->set_progress_callback(m_callback); - assert_exprs(); - } - - virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions) { - // erase current solver, and create a new one. - init_solver(); - - if (num_assumptions == 0) { - return m_context->setup_and_check(); - } - else { - return m_context->check(num_assumptions, assumptions); - } - } - - virtual void get_unsat_core(ptr_vector & r) { - SASSERT(m_context); - unsigned sz = m_context->get_unsat_core_size(); - for (unsigned i = 0; i < sz; i++) - r.push_back(m_context->get_unsat_core_expr(i)); - } - - virtual void get_model(model_ref & m) { - SASSERT(m_context); - m_context->get_model(m); - } - - virtual proof * get_proof() { - SASSERT(m_context); - return m_context->get_proof(); - } - - virtual std::string reason_unknown() const { - SASSERT(m_context); - return m_context->last_failure_as_string(); - } - - virtual void get_labels(svector & r) { - SASSERT(m_context); - buffer tmp; - m_context->get_relevant_labels(0, tmp); - r.append(tmp.size(), tmp.c_ptr()); - } - - virtual void set_cancel(bool f) { - #pragma omp critical (ni_solver) - { - if (m_context) - m_context->set_cancel(f); - } - } - - virtual void set_progress_callback(progress_callback * callback) { - m_callback = callback; - if (m_context) - m_context->set_progress_callback(callback); - } - - - virtual void collect_param_descrs(param_descrs & r) { - smt::kernel::collect_param_descrs(r); - } - -}; - -solver * mk_non_incremental_smt_solver(cmd_context & ctx) { - return alloc(ni_smt_solver, ctx); -} - -class qi_smt_solver : public ni_smt_solver { - bool m_inc_mode; -public: - qi_smt_solver(cmd_context & ctx):ni_smt_solver(ctx), m_inc_mode(false) {} - - virtual ~qi_smt_solver() {} - - virtual void init(ast_manager & m, symbol const & logic) { - if (m_inc_mode) { - init_solver(); - m_inc_mode = true; - } - } - - virtual void reset() { - ni_smt_solver::reset(); - m_inc_mode = false; - } - - void switch_to_inc() { - if (!m_inc_mode) { - init_solver(); - m_inc_mode = true; - } - SASSERT(m_inc_mode); - } - - virtual void assert_expr(expr * t) { - if (m_context != 0 && !m_inc_mode) { - // solver was already created to solve a check_sat query... - switch_to_inc(); - } - if (m_inc_mode) { - SASSERT(m_context); - m_context->assert_expr(t); - } - } - - virtual void push() { - switch_to_inc(); - SASSERT(m_context); - m_context->push(); - SASSERT(m_inc_mode); - } - - virtual void pop(unsigned n) { - switch_to_inc(); - SASSERT(m_context); - m_context->pop(n); - SASSERT(m_inc_mode); - } - - virtual unsigned get_scope_level() const { - if (!m_inc_mode) - return 0; - else - return m_context->get_scope_level(); - } - - - virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions) { - if (!m_inc_mode) { - lbool r = ni_smt_solver::check_sat(num_assumptions, assumptions); - SASSERT(!m_inc_mode); - return r; - } - else { - return m_context->check(num_assumptions, assumptions); - } - } -}; - - -solver * mk_quasi_incremental_smt_solver(cmd_context & ctx) { - return alloc(qi_smt_solver, ctx); -} diff --git a/src/smt/ni_solver.h b/src/smt/ni_solver.h deleted file mode 100644 index c78707319..000000000 --- a/src/smt/ni_solver.h +++ /dev/null @@ -1,30 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - ni_solver.h - -Abstract: - Wrappers for smt::context that are non-incremental & (quasi-incremental). - -Author: - - Leonardo (leonardo) 2011-03-30 - -Notes: - ---*/ -#ifndef _NI_SOLVER_H_ -#define _NI_SOLVER_H_ - -#include"solver.h" -class cmd_context; - -// Creates a solver that restarts from scratch for every call to check_sat -solver * mk_non_incremental_smt_solver(cmd_context & ctx); - -// Creates a solver that restarts from scratch for the first call to check_sat, and then moves to incremental behavior. -solver * mk_quasi_incremental_smt_solver(cmd_context & ctx); - -#endif diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 516a6321e..888e1b34c 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -16,18 +16,19 @@ Author: Notes: --*/ -#include"solver.h" +#include"solver_na2as.h" #include"smt_kernel.h" #include"reg_decl_plugins.h" #include"front_end_params.h" namespace smt { - class solver : public ::solver { - front_end_params * m_params; - smt::kernel * m_context; + class solver : public solver_na2as { + front_end_params * m_params; + smt::kernel * m_context; + progress_callback * m_callback; public: - solver():m_params(0), m_context(0) {} + solver():m_params(0), m_context(0), m_callback(0) {} virtual ~solver() { if (m_context != 0) @@ -57,12 +58,14 @@ namespace smt { } } - virtual void init(ast_manager & m, symbol const & logic) { + virtual void init_core(ast_manager & m, symbol const & logic) { SASSERT(m_params); reset(); #pragma omp critical (solver) { m_context = alloc(smt::kernel, m, *m_params); + if (m_callback) + m_context->set_progress_callback(m_callback); } if (logic != symbol::null) m_context->set_logic(logic); @@ -77,7 +80,7 @@ namespace smt { } } - virtual void reset() { + virtual void reset_core() { if (m_context != 0) { #pragma omp critical (solver) { @@ -92,25 +95,19 @@ namespace smt { m_context->assert_expr(t); } - virtual void push() { + virtual void push_core() { SASSERT(m_context); m_context->push(); } - virtual void pop(unsigned n) { + virtual void pop_core(unsigned n) { SASSERT(m_context); m_context->pop(n); } - virtual unsigned get_scope_level() const { - if (m_context) - return m_context->get_scope_level(); - else - return 0; - } - - virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions) { + virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) { SASSERT(m_context); + TRACE("solver_na2as", tout << "smt_solver::check_sat_core: " << num_assumptions << "\n";); return m_context->check(num_assumptions, assumptions); } @@ -152,8 +149,9 @@ namespace smt { } virtual void set_progress_callback(progress_callback * callback) { - SASSERT(m_context); - m_context->set_progress_callback(callback); + m_callback = callback; + if (m_context) + m_context->set_progress_callback(callback); } virtual unsigned get_num_assertions() const { diff --git a/src/solver/solver.h b/src/solver/solver.h index 1cbc681c0..6f9887c1a 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -64,19 +64,20 @@ public: /** \brief Enable/Disable proof production for this solver object. - It is invoked after init(m, logic). + It is invoked before init(m, logic). */ virtual void set_produce_proofs(bool f) {} /** \brief Enable/Disable model generation for this solver object. - It is invoked after init(m, logic). + It is invoked before init(m, logic). + The user may optionally invoke it after init(m, logic). */ virtual void set_produce_models(bool f) {} /** \brief Enable/Disable unsat core generation for this solver object. - It is invoked after init(m, logic). + It is invoked before init(m, logic). */ virtual void set_produce_unsat_cores(bool f) {} @@ -95,6 +96,13 @@ public: */ virtual void assert_expr(expr * t) = 0; + /** + \brief Add a new formula \c t to the assertion stack, and "tag" it with \c a. + The propositional varialbe \c a is used to track the use of \c t in a proof + of unsatisfiability. + */ + virtual void assert_expr(expr * t, expr * a) = 0; + /** \brief Create a backtracking point. */ diff --git a/src/solver/solver_na2as.cpp b/src/solver/solver_na2as.cpp new file mode 100644 index 000000000..f6d7414a5 --- /dev/null +++ b/src/solver/solver_na2as.cpp @@ -0,0 +1,101 @@ +/*++ +Copyright (c) 2012 Microsoft Corporation + +Module Name: + + solver_na2as.cpp + +Abstract: + + Solver that implements "named" assertions using assumptions (aka answer literals). + That is, a named assertion assert_expr(t, a) is mapped into + a implies t + and 'a' is used as an extra assumption for check_sat. + +Author: + + Leonardo (leonardo) 2012-11-02 + +Notes: + +--*/ +#include"solver_na2as.h" +#include"ast_smt2_pp.h" + +solver_na2as::solver_na2as() { + m_manager = 0; +} + +solver_na2as::~solver_na2as() { + restore_assumptions(0); +} + +void solver_na2as::assert_expr(expr * t, expr * a) { + SASSERT(m_manager != 0); + SASSERT(is_uninterp_const(a)); + SASSERT(m_manager->is_bool(a)); + TRACE("solver_na2as", tout << "asserting\n" << mk_ismt2_pp(t, *m_manager) << "\n" << mk_ismt2_pp(a, *m_manager) << "\n";); + m_manager->inc_ref(a); + m_assumptions.push_back(a); + expr_ref new_t(*m_manager); + new_t = m_manager->mk_implies(a, t); + assert_expr(new_t); +} + +void solver_na2as::init(ast_manager & m, symbol const & logic) { + SASSERT(m_assumptions.empty()); + m_manager = &m; + init_core(m, logic); +} + +struct append_assumptions { + ptr_vector & m_assumptions; + unsigned m_old_sz; + append_assumptions(ptr_vector & _m_assumptions, + unsigned num_assumptions, + expr * const * assumptions): + m_assumptions(_m_assumptions) { + m_old_sz = m_assumptions.size(); + m_assumptions.append(num_assumptions, assumptions); + } + + ~append_assumptions() { + m_assumptions.shrink(m_old_sz); + } +}; + +lbool solver_na2as::check_sat(unsigned num_assumptions, expr * const * assumptions) { + append_assumptions app(m_assumptions, num_assumptions, assumptions); + return check_sat_core(m_assumptions.size(), m_assumptions.c_ptr()); +} + +void solver_na2as::push() { + m_scopes.push_back(m_assumptions.size()); + push_core(); +} + +void solver_na2as::pop(unsigned n) { + pop_core(n); + unsigned lvl = m_scopes.size(); + SASSERT(n <= lvl); + unsigned new_lvl = lvl - n; + restore_assumptions(m_scopes[new_lvl]); + m_scopes.shrink(new_lvl); +} + +void solver_na2as::restore_assumptions(unsigned old_sz) { + SASSERT(old_sz == 0 || m_manager != 0); + for (unsigned i = old_sz; i < m_assumptions.size(); i++) { + m_manager->dec_ref(m_assumptions[i]); + } + m_assumptions.shrink(old_sz); +} + +unsigned solver_na2as::get_scope_level() const { + return m_scopes.size(); +} + +void solver_na2as::reset() { + reset_core(); + restore_assumptions(0); +} diff --git a/src/solver/solver_na2as.h b/src/solver/solver_na2as.h new file mode 100644 index 000000000..eb12479fc --- /dev/null +++ b/src/solver/solver_na2as.h @@ -0,0 +1,55 @@ +/*++ +Copyright (c) 2012 Microsoft Corporation + +Module Name: + + solver_na2as.h + +Abstract: + + Solver that implements "named" assertions using assumptions (aka answer literals). + That is, a named assertion assert_expr(t, a) is mapped into + a implies t + and 'a' is used as an extra assumption for check_sat. + +Author: + + Leonardo (leonardo) 2012-11-02 + +Notes: + +--*/ +#ifndef _SOLVER_NA2AS_H_ +#define _SOLVER_NA2AS_H_ + +#include"solver.h" + +class solver_na2as : public solver { + ast_manager * m_manager; + ptr_vector m_assumptions; + unsigned_vector m_scopes; + void restore_assumptions(unsigned old_sz); +public: + solver_na2as(); + virtual ~solver_na2as(); + + virtual void assert_expr(expr * t, expr * a); + virtual void assert_expr(expr * t) = 0; + + // Subclasses of solver_na2as should redefine the following *_core methods instead of these ones. + virtual void init(ast_manager & m, symbol const & logic); + virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions); + virtual void push(); + virtual void pop(unsigned n); + virtual unsigned get_scope_level() const; + virtual void reset(); +protected: + virtual void init_core(ast_manager & m, symbol const & logic) = 0; + virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) = 0; + virtual void push_core() = 0; + virtual void pop_core(unsigned n) = 0; + virtual void reset_core() = 0; +}; + + +#endif diff --git a/src/solver/strategic_solver.cpp b/src/solver/strategic_solver.cpp index a32aec2b1..616ec5342 100644 --- a/src/solver/strategic_solver.cpp +++ b/src/solver/strategic_solver.cpp @@ -25,7 +25,13 @@ Notes: // minimum verbosity level for portfolio verbose messages #define PS_VB_LVL 15 -strategic_solver_core::strategic_solver_core(): + +strategic_solver::ctx::ctx(ast_manager & m): + m_assertions(m), + m_assertion_names(m) { + } + +strategic_solver::strategic_solver(): m_manager(0), m_fparams(0), m_force_tactic(false), @@ -37,6 +43,7 @@ strategic_solver_core::strategic_solver_core(): m_default_fct(0), m_curr_tactic(0), m_proof(0), + m_core(0), m_callback(0) { m_use_inc_solver_results = false; DEBUG_CODE(m_num_scopes = 0;); @@ -45,7 +52,7 @@ strategic_solver_core::strategic_solver_core(): m_produce_unsat_cores = false; } -strategic_solver_core::~strategic_solver_core() { +strategic_solver::~strategic_solver() { SASSERT(!m_curr_tactic); dictionary::iterator it = m_logic2fct.begin(); dictionary::iterator end = m_logic2fct.end(); @@ -54,9 +61,11 @@ strategic_solver_core::~strategic_solver_core() { } if (m_proof) m().dec_ref(m_proof); + if (m_core) + m().dec_ref(m_core); } -bool strategic_solver_core::has_quantifiers() const { +bool strategic_solver::has_quantifiers() const { unsigned sz = get_num_assertions(); for (unsigned i = 0; i < sz; i++) { if (::has_quantifiers(get_assertion(i))) @@ -68,7 +77,7 @@ bool strategic_solver_core::has_quantifiers() const { /** \brief Return true if a tactic should be used when the incremental solver returns unknown. */ -bool strategic_solver_core::use_tactic_when_undef() const { +bool strategic_solver::use_tactic_when_undef() const { switch (m_inc_unknown_behavior) { case IUB_RETURN_UNDEF: return false; case IUB_USE_TACTIC_IF_QF: return !has_quantifiers(); @@ -79,7 +88,7 @@ bool strategic_solver_core::use_tactic_when_undef() const { } } -void strategic_solver_core::set_inc_solver(solver * s) { +void strategic_solver::set_inc_solver(solver * s) { SASSERT(m_inc_solver == 0); SASSERT(m_num_scopes == 0); m_inc_solver = s; @@ -87,7 +96,7 @@ void strategic_solver_core::set_inc_solver(solver * s) { m_inc_solver->set_progress_callback(m_callback); } -void strategic_solver_core::updt_params(params_ref const & p) { +void strategic_solver::updt_params(params_ref const & p) { if (m_inc_solver) m_inc_solver->updt_params(p); if (m_fparams) @@ -95,7 +104,7 @@ void strategic_solver_core::updt_params(params_ref const & p) { } -void strategic_solver_core::collect_param_descrs(param_descrs & r) { +void strategic_solver::collect_param_descrs(param_descrs & r) { if (m_inc_solver) m_inc_solver->collect_param_descrs(r); } @@ -105,7 +114,7 @@ void strategic_solver_core::collect_param_descrs(param_descrs & r) { timeout == UINT_MAX means infinite After the timeout a strategy is used. */ -void strategic_solver_core::set_inc_solver_timeout(unsigned timeout) { +void strategic_solver::set_inc_solver_timeout(unsigned timeout) { m_inc_solver_timeout = timeout; } @@ -113,14 +122,14 @@ void strategic_solver_core::set_inc_solver_timeout(unsigned timeout) { \brief Set the default tactic factory. It is used if there is no tactic for a given logic. */ -void strategic_solver_core::set_default_tactic(tactic_factory * fct) { +void strategic_solver::set_default_tactic(tactic_factory * fct) { m_default_fct = fct; } /** \brief Set a tactic factory for a given logic. */ -void strategic_solver_core::set_tactic_for(symbol const & logic, tactic_factory * fct) { +void strategic_solver::set_tactic_for(symbol const & logic, tactic_factory * fct) { tactic_factory * old_fct; if (m_logic2fct.find(logic, old_fct)) { dealloc(old_fct); @@ -128,31 +137,77 @@ void strategic_solver_core::set_tactic_for(symbol const & logic, tactic_factory m_logic2fct.insert(logic, fct); } -void strategic_solver_core::init(ast_manager & m, symbol const & logic) { +void strategic_solver::init(ast_manager & m, symbol const & logic) { m_manager = &m; m_logic = logic; if (m_inc_mode) { SASSERT(m_inc_solver); m_inc_solver->init(m, logic); } + m_ctx = alloc(ctx, m); + TRACE("strategic_solver", tout << "strategic_solver was initialized.\n";); +} + +unsigned strategic_solver::get_num_assertions() const { + if (m_ctx == 0) + return 0; + return m_ctx->m_assertions.size(); +} + +expr * strategic_solver::get_assertion(unsigned idx) const { + SASSERT(m_ctx); + return m_ctx->m_assertions.get(idx); +} + +expr * strategic_solver::get_assertion_name(unsigned idx) const { + SASSERT(m_ctx); + SASSERT(m_produce_unsat_cores); + return m_ctx->m_assertion_names.get(idx); +} + +void strategic_solver::set_produce_proofs(bool f) { + m_produce_proofs = f; + // do not need to propagate to inc_solver since flag cannot be changed after initialization +} + +void strategic_solver::set_produce_models(bool f) { + m_produce_models = f; + if (m_inc_solver) + m_inc_solver->set_produce_models(f); +} + +void strategic_solver::set_produce_unsat_cores(bool f) { + m_produce_unsat_cores = f; + // do not need to propagate to inc_solver since flag cannot be changed after initialization } // delayed inc solver initialization -void strategic_solver_core::init_inc_solver() { +void strategic_solver::init_inc_solver() { if (m_inc_mode) return; // solver was already initialized if (!m_inc_solver) return; // inc solver was not installed m_inc_mode = true; + m_inc_solver->set_produce_proofs(m_produce_proofs); + m_inc_solver->set_produce_models(m_produce_models); + m_inc_solver->set_produce_unsat_cores(m_produce_unsat_cores); m_inc_solver->set_front_end_params(*m_fparams); m_inc_solver->init(m(), m_logic); unsigned sz = get_num_assertions(); - for (unsigned i = 0; i < sz; i++) { - m_inc_solver->assert_expr(get_assertion(i)); + if (m_produce_unsat_cores) { + SASSERT(m_ctx->m_assertions.size() == m_ctx->m_assertion_names.size()); + for (unsigned i = 0; i < sz; i++) { + m_inc_solver->assert_expr(get_assertion(i), get_assertion_name(i)); + } + } + else { + for (unsigned i = 0; i < sz; i++) { + m_inc_solver->assert_expr(get_assertion(i)); + } } } -void strategic_solver_core::collect_statistics(statistics & st) const { +void strategic_solver::collect_statistics(statistics & st) const { if (m_use_inc_solver_results) { SASSERT(m_inc_solver); m_inc_solver->collect_statistics(st); @@ -165,7 +220,8 @@ void strategic_solver_core::collect_statistics(statistics & st) const { } } -void strategic_solver_core::reset() { +void strategic_solver::reset() { + m_ctx = 0; m_logic = symbol::null; m_inc_mode = false; m_check_sat_executed = false; @@ -176,18 +232,22 @@ void strategic_solver_core::reset() { reset_results(); } -void strategic_solver_core::reset_results() { +void strategic_solver::reset_results() { m_use_inc_solver_results = false; m_model = 0; if (m_proof) { m().dec_ref(m_proof); m_proof = 0; } + if (m_core) { + m().dec_ref(m_core); + m_core = 0; + } m_reason_unknown.clear(); m_stats.reset(); } -void strategic_solver_core::assert_expr(expr * t) { +void strategic_solver::assert_expr(expr * t) { if (m_check_sat_executed && !m_inc_mode) { // a check sat was already executed --> switch to incremental mode init_inc_solver(); @@ -197,16 +257,37 @@ void strategic_solver_core::assert_expr(expr * t) { SASSERT(m_inc_solver); m_inc_solver->assert_expr(t); } + SASSERT(m_ctx); + m_ctx->m_assertions.push_back(t); + if (m_produce_unsat_cores) + m_ctx->m_assertion_names.push_back(0); } -void strategic_solver_core::push() { +void strategic_solver::assert_expr(expr * t, expr * a) { + if (m_check_sat_executed && !m_inc_mode) { + // a check sat was already executed --> switch to incremental mode + init_inc_solver(); + SASSERT(m_inc_solver == 0 || m_inc_mode); + } + if (m_inc_mode) { + SASSERT(m_inc_solver); + m_inc_solver->assert_expr(t, a); + } + SASSERT(m_ctx); + m_ctx->m_assertions.push_back(t); + if (m_produce_unsat_cores) + m_ctx->m_assertion_names.push_back(a); +} + +void strategic_solver::push() { DEBUG_CODE(m_num_scopes++;); init_inc_solver(); if (m_inc_solver) m_inc_solver->push(); + m_ctx->m_scopes.push_back(m_ctx->m_assertions.size()); } -void strategic_solver_core::pop(unsigned n) { +void strategic_solver::pop(unsigned n) { DEBUG_CODE({ SASSERT(n <= m_num_scopes); m_num_scopes -= n; @@ -214,13 +295,20 @@ void strategic_solver_core::pop(unsigned n) { init_inc_solver(); if (m_inc_solver) m_inc_solver->pop(n); + + SASSERT(m_ctx); + unsigned new_lvl = m_ctx->m_scopes.size() - n; + unsigned old_sz = m_ctx->m_scopes[new_lvl]; + m_ctx->m_assertions.shrink(old_sz); + if (m_produce_unsat_cores) + m_ctx->m_assertion_names.shrink(old_sz); + m_ctx->m_scopes.shrink(new_lvl); } -unsigned strategic_solver_core::get_scope_level() const { - if (m_inc_solver) - return m_inc_solver->get_scope_level(); - else +unsigned strategic_solver::get_scope_level() const { + if (m_ctx == 0) return 0; + return m_ctx->m_assertions.size(); } struct aux_timeout_eh : public event_handler { @@ -233,10 +321,10 @@ struct aux_timeout_eh : public event_handler { } }; -struct strategic_solver_core::mk_tactic { - strategic_solver_core * m_solver; +struct strategic_solver::mk_tactic { + strategic_solver * m_solver; - mk_tactic(strategic_solver_core * s, tactic_factory * f):m_solver(s) { + mk_tactic(strategic_solver * s, tactic_factory * f):m_solver(s) { ast_manager & m = s->m(); params_ref p; front_end_params2params(*s->m_fparams, p); @@ -259,14 +347,14 @@ struct strategic_solver_core::mk_tactic { } }; -tactic_factory * strategic_solver_core::get_tactic_factory() const { +tactic_factory * strategic_solver::get_tactic_factory() const { tactic_factory * f = 0; if (m_logic2fct.find(m_logic, f)) return f; return m_default_fct.get(); } -lbool strategic_solver_core::check_sat_with_assumptions(unsigned num_assumptions, expr * const * assumptions) { +lbool strategic_solver::check_sat_with_assumptions(unsigned num_assumptions, expr * const * assumptions) { if (!m_inc_solver) { IF_VERBOSE(PS_VB_LVL, verbose_stream() << "incremental solver was not installed, returning unknown...\n";); m_use_inc_solver_results = false; @@ -275,10 +363,16 @@ lbool strategic_solver_core::check_sat_with_assumptions(unsigned num_assumptions } init_inc_solver(); m_use_inc_solver_results = true; + TRACE("strategic_solver", tout << "invoking inc_solver with " << num_assumptions << " assumptions\n";); return m_inc_solver->check_sat(num_assumptions, assumptions); } -lbool strategic_solver_core::check_sat(unsigned num_assumptions, expr * const * assumptions) { +lbool strategic_solver::check_sat(unsigned num_assumptions, expr * const * assumptions) { + TRACE("strategic_solver", tout << "assumptions at strategic_solver:\n"; + for (unsigned i = 0; i < num_assumptions; i++) { + tout << mk_ismt2_pp(assumptions[i], m()) << "\n"; + } + tout << "m_produce_unsat_cores: " << m_produce_unsat_cores << ", m_inc_mode: " << m_inc_mode << "\n";); reset_results(); m_check_sat_executed = true; if (num_assumptions > 0 || // assumptions were provided @@ -333,10 +427,18 @@ lbool strategic_solver_core::check_sat(unsigned num_assumptions, expr * const * goal_ref g = alloc(goal, m(), m_produce_proofs, m_produce_models, m_produce_unsat_cores); unsigned sz = get_num_assertions(); - for (unsigned i = 0; i < sz; i++) { - g->assert_expr(get_assertion(i)); + if (m_produce_unsat_cores) { + SASSERT(m_ctx->m_assertions.size() == m_ctx->m_assertion_names.size()); + for (unsigned i = 0; i < sz; i++) + g->assert_expr(get_assertion(i), get_assertion_name(i)); + } + else { + for (unsigned i = 0; i < sz; i++) + g->assert_expr(get_assertion(i)); } expr_dependency_ref core(m()); + + TRACE("strategic_solver", tout << "using goal...\n"; g->display_with_dependencies(tout);); mk_tactic tct_maker(this, factory); SASSERT(m_curr_tactic); @@ -348,10 +450,14 @@ lbool strategic_solver_core::check_sat(unsigned num_assumptions, expr * const * m_proof = pr; m().inc_ref(m_proof); } + if (core) { + m_core = core; + m().inc_ref(m_core); + } return r; } -void strategic_solver_core::set_cancel(bool f) { +void strategic_solver::set_cancel(bool f) { if (m_inc_solver) m_inc_solver->set_cancel(f); #pragma omp critical (strategic_solver) @@ -361,14 +467,18 @@ void strategic_solver_core::set_cancel(bool f) { } } -void strategic_solver_core::get_unsat_core(ptr_vector & r) { +void strategic_solver::get_unsat_core(ptr_vector & r) { + TRACE("strategic_solver", tout << "get_unsat_core, m_use_inc_solver_results: " << m_use_inc_solver_results << "\n";); if (m_use_inc_solver_results) { SASSERT(m_inc_solver); m_inc_solver->get_unsat_core(r); } + else { + m().linearize(m_core, r); + } } -void strategic_solver_core::get_model(model_ref & m) { +void strategic_solver::get_model(model_ref & m) { if (m_use_inc_solver_results) { SASSERT(m_inc_solver); m_inc_solver->get_model(m); @@ -378,7 +488,7 @@ void strategic_solver_core::get_model(model_ref & m) { } } -proof * strategic_solver_core::get_proof() { +proof * strategic_solver::get_proof() { if (m_use_inc_solver_results) { SASSERT(m_inc_solver); return m_inc_solver->get_proof(); @@ -388,7 +498,7 @@ proof * strategic_solver_core::get_proof() { } } -std::string strategic_solver_core::reason_unknown() const { +std::string strategic_solver::reason_unknown() const { if (m_use_inc_solver_results) { SASSERT(m_inc_solver); return m_inc_solver->reason_unknown(); @@ -396,20 +506,20 @@ std::string strategic_solver_core::reason_unknown() const { return m_reason_unknown; } -void strategic_solver_core::get_labels(svector & r) { +void strategic_solver::get_labels(svector & r) { if (m_use_inc_solver_results) { SASSERT(m_inc_solver); m_inc_solver->get_labels(r); } } -void strategic_solver_core::set_progress_callback(progress_callback * callback) { +void strategic_solver::set_progress_callback(progress_callback * callback) { m_callback = callback; if (m_inc_solver) m_inc_solver->set_progress_callback(callback); } -void strategic_solver_core::display(std::ostream & out) const { +void strategic_solver::display(std::ostream & out) const { if (m_manager) { unsigned num = get_num_assertions(); out << "(solver"; @@ -424,50 +534,7 @@ void strategic_solver_core::display(std::ostream & out) const { } -strategic_solver::ctx::ctx(ast_manager & m):m_assertions(m) { -} - -void strategic_solver::init(ast_manager & m, symbol const & logic) { - strategic_solver_core::init(m, logic); - m_ctx = alloc(ctx, m); -} - -unsigned strategic_solver::get_num_assertions() const { - if (m_ctx == 0) - return 0; - return m_ctx->m_assertions.size(); -} - -expr * strategic_solver::get_assertion(unsigned idx) const { - SASSERT(m_ctx); - return m_ctx->m_assertions.get(idx); -} - -void strategic_solver::assert_expr(expr * t) { - SASSERT(m_ctx); - strategic_solver_core::assert_expr(t); - m_ctx->m_assertions.push_back(t); -} - -void strategic_solver::push() { - SASSERT(m_ctx); - strategic_solver_core::push(); - m_ctx->m_scopes.push_back(m_ctx->m_assertions.size()); -} - -void strategic_solver::pop(unsigned n) { - SASSERT(m_ctx); - unsigned new_lvl = m_ctx->m_scopes.size() - n; - unsigned old_sz = m_ctx->m_scopes[new_lvl]; - m_ctx->m_assertions.shrink(old_sz); - m_ctx->m_scopes.shrink(new_lvl); - strategic_solver_core::pop(n); -} - -void strategic_solver::reset() { - m_ctx = 0; - strategic_solver_core::reset(); -} + diff --git a/src/solver/strategic_solver.h b/src/solver/strategic_solver.h index 4d4a47388..e903e9bd0 100644 --- a/src/solver/strategic_solver.h +++ b/src/solver/strategic_solver.h @@ -46,7 +46,7 @@ struct front_end_params; It goes back to non_incremental mode when: - reset is invoked. */ -class strategic_solver_core : public solver { +class strategic_solver : public solver { public: // Behavior when the incremental solver returns unknown. enum inc_unknown_behavior { @@ -73,9 +73,18 @@ private: bool m_use_inc_solver_results; model_ref m_model; proof * m_proof; + expr_dependency * m_core; std::string m_reason_unknown; statistics m_stats; + struct ctx { + expr_ref_vector m_assertions; + expr_ref_vector m_assertion_names; + unsigned_vector m_scopes; + ctx(ast_manager & m); + }; + scoped_ptr m_ctx; + #ifdef Z3DEBUG unsigned m_num_scopes; #endif @@ -97,8 +106,8 @@ private: bool use_tactic_when_undef() const; public: - strategic_solver_core(); - ~strategic_solver_core(); + strategic_solver(); + ~strategic_solver(); ast_manager & m() const { SASSERT(m_manager); return *m_manager; } @@ -114,19 +123,21 @@ public: virtual void updt_params(params_ref const & p); virtual void collect_param_descrs(param_descrs & r); - virtual void set_produce_proofs(bool f) { m_produce_proofs = f; } - virtual void set_produce_models(bool f) { m_produce_models = f; } - virtual void set_produce_unsat_cores(bool f) { m_produce_unsat_cores = f; } + virtual void set_produce_proofs(bool f); + virtual void set_produce_models(bool f); + virtual void set_produce_unsat_cores(bool f); + + unsigned get_num_assertions() const; + expr * get_assertion(unsigned idx) const; + expr * get_assertion_name(unsigned idx) const; - virtual unsigned get_num_assertions() const = 0; - virtual expr * get_assertion(unsigned idx) const = 0; - virtual void display(std::ostream & out) const; virtual void init(ast_manager & m, symbol const & logic); virtual void collect_statistics(statistics & st) const; virtual void reset(); virtual void assert_expr(expr * t); + virtual void assert_expr(expr * t, expr * a); virtual void push(); virtual void pop(unsigned n); virtual unsigned get_scope_level() const; @@ -140,30 +151,4 @@ public: virtual void set_progress_callback(progress_callback * callback); }; -/** - \brief Default implementation of strategic_solver_core -*/ -class strategic_solver : public strategic_solver_core { - struct ctx { - expr_ref_vector m_assertions; - unsigned_vector m_scopes; - ctx(ast_manager & m); - }; - scoped_ptr m_ctx; -public: - strategic_solver() {} - - virtual void init(ast_manager & m, symbol const & logic); - - virtual void assert_expr(expr * t); - virtual void push(); - virtual void pop(unsigned n); - virtual void reset(); - - virtual unsigned get_num_assertions() const; - virtual expr * get_assertion(unsigned idx) const; -}; - - - #endif diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index 0747c7c9d..63308bd27 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -31,7 +31,7 @@ tactic2solver_core::ctx::ctx(ast_manager & m, symbol const & logic): tactic2solver_core::~tactic2solver_core() { } -void tactic2solver_core::init(ast_manager & m, symbol const & logic) { +void tactic2solver_core::init_core(ast_manager & m, symbol const & logic) { m_ctx = alloc(ctx, m, logic); } @@ -62,7 +62,7 @@ void tactic2solver_core::collect_param_descrs(param_descrs & r) { } } -void tactic2solver_core::reset() { +void tactic2solver_core::reset_core() { SASSERT(m_ctx); m_ctx->m_assertions.reset(); m_ctx->m_scopes.reset(); @@ -75,13 +75,13 @@ void tactic2solver_core::assert_expr(expr * t) { m_ctx->m_result = 0; } -void tactic2solver_core::push() { +void tactic2solver_core::push_core() { SASSERT(m_ctx); m_ctx->m_scopes.push_back(m_ctx->m_assertions.size()); m_ctx->m_result = 0; } -void tactic2solver_core::pop(unsigned n) { +void tactic2solver_core::pop_core(unsigned n) { SASSERT(m_ctx); unsigned new_lvl = m_ctx->m_scopes.size() - n; unsigned old_sz = m_ctx->m_scopes[new_lvl]; @@ -90,12 +90,7 @@ void tactic2solver_core::pop(unsigned n) { m_ctx->m_result = 0; } -unsigned tactic2solver_core::get_scope_level() const { - SASSERT(m_ctx); - return m_ctx->m_scopes.size(); -} - -lbool tactic2solver_core::check_sat(unsigned num_assumptions, expr * const * assumptions) { +lbool tactic2solver_core::check_sat_core(unsigned num_assumptions, expr * const * assumptions) { SASSERT(m_ctx); ast_manager & m = m_ctx->m(); params_ref p = m_params; diff --git a/src/solver/tactic2solver.h b/src/solver/tactic2solver.h index fe92f3a7d..8cf3551b4 100644 --- a/src/solver/tactic2solver.h +++ b/src/solver/tactic2solver.h @@ -22,7 +22,7 @@ Notes: #ifndef _TACTIC2SOLVER_H_ #define _TACTIC2SOLVER_H_ -#include"solver.h" +#include"solver_na2as.h" #include"tactic.h" /** @@ -32,7 +32,7 @@ Notes: option for applications trying to solve many easy queries that a similar to each other. */ -class tactic2solver_core : public solver { +class tactic2solver_core : public solver_na2as { struct ctx { symbol m_logic; expr_ref_vector m_assertions; @@ -63,13 +63,13 @@ public: virtual void set_produce_models(bool f) { m_produce_models = f; } virtual void set_produce_unsat_cores(bool f) { m_produce_unsat_cores = f; } - virtual void init(ast_manager & m, symbol const & logic); - virtual void reset(); virtual void assert_expr(expr * t); - virtual void push(); - virtual void pop(unsigned n); - virtual unsigned get_scope_level() const; - virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions); + + virtual void init_core(ast_manager & m, symbol const & logic); + virtual void reset_core(); + virtual void push_core(); + virtual void pop_core(unsigned n); + virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions); virtual void set_cancel(bool f); diff --git a/src/tactic/core/propagate_values_tactic.cpp b/src/tactic/core/propagate_values_tactic.cpp index 52637b1c3..9ab597dfa 100644 --- a/src/tactic/core/propagate_values_tactic.cpp +++ b/src/tactic/core/propagate_values_tactic.cpp @@ -209,6 +209,7 @@ class propagate_values_tactic : public tactic { result.push_back(m_goal); SASSERT(m_goal->is_well_sorted()); TRACE("propagate_values", m_goal->display(tout);); + TRACE("propagate_values_core", m_goal->display_with_dependencies(tout);); m_goal = 0; } }; diff --git a/src/tactic/goal.cpp b/src/tactic/goal.cpp index ad259f843..c6dad42b2 100644 --- a/src/tactic/goal.cpp +++ b/src/tactic/goal.cpp @@ -233,6 +233,10 @@ void goal::assert_expr(expr * f, proof * pr, expr_dependency * d) { quick_process(false, f, d); } +void goal::assert_expr(expr * f, expr_dependency * d) { + assert_expr(f, proofs_enabled() ? m().mk_asserted(f) : 0, d); +} + void goal::get_formulas(ptr_vector & result) { unsigned sz = size(); for (unsigned i = 0; i < sz; i++) { diff --git a/src/tactic/goal.h b/src/tactic/goal.h index 2b7162b85..294987699 100644 --- a/src/tactic/goal.h +++ b/src/tactic/goal.h @@ -105,9 +105,9 @@ public: void copy_from(goal const & src) { src.copy_to(*this); } void assert_expr(expr * f, proof * pr, expr_dependency * d); - void assert_expr(expr * f) { - assert_expr(f, proofs_enabled() ? m().mk_asserted(f) : 0, 0); - } + void assert_expr(expr * f, expr_dependency * d); + void assert_expr(expr * f, expr * d) { assert_expr(f, m().mk_leaf(d)); } + void assert_expr(expr * f) { assert_expr(f, static_cast(0)); } unsigned size() const { return m().size(m_forms); } diff --git a/src/tactic/portfolio/smt_strategic_solver.cpp b/src/tactic/portfolio/smt_strategic_solver.cpp index 00c0afaa5..50d972a0d 100644 --- a/src/tactic/portfolio/smt_strategic_solver.cpp +++ b/src/tactic/portfolio/smt_strategic_solver.cpp @@ -18,8 +18,7 @@ Notes: --*/ #include"cmd_context.h" -#include"ni_solver.h" -#include"strategic_solver_cmd.h" +#include"strategic_solver.h" #include"qfbv_tactic.h" #include"qflia_tactic.h" #include"qfnia_tactic.h" @@ -56,7 +55,7 @@ MK_SIMPLE_TACTIC_FACTORY(qfnra_fct, mk_qfnra_tactic(m, p)); MK_SIMPLE_TACTIC_FACTORY(qffpa_fct, mk_qffpa_tactic(m, p)); MK_SIMPLE_TACTIC_FACTORY(ufbv_fct, mk_ufbv_tactic(m, p)); -static void init(strategic_solver_core * s) { +static void init(strategic_solver * s) { s->set_default_tactic(alloc(default_fct)); s->set_tactic_for(symbol("QF_UF"), alloc(qfuf_fct)); s->set_tactic_for(symbol("QF_BV"), alloc(qfbv_fct)); @@ -80,13 +79,6 @@ static void init(strategic_solver_core * s) { s->set_tactic_for(symbol("QF_FPA"), alloc(qffpa_fct)); } -solver * mk_smt_strategic_solver(cmd_context & ctx) { - strategic_solver_cmd * s = alloc(strategic_solver_cmd, ctx); - s->set_inc_solver(mk_quasi_incremental_smt_solver(ctx)); - init(s); - return s; -} - solver * mk_smt_strategic_solver(bool force_tactic) { strategic_solver * s = alloc(strategic_solver); s->force_tactic(force_tactic); diff --git a/src/tactic/portfolio/smt_strategic_solver.h b/src/tactic/portfolio/smt_strategic_solver.h index f3cc2e0e0..060721e09 100644 --- a/src/tactic/portfolio/smt_strategic_solver.h +++ b/src/tactic/portfolio/smt_strategic_solver.h @@ -20,9 +20,7 @@ Notes: #ifndef _SMT_STRATEGIC_SOLVER_H_ #define _SMT_STRATEGIC_SOLVER_H_ -class cmd_context; -// Create a strategic solver for the SMT 2.0 frontend. -solver * mk_smt_strategic_solver(cmd_context & ctx); +class solver; // Create a strategic solver for the Z3 API solver * mk_smt_strategic_solver(bool force_tactic=false);