From 7d67dbfcfc81143bf35084e78543b658268afe37 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Sun, 12 Jul 2026 18:53:15 -0700 Subject: [PATCH] Add QE regression for unsound `check-sat-using qe` result on quantified reals (#10097) `check-sat-using qe` was reported to return `unsat` on a satisfiable quantified-real formula, while a subsequent `check-sat` on the same assertion returned `sat`. This PR adds focused regression coverage for that shape to prevent reintroduction. - **Regression coverage for the reported formula** - Added `test_qe_regression_4175()` in `src/test/quant_solve.cpp`. - Parses and quantifier-eliminates: ```smt2 (forall ((b Real)) (= (= r1 b) (= b 0))) ``` - **Behavioral oracle encoded in the test** - Verifies the QE result is satisfiable under `r1 = 0`. - Verifies the QE result is unsatisfiable under `r1 != 0`. - This captures the intended semantics of the original formula and guards against the unsound `unsat` outcome from the QE path. - **Integration** - Wires the new regression into `tst_quant_solve()` so it runs with existing quantifier-solver test coverage. Example snippet from the new test logic: ```cpp solver.assert_expr(result); solver.assert_expr(m.mk_eq(r1, zero)); VERIFY(l_true == solver.check()); solver.assert_expr(result); solver.assert_expr(m.mk_not(m.mk_eq(r1, zero))); VERIFY(l_false == solver.check()); ``` --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> --- src/test/quant_solve.cpp | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/test/quant_solve.cpp b/src/test/quant_solve.cpp index 28667917fc..59e35d927e 100644 --- a/src/test/quant_solve.cpp +++ b/src/test/quant_solve.cpp @@ -168,6 +168,36 @@ static void test_quant_solver(ast_manager& m, char const* str, bool validate = t test_quant_solver(m, vars.size(), vars.data(), fml, validate); } +static void test_qe_regression_4175() { + ast_manager m; + reg_decl_plugins(m); + smt_params params; + arith_util a(m); + + expr_ref fml = parse_fml(m, "(forall ((b Real)) (= (= r1 b) (= b 0)))"); + VERIFY(fml); + expr_ref result(m); + qe::expr_quant_elim qe(m, params); + qe(m.mk_true(), fml, result); + VERIFY(result); + + expr_ref r1(m.mk_const(symbol("r1"), a.mk_real()), m); + expr_ref zero(a.mk_numeral(rational(0), false), m); + + { + smt::kernel solver(m, params); + solver.assert_expr(result); + solver.assert_expr(m.mk_eq(r1, zero)); + VERIFY(l_true == solver.check()); + } + { + smt::kernel solver(m, params); + solver.assert_expr(result); + solver.assert_expr(m.mk_not(m.mk_eq(r1, zero))); + VERIFY(l_false == solver.check()); + } +} + static void test_quant_solve1() { ast_manager m; @@ -253,6 +283,7 @@ void tst_quant_solve() { disable_debug("heap"); test_quant_solve1(); + test_qe_regression_4175(); #if 0 memory::finalize(); @@ -262,5 +293,3 @@ void tst_quant_solve() { exit(0); #endif } - -