mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 11:42:28 +00:00 
			
		
		
		
	fix and coallesce clique functionality
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
		
							parent
							
								
									1600823435
								
							
						
					
					
						commit
						ea601dd403
					
				
					 17 changed files with 361 additions and 119 deletions
				
			
		|  | @ -9,6 +9,7 @@ z3_add_component(opt | ||||||
|     optsmt.cpp |     optsmt.cpp | ||||||
|     opt_solver.cpp |     opt_solver.cpp | ||||||
|     pb_sls.cpp |     pb_sls.cpp | ||||||
|  |     sortmax.cpp | ||||||
|     wmax.cpp |     wmax.cpp | ||||||
|   COMPONENT_DEPENDENCIES |   COMPONENT_DEPENDENCIES | ||||||
|     sat_solver |     sat_solver | ||||||
|  |  | ||||||
|  | @ -584,6 +584,7 @@ namespace pdr { | ||||||
|         init_atom(pts, rule.get_head(), var_reprs, conj, UINT_MAX); |         init_atom(pts, rule.get_head(), var_reprs, conj, UINT_MAX); | ||||||
|         for (unsigned i = 0; i < ut_size; ++i) { |         for (unsigned i = 0; i < ut_size; ++i) { | ||||||
|             if (rule.is_neg_tail(i)) { |             if (rule.is_neg_tail(i)) { | ||||||
|  |                 dealloc(&var_reprs); | ||||||
|                 throw default_exception("PDR does not support negated predicates in rule tails"); |                 throw default_exception("PDR does not support negated predicates in rule tails"); | ||||||
|             } |             } | ||||||
|             init_atom(pts, rule.get_tail(i), var_reprs, conj, i); |             init_atom(pts, rule.get_tail(i), var_reprs, conj, i); | ||||||
|  | @ -602,7 +603,13 @@ namespace pdr { | ||||||
|             var_subst(m, false)(tail[i].get(), var_reprs.size(), (expr*const*)var_reprs.c_ptr(), tmp); |             var_subst(m, false)(tail[i].get(), var_reprs.size(), (expr*const*)var_reprs.c_ptr(), tmp); | ||||||
|             conj.push_back(tmp); |             conj.push_back(tmp); | ||||||
|             TRACE("pdr", tout << mk_pp(tail[i].get(), m) << "\n" << mk_pp(tmp, m) << "\n";); |             TRACE("pdr", tout << mk_pp(tail[i].get(), m) << "\n" << mk_pp(tmp, m) << "\n";); | ||||||
|             SASSERT(is_ground(tmp)); |             if (!is_ground(tmp)) { | ||||||
|  |                 std::stringstream msg; | ||||||
|  |                 msg << "PDR cannot solve non-ground tails: " << tmp; | ||||||
|  |                 IF_VERBOSE(0, verbose_stream() << msg.str() << "\n";); | ||||||
|  |                 dealloc(&var_reprs); | ||||||
|  |                 throw default_exception(msg.str()); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|         expr_ref fml = pm.mk_and(conj); |         expr_ref fml = pm.mk_and(conj); | ||||||
|         th_rewriter rw(m); |         th_rewriter rw(m); | ||||||
|  |  | ||||||
|  | @ -162,7 +162,6 @@ public: | ||||||
|         if (m_asm2weight.find(e, weight)) { |         if (m_asm2weight.find(e, weight)) { | ||||||
|             weight += w; |             weight += w; | ||||||
|             m_asm2weight.insert(e, weight); |             m_asm2weight.insert(e, weight); | ||||||
|             m_upper += w; |  | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         if (is_literal(e)) { |         if (is_literal(e)) { | ||||||
|  | @ -174,7 +173,6 @@ public: | ||||||
|             s().assert_expr(fml); |             s().assert_expr(fml); | ||||||
|         } |         } | ||||||
|         new_assumption(asum, w); |         new_assumption(asum, w); | ||||||
|         m_upper += w; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void new_assumption(expr* e, rational const& w) { |     void new_assumption(expr* e, rational const& w) { | ||||||
|  | @ -805,7 +803,6 @@ public: | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     lbool init_local() { |     lbool init_local() { | ||||||
|         m_upper.reset(); |  | ||||||
|         m_lower.reset(); |         m_lower.reset(); | ||||||
|         m_trail.reset(); |         m_trail.reset(); | ||||||
|         obj_map<expr, rational> new_soft; |         obj_map<expr, rational> new_soft; | ||||||
|  |  | ||||||
|  | @ -235,6 +235,9 @@ namespace opt { | ||||||
|         else if (maxsat_engine == symbol("wmax")) { |         else if (maxsat_engine == symbol("wmax")) { | ||||||
|             m_msolver = mk_wmax(m_c, m_weights, m_soft_constraints); |             m_msolver = mk_wmax(m_c, m_weights, m_soft_constraints); | ||||||
|         } |         } | ||||||
|  |         else if (maxsat_engine == symbol("sortmax")) { | ||||||
|  |             m_msolver = mk_sortmax(m_c, m_weights, m_soft_constraints); | ||||||
|  |         } | ||||||
|         else { |         else { | ||||||
|             warning_msg("solver %s is not recognized, using default 'maxres'", maxsat_engine.str().c_str()); |             warning_msg("solver %s is not recognized, using default 'maxres'", maxsat_engine.str().c_str()); | ||||||
|             m_msolver = mk_maxres(m_c, m_index, m_weights, m_soft_constraints); |             m_msolver = mk_maxres(m_c, m_index, m_weights, m_soft_constraints); | ||||||
|  |  | ||||||
							
								
								
									
										141
									
								
								src/opt/sortmax.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								src/opt/sortmax.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,141 @@ | ||||||
|  | /*++
 | ||||||
|  | Copyright (c) 2014 Microsoft Corporation | ||||||
|  | 
 | ||||||
|  | Module Name: | ||||||
|  | 
 | ||||||
|  |     sortmax.cpp | ||||||
|  | 
 | ||||||
|  | Abstract: | ||||||
|  | 
 | ||||||
|  |     Theory based MaxSAT. | ||||||
|  | 
 | ||||||
|  | Author: | ||||||
|  | 
 | ||||||
|  |     Nikolaj Bjorner (nbjorner) 2016-11-18 | ||||||
|  | 
 | ||||||
|  | Notes: | ||||||
|  | 
 | ||||||
|  | --*/ | ||||||
|  | #include "maxsmt.h" | ||||||
|  | #include "uint_set.h" | ||||||
|  | #include "ast_pp.h" | ||||||
|  | #include "model_smt2_pp.h" | ||||||
|  | #include "smt_theory.h" | ||||||
|  | #include "smt_context.h" | ||||||
|  | #include "opt_context.h" | ||||||
|  | #include "sorting_network.h" | ||||||
|  | #include "filter_model_converter.h" | ||||||
|  | 
 | ||||||
|  | namespace opt { | ||||||
|  | 
 | ||||||
|  |     class sortmax : public maxsmt_solver_base { | ||||||
|  |     public: | ||||||
|  |         typedef expr* literal; | ||||||
|  |         typedef ptr_vector<expr> literal_vector; | ||||||
|  |         psort_nw<sortmax> m_sort; | ||||||
|  |         expr_ref_vector   m_trail; | ||||||
|  |         func_decl_ref_vector m_fresh; | ||||||
|  |         ref<filter_model_converter> m_filter; | ||||||
|  |         sortmax(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft):  | ||||||
|  |             maxsmt_solver_base(c, ws, soft), m_sort(*this), m_trail(m), m_fresh(m) {} | ||||||
|  | 
 | ||||||
|  |         virtual ~sortmax() {} | ||||||
|  | 
 | ||||||
|  |         lbool operator()() { | ||||||
|  |             obj_map<expr, rational> soft;             | ||||||
|  |             if (!init()) { | ||||||
|  |                 return l_false; | ||||||
|  |             } | ||||||
|  |             lbool is_sat = find_mutexes(soft); | ||||||
|  |             if (is_sat != l_true) { | ||||||
|  |                 return is_sat; | ||||||
|  |             } | ||||||
|  |             m_filter = alloc(filter_model_converter, m); | ||||||
|  |             rational offset = m_lower; | ||||||
|  |             m_upper = offset; | ||||||
|  |             expr_ref_vector in(m); | ||||||
|  |             expr_ref tmp(m); | ||||||
|  |             ptr_vector<expr> out; | ||||||
|  |             obj_map<expr, rational>::iterator it = soft.begin(), end = soft.end(); | ||||||
|  |             for (; it != end; ++it) { | ||||||
|  |                 unsigned n = it->m_value.get_unsigned(); | ||||||
|  |                 while (n > 0) { | ||||||
|  |                     in.push_back(it->m_key); | ||||||
|  |                     --n; | ||||||
|  |                 } | ||||||
|  |                 m_upper += it->m_value; | ||||||
|  |             } | ||||||
|  |             m_sort.sorting(in.size(), in.c_ptr(), out); | ||||||
|  |             unsigned first = 0; | ||||||
|  |             while (l_true == is_sat && first < out.size() && m_lower < m_upper) { | ||||||
|  |                 trace_bounds("sortmax"); | ||||||
|  |                 s().assert_expr(out[first]); | ||||||
|  |                 is_sat = s().check_sat(0, 0); | ||||||
|  |                 TRACE("opt", tout << is_sat << "\n"; s().display(tout); tout << "\n";); | ||||||
|  |                 if (m.canceled()) { | ||||||
|  |                     is_sat = l_undef; | ||||||
|  |                 } | ||||||
|  |                 if (is_sat == l_true) { | ||||||
|  |                     ++first; | ||||||
|  |                     s().get_model(m_model); | ||||||
|  |                     update_assignment(); | ||||||
|  |                     for (; first < out.size() && is_true(out[first]); ++first) {  | ||||||
|  |                         s().assert_expr(out[first]); | ||||||
|  |                     } | ||||||
|  |                     TRACE("opt", model_smt2_pp(tout, m, *m_model.get(), 0);); | ||||||
|  |                     m_upper = m_lower + rational(out.size() - first); | ||||||
|  |                     (*m_filter)(m_model); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             if (is_sat == l_false) { | ||||||
|  |                 is_sat = l_true; | ||||||
|  |                 m_lower = m_upper; | ||||||
|  |             } | ||||||
|  |             TRACE("opt", tout << "min cost: " << m_upper << "\n";); | ||||||
|  |             return is_sat; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         void update_assignment() { | ||||||
|  |             for (unsigned i = 0; i < m_soft.size(); ++i) { | ||||||
|  |                 m_assignment[i] = is_true(m_soft[i]); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         bool is_true(expr* e) { | ||||||
|  |             expr_ref tmp(m); | ||||||
|  |             return m_model->eval(e, tmp) && m.is_true(tmp); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // definitions used for sorting network
 | ||||||
|  |         literal mk_false() { return m.mk_false(); } | ||||||
|  |         literal mk_true() { return m.mk_true(); } | ||||||
|  |         literal mk_max(literal a, literal b) { return trail(m.mk_or(a, b)); } | ||||||
|  |         literal mk_min(literal a, literal b) { return trail(m.mk_and(a, b)); } | ||||||
|  |         literal mk_not(literal a) { if (m.is_not(a,a)) return a; return trail(m.mk_not(a)); } | ||||||
|  | 
 | ||||||
|  |         std::ostream& pp(std::ostream& out, literal lit) {  return out << mk_pp(lit, m);  } | ||||||
|  |          | ||||||
|  |         literal trail(literal l) { | ||||||
|  |             m_trail.push_back(l); | ||||||
|  |             return l; | ||||||
|  |         } | ||||||
|  |         literal fresh() { | ||||||
|  |             expr_ref fr(m.mk_fresh_const("sn", m.mk_bool_sort()), m); | ||||||
|  |             func_decl* f = to_app(fr)->get_decl(); | ||||||
|  |             m_fresh.push_back(f); | ||||||
|  |             m_filter->insert(f); | ||||||
|  |             return trail(fr); | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         void mk_clause(unsigned n, literal const* lits) { | ||||||
|  |             s().assert_expr(mk_or(m, n, lits)); | ||||||
|  |         }         | ||||||
|  |          | ||||||
|  |     }; | ||||||
|  |      | ||||||
|  |      | ||||||
|  |     maxsmt_solver_base* mk_sortmax(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft) { | ||||||
|  |         return alloc(sortmax, c, ws, soft); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -51,7 +51,10 @@ namespace opt { | ||||||
|             obj_map<expr, rational>::iterator it = soft.begin(), end = soft.end(); |             obj_map<expr, rational>::iterator it = soft.begin(), end = soft.end(); | ||||||
|             for (; it != end; ++it) { |             for (; it != end; ++it) { | ||||||
|                 wth().assert_weighted(it->m_key, it->m_value); |                 wth().assert_weighted(it->m_key, it->m_value); | ||||||
|                 m_upper += it->m_value; |                 expr_ref tmp(m); | ||||||
|  |                 if (!m_model->eval(it->m_key, tmp) || !m.is_true(tmp)) { | ||||||
|  |                     m_upper += it->m_value; | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|             trace_bounds("wmax"); |             trace_bounds("wmax"); | ||||||
|             while (l_true == is_sat && m_lower < m_upper) { |             while (l_true == is_sat && m_lower < m_upper) { | ||||||
|  |  | ||||||
|  | @ -25,5 +25,7 @@ Notes: | ||||||
| namespace opt { | namespace opt { | ||||||
|     maxsmt_solver_base* mk_wmax(maxsat_context& c, weights_t & ws, expr_ref_vector const& soft); |     maxsmt_solver_base* mk_wmax(maxsat_context& c, weights_t & ws, expr_ref_vector const& soft); | ||||||
| 
 | 
 | ||||||
|  |     maxsmt_solver_base* mk_sortmax(maxsat_context& c, weights_t & ws, expr_ref_vector const& soft); | ||||||
|  | 
 | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | @ -21,6 +21,7 @@ Revision History: | ||||||
| #include"luby.h" | #include"luby.h" | ||||||
| #include"trace.h" | #include"trace.h" | ||||||
| #include"sat_bceq.h" | #include"sat_bceq.h" | ||||||
|  | #include"max_cliques.h" | ||||||
| 
 | 
 | ||||||
| // define to update glue during propagation
 | // define to update glue during propagation
 | ||||||
| #define UPDATE_GLUE | #define UPDATE_GLUE | ||||||
|  | @ -3062,74 +3063,44 @@ namespace sat { | ||||||
|     //
 |     //
 | ||||||
|     // -----------------------
 |     // -----------------------
 | ||||||
| 
 | 
 | ||||||
|  |     struct neg_literal { | ||||||
|  |         unsigned negate(unsigned idx) { | ||||||
|  |             return (~to_literal(idx)).index(); | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|     lbool solver::find_mutexes(literal_vector const& lits, vector<literal_vector> & mutexes) { |     lbool solver::find_mutexes(literal_vector const& lits, vector<literal_vector> & mutexes) { | ||||||
|         literal_vector ps(lits); |         max_cliques<neg_literal> mc; | ||||||
|         m_user_bin_clauses.reset(); |         m_user_bin_clauses.reset(); | ||||||
|         m_binary_clause_graph.reset(); |         m_binary_clause_graph.reset(); | ||||||
|         collect_bin_clauses(m_user_bin_clauses, true); |         collect_bin_clauses(m_user_bin_clauses, true); | ||||||
|         collect_bin_clauses(m_user_bin_clauses, false); |         collect_bin_clauses(m_user_bin_clauses, false); | ||||||
|  |         hashtable<literal_pair, pair_hash<literal_hash, literal_hash>, default_eq<literal_pair> > seen_bc; | ||||||
|         for (unsigned i = 0; i < m_user_bin_clauses.size(); ++i) { |         for (unsigned i = 0; i < m_user_bin_clauses.size(); ++i) { | ||||||
|             literal l1 = m_user_bin_clauses[i].first; |             literal l1 = m_user_bin_clauses[i].first; | ||||||
|             literal l2 = m_user_bin_clauses[i].second; |             literal l2 = m_user_bin_clauses[i].second; | ||||||
|             m_binary_clause_graph.reserve(l1.index() + 1); |             literal_pair p(l1, l2); | ||||||
|             m_binary_clause_graph.reserve(l2.index() + 1); |             if (!seen_bc.contains(p)) { | ||||||
|             m_binary_clause_graph.reserve((~l1).index() + 1); |                 seen_bc.insert(p); | ||||||
|             m_binary_clause_graph.reserve((~l2).index() + 1); |                 mc.add_edge(l1.index(), l2.index());              | ||||||
|             m_binary_clause_graph[l1.index()].push_back(l2); |             } | ||||||
|             m_binary_clause_graph[l2.index()].push_back(l1); |  | ||||||
|         } |         } | ||||||
|  |         vector<unsigned_vector> _mutexes; | ||||||
|  |         unsigned_vector ps; | ||||||
|         for (unsigned i = 0; i < lits.size(); ++i) { |         for (unsigned i = 0; i < lits.size(); ++i) { | ||||||
|             m_binary_clause_graph.reserve(lits[i].index() + 1); |             ps.push_back(lits[i].index()); | ||||||
|             m_binary_clause_graph.reserve((~lits[i]).index() + 1); |  | ||||||
|         } |         } | ||||||
|         bool non_empty = true; |         mc.cliques(ps, _mutexes); | ||||||
|         m_seen[0].reset(); |         for (unsigned i = 0; i < _mutexes.size(); ++i) { | ||||||
|         while (non_empty) { |             literal_vector lits; | ||||||
|             literal_vector mutex; |             for (unsigned j = 0; j < _mutexes[i].size(); ++j) { | ||||||
|             bool turn = false; |                 lits.push_back(to_literal(_mutexes[i][j])); | ||||||
|             m_reachable[turn] = ps; |  | ||||||
|             while (!m_reachable[turn].empty()) { |  | ||||||
|                 literal p = m_reachable[turn].pop(); |  | ||||||
|                 if (m_seen[0].contains(p)) { |  | ||||||
|                     continue; |  | ||||||
|                 } |  | ||||||
|                 m_reachable[turn].remove(p); |  | ||||||
|                 m_seen[0].insert(p); |  | ||||||
|                 mutex.push_back(p); |  | ||||||
|                 if (m_reachable[turn].empty()) { |  | ||||||
|                     break; |  | ||||||
|                 } |  | ||||||
|                 m_reachable[!turn].reset(); |  | ||||||
|                 get_reachable(p, m_reachable[turn], m_reachable[!turn]); |  | ||||||
|                 turn = !turn; |  | ||||||
|             } |             } | ||||||
|             if (mutex.size() > 1) { |             mutexes.push_back(lits); | ||||||
|                 mutexes.push_back(mutex); |  | ||||||
|             } |  | ||||||
|             non_empty = !mutex.empty(); |  | ||||||
|         } |         } | ||||||
|         return l_true; |         return l_true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void solver::get_reachable(literal p, literal_set const& goal, literal_set& reachable) { |  | ||||||
|         m_seen[1].reset(); |  | ||||||
|         m_todo.reset(); |  | ||||||
|         m_todo.push_back(p); |  | ||||||
|         while (!m_todo.empty()) { |  | ||||||
|             p = m_todo.back(); |  | ||||||
|             m_todo.pop_back(); |  | ||||||
|             if (m_seen[1].contains(p)) { |  | ||||||
|                 continue; |  | ||||||
|             } |  | ||||||
|             m_seen[1].insert(p); |  | ||||||
|             literal np = ~p; |  | ||||||
|             if (goal.contains(np)) { |  | ||||||
|                 reachable.insert(np); |  | ||||||
|             } |  | ||||||
|             m_todo.append(m_binary_clause_graph[np.index()]); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // -----------------------
 |     // -----------------------
 | ||||||
|     //
 |     //
 | ||||||
|     // Consequence generation.
 |     // Consequence generation.
 | ||||||
|  |  | ||||||
|  | @ -451,14 +451,9 @@ namespace sat { | ||||||
| 
 | 
 | ||||||
|         u_map<index_set>       m_antecedents; |         u_map<index_set>       m_antecedents; | ||||||
|         vector<literal_vector> m_binary_clause_graph; |         vector<literal_vector> m_binary_clause_graph; | ||||||
|         literal_set            m_reachable[2]; |  | ||||||
|         literal_set            m_seen[2]; |  | ||||||
|         literal_vector         m_todo; |  | ||||||
| 
 | 
 | ||||||
|         void extract_assumptions(literal lit, index_set& s); |         void extract_assumptions(literal lit, index_set& s); | ||||||
| 
 | 
 | ||||||
|         void get_reachable(literal p, literal_set const& goal, literal_set& reachable); |  | ||||||
| 
 |  | ||||||
|         lbool get_consequences(literal_vector const& assms, literal_vector const& lits, vector<literal_vector>& conseq); |         lbool get_consequences(literal_vector const& assms, literal_vector const& lits, vector<literal_vector>& conseq); | ||||||
| 
 | 
 | ||||||
|         void delete_unfixed(literal_set& unfixed); |         void delete_unfixed(literal_set& unfixed); | ||||||
|  |  | ||||||
|  | @ -96,6 +96,7 @@ namespace sat { | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     const literal null_literal; |     const literal null_literal; | ||||||
|  |     struct literal_hash : obj_hash<literal> {}; | ||||||
| 
 | 
 | ||||||
|     inline literal to_literal(unsigned x) { return literal(x); } |     inline literal to_literal(unsigned x) { return literal(x); } | ||||||
|     inline bool operator<(literal const & l1, literal const & l2) { return l1.m_val < l2.m_val;  } |     inline bool operator<(literal const & l1, literal const & l2) { return l1.m_val < l2.m_val;  } | ||||||
|  |  | ||||||
|  | @ -20,6 +20,8 @@ Revision History: | ||||||
| #include "ast_util.h" | #include "ast_util.h" | ||||||
| #include "datatype_decl_plugin.h" | #include "datatype_decl_plugin.h" | ||||||
| #include "model_pp.h" | #include "model_pp.h" | ||||||
|  | #include "max_cliques.h" | ||||||
|  | #include "stopwatch.h" | ||||||
| 
 | 
 | ||||||
| namespace smt { | namespace smt { | ||||||
| 
 | 
 | ||||||
|  | @ -367,67 +369,46 @@ namespace smt { | ||||||
|              << ")\n"; |              << ")\n"; | ||||||
|     }   |     }   | ||||||
| 
 | 
 | ||||||
|  |     struct neg_literal { | ||||||
|  |         unsigned negate(unsigned i) { | ||||||
|  |             return (~to_literal(i)).index(); | ||||||
|  |         } | ||||||
|  |     }; | ||||||
| 
 | 
 | ||||||
|     lbool context::find_mutexes(expr_ref_vector const& vars, vector<expr_ref_vector>& mutexes) { |     lbool context::find_mutexes(expr_ref_vector const& vars, vector<expr_ref_vector>& mutexes) { | ||||||
|         uint_set lits; |         unsigned_vector ps; | ||||||
|  |         max_cliques<neg_literal> mc; | ||||||
|  |         expr_ref lit(m_manager); | ||||||
|         for (unsigned i = 0; i < vars.size(); ++i) { |         for (unsigned i = 0; i < vars.size(); ++i) { | ||||||
|             expr* n = vars[i]; |             expr* n = vars[i]; | ||||||
|             bool neg = m_manager.is_not(n, n); |             bool neg = m_manager.is_not(n, n); | ||||||
|             if (b_internalized(n)) { |             if (b_internalized(n)) { | ||||||
|                 lits.insert(literal(get_bool_var(n), neg).index()); |                 ps.push_back(literal(get_bool_var(n), neg).index()); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         while (!lits.empty()) { |         for (unsigned i = 0; i < m_watches.size(); ++i) { | ||||||
|             literal_vector mutex; |             watch_list & w = m_watches[i]; | ||||||
|             uint_set other(lits); |             for (literal const* it = w.begin_literals(), *end = w.end_literals(); it != end; ++it) { | ||||||
|             while (!other.empty()) { |                 unsigned idx1 = (~to_literal(i)).index(); | ||||||
|                 uint_set conseq; |                 unsigned idx2 = it->index(); | ||||||
|                 literal p = to_literal(*other.begin()); |                 if (idx1 < idx2) { | ||||||
|                 other.remove(p.index()); |                     mc.add_edge(idx1, idx2); | ||||||
|                 mutex.push_back(p); |  | ||||||
|                 if (other.empty()) { |  | ||||||
|                     break; |  | ||||||
|                 } |                 } | ||||||
|                 get_reachable(p, other, conseq); |  | ||||||
|                 other = conseq; |  | ||||||
|             } |             } | ||||||
|             if (mutex.size() > 1) { |         } | ||||||
|                 expr_ref_vector mux(m_manager); |         vector<unsigned_vector> _mutexes; | ||||||
|                 for (unsigned i = 0; i < mutex.size(); ++i) { |         mc.cliques(ps, _mutexes); | ||||||
|                     expr_ref e(m_manager); |         for (unsigned i = 0; i < _mutexes.size(); ++i) { | ||||||
|                     literal2expr(mutex[i], e); |             expr_ref_vector lits(m_manager); | ||||||
|                     mux.push_back(e); |             for (unsigned j = 0; j < _mutexes[i].size(); ++j) { | ||||||
|                 } |                 literal2expr(to_literal(_mutexes[i][j]), lit); | ||||||
|                 mutexes.push_back(mux); |                 lits.push_back(lit); | ||||||
|             } |  | ||||||
|             for (unsigned i = 0; i < mutex.size(); ++i) { |  | ||||||
|                 lits.remove(mutex[i].index()); |  | ||||||
|             } |             } | ||||||
|  |             mutexes.push_back(lits); | ||||||
|         }         |         }         | ||||||
|         return l_true; |         return l_true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void context::get_reachable(literal p, uint_set& goal, uint_set& reachable) { |  | ||||||
|         uint_set seen; |  | ||||||
|         literal_vector todo; |  | ||||||
|         todo.push_back(p); |  | ||||||
|         while (!todo.empty()) { |  | ||||||
|             // std::cout << "todo: " << todo.size() << "\n";
 |  | ||||||
|             p = todo.back(); |  | ||||||
|             todo.pop_back(); |  | ||||||
|             if (seen.contains(p.index())) { |  | ||||||
|                 continue; |  | ||||||
|             } |  | ||||||
|             seen.insert(p.index()); |  | ||||||
|             literal np = ~p; |  | ||||||
|             if (goal.contains(np.index())) { |  | ||||||
|                 reachable.insert(np.index()); |  | ||||||
|             } |  | ||||||
|             watch_list & w = m_watches[np.index()]; |  | ||||||
|             todo.append(static_cast<unsigned>(w.end_literals() - w.begin_literals()), w.begin_literals()); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     //
 |     //
 | ||||||
|     // Validate, in a slow pass, that the current consequences are correctly 
 |     // Validate, in a slow pass, that the current consequences are correctly 
 | ||||||
|     // extracted.
 |     // extracted.
 | ||||||
|  |  | ||||||
|  | @ -1367,11 +1367,6 @@ namespace smt { | ||||||
|         void validate_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars,  |         void validate_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars,  | ||||||
|                                    expr_ref_vector const& conseq, expr_ref_vector const& unfixed); |                                    expr_ref_vector const& conseq, expr_ref_vector const& unfixed); | ||||||
| 
 | 
 | ||||||
|         /*
 |  | ||||||
|           \brief Auxiliry function for mutex finding. |  | ||||||
|          */ |  | ||||||
| 
 |  | ||||||
|         void get_reachable(literal p, uint_set& goal, uint_set& reached); |  | ||||||
| 
 | 
 | ||||||
|     public: |     public: | ||||||
|         context(ast_manager & m, smt_params & fp, params_ref const & p = params_ref()); |         context(ast_manager & m, smt_params & fp, params_ref const & p = params_ref()); | ||||||
|  |  | ||||||
|  | @ -194,6 +194,7 @@ namespace smt { | ||||||
|               } |               } | ||||||
|               tout << "\n";); |               tout << "\n";); | ||||||
|          |          | ||||||
|  |         max_generation = std::max(m_qm->get_generation(q), max_generation); | ||||||
|         add_instance(q, bindings, max_generation); |         add_instance(q, bindings, max_generation); | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
							
								
								
									
										140
									
								
								src/util/max_cliques.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								src/util/max_cliques.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,140 @@ | ||||||
|  | /*++
 | ||||||
|  | Copyright (c) 2016 Microsoft Corporation | ||||||
|  | 
 | ||||||
|  | Module Name: | ||||||
|  | 
 | ||||||
|  |     max_cliques.h | ||||||
|  | 
 | ||||||
|  | Abstract: | ||||||
|  | 
 | ||||||
|  |     Utility for enumerating locally maximal sub cliques. | ||||||
|  | 
 | ||||||
|  | Author: | ||||||
|  | 
 | ||||||
|  |     Nikolaj Bjorner (nbjorner) 2016-11-18 | ||||||
|  | 
 | ||||||
|  | Notes: | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | --*/ | ||||||
|  | 
 | ||||||
|  | #include "vector.h" | ||||||
|  | #include "uint_set.h" | ||||||
|  | 
 | ||||||
|  | class max_cliques_plugin { | ||||||
|  | public: | ||||||
|  |     virtual unsigned operator()(unsigned i) = 0; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | template<class T> | ||||||
|  | class max_cliques : public T { | ||||||
|  |     vector<unsigned_vector> m_next, m_tc; | ||||||
|  |     uint_set                m_reachable[2]; | ||||||
|  |     uint_set                m_seen1, m_seen2; | ||||||
|  |     unsigned_vector         m_todo; | ||||||
|  | 
 | ||||||
|  |     void get_reachable(unsigned p, uint_set const& goal, uint_set& reachable) { | ||||||
|  |         m_seen1.reset(); | ||||||
|  |         m_todo.reset(); | ||||||
|  |         m_todo.push_back(p); | ||||||
|  |         for (unsigned i = 0; i < m_todo.size(); ++i) { | ||||||
|  |             p = m_todo[i]; | ||||||
|  |             if (m_seen1.contains(p)) { | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |             m_seen1.insert(p); | ||||||
|  |             if (m_seen2.contains(p)) { | ||||||
|  |                 unsigned_vector const& tc = m_tc[p]; | ||||||
|  |                 for (unsigned j = 0; j < tc.size(); ++j) { | ||||||
|  |                     unsigned np = tc[j]; | ||||||
|  |                     if (goal.contains(np)) { | ||||||
|  |                         reachable.insert(np); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             else { | ||||||
|  |                 unsigned np = negate(p); | ||||||
|  |                 if (goal.contains(np)) { | ||||||
|  |                     reachable.insert(np); | ||||||
|  |                 } | ||||||
|  |                 m_todo.append(next(np)); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         for (unsigned i = m_todo.size(); i > 0; ) { | ||||||
|  |             --i; | ||||||
|  |             p = m_todo[i]; | ||||||
|  |             if (m_seen2.contains(p)) { | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |             m_seen2.insert(p); | ||||||
|  |             unsigned np = negate(p); | ||||||
|  |             unsigned_vector& tc = m_tc[p]; | ||||||
|  |             if (goal.contains(np)) { | ||||||
|  |                 tc.push_back(np); | ||||||
|  |             } | ||||||
|  |             else { | ||||||
|  |                 unsigned_vector const& succ = next(np); | ||||||
|  |                 for (unsigned j = 0; j < succ.size(); ++j) { | ||||||
|  |                     tc.append(m_tc[succ[j]]); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |      | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     unsigned_vector const& next(unsigned vertex) const { return m_next[vertex]; } | ||||||
|  |      | ||||||
|  | public: | ||||||
|  |     max_cliques() {} | ||||||
|  | 
 | ||||||
|  |     void add_edge(unsigned src, unsigned dst) { | ||||||
|  |         m_next.reserve(std::max(src, dst) + 1); | ||||||
|  |         m_next.reserve(std::max(negate(src), negate(dst)) + 1); | ||||||
|  |         m_next[src].push_back(dst); | ||||||
|  |         m_next[dst].push_back(src); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void cliques(unsigned_vector const& ps, vector<unsigned_vector>& cliques) {      | ||||||
|  |         unsigned max = 0; | ||||||
|  |         unsigned num_ps = ps.size(); | ||||||
|  |         for (unsigned i = 0; i < num_ps; ++i) { | ||||||
|  |             unsigned  p = ps[i]; | ||||||
|  |             unsigned np = negate(p); | ||||||
|  |             max = std::max(max, std::max(np, p) + 1); | ||||||
|  |         } | ||||||
|  |         m_next.reserve(max); | ||||||
|  |         m_tc.reserve(max); | ||||||
|  |         unsigned_vector clique; | ||||||
|  |         uint_set vars; | ||||||
|  |         for (unsigned i = 0; i < num_ps; ++i) { | ||||||
|  |             vars.insert(ps[i]); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         while (!vars.empty()) { | ||||||
|  |             clique.reset(); | ||||||
|  |             bool turn = false; | ||||||
|  |             m_reachable[turn] = vars; | ||||||
|  |             while (!m_reachable[turn].empty()) { | ||||||
|  |                 unsigned p = *m_reachable[turn].begin(); | ||||||
|  |                 m_reachable[turn].remove(p); | ||||||
|  |                 vars.remove(p); | ||||||
|  |                 clique.push_back(p); | ||||||
|  |                 if (m_reachable[turn].empty()) { | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |                 m_reachable[!turn].reset(); | ||||||
|  |                 get_reachable(p, m_reachable[turn], m_reachable[!turn]); | ||||||
|  |                 turn = !turn; | ||||||
|  |             } | ||||||
|  |             if (clique.size() > 1) { | ||||||
|  |                 std::cout << clique.size() << "\n"; | ||||||
|  |                 cliques.push_back(clique); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | }; | ||||||
|  | @ -744,6 +744,7 @@ Notes: | ||||||
|             return vc_cmp()*std::min(a-1,b); |             return vc_cmp()*std::min(a-1,b); | ||||||
|         } |         } | ||||||
|          |          | ||||||
|  |     public: | ||||||
|         void sorting(unsigned n, literal const* xs, literal_vector& out) { |         void sorting(unsigned n, literal const* xs, literal_vector& out) { | ||||||
|             TRACE("pb", tout << "sorting: " << n << "\n";); |             TRACE("pb", tout << "sorting: " << n << "\n";); | ||||||
|             switch(n) { |             switch(n) { | ||||||
|  | @ -773,8 +774,9 @@ Notes: | ||||||
|             TRACE("pb", tout << "sorting: " << n << "\n"; |             TRACE("pb", tout << "sorting: " << n << "\n"; | ||||||
|                   pp(tout << "in:", n, xs) << "\n";  |                   pp(tout << "in:", n, xs) << "\n";  | ||||||
|                   pp(tout << "out:", out) << "\n";); |                   pp(tout << "out:", out) << "\n";); | ||||||
| 
 |  | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |     private: | ||||||
|         vc vc_sorting(unsigned n) { |         vc vc_sorting(unsigned n) { | ||||||
|             switch(n) { |             switch(n) { | ||||||
|             case 0: return vc(0,0); |             case 0: return vc(0,0); | ||||||
|  |  | ||||||
|  | @ -163,10 +163,11 @@ public: | ||||||
|     class iterator { |     class iterator { | ||||||
|         uint_set const* m_set; |         uint_set const* m_set; | ||||||
|         unsigned  m_index; |         unsigned  m_index; | ||||||
|  |         unsigned  m_last; | ||||||
| 
 | 
 | ||||||
|         bool invariant() const { return m_index <= m_set->get_max_elem(); } |         bool invariant() const { return m_index <= m_last; } | ||||||
| 
 | 
 | ||||||
|         bool at_end() const { return m_index == m_set->get_max_elem(); } |         bool at_end() const { return m_index == m_last; } | ||||||
| 
 | 
 | ||||||
|         void scan_idx() { |         void scan_idx() { | ||||||
|             SASSERT(invariant()); |             SASSERT(invariant()); | ||||||
|  | @ -200,7 +201,7 @@ public: | ||||||
|         } |         } | ||||||
|     public: |     public: | ||||||
|         iterator(uint_set const& s, bool at_end):  |         iterator(uint_set const& s, bool at_end):  | ||||||
|             m_set(&s), m_index(at_end?s.get_max_elem():0) { |             m_set(&s), m_index(at_end?s.get_max_elem():0), m_last(s.get_max_elem()) { | ||||||
|             scan(); |             scan(); | ||||||
|             SASSERT(invariant()); |             SASSERT(invariant()); | ||||||
|           } |           } | ||||||
|  | @ -212,6 +213,7 @@ public: | ||||||
|         iterator & operator=(iterator const& other) {  |         iterator & operator=(iterator const& other) {  | ||||||
|             m_set = other.m_set; |             m_set = other.m_set; | ||||||
|             m_index = other.m_index; |             m_index = other.m_index; | ||||||
|  |             m_last = other.m_last; | ||||||
|             return *this; |             return *this; | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue