Skip to content

Commit eee80b7

Browse files
thomasahleclaude
andcommitted
book_layout: E-box arc fits, wire-breaking, x-distance arc shapes
Three fixes for the main18/20/21 mess: - E-box fits now include enclosed arc/loop tops (the treatment deriv ellipses already had), so a dome inside an expectation grows the box instead of sweeping outside its brackets. - A conservation wire whose straight path would cut through a bracket group is no longer drawn through it: it is BROKEN into two matching labeled stubs (edge names connect them), per review suggestion. - Arcs choose flat-dome vs steep style by horizontal extent rather than spine-step count: an arc hopping one step across a WIDE group no longer balloons, and the ellipse/box fit formulas mirror the same rule so containers actually contain their domes. main20's raw pre-simplify step and main18's giant intermediate rows remain at the router's documented limit (bracket-cut warnings fire). 38 tests, mypy clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018PzG3QbNtaFmABBHBG39wp
1 parent 529d4d7 commit eee80b7

1 file changed

Lines changed: 45 additions & 3 deletions

File tree

tensorgrad/extras/book_layout.py

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1567,7 +1567,7 @@ def _far(nid: int, other: int) -> str:
15671567
rf"\draw ({fa}.north) .. controls +(0.2,{h:.2f}) and"
15681568
rf" +(-0.2,{h:.2f}) .. ({fb}.north){mid};"
15691569
)
1570-
elif w.span <= 3:
1570+
elif abs(nodes[w.a].x - nodes[w.b].x) <= 3.0:
15711571
na, nb = endpoint(w.a, w.b), endpoint(w.b, w.a)
15721572
loose = 0.55 + 0.47 * w.span + 0.5 * (w.lane - 1)
15731573
lines.append(
@@ -1587,6 +1587,31 @@ def _far(nid: int, other: int) -> str:
15871587
elif w.kind == "extra":
15881588
a, b = w.a, w.b
15891589
assert a is not None and b is not None
1590+
# if the straight path would cut through a bracket group, don't
1591+
# draw it: split into two matching labeled stubs (edge names
1592+
# connect them, like the book does for far-apart contractions)
1593+
cut = False
1594+
for gid in group_side:
1595+
gn = nodes[gid]
1596+
if gid in (a, b):
1597+
continue
1598+
hw_ = gn.width / 2
1599+
if max(nodes[a].x, nodes[b].x) <= gn.x - hw_:
1600+
continue
1601+
if min(nodes[a].x, nodes[b].x) >= gn.x + hw_:
1602+
continue
1603+
cut = True
1604+
break
1605+
if cut and w.label:
1606+
for nid, other in ((a, b), (b, a)):
1607+
side = 1 if nodes[other].x >= nodes[nid].x else -1
1608+
src_ = endpoint(nid, other)
1609+
lines.append(
1610+
rf"\draw ({src_}) -- ++({0.3 * side:.2f},0)"
1611+
rf" node[anchor=south, font=\scriptsize,"
1612+
rf" inner sep=1.5pt] {{${_tex_edge(w.label)}$}};"
1613+
)
1614+
continue
15901615
direction = w.direction # '->'=head at b, '<-'=head at a (orig order)
15911616
# start from the lower endpoint; bend so the curve bows DOWN,
15921617
# away from the spine and its arcs
@@ -1686,6 +1711,22 @@ def _emit_boxes(layout: BookLayout, lines: list[str], prefix: str,
16861711
parts.append(f"({name[aid]})")
16871712
if not parts:
16881713
continue
1714+
eset_b = set(enclosed)
1715+
nodes_b = {n.id: n for n in layout.nodes}
1716+
for w in layout.wires:
1717+
if w.kind == "arc" and w.a in eset_b and w.b in eset_b:
1718+
na_, nb_ = nodes_b[w.a], nodes_b[w.b]
1719+
wide_b = abs(na_.x - nb_.x) > 3.0
1720+
h = (0.35 + 0.08 * w.span if wide_b
1721+
else 0.32 + 0.16 * w.span + 0.24 * (w.lane - 1))
1722+
if na_.kind == "group" or nb_.kind == "group":
1723+
h = 0.45 + 0.05 * (abs(na_.x - nb_.x) + na_.width)
1724+
mx_ = (na_.x + nb_.x) / 2
1725+
my_ = max(na_.y, nb_.y) + h + 0.15
1726+
parts.append(f"({mx_:.2f},{my_:.2f})")
1727+
elif w.kind == "loop" and w.a in eset_b:
1728+
parts.append(
1729+
f"({nodes_b[w.a].x:.2f},{nodes_b[w.a].y + 0.55:.2f})")
16891730
inside = sum(1 for e2, _ in layout.boxes if set(e2) < set(enclosed))
16901731
sep = 3.5 + 4.0 * inside
16911732
bn = f"{prefix}bE{bi}"
@@ -1742,8 +1783,9 @@ def _emit_derivs(layout: BookLayout, lines: list[str], prefix: str,
17421783
base = max(base, nd_.y + half)
17431784
my = base + h + 0.15 + dy
17441785
else:
1745-
h = (0.32 + 0.16 * w.span + 0.24 * (w.lane - 1)
1746-
if w.span <= 3 else 0.35 + 0.08 * w.span)
1786+
wide = abs(na_.x - nb_.x) > 3.0
1787+
h = (0.35 + 0.08 * w.span if wide
1788+
else 0.32 + 0.16 * w.span + 0.24 * (w.lane - 1))
17471789
my = max(na_.y, nb_.y) + h + 0.12 + dy
17481790
mx = (na_.x + nb_.x) / 2 + dx
17491791
parts.append(f"({mx:.2f},{my:.2f})")

0 commit comments

Comments
 (0)