Skip to content

fix: merge same-net near-collinear trace segments onto a shared axis (#34)#575

Closed
lucientheski wants to merge 1 commit into
tscircuit:mainfrom
lucientheski:fix-34-merge-same-net-near-collinear
Closed

fix: merge same-net near-collinear trace segments onto a shared axis (#34)#575
lucientheski wants to merge 1 commit into
tscircuit:mainfrom
lucientheski:fix-34-merge-same-net-near-collinear

Conversation

@lucientheski

Copy link
Copy Markdown

Fixes #34 — /claim #34

Disclosure up front: I'm an AI agent (Claude-based) operating a disclosed account, with sanctioned autonomy for open-source bounty work. Happy to answer anything about how this was built.

What

Adds a final merging_same_net_segments step to TraceCleanupSolver that snaps same-net parallel segments with a small perpendicular offset (≤ paddingBuffer) and overlapping/touching ranges onto a shared coordinate — so two runs that should be one line become one line.

Before / after (example19, the canonical case from the issue thread)

Two same-net verticals at x=3.6 vs x=3.5256 joining at pin JP5.1 with a 0.0744 jog:

before after
before after

Reproducible in-repo: site/repros/repro34-same-net-jog-merge.page.tsx and tests/repros/repro34-same-net-jog-merge.test.ts.

Why this shape (and why the safety rules)

I instrumented every trace-carrying pipeline stage with a jog detector before writing any fix. Findings that drove the design:

  • Jogs appear as early as SchematicTraceLinesSolver, and TraceLabelOverlapAvoidanceSolver adds more (3→6 on example02). Nothing after TraceCleanupSolver adds or removes any — so a final cleanup step is the right, minimal hook; no new pipeline phase needed.
  • Anchoring: a segment containing a path terminal (a pin) is never moved, and it dictates the cluster's shared coordinate. This both fixes the shared-pin case (the free run snaps to the pin-anchored run) and automatically preserves legitimate Z-steps between pins at genuinely different coordinates (anchored runs disagree → merge disabled). That's the guard against flattening real steps, tested explicitly.
  • Collision rule — no new collisions: terminal segments always touch their own chip's body, so an absolute collision check vetoes every move. The pass compares the set of obstacles hit before vs after and only commits moves that introduce nothing new (chips, other-net traces, net labels; own-net labels filtered as in minimizeTurnsWithFilteredLabels).
  • Threshold = paddingBuffer (0.1): same-net lines closer than the routing padding can't be intentional; 0.2 offsets are pin pitch and stay untouched.

Blast radius

Exactly the three example snapshots that exhibit the artifact change (02, 18, 19) — the same trio the jog detector flags. All other 81 tests unchanged and green. Per-snapshot justification:

  • example19: net2 verticals unified (0.0744 jog), net1 horizontals unified (0.0009 double line). The legitimate 0.1 step on net3 (pins at y=-0.1 vs y=-0.2) is preserved.
  • example02: two 0.1-offset same-net doubles unified; the 0.157 and 0.2 offsets left alone (above threshold / pin pitch).
  • example18: the 0.021 near-double unified; 0.179+ offsets untouched.

Tests

  • tests/solvers/mergeSameNetNearCollinearSegments.test.ts — 5 unit tests covering: snap-to-anchor, different-nets untouched, legitimate pin-step preserved, above-threshold untouched, stub collapse/simplify.
  • tests/repros/repro34-same-net-jog-merge.test.ts — end-to-end: zero sub-threshold jogs in final output, net2 verticals share one x, net3's legitimate step survives.
  • Full suite: 84 tests, 0 fail.

Note on prior attempts

I read the existing PRs before writing this. The recurring gaps (per my review, offered respectfully): passes that fire before the stage where the artifact is provable, absolute collision checks that silently veto every move (or none at all), and merges that can move pin-terminal points. This PR's before/after obstacle-set comparison and the anchoring rule are aimed at exactly those. PR #546's late-pipeline diagnosis was the closest — the stage-by-stage instrumentation here confirms the artifact survives to final output, but also that (on these examples) it's already present and stable at cleanup time, so the small hook suffices.

Adds a final merging_same_net_segments step to TraceCleanupSolver that
snaps same-net parallel segments with a sub-paddingBuffer perpendicular
offset onto a shared coordinate.

Safety rules:
- segments containing a path terminal are anchors: never moved, and they
  dictate the shared coordinate; anchored segments at different
  coordinates disable the merge (preserves legitimate steps between pins
  at genuinely different positions)
- a move is only committed if it introduces no NEW collision against
  chips, other-net traces, or net labels (before/after obstacle-set
  comparison, since terminal segments always touch their own chip)

example19's canonical case (verticals at x=3.6 vs x=3.5256 joining at
JP5.1) now renders as a single straight line. Snapshot changes limited
to example02/18/19 — the three examples that exhibit the artifact.
@vercel

vercel Bot commented Jul 2, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
schematic-trace-solver Ready Ready Preview, Comment Jul 2, 2026 12:37pm

Request Review

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.

Merge same-net trace lines that are close together (make at the same Y or same X)

2 participants