mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 11:42:28 +00:00 
			
		
		
		
	add way to unit test mbp from command line
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
		
							parent
							
								
									402234757e
								
							
						
					
					
						commit
						e281f85586
					
				
					 4 changed files with 54 additions and 174 deletions
				
			
		|  | @ -30,6 +30,7 @@ Notes: | |||
| #include "ast/used_vars.h" | ||||
| #include "ast/rewriter/var_subst.h" | ||||
| #include "util/gparams.h" | ||||
| #include "qe/qe_mbp.h" | ||||
| 
 | ||||
| 
 | ||||
| BINARY_SYM_CMD(get_quantifier_body_cmd, | ||||
|  | @ -352,6 +353,43 @@ public: | |||
|     void execute(cmd_context & ctx) override { ctx.display_dimacs(); } | ||||
| }; | ||||
| 
 | ||||
| class mbp_cmd : public cmd { | ||||
|     expr* m_fml; | ||||
|     ptr_vector<expr> m_vars; | ||||
| public: | ||||
|     mbp_cmd():cmd("mbp") {} | ||||
|     char const * get_usage() const override { return "<expr>"; } | ||||
|     char const * get_descr(cmd_context & ctx) const override { return "perform model based projection"; } | ||||
|     unsigned get_arity() const override { return 2; } | ||||
|     cmd_arg_kind next_arg_kind(cmd_context& ctx) const override { | ||||
|         if (m_fml == nullptr) return CPK_EXPR;  | ||||
|         return CPK_EXPR_LIST; | ||||
|     } | ||||
|     void set_next_arg(cmd_context& ctx, expr * arg) { m_fml = arg; } | ||||
|     void set_next_arg(cmd_context & ctx, unsigned num, expr * const * ts) override { | ||||
|         m_vars.append(num, ts); | ||||
|     } | ||||
|     void prepare(cmd_context & ctx) override { m_fml = nullptr; } | ||||
|     void execute(cmd_context & ctx) override {  | ||||
|         ast_manager& m = ctx.m(); | ||||
|         app_ref_vector vars(m); | ||||
|         model_ref mdl; | ||||
|         if (!ctx.is_model_available(mdl) || !ctx.get_check_sat_result()) { | ||||
|             throw cmd_exception("model is not available"); | ||||
|         } | ||||
|         for (expr* v : m_vars) { | ||||
|             if (!is_uninterp_const(v)) { | ||||
|                 throw cmd_exception("invalid variable argument. Uninterpreted variable expected"); | ||||
|             } | ||||
|             vars.push_back(to_app(v)); | ||||
|         } | ||||
|         qe::mbp mbp(m); | ||||
|         expr_ref fml(m_fml, m); | ||||
|         mbp.spacer(vars, *mdl.get(), fml); | ||||
|         ctx.regular_stream() << fml << "\n"; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| void install_dbg_cmds(cmd_context & ctx) { | ||||
|     ctx.insert(alloc(print_dimacs_cmd)); | ||||
|  | @ -377,4 +415,5 @@ void install_dbg_cmds(cmd_context & ctx) { | |||
|     ctx.insert(alloc(instantiate_cmd)); | ||||
|     ctx.insert(alloc(instantiate_nested_cmd)); | ||||
|     ctx.insert(alloc(set_next_id)); | ||||
|     ctx.insert(alloc(mbp_cmd)); | ||||
| } | ||||
|  |  | |||
|  | @ -631,13 +631,13 @@ namespace qe { | |||
|                 m_v = arr_vars.get (i); | ||||
|                 if (!m_arr_u.is_array (m_v)) { | ||||
|                     TRACE ("qe", | ||||
|                             tout << "not an array variable: " << mk_pp (m_v, m) << "\n"; | ||||
|                             tout << "not an array variable: " << m_v << "\n"; | ||||
|                           ); | ||||
|                     aux_vars.push_back (m_v); | ||||
|                     continue; | ||||
|                 } | ||||
|                 TRACE ("qe", | ||||
|                         tout << "projecting equalities on variable: " << mk_pp (m_v, m) << "\n"; | ||||
|                         tout << "projecting equalities on variable: " << m_v << "\n"; | ||||
|                       ); | ||||
| 
 | ||||
|                 if (project (fml)) { | ||||
|  | @ -653,8 +653,8 @@ namespace qe { | |||
|                           ); | ||||
|                 } | ||||
|                 else { | ||||
|                     IF_VERBOSE(2, verbose_stream() << "can't project:" << mk_pp(m_v, m) << "\n";); | ||||
|                     TRACE ("qe", tout << "Failed to project: " << mk_pp (m_v, m) << "\n";); | ||||
|                     IF_VERBOSE(2, verbose_stream() << "can't project:" << m_v << "\n";); | ||||
|                     TRACE ("qe", tout << "Failed to project: " << m_v << "\n";); | ||||
|                     arr_vars[j++] = m_v; | ||||
|                 } | ||||
|             } | ||||
|  | @ -1196,67 +1196,6 @@ namespace qe { | |||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) { | ||||
| 
 | ||||
|             TRACE("qe", tout << mk_pp(var, m) << "\n" << lits;); | ||||
|             m_var = alloc(contains_app, m, var); | ||||
| 
 | ||||
|             // reduce select-store redeces based on model.
 | ||||
|             // rw_cfg rw(m);
 | ||||
|             // rw(lits);
 | ||||
| 
 | ||||
|             // try first to solve for var.
 | ||||
|             if (solve_eq(model, vars, lits)) { | ||||
|                 return true; | ||||
|             }  | ||||
| 
 | ||||
|             app_ref_vector selects(m); | ||||
| 
 | ||||
|             // check that only non-select occurrences are in disequalities.
 | ||||
|             if (!check_diseqs(lits, selects)) { | ||||
|                 TRACE("qe", tout << "Could not project " << mk_pp(var, m) << " for:\n" << lits << "\n";); | ||||
|                 return false; | ||||
|             } | ||||
| 
 | ||||
|             // remove disequalities.
 | ||||
|             elim_diseqs(lits); | ||||
| 
 | ||||
|             // Ackerman reduction on remaining select occurrences
 | ||||
|             // either replace occurrences by model value or other node
 | ||||
|             // that is congruent to model value.
 | ||||
| 
 | ||||
|             ackermanize_select(model, selects, vars, lits); | ||||
|             | ||||
|             TRACE("qe", tout << selects << "\n" << lits << "\n";); | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         void ackermanize_select(model& model, app_ref_vector const& selects, app_ref_vector& vars, expr_ref_vector& lits) { | ||||
|             expr_ref_vector vals(m), reps(m); | ||||
|             expr_ref val(m); | ||||
|             expr_safe_replace sub(m); | ||||
| 
 | ||||
|             if (selects.empty()) { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             app_ref sel(m); | ||||
|             for (unsigned i = 0; i < selects.size(); ++i) {                 | ||||
|                 sel = m.mk_fresh_const("sel", m.get_sort(selects[i])); | ||||
|                 VERIFY (model.eval(selects[i], val)); | ||||
|                 model.register_decl(sel->get_decl(), val); | ||||
|                 vals.push_back(to_app(val)); | ||||
|                 reps.push_back(val);               // TODO: direct pass could handle nested selects.
 | ||||
|                 vars.push_back(sel); | ||||
|                 sub.insert(selects[i], val); | ||||
|             } | ||||
| 
 | ||||
|             sub(lits); | ||||
|             remove_true(lits); | ||||
|             project_plugin::partition_args(model, selects, lits); | ||||
|             project_plugin::partition_values(model, reps, lits); | ||||
|         } | ||||
| 
 | ||||
|         void remove_true(expr_ref_vector& lits) { | ||||
|             for (unsigned i = 0; i < lits.size(); ++i) { | ||||
|                 if (m.is_true(lits[i].get())) { | ||||
|  | @ -1275,113 +1214,7 @@ namespace qe { | |||
|             for (unsigned j = 0; j < n; ++j) { | ||||
|                 lits.push_back(m.mk_eq(x.m_vars[j], y.m_vars[j])); | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         // check that x occurs only under selects or in disequalities.
 | ||||
|         bool check_diseqs(expr_ref_vector const& lits, app_ref_vector& selects) { | ||||
|             expr_mark mark; | ||||
|             ptr_vector<app> todo; | ||||
|             app* e; | ||||
|             for (unsigned i = 0; i < lits.size(); ++i) { | ||||
|                 e = to_app(lits[i]); | ||||
|                 if (is_diseq_x(e)) { | ||||
|                     continue; | ||||
|                 } | ||||
|                 if (contains_x(e)) { | ||||
|                     todo.push_back(e); | ||||
|                 } | ||||
|             } | ||||
|             while (!todo.empty()) { | ||||
|                 e = todo.back(); | ||||
|                 todo.pop_back();                     | ||||
|                 if (mark.is_marked(e)) { | ||||
|                     continue; | ||||
|                 } | ||||
|                 mark.mark(e); | ||||
|                 if (m_var->x() == e) { | ||||
|                     return false; | ||||
|                 } | ||||
|                 unsigned start = 0; | ||||
|                 if (a.is_select(e)) { | ||||
|                     if (e->get_arg(0) == m_var->x()) { | ||||
|                         start = 1; | ||||
|                         selects.push_back(e); | ||||
|                     }  | ||||
|                 } | ||||
|                 for (unsigned i = start; i < e->get_num_args(); ++i) { | ||||
|                     todo.push_back(to_app(e->get_arg(i))); | ||||
|                 } | ||||
|             } | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         void elim_diseqs(expr_ref_vector& lits) { | ||||
|             for (unsigned i = 0; i < lits.size(); ++i) { | ||||
|                 if (is_diseq_x(lits[i].get())) { | ||||
|                     project_plugin::erase(lits, i); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         bool is_update_x(app* e) { | ||||
|             do { | ||||
|                 if (m_var->x() == e) { | ||||
|                     return true; | ||||
|                 } | ||||
|                 if (a.is_store(e) && contains_x(e->get_arg(0))) { | ||||
|                     for (unsigned i = 1; i < e->get_num_args(); ++i) { | ||||
|                         if (contains_x(e->get_arg(i))) { | ||||
|                             return false; | ||||
|                         } | ||||
|                     } | ||||
|                     e = to_app(e->get_arg(0)); | ||||
|                     continue; | ||||
|                 } | ||||
|             } | ||||
|             while (false); | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         bool is_diseq_x(expr* e) { | ||||
|             expr *f, * s, *t; | ||||
|             if (m.is_not(e, f) && m.is_eq(f, s, t)) { | ||||
|                 if (contains_x(s) && !contains_x(t) && is_update_x(to_app(s))) return true; | ||||
|                 if (contains_x(t) && !contains_x(s) && is_update_x(to_app(t))) return true; | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         bool solve_eq(model& model, app_ref_vector& vars, expr_ref_vector& lits) { | ||||
|             // find an equality to solve for.
 | ||||
|             expr* s, *t; | ||||
|             for (unsigned i = 0; i < lits.size(); ++i) { | ||||
|                 if (m.is_eq(lits[i].get(), s, t)) { | ||||
|                     vector<indices> idxs; | ||||
|                     expr_ref save(m), back(m); | ||||
|                     save = lits[i].get(); | ||||
|                     back = lits.back(); | ||||
|                     lits[i] = back; | ||||
|                     lits.pop_back(); | ||||
|                     unsigned sz = lits.size(); | ||||
|                     if (contains_x(s) && !contains_x(t) && is_app(s)) { | ||||
|                         if (solve(model, to_app(s), t, idxs, vars, lits)) { | ||||
|                             return true; | ||||
|                         } | ||||
|                     } | ||||
|                     else if (contains_x(t) && !contains_x(s) && is_app(t)) { | ||||
|                         if (solve(model, to_app(t), s, idxs, vars, lits)) { | ||||
|                             return true; | ||||
|                         } | ||||
|                     } | ||||
|                     // put back the equality literal.
 | ||||
|                     lits.resize(sz); | ||||
|                     lits.push_back(back); | ||||
|                     lits[i] = save; | ||||
|                 } | ||||
|                 // TBD: not distinct?
 | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
|         }         | ||||
| 
 | ||||
|         bool solve(model& model, app* s, expr* t, vector<indices>& idxs, app_ref_vector& vars, expr_ref_vector& lits) { | ||||
|             SASSERT(contains_x(s)); | ||||
|  | @ -1502,7 +1335,13 @@ namespace qe { | |||
|     } | ||||
|      | ||||
|     bool array_project_plugin::operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) { | ||||
|         return (*m_imp)(model, var, vars, lits); | ||||
|         ast_manager& m = vars.get_manager(); | ||||
|         app_ref_vector vvars(m, 1, &var); | ||||
|         expr_ref fml = mk_and(lits); | ||||
|         (*this)(model, vvars, fml, vars, false); | ||||
|         lits.reset(); | ||||
|         flatten_and(fml, lits); | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     bool array_project_plugin::solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) { | ||||
|  |  | |||
|  | @ -99,6 +99,7 @@ void project_plugin::partition_values(model& model, expr_ref_vector const& vals, | |||
|     } | ||||
| } | ||||
| 
 | ||||
| #if 0 | ||||
| void project_plugin::partition_args(model& model, app_ref_vector const& selects, expr_ref_vector& lits) { | ||||
|     ast_manager& m = selects.get_manager(); | ||||
|     if (selects.empty()) return; | ||||
|  | @ -111,6 +112,7 @@ void project_plugin::partition_args(model& model, app_ref_vector const& selects, | |||
|         project_plugin::partition_values(model, args, lits); | ||||
|     } | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| void project_plugin::erase(expr_ref_vector& lits, unsigned& i) { | ||||
|     lits[i] = lits.back(); | ||||
|  |  | |||
|  | @ -41,7 +41,7 @@ namespace qe { | |||
| 
 | ||||
|         static expr_ref pick_equality(ast_manager& m, model& model, expr* t); | ||||
|         static void partition_values(model& model, expr_ref_vector const& vals, expr_ref_vector& lits); | ||||
|         static void partition_args(model& model, app_ref_vector const& sels, expr_ref_vector& lits); | ||||
|         //static void partition_args(model& model, app_ref_vector const& sels, expr_ref_vector& lits);
 | ||||
|         static void erase(expr_ref_vector& lits, unsigned& i); | ||||
|         static void push_back(expr_ref_vector& lits, expr* lit); | ||||
|         static void mark_rec(expr_mark& visited, expr* e); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue