/*++ Copyright (c) 2011 Microsoft Corporation Module Name: tactic.h Abstract: Abstract tactic object. Author: Leonardo (leonardo) 2011-10-13 Notes: --*/ #include #include"tactic.h" #include"probe.h" #include"stopwatch.h" #include"model_v2_pp.h" #include"cmd_context.h" void tactic::cancel() { #pragma omp critical (tactic_cancel) { set_cancel(true); } } void tactic::reset_cancel() { #pragma omp critical (tactic_cancel) { set_cancel(false); } } struct tactic_report::imp { char const * m_id; goal const & m_goal; stopwatch m_watch; double m_start_memory; imp(char const * id, goal const & g): m_id(id), m_goal(g), m_start_memory(static_cast(memory::get_allocation_size())/static_cast(1024*1024)) { m_watch.start(); } ~imp() { m_watch.stop(); double end_memory = static_cast(memory::get_allocation_size())/static_cast(1024*1024); verbose_stream() << "(" << m_id << " :num-exprs " << m_goal.num_exprs() << " :num-asts " << m_goal.m().get_num_asts() << " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << " :before-memory " << std::fixed << std::setprecision(2) << m_start_memory << " :after-memory " << std::fixed << std::setprecision(2) << end_memory << ")" << std::endl; } }; tactic_report::tactic_report(char const * id, goal const & g) { if (get_verbosity_level() >= TACTIC_VERBOSITY_LVL) m_imp = alloc(imp, id, g); else m_imp = 0; } tactic_report::~tactic_report() { if (m_imp) dealloc(m_imp); } void report_tactic_progress(char const * id, unsigned val) { if (val > 0) { IF_VERBOSE(TACTIC_VERBOSITY_LVL, verbose_stream() << "(" << id << " " << val << ")" << std::endl;); } } class skip_tactic : public tactic { public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) { result.reset(); result.push_back(in.get()); mc = 0; pc = 0; core = 0; } virtual void cleanup() {} virtual tactic * translate(ast_manager & m) { return this; } }; tactic * mk_skip_tactic() { return alloc(skip_tactic); } class fail_tactic : public tactic { public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) { throw tactic_exception("fail tactic"); } virtual void cleanup() {} virtual tactic * translate(ast_manager & m) { return this; } }; tactic * mk_fail_tactic() { return alloc(fail_tactic); } class report_verbose_tactic : public skip_tactic { char const * m_msg; unsigned m_lvl; public: report_verbose_tactic(char const * msg, unsigned lvl) : m_msg(msg), m_lvl(lvl) {} virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) { IF_VERBOSE(m_lvl, verbose_stream() << m_msg << "\n";); skip_tactic::operator()(in, result, mc, pc, core); } }; tactic * mk_report_verbose_tactic(char const * msg, unsigned lvl) { return alloc(report_verbose_tactic, msg, lvl); } class trace_tactic : public skip_tactic { char const * m_tag; public: trace_tactic(char const * tag):m_tag(tag) {} virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) { TRACE(m_tag, in->display(tout);); skip_tactic::operator()(in, result, mc, pc, core); } }; tactic * mk_trace_tactic(char const * tag) { return alloc(trace_tactic, tag); } class echo_tactic : public skip_tactic { cmd_context & m_ctx; char const * m_msg; bool m_newline; public: echo_tactic(cmd_context & ctx, char const * msg, bool newline):m_ctx(ctx), m_msg(msg), m_newline(newline) {} virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) { #pragma omp critical (echo_tactic) { m_ctx.diagnostic_stream() << m_msg; if (m_newline) m_ctx.diagnostic_stream() << std::endl; } skip_tactic::operator()(in, result, mc, pc, core); } }; tactic * mk_echo_tactic(cmd_context & ctx, char const * msg, bool newline) { return alloc(echo_tactic, ctx, msg, newline); } class probe_value_tactic : public skip_tactic { cmd_context & m_ctx; char const * m_msg; probe * m_p; bool m_newline; public: probe_value_tactic(cmd_context & ctx, char const * msg, probe * p, bool newline):m_ctx(ctx), m_msg(msg), m_p(p), m_newline(newline) { SASSERT(m_p); m_p->inc_ref(); } ~probe_value_tactic() { m_p->dec_ref(); } virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) { double val = (*m_p)(*(in.get())).get_value(); #pragma omp critical (probe_value_tactic) { if (m_msg) m_ctx.diagnostic_stream() << m_msg << " "; m_ctx.diagnostic_stream() << val; if (m_newline) m_ctx.diagnostic_stream() << std::endl; } skip_tactic::operator()(in, result, mc, pc, core); } }; tactic * mk_probe_value_tactic(cmd_context & ctx, char const * msg, probe * p, bool newline) { return alloc(probe_value_tactic, ctx, msg, p, newline); } class fail_if_undecided_tactic : public skip_tactic { public: fail_if_undecided_tactic() {} virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) { if (!in->is_decided()) throw tactic_exception("undecided"); skip_tactic::operator()(in, result, mc, pc, core); } }; tactic * mk_fail_if_undecided_tactic() { return alloc(fail_if_undecided_tactic); } void exec(tactic & t, goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) { t.reset_statistics(); t.reset_cancel(); try { t(in, result, mc, pc, core); t.cleanup(); } catch (tactic_exception & ex) { IF_VERBOSE(TACTIC_VERBOSITY_LVL, verbose_stream() << "(tactic-exception \"" << escaped(ex.msg()) << "\")" << std::endl;); t.cleanup(); throw ex; } } lbool check_sat(tactic & t, goal_ref & g, model_ref & md, proof_ref & pr, expr_dependency_ref & core, std::string & reason_unknown) { bool models_enabled = g->models_enabled(); bool proofs_enabled = g->proofs_enabled(); bool cores_enabled = g->unsat_core_enabled(); md = 0; pr = 0; core = 0; ast_manager & m = g->m(); goal_ref_buffer r; model_converter_ref mc; proof_converter_ref pc; try { exec(t, g, r, mc, pc, core); } catch (tactic_exception & ex) { reason_unknown = ex.msg(); return l_undef; } TRACE("tactic_mc", mc->display(tout);); TRACE("tactic_check_sat", tout << "r.size(): " << r.size() << "\n"; for (unsigned i = 0; i < r.size(); i++) r[0]->display(tout);); if (is_decided_sat(r)) { if (models_enabled) { model_converter2model(m, mc.get(), md); if (!md) { // create empty model. md = alloc(model, m); } } return l_true; } else if (is_decided_unsat(r)) { goal * final = r[0]; SASSERT(m.is_false(final->form(0))); if (proofs_enabled) pr = final->pr(0); if (cores_enabled) core = final->dep(0); return l_false; } else { if (models_enabled) model_converter2model(m, mc.get(), md); reason_unknown = "incomplete"; return l_undef; } } void fail_if_proof_generation(char const * tactic_name, goal_ref const & in) { if (in->proofs_enabled()) { std::string msg = tactic_name; msg += " does not support proof production"; throw tactic_exception(msg.c_str()); } } void fail_if_unsat_core_generation(char const * tactic_name, goal_ref const & in) { if (in->unsat_core_enabled()) { std::string msg = tactic_name; msg += " does not support unsat core production"; throw tactic_exception(msg.c_str()); } } void fail_if_model_generation(char const * tactic_name, goal_ref const & in) { if (in->models_enabled()) { std::string msg = tactic_name; msg += " does not generate models"; throw tactic_exception(msg.c_str()); } }