mirror of
				https://github.com/Z3Prover/z3
				synced 2025-11-04 05:19:11 +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
							
								
									20300bbf94
								
							
						
					
					
						commit
						7642106e73
					
				
					 4 changed files with 17 additions and 174 deletions
				
			
		| 
						 | 
				
			
			@ -369,7 +369,7 @@ public:
 | 
			
		|||
    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; m_vars.reset(); }
 | 
			
		||||
    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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,6 +40,8 @@ namespace qe {
 | 
			
		|||
        virtual void operator()(model& model, app_ref_vector& vars, expr_ref_vector& lits) { };
 | 
			
		||||
 | 
			
		||||
        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 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