mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 03:32:28 +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).
		
			
				
	
	
		
			233 lines
		
	
	
	
		
			8.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			233 lines
		
	
	
	
		
			8.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*++
 | |
| Copyright (c) 2011 Microsoft Corporation
 | |
| 
 | |
| Module Name:
 | |
| 
 | |
|     sat_cleaner.h
 | |
| 
 | |
| Abstract:
 | |
| 
 | |
|     Eliminate satisfied clauses, and literals assigned to false.
 | |
| 
 | |
| Author:
 | |
| 
 | |
|     Leonardo de Moura (leonardo) 2011-05-24.
 | |
| 
 | |
| Revision History:
 | |
| 
 | |
| --*/
 | |
| #include "sat/sat_cleaner.h"
 | |
| #include "sat/sat_solver.h"
 | |
| #include "util/trace.h"
 | |
| #include "util/stopwatch.h"
 | |
| 
 | |
| namespace sat {
 | |
| 
 | |
|     cleaner::cleaner(solver & _s):
 | |
|         s(_s),
 | |
|         m_last_num_units(0), 
 | |
|         m_cleanup_counter(0) {
 | |
|         reset_statistics();
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|        - Delete watch lists of assigned literals.
 | |
|        - Delete satisfied binary watched binary clauses
 | |
|        - Delete watched clauses (they will be reinserted after they are cleaned).
 | |
|     */
 | |
|     void cleaner::cleanup_watches() {
 | |
|         vector<watch_list>::iterator it  = s.m_watches.begin();
 | |
|         vector<watch_list>::iterator end = s.m_watches.end();
 | |
|         unsigned l_idx = 0;
 | |
|         for (; it != end; ++it, ++l_idx) {
 | |
|             if (s.value(to_literal(l_idx)) != l_undef) {
 | |
|                 it->finalize();
 | |
|                 SASSERT(it->empty());
 | |
|                 continue;
 | |
|             }
 | |
|             TRACE(cleanup_bug, tout << "processing wlist of " << to_literal(l_idx) << "\n";);
 | |
|             watch_list & wlist = *it;
 | |
|             watch_list::iterator it2      = wlist.begin();
 | |
|             watch_list::iterator it_prev  = it2;
 | |
|             watch_list::iterator end2     = wlist.end();
 | |
|             for (; it2 != end2; ++it2) {
 | |
|                 switch (it2->get_kind()) {
 | |
|                 case watched::BINARY:
 | |
|                     TRACE(cleanup_bug, 
 | |
|                           tout << ~to_literal(l_idx) << " " << it2->get_literal() << "\n";
 | |
|                           tout << s.value(~to_literal(l_idx)) << " " << s.value(it2->get_literal()) << "\n";
 | |
|                           tout << s.was_eliminated(it2->get_literal()) << " " << s.inconsistent() << "\n";);
 | |
|                     SASSERT(s.value(it2->get_literal()) == l_true || s.value(it2->get_literal()) == l_undef);
 | |
|                     if (s.value(it2->get_literal()) == l_undef) {
 | |
|                         *it_prev = *it2;
 | |
|                         ++it_prev;
 | |
|                     }
 | |
|                     TRACE(cleanup_bug, tout << "keeping: " << ~to_literal(l_idx) << " " << it2->get_literal() << "\n";);
 | |
|                     break;
 | |
|                 case watched::CLAUSE:
 | |
|                     // skip
 | |
|                     break;
 | |
|                 case watched::EXT_CONSTRAINT:
 | |
|                     *it_prev = *it2;
 | |
|                     ++it_prev;
 | |
|                     break;
 | |
|                 default:
 | |
|                     UNREACHABLE();
 | |
|                     break;
 | |
|                 }
 | |
|             }
 | |
|             wlist.set_end(it_prev);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     void cleaner::cleanup_clauses(clause_vector & cs) {
 | |
|         clause_vector::iterator it  = cs.begin();
 | |
|         clause_vector::iterator it2 = it;
 | |
|         clause_vector::iterator end = cs.end();
 | |
|         for (; it != end; ++it) {
 | |
|             clause & c = *(*it);
 | |
|             TRACE(sat_cleaner_bug, tout << "cleaning: " << c << "\n";
 | |
|                   for (unsigned i = 0; i < c.size(); i++) tout << c[i] << ": " << s.value(c[i]) << "\n";);
 | |
|             CTRACE(sat_cleaner_frozen, c.frozen(), tout << c << "\n";);
 | |
|             unsigned sz = c.size();
 | |
|             unsigned i = 0, j = 0;
 | |
|             m_cleanup_counter += sz;
 | |
|             for (; i < sz; i++) {
 | |
|                 switch (s.value(c[i])) {
 | |
|                 case l_true:
 | |
|                     goto end_loop;
 | |
|                 case l_false:
 | |
|                     m_elim_literals++;
 | |
|                     break;
 | |
|                 case l_undef:
 | |
|                     if (i != j) {
 | |
|                         std::swap(c[j], c[i]);
 | |
|                     }
 | |
|                     j++;
 | |
|                     break;
 | |
|                 }
 | |
|             }
 | |
|         end_loop:
 | |
|             CTRACE(sat_cleaner_frozen, c.frozen(),
 | |
|                    tout << "sat: " << (i < sz) << ", new_size: " << j << "\n";
 | |
|                    tout << mk_lits_pp(j, c.begin()) << "\n";);
 | |
|             if (i < sz) {
 | |
|                 m_elim_clauses++;
 | |
|                 s.del_clause(c);
 | |
|             }
 | |
|             else {
 | |
|                 unsigned new_sz = j;
 | |
|                 CTRACE(sat_cleaner_bug, new_sz < 2, tout << "new_sz: " << new_sz << "\n";
 | |
|                        if (c.size() > 0) tout << "unit: " << c[0] << "\n";
 | |
|                        s.display_watches(tout););
 | |
|                 switch (new_sz) {
 | |
|                 case 0:
 | |
|                     s.set_conflict();
 | |
|                     s.del_clause(c);
 | |
|                     break;
 | |
|                 case 1:
 | |
|                     s.assign_unit(c[0]);
 | |
|                     s.del_clause(c);
 | |
|                     break;
 | |
|                 case 2:
 | |
|                     SASSERT(s.value(c[0]) == l_undef && s.value(c[1]) == l_undef);
 | |
|                     TRACE(cleanup_bug, tout << "clause became binary: " << c[0] << " " << c[1] << "\n";);
 | |
|                     s.mk_bin_clause(c[0], c[1], c.is_learned());
 | |
|                     s.del_clause(c);
 | |
|                     break;
 | |
|                 default:
 | |
|                     s.shrink(c, sz, new_sz);
 | |
|                     *it2 = *it;
 | |
|                     it2++;
 | |
|                     if (!c.frozen()) {                            
 | |
|                         s.attach_clause(c);
 | |
|                     }
 | |
|                     break;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         cs.set_end(it2);
 | |
|     }
 | |
| 
 | |
|     struct cleaner::report {
 | |
|         cleaner & m_cleaner;
 | |
|         stopwatch m_watch;
 | |
|         unsigned  m_elim_clauses;
 | |
|         unsigned  m_elim_literals;
 | |
|         report(cleaner & c):
 | |
|             m_cleaner(c),
 | |
|             m_elim_clauses(c.m_elim_clauses),
 | |
|             m_elim_literals(c.m_elim_literals) {
 | |
|             m_watch.start();
 | |
|         }
 | |
|         ~report() {
 | |
|             m_watch.stop();
 | |
|             IF_VERBOSE(2,
 | |
|                        verbose_stream() << " (sat-cleaner";
 | |
|                        verbose_stream() << " :elim-literals " << (m_cleaner.m_elim_literals - m_elim_literals);
 | |
|                        verbose_stream() << " :elim-clauses " << (m_cleaner.m_elim_clauses - m_elim_clauses);
 | |
|                        verbose_stream() << " :cost " << m_cleaner.m_cleanup_counter << m_watch << ")\n";);
 | |
|         }
 | |
|     };
 | |
| 
 | |
|     bool cleaner::is_clean() const {
 | |
|         for (clause* cp : s.m_clauses) {
 | |
|             for (literal lit : *cp) {
 | |
|                 if (s.value(lit) != l_undef && s.lvl(lit) == 0) return false;
 | |
|             }
 | |
|         }
 | |
|         for (clause* cp : s.m_learned) {
 | |
|             for (literal lit : *cp) {
 | |
|                 if (s.value(lit) != l_undef && s.lvl(lit) == 0) return false;
 | |
|             }
 | |
|         }
 | |
|         unsigned idx = 0;
 | |
|         for (auto& wlist : s.m_watches) {
 | |
|             literal lit = to_literal(idx);
 | |
|             if (s.value(lit) != l_undef && s.lvl(lit) == 0 && !wlist.empty()) return false;
 | |
|             ++idx;
 | |
|         }
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|        \brief Return true if cleaner executed.
 | |
|     */
 | |
|     bool cleaner::operator()(bool force) {
 | |
|         CASSERT("cleaner_bug", s.check_invariant());
 | |
|         unsigned trail_sz = s.m_trail.size();
 | |
| 
 | |
|         s.propagate(false); // make sure that everything was propagated.
 | |
|         TRACE(sat_cleaner_bug, s.display(tout); s.display_watches(tout););
 | |
|         if (s.m_inconsistent)
 | |
|             return false;
 | |
|         if (m_last_num_units == trail_sz)
 | |
|             return false; // there are no new assigned literals since last time... nothing to be done
 | |
|         if (!force && m_cleanup_counter > 0)
 | |
|             return false; // prevent simplifier from being executed over and over again.
 | |
|         report rpt(*this);
 | |
|         m_last_num_units = trail_sz;
 | |
|         m_cleanup_counter = 0;
 | |
|         do {
 | |
|             trail_sz = s.m_trail.size();
 | |
|             cleanup_watches();
 | |
|             cleanup_clauses(s.m_clauses);
 | |
|             cleanup_clauses(s.m_learned);
 | |
|             s.propagate(false);
 | |
|         }
 | |
|         while (trail_sz < s.m_trail.size() && !s.inconsistent());
 | |
|         CASSERT("cleaner_bug", s.check_invariant());
 | |
|         return true;
 | |
|     }
 | |
|     
 | |
|     void cleaner::reset_statistics() {
 | |
|         m_elim_clauses = 0;
 | |
|         m_elim_literals = 0;
 | |
|     }
 | |
|     
 | |
|     void cleaner::collect_statistics(statistics & st) const {
 | |
|         st.update("sat elim clauses", m_elim_clauses);
 | |
|         st.update("sat elim literals", m_elim_literals);
 | |
|     }
 | |
| 
 | |
| };
 |