mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 11:42:28 +00:00 
			
		
		
		
	fix bug reported in issue #193: MBQI needs to avoid instantiating data-types that contain model values in nested positions
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
		
							parent
							
								
									702af71a2d
								
							
						
					
					
						commit
						cd838e5cf4
					
				
					 7 changed files with 100 additions and 40 deletions
				
			
		|  | @ -45,6 +45,7 @@ namespace sat { | ||||||
|         m_R.reset(); |         m_R.reset(); | ||||||
|         m_L_blits.reset(); |         m_L_blits.reset(); | ||||||
|         m_R_blits.reset(); |         m_R_blits.reset(); | ||||||
|  |         m_bce_use_list.finalize(); | ||||||
|         clause * const* it = m_solver.begin_clauses(); |         clause * const* it = m_solver.begin_clauses(); | ||||||
|         clause * const* end = m_solver.end_clauses(); |         clause * const* end = m_solver.end_clauses(); | ||||||
|         for (; it != end; ++it) { |         for (; it != end; ++it) { | ||||||
|  | @ -140,7 +141,6 @@ namespace sat { | ||||||
|         for (unsigned i = 0; i < m_L.size(); ++i) { |         for (unsigned i = 0; i < m_L.size(); ++i) { | ||||||
|             ul.insert(*m_L[i]); |             ul.insert(*m_L[i]); | ||||||
|         } |         } | ||||||
| #define MOVE_R_TO_L                             \ |  | ||||||
| 
 | 
 | ||||||
|         // cheap pass: add clauses from R in order
 |         // cheap pass: add clauses from R in order
 | ||||||
|         // such that they are blocked with respect to
 |         // such that they are blocked with respect to
 | ||||||
|  | @ -161,6 +161,10 @@ namespace sat { | ||||||
|         } |         } | ||||||
|         // expensive pass: add clauses from R as long
 |         // expensive pass: add clauses from R as long
 | ||||||
|         // as BCE produces the empty set of clauses.
 |         // as BCE produces the empty set of clauses.
 | ||||||
|  |         m_bce_use_list.init(m_solver.num_vars()); | ||||||
|  |         for (unsigned i = 0; i < m_L.size(); ++i) { | ||||||
|  |             m_bce_use_list.insert(*m_L[i]); | ||||||
|  |         } | ||||||
|         for (unsigned i = 0; i < m_R.size(); ++i) { |         for (unsigned i = 0; i < m_R.size(); ++i) { | ||||||
|             if (bce(*m_R[i])) { |             if (bce(*m_R[i])) { | ||||||
|                 m_R[i] = m_R.back(); |                 m_R[i] = m_R.back(); | ||||||
|  | @ -173,29 +177,29 @@ namespace sat { | ||||||
|         m_use_list = save; |         m_use_list = save; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     bool bceq::bce(clause& cls) { |     bool bceq::bce(clause& cls0) { | ||||||
|  |         IF_VERBOSE(1, verbose_stream() << "bce " << m_L.size() << " " << m_R.size() << " " << cls0 << "\n";); | ||||||
|         svector<bool> live_clauses; |         svector<bool> live_clauses; | ||||||
|         use_list ul; |         m_use_list = &m_bce_use_list; | ||||||
|         m_use_list = &ul; |         m_bce_use_list.insert(cls0); | ||||||
|         ul.init(m_solver.num_vars()); |  | ||||||
|         for (unsigned i = 0; i < m_L.size(); ++i) { |  | ||||||
|             ul.insert(*m_L[i]); |  | ||||||
|         } |  | ||||||
|         ul.insert(cls); |  | ||||||
|         svector<clause*> clauses(m_L), new_clauses; |         svector<clause*> clauses(m_L), new_clauses; | ||||||
|         literal_vector blits(m_L_blits), new_blits; |         literal_vector blits(m_L_blits), new_blits; | ||||||
|         clauses.push_back(&cls); |         clauses.push_back(&cls0); | ||||||
|         blits.push_back(null_literal); |         blits.push_back(null_literal); | ||||||
|         bool removed = false; |         bool removed = false; | ||||||
|         m_removed.reset(); |         m_removed.reset(); | ||||||
|         do { |         do { | ||||||
|             removed = false; |             removed = false; | ||||||
|             for (unsigned i = 0; i < clauses.size(); ++i) { |             for (unsigned i = 0; i < clauses.size(); ++i) { | ||||||
|                 clause& cls = *clauses[i]; |                 clause& cls1 = *clauses[i]; | ||||||
|                 literal lit = find_blocked(cls); |                 literal lit = find_blocked(cls1); | ||||||
|                 if (lit != null_literal) { |                 if (lit == null_literal) { | ||||||
|                     m_removed.setx(cls.id(), true, false); |                     m_bce_use_list.erase(cls1); | ||||||
|                     new_clauses.push_back(&cls); |                 } | ||||||
|  |                 else { | ||||||
|  |                     IF_VERBOSE(2, verbose_stream() << "; remove " << cls1 << "\n";); | ||||||
|  |                     m_removed.setx(cls1.id(), true, false); | ||||||
|  |                     new_clauses.push_back(&cls1); | ||||||
|                     new_blits.push_back(lit); |                     new_blits.push_back(lit); | ||||||
|                     removed = true; |                     removed = true; | ||||||
|                     clauses[i] = clauses.back(); |                     clauses[i] = clauses.back(); | ||||||
|  | @ -215,7 +219,7 @@ namespace sat { | ||||||
|             m_L.append(new_clauses); |             m_L.append(new_clauses); | ||||||
|             m_L_blits.append(new_blits); |             m_L_blits.append(new_blits); | ||||||
|         } |         } | ||||||
|         if (!clauses.empty()) std::cout << "Number left after BCE: " << clauses.size() << "\n"; |         IF_VERBOSE(1, if (!clauses.empty()) verbose_stream() << "; clauses left after BCE: " << clauses.size() << "\n";); | ||||||
|         return clauses.empty(); |         return clauses.empty(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -442,9 +446,10 @@ namespace sat { | ||||||
|         roots[l2.var()] = l1; |         roots[l2.var()] = l1; | ||||||
|         vars.push_back(l2.var()); |         vars.push_back(l2.var()); | ||||||
|         elim_eqs elim(m_solver); |         elim_eqs elim(m_solver); | ||||||
|         for (unsigned i = 0; i < vars.size(); ++i) { |         IF_VERBOSE(1,  | ||||||
|             std::cout << "var: " << vars[i] << " root: " << roots[vars[i]] << "\n"; |                    for (unsigned i = 0; i < vars.size(); ++i) { | ||||||
|         } |                        verbose_stream() << "var: " << vars[i] << " root: " << roots[vars[i]] << "\n"; | ||||||
|  |                    }); | ||||||
|         elim(roots, vars); |         elim(roots, vars); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -473,7 +478,7 @@ namespace sat { | ||||||
|         init(); |         init(); | ||||||
|         pure_decompose(); |         pure_decompose(); | ||||||
|         post_decompose(); |         post_decompose(); | ||||||
|         std::cout << "Decomposed set " << m_L.size() << " rest: " << m_R.size() << "\n"; |         IF_VERBOSE(1, verbose_stream() << "Decomposed set " << m_L.size() << " rest: " << m_R.size() << "\n";); | ||||||
| 
 | 
 | ||||||
|         TRACE("sat", |         TRACE("sat", | ||||||
|               tout << "Decomposed set " << m_L.size() << "\n"; |               tout << "Decomposed set " << m_L.size() << "\n"; | ||||||
|  |  | ||||||
|  | @ -21,6 +21,7 @@ Revision History: | ||||||
| 
 | 
 | ||||||
| #include"sat_types.h" | #include"sat_types.h" | ||||||
| #include "union_find.h" | #include "union_find.h" | ||||||
|  | #include "sat_simplifier.h" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| namespace sat { | namespace sat { | ||||||
|  | @ -33,6 +34,7 @@ namespace sat { | ||||||
|         typedef svector<bin_clause> bin_clauses;         |         typedef svector<bin_clause> bin_clauses;         | ||||||
|         solver &          m_solver; |         solver &          m_solver; | ||||||
|         use_list*         m_use_list; |         use_list*         m_use_list; | ||||||
|  |         use_list          m_bce_use_list; | ||||||
|         solver*           m_s; |         solver*           m_s; | ||||||
|         random_gen        m_rand; |         random_gen        m_rand; | ||||||
|         svector<clause*>  m_clauses; |         svector<clause*>  m_clauses; | ||||||
|  |  | ||||||
|  | @ -100,6 +100,7 @@ public: | ||||||
|     virtual void set_progress_callback(progress_callback * callback) {} |     virtual void set_progress_callback(progress_callback * callback) {} | ||||||
| 
 | 
 | ||||||
|     virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions) {         |     virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions) {         | ||||||
|  | 
 | ||||||
|         m_solver.pop_to_base_level(); |         m_solver.pop_to_base_level(); | ||||||
|         dep2asm_t dep2asm; |         dep2asm_t dep2asm; | ||||||
|         m_model = 0; |         m_model = 0; | ||||||
|  | @ -112,6 +113,7 @@ public: | ||||||
|         r = initialize_soft_constraints(); |         r = initialize_soft_constraints(); | ||||||
|         if (r != l_true) return r; |         if (r != l_true) return r; | ||||||
| 
 | 
 | ||||||
|  |         m_solver.display_dimacs(std::cout); | ||||||
|         r = m_solver.check(m_asms.size(), m_asms.c_ptr()); |         r = m_solver.check(m_asms.size(), m_asms.c_ptr()); | ||||||
|         switch (r) { |         switch (r) { | ||||||
|         case l_true: |         case l_true: | ||||||
|  |  | ||||||
|  | @ -171,7 +171,7 @@ namespace smt { | ||||||
|                     sk_value = sk_term; |                     sk_value = sk_term; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             if (m_manager.is_model_value(sk_value)) |             if (contains_model_value(sk_value)) | ||||||
|                 return false; |                 return false; | ||||||
|             bindings.set(num_decls - i - 1, sk_value); |             bindings.set(num_decls - i - 1, sk_value); | ||||||
|         } |         } | ||||||
|  | @ -190,6 +190,30 @@ namespace smt { | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     void model_checker::operator()(expr *n) { | ||||||
|  |         if (m_manager.is_model_value(n)) { | ||||||
|  |             throw is_model_value(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool model_checker::contains_model_value(expr* n) { | ||||||
|  |         if (m_manager.is_model_value(n)) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         if (is_app(n) && to_app(n)->get_num_args() == 0) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         m_visited.reset(); | ||||||
|  |         try { | ||||||
|  |             for_each_expr(*this, m_visited, n); | ||||||
|  |         } | ||||||
|  |         catch (is_model_value) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|     bool model_checker::add_blocking_clause(model * cex, expr_ref_vector & sks) { |     bool model_checker::add_blocking_clause(model * cex, expr_ref_vector & sks) { | ||||||
|         SASSERT(cex != 0); |         SASSERT(cex != 0); | ||||||
|         unsigned num_sks  = sks.size(); |         unsigned num_sks  = sks.size(); | ||||||
|  |  | ||||||
|  | @ -80,6 +80,10 @@ namespace smt { | ||||||
| 
 | 
 | ||||||
|         quantifier * get_flat_quantifier(quantifier * q); |         quantifier * get_flat_quantifier(quantifier * q); | ||||||
| 
 | 
 | ||||||
|  |         struct is_model_value {}; | ||||||
|  |         expr_mark m_visited; | ||||||
|  |         bool contains_model_value(expr* e); | ||||||
|  | 
 | ||||||
|     public: |     public: | ||||||
|         model_checker(ast_manager & m, qi_params const & p, model_finder & mf); |         model_checker(ast_manager & m, qi_params const & p, model_finder & mf); | ||||||
|         ~model_checker(); |         ~model_checker(); | ||||||
|  | @ -95,6 +99,9 @@ namespace smt { | ||||||
|         void reset(); |         void reset(); | ||||||
| 
 | 
 | ||||||
|         void set_cancel(bool f) { m_cancel = f; } |         void set_cancel(bool f) { m_cancel = f; } | ||||||
|  | 
 | ||||||
|  |         void operator()(expr* e); | ||||||
|  | 
 | ||||||
|     }; |     }; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -83,6 +83,7 @@ namespace smt { | ||||||
|             ast_manager &           m_manager; |             ast_manager &           m_manager; | ||||||
|             obj_map<expr, unsigned> m_elems; // and the associated generation
 |             obj_map<expr, unsigned> m_elems; // and the associated generation
 | ||||||
|             obj_map<expr, expr *>   m_inv; |             obj_map<expr, expr *>   m_inv; | ||||||
|  |             expr_mark               m_visited; | ||||||
|         public: |         public: | ||||||
|             instantiation_set(ast_manager & m):m_manager(m) {} |             instantiation_set(ast_manager & m):m_manager(m) {} | ||||||
|              |              | ||||||
|  | @ -98,11 +99,11 @@ namespace smt { | ||||||
|             obj_map<expr, unsigned> const & get_elems() const { return m_elems; } |             obj_map<expr, unsigned> const & get_elems() const { return m_elems; } | ||||||
| 
 | 
 | ||||||
|             void insert(expr * n, unsigned generation) { |             void insert(expr * n, unsigned generation) { | ||||||
|                 if (m_elems.contains(n)) |                 if (m_elems.contains(n) || contains_model_value(n)) | ||||||
|                     return; |                     return; | ||||||
|  |                 TRACE("model_finder", tout << mk_pp(n, m_manager) << "\n";); | ||||||
|                 m_manager.inc_ref(n); |                 m_manager.inc_ref(n); | ||||||
|                 m_elems.insert(n, generation); |                 m_elems.insert(n, generation); | ||||||
|                 CTRACE("model_finder", m_manager.is_model_value(n), tout << mk_pp(n, m_manager) << "\n";); |  | ||||||
|                 SASSERT(!m_manager.is_model_value(n)); |                 SASSERT(!m_manager.is_model_value(n)); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  | @ -145,9 +146,10 @@ namespace smt { | ||||||
|                 obj_map<expr, unsigned>::iterator end = m_elems.end(); |                 obj_map<expr, unsigned>::iterator end = m_elems.end(); | ||||||
|                 for (; it != end; ++it) { |                 for (; it != end; ++it) { | ||||||
|                     expr *     t = (*it).m_key; |                     expr *     t = (*it).m_key; | ||||||
|                     SASSERT(!m_manager.is_model_value(t)); |                     SASSERT(!contains_model_value(t)); | ||||||
|                     unsigned gen = (*it).m_value; |                     unsigned gen = (*it).m_value; | ||||||
|                     expr * t_val = ev.eval(t, true); |                     expr * t_val = ev.eval(t, true); | ||||||
|  |                     TRACE("model_finder", tout << mk_pp(t, m_manager) << "\n";); | ||||||
| 
 | 
 | ||||||
|                     expr * old_t = 0; |                     expr * old_t = 0; | ||||||
|                     if (m_inv.find(t_val, old_t)) { |                     if (m_inv.find(t_val, old_t)) { | ||||||
|  | @ -167,6 +169,30 @@ namespace smt { | ||||||
|             obj_map<expr, expr *> const & get_inv_map() const { |             obj_map<expr, expr *> const & get_inv_map() const { | ||||||
|                 return m_inv; |                 return m_inv; | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|  |             struct is_model_value {}; | ||||||
|  |             void operator()(expr *n) { | ||||||
|  |                 if (m_manager.is_model_value(n)) { | ||||||
|  |                     throw is_model_value(); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             bool contains_model_value(expr* n) { | ||||||
|  |                 if (m_manager.is_model_value(n)) { | ||||||
|  |                     return true; | ||||||
|  |                 } | ||||||
|  |                 if (is_app(n) && to_app(n)->get_num_args() == 0) { | ||||||
|  |                     return false; | ||||||
|  |                 } | ||||||
|  |                 m_visited.reset(); | ||||||
|  |                 try { | ||||||
|  |                     for_each_expr(*this, m_visited, n); | ||||||
|  |                 } | ||||||
|  |                 catch (is_model_value) { | ||||||
|  |                     return true; | ||||||
|  |                 } | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         /**
 |         /**
 | ||||||
|  | @ -286,7 +312,7 @@ namespace smt { | ||||||
|                 return get_root()->m_signed_proj; |                 return get_root()->m_signed_proj; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             void mk_instatiation_set(ast_manager & m) { |             void mk_instantiation_set(ast_manager & m) { | ||||||
|                 SASSERT(is_root()); |                 SASSERT(is_root()); | ||||||
|                 m_set = alloc(instantiation_set, m); |                 m_set = alloc(instantiation_set, m); | ||||||
|             } |             } | ||||||
|  | @ -527,13 +553,13 @@ namespace smt { | ||||||
|                 return 0; |                 return 0; | ||||||
|             } |             } | ||||||
|              |              | ||||||
|             void mk_instatiation_sets() { |             void mk_instantiation_sets() { | ||||||
|                 ptr_vector<node>::const_iterator it  = m_nodes.begin(); |                 ptr_vector<node>::const_iterator it  = m_nodes.begin(); | ||||||
|                 ptr_vector<node>::const_iterator end = m_nodes.end(); |                 ptr_vector<node>::const_iterator end = m_nodes.end(); | ||||||
|                 for (; it != end; ++it) { |                 for (; it != end; ++it) { | ||||||
|                     node * curr = *it; |                     node * curr = *it; | ||||||
|                     if (curr->is_root()) { |                     if (curr->is_root()) { | ||||||
|                         curr->mk_instatiation_set(m_manager); |                         curr->mk_instantiation_set(m_manager); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  | @ -695,6 +721,7 @@ namespace smt { | ||||||
|                     return 0; |                     return 0; | ||||||
|                 m_model->register_decl(k_decl, r); |                 m_model->register_decl(k_decl, r); | ||||||
|                 SASSERT(m_model->get_const_interp(k_decl) == r); |                 SASSERT(m_model->get_const_interp(k_decl) == r); | ||||||
|  |                 TRACE("model_finder", tout << mk_pp(r, m_manager) << "\n";); | ||||||
|                 return r; |                 return r; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  | @ -1204,7 +1231,7 @@ namespace smt { | ||||||
|                         // a necessary instantiation.
 |                         // a necessary instantiation.
 | ||||||
|                         enode * e_arg = n->get_arg(m_arg_i); |                         enode * e_arg = n->get_arg(m_arg_i); | ||||||
|                         expr * arg    = e_arg->get_owner(); |                         expr * arg    = e_arg->get_owner(); | ||||||
|                         A_f_i->insert(arg, e_arg->get_generation()); |                         A_f_i->insert(arg, e_arg->get_generation());                         | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  | @ -1225,7 +1252,7 @@ namespace smt { | ||||||
|                     if (ctx->is_relevant(n)) { |                     if (ctx->is_relevant(n)) { | ||||||
|                         enode * e_arg = n->get_arg(m_arg_i); |                         enode * e_arg = n->get_arg(m_arg_i); | ||||||
|                         expr * arg    = e_arg->get_owner(); |                         expr * arg    = e_arg->get_owner(); | ||||||
|                         s->insert(arg, e_arg->get_generation()); |                         s->insert(arg, e_arg->get_generation());                         | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  | @ -3378,7 +3405,7 @@ namespace smt { | ||||||
|             quantifier_info * qi = get_quantifier_info(q); |             quantifier_info * qi = get_quantifier_info(q); | ||||||
|             qi->process_auf(*(m_auf_solver.get()), m_context); |             qi->process_auf(*(m_auf_solver.get()), m_context); | ||||||
|         } |         } | ||||||
|         m_auf_solver->mk_instatiation_sets(); |         m_auf_solver->mk_instantiation_sets(); | ||||||
|         it  = qs.begin(); |         it  = qs.begin(); | ||||||
|         for (; it != end; ++it) { |         for (; it != end; ++it) { | ||||||
|             quantifier * q       = *it; |             quantifier * q       = *it; | ||||||
|  |  | ||||||
|  | @ -68,17 +68,10 @@ namespace smt { | ||||||
| 
 | 
 | ||||||
|      |      | ||||||
|     bool theory_opt::is_numeral(arith_util& a, expr* term) { |     bool theory_opt::is_numeral(arith_util& a, expr* term) { | ||||||
|         while (true) { |         while (a.is_uminus(term) || a.is_to_real(term) || a.is_to_int(term)) { | ||||||
|             if (a.is_uminus(term) || a.is_to_real(term) || a.is_to_int(term)) { |             term = to_app(term)->get_arg(0); | ||||||
|                 term = to_app(term)->get_arg(0); |  | ||||||
|             } |  | ||||||
|             else if (a.is_numeral(term)) { |  | ||||||
|                 return true; |  | ||||||
|             } |  | ||||||
|             else { |  | ||||||
|                 return false; |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|  |         return a.is_numeral(term); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| }; | }; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue