Repository navigation
fix(layout): make Smart Layout refinement deterministic and never worse - #104
Merged
Merged
Conversation
Measured on the bundled sample model and synthetic landscapes, the simulated-annealing stage ended worse than the best raw ELK candidate in most runs, left overlapping boxes, and gave a different layout on every click. Collapsed containers made every ELK candidate throw. - Layout engines only see the visible graph: hidden children are dropped and their relations re-attached to the visible ancestor. The store feeds layouts the same collapse/expand/hidden-relation rules the canvas uses and no longer overwrites a collapsed node's stored size. - Overlap between siblings is a hard constraint for the annealer, and every candidate and phase is scored after fitting parents and separating boxes (layoutFinalize.ts), so the score describes what gets rendered. - The refined layout competes with the best raw candidate and with the current layout; if nothing beats the current one, nothing changes. - New annealing engine (annealing.ts): seeded PRNG from the diagram's structure, work-based budgets instead of milliseconds, step size separate from a calibrated temperature, no aestheticBoost discontinuity, and an incremental proxy energy that only re-tests pairs a move affects. - Radical layout recurses by parentId (nested systems, databases, queues), breaks cycles from the entry points before layering, and sizes external systems from their children. - Fix the SA throughput benchmark's stale import. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 of 5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Smart Layout's simulated-annealing stage was making results worse more often than better. In a before/after run on the bundled sample model and synthetic landscapes, the refined layout scored worse than the best raw ELK candidate in 10 of 14 runs, often by overlapping boxes to shave off crossings. The same diagram also got a different layout on every click, and a collapsed container with related children made all 9 ELK candidates throw (
Referenced shape does not exist).This PR fixes those and makes the output reproducible.
deriveRFEdgesdoes it (projectToVisibleGraphingeometry.ts). The store builds layout input with the render path's rules (view-collapsed, per-view collapsed/expanded, hidden relations). It also stops overwriting a collapsed node's stored size with the collapsed size. This also fixes Tree Layout, which crashed on collapsed containers the same way.layoutFinalize.ts), so the score describes what gets rendered. Compound padding is shared with the store'sfitParentToChildren.keptCurrent).annealing.ts).aestheticBoostdiscontinuity is removed; it used to make removing the last crossing cost energy.parentId. Before, nested systems, databases and queues got no position: 16 of 20 nodes in the bench fixture.saThroughput.bench.mjsimported a no-longer-exported function.Results
Composite cost is the Smart Layout score (lower is better). "Before" is the mean of 3 runs of
origin/main, re-scored with this branch's scorer. "After" is identical on every run.Known issues / follow-ups
minimizeCrossings(300–400 ms × 10 candidates), not ELK itself. Moving it into the worker is the natural next step.runSmartLayoutSAPhasealready takes aseed, so a "try another arrangement" action would be small.Test plan
npm run typechecknpm test: 428 passed, 15 of them new. 6 of the new tests fail onorigin/main: nested compounds, cycle entry order, expanded externals, determinism, keep-current, collapsed container.🤖 Generated with Claude Code