mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 19:52:29 +00:00 
			
		
		
		
	* Introduce X-macro-based trace tag definition - Created trace_tags.def to centralize TRACE tag definitions - Each tag includes a symbolic name and description - Set up enum class TraceTag for type-safe usage in TRACE macros * Add script to generate Markdown documentation from trace_tags.def - Python script parses trace_tags.def and outputs trace_tags.md * Refactor TRACE_NEW to prepend TraceTag and pass enum to is_trace_enabled * trace: improve trace tag handling system with hierarchical tagging - Introduce hierarchical tag-class structure: enabling a tag class activates all child tags - Unify TRACE, STRACE, SCTRACE, and CTRACE under enum TraceTag - Implement initial version of trace_tag.def using X(tag, tag_class, description) (class names and descriptions to be refined in a future update) * trace: replace all string-based TRACE tags with enum TraceTag - Migrated all TRACE, STRACE, SCTRACE, and CTRACE macros to use enum TraceTag values instead of raw string literals * trace : add cstring header * trace : Add Markdown documentation generation from trace_tags.def via mk_api_doc.py * trace : rename macro parameter 'class' to 'tag_class' and remove Unicode comment in trace_tags.h. * trace : Add TODO comment for future implementation of tag_class activation * trace : Disable code related to tag_class until implementation is ready (#7663).
		
			
				
	
	
		
			312 lines
		
	
	
	
		
			9.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			312 lines
		
	
	
	
		
			9.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*++
 | |
| Copyright (c) 2011 Microsoft Corporation
 | |
| 
 | |
| Module Name:
 | |
| 
 | |
|     tactic.h
 | |
| 
 | |
| Abstract:
 | |
| 
 | |
|     Abstract tactic object.
 | |
| 
 | |
| Author:
 | |
| 
 | |
|     Leonardo (leonardo) 2011-10-13
 | |
| 
 | |
| Notes:
 | |
| 
 | |
| --*/
 | |
| #include<iomanip>
 | |
| #include "tactic/tactic.h"
 | |
| #include "tactic/probe.h"
 | |
| #include "util/stopwatch.h"
 | |
| #include "model/model_v2_pp.h"
 | |
| 
 | |
| 
 | |
| 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<double>(memory::get_allocation_size())/static_cast<double>(1024*1024)) {
 | |
|         m_watch.start();
 | |
|         TRACE(tactic, g.display_with_proofs(tout << id << "\n"););
 | |
|         SASSERT(g.is_well_formed());
 | |
|     }
 | |
|         
 | |
|     ~imp() {
 | |
|         m_watch.stop();
 | |
|         double end_memory = static_cast<double>(memory::get_allocation_size())/static_cast<double>(1024*1024);
 | |
|         TRACE(tactic, m_goal.display(tout << m_id << "\n");
 | |
|               if (m_goal.mc()) m_goal.mc()->display(tout);
 | |
|               );
 | |
|         IF_VERBOSE(0, 
 | |
|                    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
 | |
|                    << ")\n");
 | |
|         IF_VERBOSE(20, m_goal.display(verbose_stream() << m_id << "\n"));
 | |
|         SASSERT(m_goal.is_well_formed());
 | |
|     }
 | |
| };
 | |
| 
 | |
| 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 = nullptr;
 | |
| }
 | |
| 
 | |
| 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 << ")\n");        
 | |
|     }
 | |
| }
 | |
| statistics_report::~statistics_report() {
 | |
|     statistics st;
 | |
|     if (m_tactic)
 | |
|         m_tactic->collect_statistics(st);
 | |
|     else if (m_collector)
 | |
|         m_collector(st);
 | |
|     if (st.size() == 0)
 | |
|         return;
 | |
|     IF_VERBOSE(TACTIC_VERBOSITY_LVL, st.display_smt2(verbose_stream()));
 | |
| }
 | |
| 
 | |
| 
 | |
| void skip_tactic::operator()(goal_ref const & in, goal_ref_buffer& result) {
 | |
|     result.push_back(in.get());
 | |
| }
 | |
| 
 | |
| tactic * mk_skip_tactic() {
 | |
|     return alloc(skip_tactic);
 | |
| }
 | |
| 
 | |
| class lazy_tactic : public tactic {
 | |
|     ast_manager& m;
 | |
|     params_ref p;
 | |
|     std::function<tactic* (ast_manager& m, params_ref const& p)> m_mk_tactic;
 | |
|     tactic* m_tactic = nullptr;
 | |
|     void ensure_tactic() {
 | |
|         if (!m_tactic) {
 | |
|             m_tactic = m_mk_tactic(m, p);
 | |
|             m_tactic->updt_params(p);
 | |
|         }
 | |
|     }
 | |
| public:
 | |
|     lazy_tactic(ast_manager& m, params_ref const& p, std::function<tactic* (ast_manager&, params_ref const&)> mk_tactic) : m(m), p(p), m_mk_tactic(mk_tactic) {}
 | |
|     ~lazy_tactic() override { dealloc(m_tactic); }
 | |
|     void operator()(goal_ref const& in, goal_ref_buffer& result) override {
 | |
|         ensure_tactic();
 | |
|         (*m_tactic)(in, result);
 | |
|     }
 | |
|     void updt_params(params_ref const& p) override { 
 | |
|         this->p.append(p);
 | |
|         if (m_tactic) m_tactic->updt_params(p);
 | |
|     }
 | |
|     void cleanup() override { if (m_tactic) m_tactic->cleanup(); }
 | |
|     char const* name() const override { return "lazy tactic"; }
 | |
|     void collect_statistics(statistics& st) const override { if (m_tactic) m_tactic->collect_statistics(st); }
 | |
|     void user_propagate_initialize_value(expr* var, expr* value) override { if (m_tactic) m_tactic->user_propagate_initialize_value(var, value); }
 | |
|     tactic* translate(ast_manager& m) override { ensure_tactic(); return m_tactic->translate(m); }
 | |
|     void reset() override { if (m_tactic) m_tactic->reset(); }
 | |
|     void reset_statistics() override { if (m_tactic) m_tactic->reset_statistics(); }
 | |
|     void register_on_clause(void* ctx, user_propagator::on_clause_eh_t& on_clause) override {
 | |
|         ensure_tactic();
 | |
|         m_tactic->register_on_clause(ctx, on_clause);
 | |
|     }
 | |
| };
 | |
| 
 | |
| 
 | |
| tactic* mk_lazy_tactic(ast_manager& m, params_ref const& p, std::function<tactic*(ast_manager& m, params_ref const& p)> mkt) {
 | |
|     return alloc(lazy_tactic, m, p, mkt);
 | |
| }
 | |
| 
 | |
| class fail_tactic : public tactic {
 | |
| public:
 | |
|     void operator()(goal_ref const & in, goal_ref_buffer & result) override {
 | |
|         throw tactic_exception("fail tactic");
 | |
|     }
 | |
| 
 | |
|     void cleanup() override {}
 | |
| 
 | |
|     char const* name() const override { return "fail"; }
 | |
| 
 | |
|     tactic * translate(ast_manager & m) override { 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) {}
 | |
| 
 | |
|     void operator()(goal_ref const & in, goal_ref_buffer& result) override {
 | |
|         IF_VERBOSE(m_lvl, verbose_stream() << m_msg << "\n";);
 | |
|         skip_tactic::operator()(in, result);
 | |
|     }
 | |
| };
 | |
| 
 | |
| 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) {}
 | |
|     
 | |
|     void operator()(goal_ref const & in, goal_ref_buffer& result) override {
 | |
|         TRACE(m_tag, in->display(tout););
 | |
|         (void)m_tag;
 | |
|         skip_tactic::operator()(in, result);
 | |
|     }
 | |
| };
 | |
| 
 | |
| tactic * mk_trace_tactic(char const * tag) {
 | |
|     return alloc(trace_tactic, tag);
 | |
| }
 | |
| 
 | |
| class fail_if_undecided_tactic : public skip_tactic {
 | |
| public:
 | |
|     void operator()(goal_ref const & in, goal_ref_buffer& result) override {
 | |
|         if (!in->is_decided()) 
 | |
|             throw tactic_exception("undecided");
 | |
|         skip_tactic::operator()(in, result);
 | |
|     }
 | |
|     void user_propagate_initialize_value(expr* var, expr* value) override { }
 | |
| };
 | |
| 
 | |
| tactic * mk_fail_if_undecided_tactic() {
 | |
|     return alloc(fail_if_undecided_tactic);
 | |
| }
 | |
| 
 | |
| void exec(tactic & t, goal_ref const & in, goal_ref_buffer & result) {
 | |
|     t.reset_statistics();
 | |
|     try {
 | |
|         t(in, result);
 | |
|         t.cleanup();
 | |
|     }
 | |
|     catch (tactic_exception & ex) {
 | |
|         IF_VERBOSE(TACTIC_VERBOSITY_LVL, verbose_stream() << "(tactic-exception \"" << escaped(ex.what()) << "\")\n");
 | |
|         t.cleanup();
 | |
|         throw ex;
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| lbool check_sat(tactic & t, goal_ref & g, model_ref & md, labels_vec & labels, proof_ref & pr, expr_dependency_ref & core, std::string & reason_unknown) {
 | |
|     bool models_enabled = g->models_enabled();
 | |
|     bool cores_enabled  = g->unsat_core_enabled();
 | |
|     md   = nullptr;
 | |
|     pr   = nullptr;
 | |
|     core = nullptr;
 | |
|     ast_manager & m = g->m();
 | |
|     goal_ref_buffer r;
 | |
|     try {
 | |
|         exec(t, g, r);
 | |
|     }
 | |
|     catch (z3_exception & ex) {
 | |
|         reason_unknown = ex.what();
 | |
|         if (r.size() > 0) pr = r[0]->pr(0);
 | |
|         return l_undef;
 | |
|     }
 | |
|     TRACE(tactic,
 | |
|           tout << "r.size(): " << r.size() << "\n";
 | |
|           for (unsigned i = 0; i < r.size(); i++) r[i]->display_with_dependencies(tout););
 | |
| 
 | |
|     if (r.size() > 0) {
 | |
|         pr = r[0]->pr(0);
 | |
|         CTRACE(tactic, pr, tout << pr << "\n";);
 | |
|     }    
 | |
| 
 | |
|     if (is_decided_sat(r)) {
 | |
|         model_converter_ref mc = r[0]->mc();            
 | |
|         if (mc.get()) {
 | |
|             (*mc)(labels);
 | |
|             model_converter2model(m, mc.get(), md);
 | |
|         }
 | |
|         if (!m.inc()) {
 | |
|             reason_unknown = "canceled";
 | |
|             return l_undef;
 | |
|         }
 | |
|         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)));
 | |
|         pr = final->pr(0);
 | |
|         if (cores_enabled)  core = final->dep(0);
 | |
|         return l_false;
 | |
|     }
 | |
|     else {
 | |
|         if (models_enabled && !r.empty()) {
 | |
|             model_converter_ref mc = r[0]->mc();            
 | |
|             model_converter2model(m, mc.get(), md);
 | |
|             if (mc)
 | |
|                 (*mc)(labels);
 | |
|         }
 | |
|         reason_unknown = get_reason_unknown(r);
 | |
|         if (reason_unknown.empty())
 | |
|             reason_unknown = "unknown";
 | |
|         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(std::move(msg));
 | |
|     }
 | |
| }
 | |
| 
 | |
| 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(std::move(msg));
 | |
|     }
 | |
| }
 | |
| 
 | |
| 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(std::move(msg));
 | |
|     }
 | |
| }
 | |
| 
 | |
| void fail_if_has_quantifiers(char const* tactic_name, goal_ref const& g) {
 | |
|     for (unsigned i = 0; i < g->size(); ++i)
 | |
|         if (has_quantifiers(g->form(i))) {
 | |
|             std::string msg = tactic_name;
 | |
|             msg += " does not apply to quantified goals";
 | |
|             throw tactic_exception(std::move(msg));
 | |
|         }
 | |
| }
 | |
| 
 | |
| void tactic::checkpoint(ast_manager& m) {
 | |
|     if (!m.inc())
 | |
|         throw tactic_exception(m.limit().get_cancel_msg());
 | |
| }
 |