mirror of
				https://github.com/Z3Prover/z3
				synced 2025-11-04 05:19:11 +00:00 
			
		
		
		
	spacer: fixes lim_num_generalizer
Must check that newly constructed generalization blocks the proof obligation. Was only checking that generalization is entailed by the transition system!
This commit is contained in:
		
							parent
							
								
									63840806d8
								
							
						
					
					
						commit
						1b83c677ea
					
				
					 2 changed files with 44 additions and 12 deletions
				
			
		| 
						 | 
				
			
			@ -20,6 +20,7 @@
 | 
			
		|||
#include "ast/rewriter/rewriter.h"
 | 
			
		||||
#include "ast/rewriter/rewriter_def.h"
 | 
			
		||||
#include "muz/spacer/spacer_generalizers.h"
 | 
			
		||||
#include "smt/smt_solver.h"
 | 
			
		||||
 | 
			
		||||
namespace spacer {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -74,7 +75,7 @@ struct limit_denominator_rewriter_cfg : public default_rewriter_cfg {
 | 
			
		|||
            q2 = tj * q1 + q0;
 | 
			
		||||
            p2 = tj * p1 + p0;
 | 
			
		||||
            if (q2 >= m_limit) {
 | 
			
		||||
                num = p2/q2;
 | 
			
		||||
                num = p2 / q2;
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
            rem = n - tj * d;
 | 
			
		||||
| 
						 | 
				
			
			@ -104,11 +105,11 @@ struct limit_denominator_rewriter_cfg : public default_rewriter_cfg {
 | 
			
		|||
};
 | 
			
		||||
} // namespace
 | 
			
		||||
limit_num_generalizer::limit_num_generalizer(context &ctx,
 | 
			
		||||
                                                   unsigned failure_limit)
 | 
			
		||||
                                             unsigned failure_limit)
 | 
			
		||||
    : lemma_generalizer(ctx), m_failure_limit(failure_limit) {}
 | 
			
		||||
 | 
			
		||||
bool limit_num_generalizer::limit_denominators(expr_ref_vector &lits,
 | 
			
		||||
                                                  rational &limit) {
 | 
			
		||||
                                               rational &limit) {
 | 
			
		||||
    ast_manager &m = m_ctx.get_ast_manager();
 | 
			
		||||
    limit_denominator_rewriter_cfg rw_cfg(m, limit);
 | 
			
		||||
    rewriter_tpl<limit_denominator_rewriter_cfg> rw(m, false, rw_cfg);
 | 
			
		||||
| 
						 | 
				
			
			@ -135,6 +136,10 @@ void limit_num_generalizer::operator()(lemma_ref &lemma) {
 | 
			
		|||
 | 
			
		||||
    expr_ref_vector cube(m);
 | 
			
		||||
 | 
			
		||||
    // create a solver to check whether updated cube is in a generalization
 | 
			
		||||
    ref<solver> sol = mk_smt_solver(m, params_ref::get_empty(), symbol::null);
 | 
			
		||||
    SASSERT(lemma->has_pob());
 | 
			
		||||
    sol->assert_expr(lemma->get_pob()->post());
 | 
			
		||||
    unsigned weakness = lemma->weakness();
 | 
			
		||||
    rational limit(100);
 | 
			
		||||
    for (unsigned num_failures = 0; num_failures < m_failure_limit;
 | 
			
		||||
| 
						 | 
				
			
			@ -143,8 +148,33 @@ void limit_num_generalizer::operator()(lemma_ref &lemma) {
 | 
			
		|||
        cube.append(lemma->get_cube());
 | 
			
		||||
        // try to limit denominators
 | 
			
		||||
        if (!limit_denominators(cube, limit)) return;
 | 
			
		||||
        // check that the result is inductive
 | 
			
		||||
        if (pt.check_inductive(lemma->level(), cube, uses_level, weakness)) {
 | 
			
		||||
 | 
			
		||||
        bool failed = false;
 | 
			
		||||
        // check that pob->post() ==> cube
 | 
			
		||||
        for (auto *lit : cube) {
 | 
			
		||||
            solver::scoped_push _p_(*sol);
 | 
			
		||||
            expr_ref nlit(m);
 | 
			
		||||
            nlit = m.mk_not(lit);
 | 
			
		||||
            sol->assert_expr(nlit);
 | 
			
		||||
            lbool res = sol->check_sat(0, nullptr);
 | 
			
		||||
            if (res == l_false) {
 | 
			
		||||
                // good
 | 
			
		||||
            } else {
 | 
			
		||||
                failed = true;
 | 
			
		||||
                TRACE("spacer.limnum", tout << "Failed to generalize: "
 | 
			
		||||
                      << lemma->get_cube()
 | 
			
		||||
                      << "\ninto\n"
 | 
			
		||||
                      << cube << "\n";);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // check that !cube & F & Tr ==> !cube'
 | 
			
		||||
        if (!failed && pt.check_inductive(lemma->level(), cube, uses_level, weakness)) {
 | 
			
		||||
            TRACE("spacer",
 | 
			
		||||
                  tout << "Reduced fractions from:\n"
 | 
			
		||||
                  << lemma->get_cube() << "\n\nto\n"
 | 
			
		||||
                  << cube << "\n";);
 | 
			
		||||
            lemma->update_cube(lemma->get_pob(), cube);
 | 
			
		||||
            lemma->set_level(uses_level);
 | 
			
		||||
            // done
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2655,11 +2655,6 @@ void context::init_lemma_generalizers()
 | 
			
		|||
{
 | 
			
		||||
    reset_lemma_generalizers();
 | 
			
		||||
 | 
			
		||||
    if (m_use_lim_num_gen) {
 | 
			
		||||
        // first, to get small numbers before any other smt calls
 | 
			
		||||
        m_lemma_generalizers.push_back(alloc(limit_num_generalizer, *this, 5));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (m_q3_qgen) {
 | 
			
		||||
        m_lemma_generalizers.push_back(alloc(lemma_bool_inductive_generalizer,
 | 
			
		||||
                                             *this, 0, true));
 | 
			
		||||
| 
						 | 
				
			
			@ -2678,6 +2673,12 @@ void context::init_lemma_generalizers()
 | 
			
		|||
        m_lemma_generalizers.push_back(alloc(lemma_bool_inductive_generalizer, *this, 0));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // after the lemma is minimized (maybe should also do before)
 | 
			
		||||
    if (m_use_lim_num_gen) {
 | 
			
		||||
        m_lemma_generalizers.push_back(alloc(limit_num_generalizer, *this, 5));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    if (m_use_array_eq_gen) {
 | 
			
		||||
        m_lemma_generalizers.push_back(alloc(lemma_array_eq_generalizer, *this));
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -3051,9 +3052,10 @@ lbool context::solve_core (unsigned from_lvl)
 | 
			
		|||
 | 
			
		||||
        STRACE("spacer_progress", tout << "\n* LEVEL " << lvl << "\n";);
 | 
			
		||||
        IF_VERBOSE(1,
 | 
			
		||||
                   if (m_params.print_statistics ()) {
 | 
			
		||||
                   if (m_params.print_statistics()) {
 | 
			
		||||
                       statistics st;
 | 
			
		||||
                       collect_statistics (st);
 | 
			
		||||
                       collect_statistics(st);
 | 
			
		||||
                       st.display_smt2(verbose_stream());
 | 
			
		||||
                   };
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue