diff --git a/src/muz/spacer/spacer_arith_generalizers.cpp b/src/muz/spacer/spacer_arith_generalizers.cpp index 5eef2a6d8..0e0f72558 100644 --- a/src/muz/spacer/spacer_arith_generalizers.cpp +++ b/src/muz/spacer/spacer_arith_generalizers.cpp @@ -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 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 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 diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index b4a06f361..772f58ed3 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -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()); }; );