mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 11:42:28 +00:00 
			
		
		
		
	add detection of non-fixed variables to consequence finding
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
		
							parent
							
								
									7562efbe84
								
							
						
					
					
						commit
						cb2d8d2107
					
				
					 10 changed files with 188 additions and 25 deletions
				
			
		|  | @ -23,9 +23,10 @@ Revision History: | ||||||
| #include"api_util.h" | #include"api_util.h" | ||||||
| #include"api_model.h" | #include"api_model.h" | ||||||
| #include"opt_context.h" | #include"opt_context.h" | ||||||
|  | #include"opt_cmds.h" | ||||||
| #include"cancel_eh.h" | #include"cancel_eh.h" | ||||||
| #include"scoped_timer.h" | #include"scoped_timer.h" | ||||||
| 
 | #include"smt2parser.h" | ||||||
| 
 | 
 | ||||||
| extern "C" { | extern "C" { | ||||||
| 
 | 
 | ||||||
|  | @ -248,6 +249,53 @@ extern "C" { | ||||||
|         Z3_CATCH_RETURN(0); |         Z3_CATCH_RETURN(0); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     static void Z3_optimize_from_stream( | ||||||
|  |         Z3_context    c, | ||||||
|  |         Z3_optimize opt, | ||||||
|  |         std::istream& s) { | ||||||
|  |         ast_manager& m = mk_c(c)->m(); | ||||||
|  |         cmd_context ctx(false, &m); | ||||||
|  |         install_opt_cmds(ctx, to_optimize_ptr(opt)); | ||||||
|  |         ctx.set_ignore_check(true); | ||||||
|  |         if (!parse_smt2_commands(ctx, s)) { | ||||||
|  |             SET_ERROR_CODE(Z3_PARSER_ERROR); | ||||||
|  |             return; | ||||||
|  |         }         | ||||||
|  |         ptr_vector<expr>::const_iterator it  = ctx.begin_assertions(); | ||||||
|  |         ptr_vector<expr>::const_iterator end = ctx.end_assertions(); | ||||||
|  |         for (; it != end; ++it) { | ||||||
|  |             to_optimize_ptr(opt)->add_hard_constraint(*it); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void Z3_API Z3_optimize_from_string( | ||||||
|  |         Z3_context    c, | ||||||
|  |         Z3_optimize   d, | ||||||
|  |         Z3_string     s) { | ||||||
|  |         Z3_TRY; | ||||||
|  |         //LOG_Z3_optimize_from_string(c, d, s);
 | ||||||
|  |         std::string str(s); | ||||||
|  |         std::istringstream is(str); | ||||||
|  |         Z3_optimize_from_stream(c, d, is); | ||||||
|  |         Z3_CATCH; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void Z3_API Z3_optimize_from_file( | ||||||
|  |         Z3_context    c, | ||||||
|  |         Z3_optimize   d, | ||||||
|  |         Z3_string     s) { | ||||||
|  |         Z3_TRY; | ||||||
|  |         //LOG_Z3_optimize_from_file(c, d, s);
 | ||||||
|  |         std::ifstream is(s); | ||||||
|  |         if (!is) { | ||||||
|  |             SET_ERROR_CODE(Z3_PARSER_ERROR); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         Z3_optimize_from_stream(c, d, is); | ||||||
|  |         Z3_CATCH; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -2035,6 +2035,8 @@ namespace z3 { | ||||||
|         } |         } | ||||||
|         stats statistics() const { Z3_stats r = Z3_optimize_get_statistics(ctx(), m_opt); check_error(); return stats(ctx(), r); } |         stats statistics() const { Z3_stats r = Z3_optimize_get_statistics(ctx(), m_opt); check_error(); return stats(ctx(), r); } | ||||||
|         friend std::ostream & operator<<(std::ostream & out, optimize const & s); |         friend std::ostream & operator<<(std::ostream & out, optimize const & s); | ||||||
|  |         void from_file(char const* filename) { Z3_optimize_from_file(ctx(), m_opt, filename); check_error(); } | ||||||
|  |         void from_string(char const* constraints) { Z3_optimize_from_string(ctx(), m_opt, constraints); check_error(); } | ||||||
|         std::string help() const { char const * r = Z3_optimize_get_help(ctx(), m_opt); check_error();  return r; } |         std::string help() const { char const * r = Z3_optimize_get_help(ctx(), m_opt); check_error();  return r; } | ||||||
|     }; |     }; | ||||||
|     inline std::ostream & operator<<(std::ostream & out, optimize const & s) { out << Z3_optimize_to_string(s.ctx(), s.m_opt); return out; } |     inline std::ostream & operator<<(std::ostream & out, optimize const & s) { out << Z3_optimize_to_string(s.ctx(), s.m_opt); return out; } | ||||||
|  |  | ||||||
|  | @ -273,6 +273,25 @@ namespace Microsoft.Z3 | ||||||
|             return Native.Z3_optimize_to_string(Context.nCtx, NativeObject); |             return Native.Z3_optimize_to_string(Context.nCtx, NativeObject); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         /// <summary> | ||||||
|  |         /// Parse an SMT-LIB2 file with optimization objectives and constraints. | ||||||
|  |         /// The parsed constraints and objectives are added to the optimization context. | ||||||
|  |         /// </summary>                 | ||||||
|  |         public void FromFile(string file) | ||||||
|  |         { | ||||||
|  |             Native.Z3_optimize_from_file(Context.nCtx, NativeObject, file); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         /// <summary> | ||||||
|  |         /// Similar to FromFile. Instead it takes as argument a string. | ||||||
|  |         /// </summary> | ||||||
|  |         public void FromString(string s) | ||||||
|  |         { | ||||||
|  |             Native.Z3_optimize_from_string(Context.nCtx, NativeObject, s); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         /// Optimize statistics. |         /// Optimize statistics. | ||||||
|         /// </summary> |         /// </summary> | ||||||
|  |  | ||||||
|  | @ -6755,6 +6755,14 @@ class Optimize(Z3PPObject): | ||||||
|             raise Z3Exception("Expecting objective handle returned by maximize/minimize") |             raise Z3Exception("Expecting objective handle returned by maximize/minimize") | ||||||
|         return obj.upper() |         return obj.upper() | ||||||
| 
 | 
 | ||||||
|  |     def from_file(self, filename): | ||||||
|  |         """Parse assertions and objectives from a file""" | ||||||
|  |         Z3_optimize_from_file(self.ctx.ref(), self.optimize, filename) | ||||||
|  | 
 | ||||||
|  |     def from_string(self, s): | ||||||
|  |         """Parse assertions and objectives from a string""" | ||||||
|  |         Z3_optimize_from_string(self.ctx.ref(), self.optimize, s) | ||||||
|  | 
 | ||||||
|     def __repr__(self): |     def __repr__(self): | ||||||
|         """Return a formatted string with all added rules and constraints.""" |         """Return a formatted string with all added rules and constraints.""" | ||||||
|         return self.sexpr() |         return self.sexpr() | ||||||
|  |  | ||||||
|  | @ -197,6 +197,34 @@ extern "C" { | ||||||
|     */ |     */ | ||||||
|     Z3_string Z3_API Z3_optimize_to_string(Z3_context c, Z3_optimize o); |     Z3_string Z3_API Z3_optimize_to_string(Z3_context c, Z3_optimize o); | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |        \brief Parse an SMT-LIB2 string with assertions,  | ||||||
|  |        soft constraints and optimization objectives. | ||||||
|  |        Add the parsed constraints and objectives to the optimization context. | ||||||
|  | 
 | ||||||
|  |        \param c - context. | ||||||
|  |        \param o - optimize context. | ||||||
|  |        \param s - string containing SMT2 specification. | ||||||
|  | 
 | ||||||
|  |        def_API('Z3_optimize_from_string', VOID, (_in(CONTEXT), _in(OPTIMIZE), _in(STRING))) | ||||||
|  |     */ | ||||||
|  |     void Z3_API Z3_optimize_from_string(Z3_context c, Z3_optimize o, Z3_string s); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |        \brief Parse an SMT-LIB2 file with assertions,  | ||||||
|  |        soft constraints and optimization objectives. | ||||||
|  |        Add the parsed constraints and objectives to the optimization context. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |        \param c - context. | ||||||
|  |        \param o - optimize context. | ||||||
|  |        \param s - string containing SMT2 specification. | ||||||
|  | 
 | ||||||
|  |        def_API('Z3_optimize_from_file', VOID, (_in(CONTEXT), _in(OPTIMIZE), _in(STRING))) | ||||||
|  |     */ | ||||||
|  |     void Z3_API Z3_optimize_from_file(Z3_context c, Z3_optimize o, Z3_string s); | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|        \brief Return a string containing a description of parameters accepted by optimize. |        \brief Return a string containing a description of parameters accepted by optimize. | ||||||
|  |  | ||||||
|  | @ -527,13 +527,8 @@ static void install_dl_cmds_aux(cmd_context& ctx, dl_collected_cmds* collected_c | ||||||
|     ctx.insert(alloc(dl_query_cmd, dl_ctx)); |     ctx.insert(alloc(dl_query_cmd, dl_ctx)); | ||||||
|     ctx.insert(alloc(dl_declare_rel_cmd, dl_ctx)); |     ctx.insert(alloc(dl_declare_rel_cmd, dl_ctx)); | ||||||
|     ctx.insert(alloc(dl_declare_var_cmd, dl_ctx)); |     ctx.insert(alloc(dl_declare_var_cmd, dl_ctx)); | ||||||
|     // #ifndef _EXTERNAL_RELEASE
 |     ctx.insert(alloc(dl_push_cmd, dl_ctx));  | ||||||
|     // TODO: we need these!
 |  | ||||||
| #if 1 |  | ||||||
|     ctx.insert(alloc(dl_push_cmd, dl_ctx)); // not exposed to keep command-extensions simple.
 |  | ||||||
|     ctx.insert(alloc(dl_pop_cmd, dl_ctx)); |     ctx.insert(alloc(dl_pop_cmd, dl_ctx)); | ||||||
| #endif |  | ||||||
|     // #endif
 |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void install_dl_cmds(cmd_context & ctx) { | void install_dl_cmds(cmd_context & ctx) { | ||||||
|  |  | ||||||
|  | @ -32,7 +32,10 @@ Notes: | ||||||
| #include "opt_params.hpp" | #include "opt_params.hpp" | ||||||
| #include "model_smt2_pp.h" | #include "model_smt2_pp.h" | ||||||
| 
 | 
 | ||||||
| static opt::context& get_opt(cmd_context& cmd) { | static opt::context& get_opt(cmd_context& cmd, opt::context* opt) { | ||||||
|  |     if (opt) { | ||||||
|  |         return *opt; | ||||||
|  |     } | ||||||
|     if (!cmd.get_opt()) { |     if (!cmd.get_opt()) { | ||||||
|         cmd.set_opt(alloc(opt::context, cmd.m())); |         cmd.set_opt(alloc(opt::context, cmd.m())); | ||||||
|     } |     } | ||||||
|  | @ -43,12 +46,14 @@ static opt::context& get_opt(cmd_context& cmd) { | ||||||
| class assert_soft_cmd : public parametric_cmd { | class assert_soft_cmd : public parametric_cmd { | ||||||
|     unsigned     m_idx; |     unsigned     m_idx; | ||||||
|     expr*        m_formula; |     expr*        m_formula; | ||||||
|  |     opt::context* m_opt; | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
|     assert_soft_cmd(): |     assert_soft_cmd(opt::context* opt): | ||||||
|         parametric_cmd("assert-soft"), |         parametric_cmd("assert-soft"), | ||||||
|         m_idx(0), |         m_idx(0), | ||||||
|         m_formula(0) |         m_formula(0), | ||||||
|  |         m_opt(opt) | ||||||
|     {} |     {} | ||||||
| 
 | 
 | ||||||
|     virtual ~assert_soft_cmd() { |     virtual ~assert_soft_cmd() { | ||||||
|  | @ -97,7 +102,7 @@ public: | ||||||
|             weight = rational::one(); |             weight = rational::one(); | ||||||
|         } |         } | ||||||
|         symbol id = ps().get_sym(symbol("id"), symbol::null);         |         symbol id = ps().get_sym(symbol("id"), symbol::null);         | ||||||
|         get_opt(ctx).add_soft_constraint(m_formula, weight, id); |         get_opt(ctx, m_opt).add_soft_constraint(m_formula, weight, id); | ||||||
|         reset(ctx); |         reset(ctx); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -108,11 +113,13 @@ public: | ||||||
| 
 | 
 | ||||||
| class min_maximize_cmd : public cmd { | class min_maximize_cmd : public cmd { | ||||||
|     bool         m_is_max; |     bool         m_is_max; | ||||||
|  |     opt::context* m_opt; | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
|     min_maximize_cmd(bool is_max): |     min_maximize_cmd(bool is_max, opt::context* opt): | ||||||
|         cmd(is_max?"maximize":"minimize"), |         cmd(is_max?"maximize":"minimize"), | ||||||
|         m_is_max(is_max) |         m_is_max(is_max), | ||||||
|  |         m_opt(opt) | ||||||
|     {} |     {} | ||||||
| 
 | 
 | ||||||
|     virtual void reset(cmd_context & ctx) { } |     virtual void reset(cmd_context & ctx) { } | ||||||
|  | @ -126,7 +133,7 @@ public: | ||||||
|         if (!is_app(t)) { |         if (!is_app(t)) { | ||||||
|             throw cmd_exception("malformed objective term: it cannot be a quantifier or bound variable"); |             throw cmd_exception("malformed objective term: it cannot be a quantifier or bound variable"); | ||||||
|         } |         } | ||||||
|         get_opt(ctx).add_objective(to_app(t), m_is_max); |         get_opt(ctx, m_opt).add_objective(to_app(t), m_is_max); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     virtual void failure_cleanup(cmd_context & ctx) { |     virtual void failure_cleanup(cmd_context & ctx) { | ||||||
|  | @ -139,10 +146,10 @@ public: | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| void install_opt_cmds(cmd_context & ctx) { | void install_opt_cmds(cmd_context & ctx, opt::context* opt) { | ||||||
|     ctx.insert(alloc(assert_soft_cmd)); |     ctx.insert(alloc(assert_soft_cmd, opt)); | ||||||
|     ctx.insert(alloc(min_maximize_cmd, true)); |     ctx.insert(alloc(min_maximize_cmd, true, opt)); | ||||||
|     ctx.insert(alloc(min_maximize_cmd, false)); |     ctx.insert(alloc(min_maximize_cmd, false, opt)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -19,10 +19,11 @@ Notes: | ||||||
| #define OPT_CMDS_H_ | #define OPT_CMDS_H_ | ||||||
| 
 | 
 | ||||||
| #include "ast.h" | #include "ast.h" | ||||||
|  | #include "opt_context.h" | ||||||
| 
 | 
 | ||||||
| class cmd_context; | class cmd_context; | ||||||
| 
 | 
 | ||||||
| void install_opt_cmds(cmd_context & ctx); | void install_opt_cmds(cmd_context & ctx, opt::context* opt = 0); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | @ -102,6 +102,47 @@ namespace smt { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     void context::delete_unfixed(obj_map<expr, expr*>& var2val) { | ||||||
|  |         ast_manager& m = m_manager; | ||||||
|  |         ptr_vector<expr> to_delete; | ||||||
|  |         obj_map<expr,expr*>::iterator it = var2val.begin(), end = var2val.end(); | ||||||
|  |         for (; it != end; ++it) { | ||||||
|  |             expr* k = it->m_key; | ||||||
|  |             expr* v = it->m_value; | ||||||
|  |             if (m.is_bool(k)) { | ||||||
|  |                 literal lit = get_literal(k); | ||||||
|  |                 switch (get_assignment(lit)) { | ||||||
|  |                 case l_true:  | ||||||
|  |                     if (m.is_false(v)) { | ||||||
|  |                         to_delete.push_back(k); | ||||||
|  |                     } | ||||||
|  |                     else { | ||||||
|  |                         force_phase(lit.var(), false); | ||||||
|  |                     } | ||||||
|  |                     break; | ||||||
|  |                 case l_false: | ||||||
|  |                     if (m.is_true(v)) { | ||||||
|  |                         to_delete.push_back(k); | ||||||
|  |                     } | ||||||
|  |                     else { | ||||||
|  |                         force_phase(lit.var(), true); | ||||||
|  |                     } | ||||||
|  |                     break; | ||||||
|  |                 default: | ||||||
|  |                     to_delete.push_back(k); | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             else if (e_internalized(k) && m.are_distinct(v, get_enode(k)->get_root()->get_owner())) { | ||||||
|  |                 to_delete.push_back(k); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         IF_VERBOSE(1, verbose_stream() << "(get-consequences deleting: " << to_delete.size() << " num-values: " << var2val.size() << ")\n";); | ||||||
|  |         for (unsigned i = 0; i < to_delete.size(); ++i) { | ||||||
|  |             var2val.remove(to_delete[i]); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     lbool context::get_consequences(expr_ref_vector const& assumptions,  |     lbool context::get_consequences(expr_ref_vector const& assumptions,  | ||||||
|                                     expr_ref_vector const& vars, expr_ref_vector& conseq) { |                                     expr_ref_vector const& vars, expr_ref_vector& conseq) { | ||||||
| 
 | 
 | ||||||
|  | @ -135,7 +176,10 @@ namespace smt { | ||||||
|               tout << "vars: " << vars.size() << "\n"; |               tout << "vars: " << vars.size() << "\n"; | ||||||
|               tout << "lits: " << num_units << "\n";); |               tout << "lits: " << num_units << "\n";); | ||||||
|         m_case_split_queue->init_search_eh(); |         m_case_split_queue->init_search_eh(); | ||||||
|  |         unsigned num_iterations = 0; | ||||||
|  |         unsigned model_threshold = 2; | ||||||
|         while (!var2val.empty()) { |         while (!var2val.empty()) { | ||||||
|  |             ++num_iterations; | ||||||
|             obj_map<expr,expr*>::iterator it = var2val.begin(); |             obj_map<expr,expr*>::iterator it = var2val.begin(); | ||||||
|             expr* e = it->m_key; |             expr* e = it->m_key; | ||||||
|             expr* val = it->m_value; |             expr* val = it->m_value; | ||||||
|  | @ -177,6 +221,17 @@ namespace smt { | ||||||
|             else { |             else { | ||||||
|                 TRACE("context", tout << "Fixed: " << mk_pp(e, m) << "\n";); |                 TRACE("context", tout << "Fixed: " << mk_pp(e, m) << "\n";); | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|  |             TRACE("context", tout << "Unfixed variables: " << var2val.size() << "\n";); | ||||||
|  |             if (model_threshold <= num_iterations) { | ||||||
|  |                 delete_unfixed(var2val); | ||||||
|  |                 // The next time we check the model is after 1.5 additional iterations.
 | ||||||
|  |                 model_threshold *= 3; | ||||||
|  |                 model_threshold /= 2;                 | ||||||
|  |             } | ||||||
|  |             // repeat until we either have a model with negated literal or 
 | ||||||
|  |             // the literal is implied at base.
 | ||||||
|  | 
 | ||||||
|             extract_fixed_consequences(num_units, var2val, _assumptions, conseq); |             extract_fixed_consequences(num_units, var2val, _assumptions, conseq); | ||||||
|             num_units = assigned_literals().size(); |             num_units = assigned_literals().size(); | ||||||
|             if (var2val.contains(e)) { |             if (var2val.contains(e)) { | ||||||
|  | @ -189,10 +244,8 @@ namespace smt { | ||||||
|                 SASSERT(get_assignment(lit) == l_false); |                 SASSERT(get_assignment(lit) == l_false); | ||||||
|             } |             } | ||||||
|          |          | ||||||
|             // repeat until we either have a model with negated literal or 
 |  | ||||||
|             // the literal is implied at base.
 |  | ||||||
|             TRACE("context", tout << "Unfixed variables: " << var2val.size() << "\n";); |  | ||||||
|         } |         } | ||||||
|  |         end_search(); | ||||||
|         return l_true; |         return l_true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1345,7 +1345,9 @@ namespace smt { | ||||||
|             vector<bool_var> b2v, ast_translation& tr); |             vector<bool_var> b2v, ast_translation& tr); | ||||||
| 
 | 
 | ||||||
|         u_map<uint_set> m_antecedents; |         u_map<uint_set> m_antecedents; | ||||||
|         void extract_fixed_consequences(unsigned idx, obj_map<expr, expr*>& vars, uint_set const& assumptions, expr_ref_vector& conseq); |         void extract_fixed_consequences(unsigned idx, obj_map<expr, expr*>& var2val, uint_set const& assumptions, expr_ref_vector& conseq); | ||||||
|  |          | ||||||
|  |         void delete_unfixed(obj_map<expr, expr*>& var2val); | ||||||
| 
 | 
 | ||||||
|         expr_ref antecedent2fml(uint_set const& ante); |         expr_ref antecedent2fml(uint_set const& ante); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue