Skip to content

Minimal mode: SGD stress layout with constraint-graph straightening - #230

Open
hadley wants to merge 1 commit into
mainfrom
minimal-stress-layout
Open

Minimal mode: SGD stress layout with constraint-graph straightening#230
hadley wants to merge 1 commit into
mainfrom
minimal-stress-layout

Conversation

@hadley

@hadley hadley commented Aug 13, 2026

Copy link
Copy Markdown
Member

Experimental solution to #214.

Adds a minimal mode to the rendered dictionary page (toggle in the diagram toolbar, persisted per dictionary in localStorage): each table draws as its name only, one wire per relationship, laid out by a full stress model rather than dagre.

Layout pipeline (minimal mode)

  1. Stress model solved by SGD — Zheng, Pawar & Goodman, Graph Drawing by Stochastic Gradient Descent (IEEE TVCG 2019, arXiv:1710.04626, s_gd2). All-pairs shortest-path ideal distances, weighted 1/d², inflated by box half-extents (Gansner & Hu) so the stress term itself keeps boxes apart; s_gd2 exponential annealing schedule; 8 deterministic restarts (seeded PRNG) scored on wire crossings of the wires as actually drawn.
  2. Constraint-graph align/straighten — the coordinate-assignment half of Shape-Metrics (arXiv:2508.19416) reduced to what rectangle nodes need, no SAT: wires are compass-labelled, H/V wires become centre-equality constraints, non-overlap becomes separation arcs in a per-axis DAG, longest path assigns coordinates and compacts. A merge is refused when an arc already runs between the two groups (they overlap on the other axis, so sharing a centre would stack the boxes) — that wire keeps its diagonal, which the renderer draws happily.
  3. Hill-climb polish on a cost of wire crossings + deviation from ideal length − alignment bonus.

Wire anchoring

Minimal-mode wires anchor to the nearest pair of compass points (3×3 grid: corners + edge midpoints) on the two boxes — aligned boxes get facing edge midpoints, so straight wires draw exactly straight. The layout's crossing scoring mirrors the same anchor choice.

Notes

  • One shared BOX_GAP constant feeds the solver, the hill-climb's overlap test, and the separation pass, so they don't re-move each other's placements.
  • tidy discards the saved arrangement but preserves the mode.
  • Reviewer findings addressed: literal NUL byte replaced with a \0 escape (git treats the file as text again), dead acyclicity merge check replaced with the correct arc-between-groups infeasibility test (verified on the triangle repro), latent union-find revert corruption eliminated by checking feasibility before mutating parent.

…ening

Minimal mode draws each table as its name only, one wire per
relationship. Its layout is a full stress model solved by stochastic
gradient descent (Zheng, Pawar & Goodman, IEEE TVCG 2019,
arXiv:1710.04626): all-pairs shortest-path ideal distances weighted
1/d^2, box-extent-inflated so the stress term itself keeps tables
apart, with the s_gd2 annealing schedule over several deterministic
restarts scored on wire crossings.

Once the solver settles, a constraint-graph pass straightens and
aligns: wires are labelled by compass direction, horizontal/vertical
wires become centre-equality constraints, non-overlap becomes
separation arcs in a per-axis DAG, and longest path assigns
coordinates (TSM-style compaction; the coordinate half of
Shape-Metrics, arXiv:2508.19416, without the SAT search). A wire
whose constraint would stack its tables keeps its diagonal.

Wires anchor to the nearest pair of compass points on the two boxes,
so aligned tables get exactly straight horizontal or vertical wires.
The minimal/regular mode persists in the per-dictionary layout record
in localStorage.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant