mirror of
https://github.com/Z3Prover/z3
synced 2026-04-16 01:04:12 +00:00
Add mod-factor-propagation lemma to NLA divisions solver (#9235)
When a monic x*y has a factor x with mod(x, p) = 0 (fixed), propagate mod(x*y, p) = 0. This enables Z3 to prove divisibility properties like x mod p = 0 => (x*y) mod p = 0, which previously timed out even for p = 2. The lemma fires in the NLA divisions check and allows Gröbner basis and LIA to subsequently derive distributivity of div over addition. Extends division tuples from (q, x, y) to (q, x, y, r) to track the mod lpvar. Also registers bounded divisions from the mod internalization path in theory_lra, not just the idiv path. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8d7ed66ebf
commit
477a1d817d
9 changed files with 169 additions and 42 deletions
|
|
@ -87,6 +87,7 @@ add_executable(test-z3
|
|||
memory.cpp
|
||||
model2expr.cpp
|
||||
model_based_opt.cpp
|
||||
mod_factor.cpp
|
||||
model_evaluator.cpp
|
||||
model_retrieval.cpp
|
||||
monomial_bounds.cpp
|
||||
|
|
|
|||
|
|
@ -154,6 +154,7 @@
|
|||
X(hilbert_basis) \
|
||||
X(heap_trie) \
|
||||
X(karr) \
|
||||
X(mod_factor) \
|
||||
X(no_overflow) \
|
||||
X(datalog_parser) \
|
||||
X_ARGV(datalog_parser_file) \
|
||||
|
|
|
|||
65
src/test/mod_factor.cpp
Normal file
65
src/test/mod_factor.cpp
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/*++
|
||||
Copyright (c) 2025 Microsoft Corporation
|
||||
--*/
|
||||
|
||||
#include "api/z3.h"
|
||||
#include "util/util.h"
|
||||
|
||||
// x mod 7 = 0 & (x*y) mod 7 != 0 should be unsat
|
||||
// Exercises: mod internalization path (is_mod with numeric divisor)
|
||||
static void test_mod_factor_mod_path() {
|
||||
Z3_config cfg = Z3_mk_config();
|
||||
Z3_context ctx = Z3_mk_context(cfg);
|
||||
Z3_solver s = Z3_mk_solver(ctx);
|
||||
Z3_solver_inc_ref(ctx, s);
|
||||
Z3_sort int_sort = Z3_mk_int_sort(ctx);
|
||||
Z3_ast x = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, "x"), int_sort);
|
||||
Z3_ast y = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, "y"), int_sort);
|
||||
Z3_ast seven = Z3_mk_int(ctx, 7, int_sort);
|
||||
Z3_ast zero = Z3_mk_int(ctx, 0, int_sort);
|
||||
Z3_solver_assert(ctx, s, Z3_mk_eq(ctx, Z3_mk_mod(ctx, x, seven), zero));
|
||||
Z3_ast xy_args[] = {x, y};
|
||||
Z3_ast xy = Z3_mk_mul(ctx, 2, xy_args);
|
||||
Z3_solver_assert(ctx, s, Z3_mk_not(ctx, Z3_mk_eq(ctx, Z3_mk_mod(ctx, xy, seven), zero)));
|
||||
ENSURE(Z3_solver_check(ctx, s) == Z3_L_FALSE);
|
||||
Z3_solver_dec_ref(ctx, s);
|
||||
Z3_del_config(cfg);
|
||||
Z3_del_context(ctx);
|
||||
}
|
||||
|
||||
// (x mod 100) mod 7 = 0 => ((x mod 100) * y) mod 7 = 0
|
||||
// Exercises: idiv internalization path (is_idiv + numeric divisor + bounded dividend)
|
||||
// because (x mod 100) is recognized as bounded by is_bounded()
|
||||
static void test_mod_factor_idiv_path() {
|
||||
Z3_config cfg = Z3_mk_config();
|
||||
Z3_context ctx = Z3_mk_context(cfg);
|
||||
Z3_solver s = Z3_mk_solver(ctx);
|
||||
Z3_solver_inc_ref(ctx, s);
|
||||
Z3_sort int_sort = Z3_mk_int_sort(ctx);
|
||||
Z3_ast x = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, "x"), int_sort);
|
||||
Z3_ast y = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, "y"), int_sort);
|
||||
Z3_ast seven = Z3_mk_int(ctx, 7, int_sort);
|
||||
Z3_ast zero = Z3_mk_int(ctx, 0, int_sort);
|
||||
Z3_ast hundred = Z3_mk_int(ctx, 100, int_sort);
|
||||
// xm = x mod 100 (bounded by is_bounded)
|
||||
Z3_ast xm = Z3_mk_mod(ctx, x, hundred);
|
||||
// xm mod 7 = 0
|
||||
Z3_solver_assert(ctx, s, Z3_mk_eq(ctx, Z3_mk_mod(ctx, xm, seven), zero));
|
||||
// (xm * y) div 7 — triggers idiv internalization with bounded dividend
|
||||
Z3_ast xm_y_args[] = {xm, y};
|
||||
Z3_ast xm_y = Z3_mk_mul(ctx, 2, xm_y_args);
|
||||
Z3_ast xm_y_div = Z3_mk_div(ctx, xm_y, seven);
|
||||
// assert (xm * y) mod 7 != 0
|
||||
Z3_solver_assert(ctx, s, Z3_mk_not(ctx, Z3_mk_eq(ctx, Z3_mk_mod(ctx, xm_y, seven), zero)));
|
||||
// use div to keep it alive
|
||||
Z3_solver_assert(ctx, s, Z3_mk_ge(ctx, xm_y_div, zero));
|
||||
ENSURE(Z3_solver_check(ctx, s) == Z3_L_FALSE);
|
||||
Z3_solver_dec_ref(ctx, s);
|
||||
Z3_del_config(cfg);
|
||||
Z3_del_context(ctx);
|
||||
}
|
||||
|
||||
void tst_mod_factor() {
|
||||
test_mod_factor_mod_path();
|
||||
test_mod_factor_idiv_path();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue