Skip to content

Commit d5da1db

Browse files
physicsrobclaude
andcommitted
graph: snap sub-tolerance lower>upper crossings in AffineBound.to_interval
A sound affine bound has lower <= upper for every component, so a crossing is fp accumulation noise on a near-degenerate (point-valued) component — e.g. a token embedding column at exactly 0.5 whose lower-bound eval lands ~1 ULP above 0.5. The strict Range(lo, hi) check then raised during value_type propagation through a select (surfaced building the Phase-H R_CheckPlane token, kind=1). Snap the crossing when the gap is within fp tolerance; a gross crossing still falls through to the strict Range check as a genuine-bug signal. Regression test in tests/graph/test_affine_bounds.py::TestToIntervalFpCrossing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 4e2ef0c commit d5da1db

2 files changed

Lines changed: 43 additions & 0 deletions

File tree

tests/graph/test_affine_bounds.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -906,3 +906,37 @@ def test_value_type_reflects_claimed_range(self):
906906
r = asserted.value_type.value_range
907907
assert r.lo == pytest.approx(-3.0)
908908
assert r.hi == pytest.approx(7.0)
909+
910+
911+
class TestToIntervalFpCrossing:
912+
"""``to_interval`` snaps a sub-tolerance lower>upper crossing — fp
913+
accumulation noise on a point-valued component — instead of raising; a gross
914+
crossing still raises. Regression: a token embedding column at exactly 0.5
915+
had its lower bound eval land ~1 ULP above 0.5, tripping the strict ``Range``
916+
check during ``value_type`` propagation through a ``select``."""
917+
918+
@staticmethod
919+
def _point_bound(lo_b: float, hi_b: float) -> AffineBound:
920+
# x-free (n_cols=0) component with lower offset lo_b, upper offset hi_b.
921+
return AffineBound(
922+
A_lo=torch.zeros(1, 0, dtype=torch.float64),
923+
A_hi=torch.zeros(1, 0, dtype=torch.float64),
924+
b_lo=torch.tensor([lo_b], dtype=torch.float64),
925+
b_hi=torch.tensor([hi_b], dtype=torch.float64),
926+
columns={},
927+
input_ranges={},
928+
)
929+
930+
def test_sub_tolerance_crossing_snaps(self):
931+
ab = self._point_bound(0.5 + 7.45e-9, 0.5)
932+
intervals = ab.to_interval()
933+
assert len(intervals) == 1
934+
assert intervals[0].lo == intervals[0].hi == 0.5
935+
# to_scalar_range goes through the same path.
936+
r = ab.to_scalar_range()
937+
assert r.lo == pytest.approx(0.5) and r.hi == pytest.approx(0.5)
938+
939+
def test_gross_crossing_still_raises(self):
940+
ab = self._point_bound(1.0, 0.5)
941+
with pytest.raises(ValueError):
942+
ab.to_interval()

torchwright/graph/affine_bound.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,15 @@ def to_interval(self) -> list[Range]:
160160
f"NaN in upper bound at component {i}; likely a 0*inf case "
161161
f"not caught by the eval guard"
162162
)
163+
if lo > hi:
164+
# A sound affine bound has lower <= upper for every component;
165+
# a crossing is fp accumulation noise on a near-degenerate
166+
# (point-valued) component, e.g. an embedding column at exactly
167+
# 0.5 whose lower eval lands 1 ULP above 0.5. Snap when the gap
168+
# is within fp tolerance; a gross crossing falls through to the
169+
# strict ``Range`` check below as a genuine-bug signal.
170+
if lo - hi <= 1e-6 * (1.0 + max(abs(lo), abs(hi))):
171+
lo = hi
163172
ranges.append(Range(lo, hi))
164173
return ranges
165174

0 commit comments

Comments
 (0)