mirror of
https://github.com/Z3Prover/z3
synced 2026-07-23 15:32:32 +00:00
Fix invalid model from int_to_bv missing modular reduction in bv2int_translator (#10185)
With `smt.bv.solver=2`, `int_to_bv(x)` was translated to the raw integer
`x` without normalizing it to `[0, 2^N)`. Bitwise operations like
`bvxor(A, B)` are translated as `A + B - 2·band(A, B)`, which is only
valid when both operands are in `[0, 2^N)`. When `x` was negative or ≥
2^N, the LP solver could assign a band value inconsistent with bit
semantics, producing a model that fails validation.
## Changes
- **`OP_INT2BV` translation** (`translate_bv`): Apply `umod(e, 0)`
instead of passing the raw integer argument through. This normalizes the
value to `[0, 2^N)` before it participates in any bitwise arithmetic.
```cpp
// Before
case OP_INT2BV:
r = arg(0); // raw integer, may be negative or ≥ 2^N
// After
case OP_INT2BV:
r = umod(e, 0); // normalized to [0, 2^N)
```
- **`amod` shortcut**: Add a fast-path for `mod(t, N)` when the divisor
already equals `N` — the result is already in `[0, N)`, so wrapping it
again with another `mod(_, N)` is unnecessary and avoids expression
bloat.
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
This commit is contained in:
parent
9ac438b199
commit
847ee63b2d
1 changed files with 7 additions and 1 deletions
|
|
@ -428,7 +428,10 @@ void bv2int_translator::translate_bv(app* e) {
|
|||
case OP_INT2BV:
|
||||
m_int2bv.push_back(e);
|
||||
ctx.push(push_back_vector(m_int2bv));
|
||||
r = arg(0);
|
||||
// Normalize the integer argument to [0, 2^N) so that bitwise operations
|
||||
// on int_to_bv produce correct results when the argument is negative or
|
||||
// otherwise outside the valid range.
|
||||
r = umod(e, 0);
|
||||
break;
|
||||
case OP_UBV2INT:
|
||||
m_bv2int.push_back(e);
|
||||
|
|
@ -697,6 +700,9 @@ expr* bv2int_translator::amod(expr* bv_expr, expr* x, rational const& N) {
|
|||
r = x;
|
||||
else if (a.is_mod(x, t, e) && a.is_numeral(t, v) && 0 <= v && v < N)
|
||||
r = x;
|
||||
else if (a.is_mod(x, t, e) && a.is_numeral(e, v) && v == N)
|
||||
// mod(t, N) is already in [0, N); no need to wrap it again.
|
||||
r = x;
|
||||
else if (a.is_numeral(x, v))
|
||||
r = a.mk_int(mod(v, N));
|
||||
else if (is_bounded(x, N))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue