mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 11:42:28 +00:00 
			
		
		
		
	fixes #186, remove ite-lifting from opt_context to detect weighted maxsat
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
		
							parent
							
								
									e59ec5fefd
								
							
						
					
					
						commit
						f96c0b6963
					
				
					 8 changed files with 109 additions and 22 deletions
				
			
		|  | @ -2038,11 +2038,13 @@ app * ast_manager::mk_app_core(func_decl * decl, unsigned num_args, expr * const | |||
|                 } | ||||
|             } | ||||
|         } | ||||
|         check_args(decl, num_args, new_args.c_ptr()); | ||||
|         SASSERT(new_args.size() == num_args); | ||||
|         new_node = new (mem) app(decl, num_args, new_args.c_ptr()); | ||||
|         r = register_node(new_node); | ||||
|     } | ||||
|     else { | ||||
|         check_args(decl, num_args, args); | ||||
|         new_node = new (mem) app(decl, num_args, args); | ||||
|         r = register_node(new_node); | ||||
|     } | ||||
|  | @ -2064,6 +2066,22 @@ app * ast_manager::mk_app_core(func_decl * decl, unsigned num_args, expr * const | |||
|     return r; | ||||
| } | ||||
| 
 | ||||
| void ast_manager::check_args(func_decl* f, unsigned n, expr* const* es) { | ||||
|     for (unsigned i = 0; i < n; i++) { | ||||
|         sort * actual_sort   = get_sort(es[i]); | ||||
|         sort * expected_sort = f->is_associative() ? f->get_domain(0) : f->get_domain(i); | ||||
|         if (expected_sort != actual_sort) { | ||||
|             std::ostringstream buffer; | ||||
|             buffer << "Sort mismatch at argument #" << (i+1)  | ||||
|                    << " for function " << mk_pp(f,*this)  | ||||
|                    << " supplied sort is "  | ||||
|                    << mk_pp(actual_sort, *this); | ||||
|             throw ast_exception(buffer.str().c_str());             | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| inline app * ast_manager::mk_app_core(func_decl * decl, expr * arg1, expr * arg2) { | ||||
|     expr * args[2] = { arg1, arg2 }; | ||||
|     return mk_app_core(decl, 2, args); | ||||
|  |  | |||
|  | @ -1460,6 +1460,9 @@ protected: | |||
| 
 | ||||
|     bool coercion_needed(func_decl * decl, unsigned num_args, expr * const * args); | ||||
| 
 | ||||
|     void check_args(func_decl* f, unsigned n, expr* const* es); | ||||
| 
 | ||||
| 
 | ||||
| public: | ||||
|     ast_manager(proof_gen_mode = PGM_DISABLED, char const * trace_file = 0, bool is_format_manager = false); | ||||
|     ast_manager(proof_gen_mode, std::fstream * trace_stream, bool is_format_manager = false); | ||||
|  |  | |||
|  | @ -280,3 +280,9 @@ bool pb_util::has_unit_coefficients(func_decl* f) const { | |||
|     } | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| app* pb_util::mk_fresh_bool() { | ||||
|     symbol name = m.mk_fresh_var_name("pb"); | ||||
|     func_decl_info info(m_fid, OP_PB_AUX_BOOL, 0, 0); | ||||
|     return m.mk_const(m.mk_func_decl(name, 0, (sort *const*)0, m.mk_bool_sort(), info)); | ||||
| } | ||||
|  |  | |||
|  | @ -35,6 +35,7 @@ enum pb_op_kind { | |||
|     OP_PB_LE,      // pseudo-Boolean <= (generalizes at_most_k)
 | ||||
|     OP_PB_GE,      // pseudo-Boolean >= 
 | ||||
|     OP_PB_EQ,      // equality
 | ||||
|     OP_PB_AUX_BOOL, // auxiliary internal Boolean variable.
 | ||||
|     LAST_PB_OP | ||||
| }; | ||||
| 
 | ||||
|  | @ -71,6 +72,7 @@ public: | |||
|     virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,  | ||||
|                                      unsigned arity, sort * const * domain, sort * range); | ||||
|     virtual void get_op_names(svector<builtin_name> & op_names, symbol const & logic); | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
|  | @ -101,6 +103,7 @@ public: | |||
|     bool is_ge(func_decl* a) const; | ||||
|     bool is_ge(expr* a) const { return is_app(a) && is_ge(to_app(a)->get_decl()); } | ||||
|     bool is_ge(expr* a, rational& k) const; | ||||
|     bool is_aux_bool(expr* e) const { return is_app_of(e, m_fid, OP_PB_AUX_BOOL); } | ||||
|     rational get_coeff(expr* a, unsigned index) const { return get_coeff(to_app(a)->get_decl(), index); } | ||||
|     rational get_coeff(func_decl* a, unsigned index) const;  | ||||
|     bool has_unit_coefficients(func_decl* f) const; | ||||
|  | @ -111,6 +114,8 @@ public: | |||
|     bool is_eq(expr* e) const { return is_app(e) && is_eq(to_app(e)->get_decl()); } | ||||
|     bool is_eq(expr* e, rational& k) const; | ||||
| 
 | ||||
|     app* mk_fresh_bool(); | ||||
| 
 | ||||
| 
 | ||||
| private: | ||||
|     rational to_rational(parameter const& p) const; | ||||
|  |  | |||
|  | @ -31,7 +31,6 @@ Notes: | |||
| #include "propagate_values_tactic.h" | ||||
| #include "solve_eqs_tactic.h" | ||||
| #include "elim_uncnstr_tactic.h" | ||||
| #include "elim_term_ite_tactic.h" | ||||
| #include "tactical.h" | ||||
| #include "model_smt2_pp.h" | ||||
| #include "card2bv_tactic.h" | ||||
|  | @ -652,7 +651,6 @@ namespace opt { | |||
|             and_then(mk_simplify_tactic(m),  | ||||
|                      mk_propagate_values_tactic(m), | ||||
|                      mk_solve_eqs_tactic(m), | ||||
|                      mk_elim_term_ite_tactic(m), | ||||
|                      // NB: mk_elim_uncstr_tactic(m) is not sound with soft constraints
 | ||||
|                      mk_simplify_tactic(m));    | ||||
|         opt_params optp(m_params); | ||||
|  | @ -660,14 +658,16 @@ namespace opt { | |||
|         if (optp.elim_01()) { | ||||
|             tac2 = mk_elim01_tactic(m); | ||||
|             tac3 = mk_lia2card_tactic(m); | ||||
|             tac4 = mk_elim_term_ite_tactic(m); | ||||
|             params_ref lia_p; | ||||
|             lia_p.set_bool("compile_equality", optp.pb_compile_equality()); | ||||
|             tac3->updt_params(lia_p); | ||||
|             set_simplify(and_then(tac0.get(), tac2.get(), tac3.get(), tac4.get())); | ||||
|             set_simplify(and_then(tac0.get(), tac2.get(), tac3.get(), mk_simplify_tactic(m))); | ||||
|         } | ||||
|         else { | ||||
|             set_simplify(tac0.get()); | ||||
|             tactic_ref tac1 =  | ||||
|                 and_then(tac0.get(), | ||||
|                          mk_simplify_tactic(m));             | ||||
|             set_simplify(tac1.get()); | ||||
|         } | ||||
|         proof_converter_ref pc; | ||||
|         expr_dependency_ref core(m); | ||||
|  | @ -875,9 +875,11 @@ namespace opt { | |||
|                 TRACE("opt", tout << "maxsat: " << id << " offset:" << offset << "\n";); | ||||
|             } | ||||
|             else if (is_maximize(fml, tr, orig_term, index)) { | ||||
|                 purify(tr); | ||||
|                 m_objectives[index].m_term = tr; | ||||
|             } | ||||
|             else if (is_minimize(fml, tr, orig_term, index)) { | ||||
|                 purify(tr); | ||||
|                 m_objectives[index].m_term = tr; | ||||
|                 m_objectives[index].m_adjust_value.set_negate(true); | ||||
|             } | ||||
|  | @ -887,6 +889,50 @@ namespace opt { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void context::purify(app_ref& term) { | ||||
|         filter_model_converter_ref fm; | ||||
|         if (m_arith.is_add(term)) { | ||||
|             expr_ref_vector args(m); | ||||
|             unsigned sz = term->get_num_args(); | ||||
|             for (unsigned i = 0; i < sz; ++i) { | ||||
|                 expr* arg = term->get_arg(i); | ||||
|                 if (is_mul_const(arg)) { | ||||
|                     args.push_back(arg); | ||||
|                 } | ||||
|                 else { | ||||
|                     args.push_back(purify(fm, arg)); | ||||
|                 } | ||||
|             } | ||||
|             term = m_arith.mk_add(args.size(), args.c_ptr()); | ||||
|         } | ||||
|         else if (m_arith.is_arith_expr(term) && !is_mul_const(term)) { | ||||
|             TRACE("opt", tout << "Purifying " << term << "\n";); | ||||
|             term = purify(fm, term); | ||||
|         } | ||||
|         if (fm) { | ||||
|             m_model_converter = concat(m_model_converter.get(), fm.get()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     bool context::is_mul_const(expr* e) { | ||||
|         expr* e1, *e2; | ||||
|         return  | ||||
|             is_uninterp_const(e) || | ||||
|             m_arith.is_numeral(e) || | ||||
|             (m_arith.is_mul(e, e1, e2) && m_arith.is_numeral(e1) && is_uninterp_const(e2)) || | ||||
|             (m_arith.is_mul(e, e2, e1) && m_arith.is_numeral(e1) && is_uninterp_const(e2)); | ||||
|     } | ||||
| 
 | ||||
|     app* context::purify(filter_model_converter_ref& fm, expr* term) { | ||||
|        std::ostringstream out; | ||||
|        out << mk_pp(term, m); | ||||
|        app* q = m.mk_fresh_const(out.str().c_str(), m.get_sort(term)); | ||||
|        if (!fm) fm = alloc(filter_model_converter, m); | ||||
|        m_hard_constraints.push_back(m.mk_eq(q, term)); | ||||
|        fm->insert(q->get_decl());                 | ||||
|        return q; | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|        To select the proper theory solver we have to ensure that all theory  | ||||
|        symbols from soft constraints are reflected in the hard constraints. | ||||
|  | @ -894,7 +940,7 @@ namespace opt { | |||
|        - filter "obj" from generated model. | ||||
|      */ | ||||
|     void context::mk_atomic(expr_ref_vector& terms) { | ||||
|         ref<filter_model_converter> fm; | ||||
|         filter_model_converter_ref fm; | ||||
|         for (unsigned i = 0; i < terms.size(); ++i) { | ||||
|             expr_ref p(terms[i].get(), m); | ||||
|             app_ref q(m); | ||||
|  | @ -902,11 +948,7 @@ namespace opt { | |||
|                 terms[i] = p; | ||||
|             } | ||||
|             else { | ||||
|                 q = m.mk_fresh_const("obj", m.mk_bool_sort());  | ||||
|                 terms[i] = q; | ||||
|                 m_hard_constraints.push_back(m.mk_iff(p, q)); | ||||
|                 if (!fm) fm = alloc(filter_model_converter, m); | ||||
|                 fm->insert(q->get_decl()); | ||||
|                 terms[i] = purify(fm, p); | ||||
|             } | ||||
|         } | ||||
|         if (fm) { | ||||
|  |  | |||
|  | @ -244,6 +244,9 @@ namespace opt { | |||
|         bool is_maxsat(expr* fml, expr_ref_vector& terms,  | ||||
|                        vector<rational>& weights, rational& offset, bool& neg,  | ||||
|                        symbol& id, unsigned& index); | ||||
|         void  purify(app_ref& term); | ||||
|         app* purify(filter_model_converter_ref& fm, expr* e); | ||||
|         bool is_mul_const(expr* e); | ||||
|         expr* mk_maximize(unsigned index, app* t); | ||||
|         expr* mk_minimize(unsigned index, app* t); | ||||
|         expr* mk_maxsat(unsigned index, unsigned num_fmls, expr* const* fmls); | ||||
|  |  | |||
|  | @ -410,18 +410,24 @@ namespace smt { | |||
|     } | ||||
| 
 | ||||
|     bool theory_pb::internalize_atom(app * atom, bool gate_ctx) { | ||||
|         SASSERT(m_util.is_at_most_k(atom) || m_util.is_le(atom) ||  | ||||
|                 m_util.is_ge(atom) || m_util.is_at_least_k(atom) ||  | ||||
|                 m_util.is_eq(atom)); | ||||
| 
 | ||||
|         context& ctx = get_context(); | ||||
|         if (ctx.b_internalized(atom)) { | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         SASSERT(!ctx.b_internalized(atom)); | ||||
|         m_stats.m_num_predicates++; | ||||
| 
 | ||||
|         if (m_util.is_aux_bool(atom)) { | ||||
|             bool_var abv = ctx.mk_bool_var(atom); | ||||
|             ctx.set_var_theory(abv, get_id()); | ||||
|             return true; | ||||
|         } | ||||
|         SASSERT(m_util.is_at_most_k(atom) || m_util.is_le(atom) ||  | ||||
|                 m_util.is_ge(atom) || m_util.is_at_least_k(atom) ||  | ||||
|                 m_util.is_eq(atom)); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|         unsigned num_args = atom->get_num_args(); | ||||
|         bool_var abv = ctx.mk_bool_var(atom); | ||||
|         ctx.set_var_theory(abv, get_id()); | ||||
|  | @ -617,15 +623,15 @@ namespace smt { | |||
|         // function internalize, where enodes for each argument
 | ||||
|         // is available. 
 | ||||
|         if (!has_bv) { | ||||
|             expr_ref tmp(m), fml(m); | ||||
|             tmp = m.mk_fresh_const("pb_proxy",m.mk_bool_sort()); | ||||
|             app_ref tmp(m), fml(m); | ||||
|             pb_util pb(m); | ||||
|             tmp = pb.mk_fresh_bool(); | ||||
|             fml = m.mk_iff(tmp, arg); | ||||
|             TRACE("pb", tout << "create proxy " << fml << "\n";); | ||||
|             ctx.internalize(fml, false); | ||||
|             SASSERT(ctx.b_internalized(tmp)); | ||||
|             bv = ctx.get_bool_var(tmp); | ||||
|             SASSERT(null_theory_var == ctx.get_var_theory(bv)); | ||||
|             ctx.set_var_theory(bv, get_id()); | ||||
|             SASSERT(get_id() == ctx.get_var_theory(bv)); | ||||
|             literal lit(ctx.get_bool_var(fml)); | ||||
|             ctx.mk_th_axiom(get_id(), 1, &lit); | ||||
|             ctx.mark_as_relevant(tmp.get()); | ||||
|  | @ -1148,17 +1154,19 @@ namespace smt { | |||
|         context&     ctx; | ||||
|         ast_manager& m; | ||||
|         theory_pb&   th; | ||||
|         pb_util      pb; | ||||
|         typedef smt::literal literal; | ||||
|         typedef smt::literal_vector literal_vector; | ||||
|        | ||||
|         psort_expr(context& c, theory_pb& th): | ||||
|             ctx(c),  | ||||
|             m(c.get_manager()), | ||||
|             th(th) {} | ||||
|             th(th), | ||||
|             pb(m) {} | ||||
| 
 | ||||
|         literal fresh() { | ||||
|             app_ref y(m); | ||||
|             y = m.mk_fresh_const("y", m.mk_bool_sort()); | ||||
|             y = pb.mk_fresh_bool(); | ||||
|             return literal(ctx.mk_bool_var(y)); | ||||
|         } | ||||
|          | ||||
|  |  | |||
|  | @ -45,4 +45,6 @@ public: | |||
|     virtual model_converter * translate(ast_translation & translator); | ||||
| }; | ||||
| 
 | ||||
| typedef ref<filter_model_converter> filter_model_converter_ref; | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue