3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-06-19 15:16:29 +00:00

fix: negate offset on swap in seq_offset_eq::find (#9722)

`seq_offset_eq::find` returned the stored offset with the wrong sign
whenever the enode arguments were reordered to match the canonical key
ordering (`r1.id ≤ r2.id`), causing `len_based_split` to silently skip
~50% of eligible length-based splits.

### Root cause

`m_offset_equalities` stores `(rA, rB) → v` meaning `len(rA) − len(rB) =
v` with `rA.id ≤ rB.id`. `len_offset()` correctly negates `val` when
inserting with swapped keys. `find()` performed the same swap for the
lookup but never negated the returned value, so callers received
`len(n2) − len(n1)` instead of `len(n1) − len(n2)`.

### Fix

```cpp
// BEFORE
if (n1->get_owner_id() > n2->get_owner_id())
    std::swap(n1, n2);
if (m_offset_equalities.find(n1, n2, offset))
    return offset;  // wrong sign when swapped

// AFTER
bool swapped = n1->get_owner_id() > n2->get_owner_id();
if (swapped)
    std::swap(n1, n2);
if (m_offset_equalities.find(n1, n2, offset))
    return swapped ? -offset : offset;
```

This makes `find` consistent with the documented contract (`r1 = r2 +
offset`) and symmetric with the insertion logic in `len_offset()`.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
This commit is contained in:
Copilot 2026-06-06 13:25:16 -07:00 committed by GitHub
parent 7c7ca27822
commit 206569c0d6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -97,13 +97,14 @@ void seq_offset_eq::prop_arith_to_len_offset() {
std::optional<int> seq_offset_eq::find(enode* n1, enode* n2) const {
n1 = n1->get_root();
n2 = n2->get_root();
if (n1->get_owner_id() > n2->get_owner_id())
bool swapped = n1->get_owner_id() > n2->get_owner_id();
if (swapped)
std::swap(n1, n2);
if (a.is_numeral(n1->get_expr()) || a.is_numeral(n2->get_expr()))
return std::nullopt;
int offset;
if (m_offset_equalities.find(n1, n2, offset))
return offset;
return swapped ? -offset : offset;
return std::nullopt;
}