Skip to content

feat: specialized horizontal-row layout for decoupling caps (#15)#72

Open
solomonshalom wants to merge 1 commit intotscircuit:mainfrom
solomonshalom:add-decoupling-caps-row-layout
Open

feat: specialized horizontal-row layout for decoupling caps (#15)#72
solomonshalom wants to merge 1 commit intotscircuit:mainfrom
solomonshalom:add-decoupling-caps-row-layout

Conversation

@solomonshalom
Copy link
Copy Markdown

Summary

Implements the layout requested in #15 by adding DecouplingCapsHorizontalRowSolver and routing partitions tagged partitionType: \"decoupling_caps\" through it instead of PackSolver2. The general packer is fine for arbitrary chips but produces stacked / scattered layouts for cap groups; this solver lays them out as a single tidy horizontal row matching the acceptable solution image in the issue.

Approach

The pipeline already does the hard work — IdentifyDecouplingCapsSolver finds the cap groups, ChipPartitionsSolver builds dedicated decoupling_caps partitions for them. The missing piece was the per-partition packer.

DecouplingCapsHorizontalRowSolver:

  1. Sorts the caps by chipId so the row order is stable across runs (important for snapshot stability and for the outer packer's nearest-neighbor logic).
  2. Walks the sorted list along x, advancing by cap.size.x + gap per step, centering the whole row on the origin so the outer PartitionPackingSolver treats the partition as one block to attach next to the main chip's power pins.
  3. Applies each cap's first availableRotation (typically ), which IdentifyDecouplingCapsSolver already restricts to keep the y+/y- pin pair upright.

gap defaults to partition.decouplingCapsGap → partition.chipGap, exactly mirroring the fallback chain that SingleInnerPartitionPackingSolver already uses when configuring PackSolver2. Callers wanting a tighter or wider row can pass gap explicitly.

The solver shape (step / solved / failed / error / packedComponents) is assignment-compatible with PackSolver2, so the parent inner-partition packer routes through whichever child it instantiated without any special-casing in the layout-extraction code path.

Files

  • New lib/solvers/DecouplingCapsHorizontalRowSolver/DecouplingCapsHorizontalRowSolver.ts — solver + visualize.
  • Edit lib/solvers/PackInnerPartitionsSolver/SingleInnerPartitionPackingSolver.ts — branch on partitionType === \"decoupling_caps\" to instantiate the row solver, otherwise stay on PackSolver2. Loosened the activeSubSolver and createLayoutFromPackingResult types to accept either child shape.

Tests (16 new)

Unit tests in tests/DecouplingCapsHorizontalRowSolver/DecouplingCapsHorizontalRowSolver.test.ts:

  • empty / single / multi-cap rows
  • horizontal alignment on shared y-axis
  • uniform x spacing between adjacent centers
  • row centered on the origin
  • explicit gap parameter overrides partition fallbacks
  • decouplingCapsGap fallback used when gap unset
  • chipGap fallback used when decouplingCapsGap missing
  • non-uniform cap widths produce a correctly-spaced centered row
  • deterministic chipId-based lex ordering
  • rotation taken from first availableRotation, defaulting to 0
  • packedComponents shape matches PackSolver2 consumer expectations
  • single-step completion regardless of cap count
  • idempotency across re-runs
  • visualize() emits one rect per cap with correct dimensions

Integration tests in tests/DecouplingCapsHorizontalRowSolver/integration.test.ts:

  • decoupling_caps partition routes through the row solver and produces the expected y-aligned, uniformly-spaced layout via SingleInnerPartitionPackingSolver.
  • default partitions still drive PackSolver2 (regression guard so the new branch can never silently capture non-decap partitions).

Test plan

  • bun test tests/DecouplingCapsHorizontalRowSolver/ — 16 pass, 0 fail.
  • bun test (full suite) — 33 pass + 1 skip + 1 pre-existing failure + 1 pre-existing import error. No new failures introduced.
  • bun run format — biome clean.
  • bunx tsc --noEmit — no new type errors involving the new code.

/claim #15

…t#15)

Adds DecouplingCapsHorizontalRowSolver and wires it into
SingleInnerPartitionPackingSolver so partitions tagged
partitionType: "decoupling_caps" get a deterministic horizontal-row
layout instead of running through the general-purpose PackSolver2.

Behavior:
- Caps are sorted by chipId for deterministic ordering across runs.
- Centers are spaced along x at (cap.size.x + gap) intervals, with the
  whole row centered on the origin so the outer PartitionPackingSolver
  treats it as a single rectangular block to attach next to the main
  chip's power pins.
- Gap defaults to partition.decouplingCapsGap, then chipGap, mirroring
  the existing fallback chain in SingleInnerPartitionPackingSolver.
  Callers can override via the constructor.
- Each cap uses its first availableRotation (typically 0°), which the
  existing IdentifyDecouplingCapsSolver already restricts to keep
  y+/y- pin pairs upright.
- Solver completes in a single step but conforms to the BaseSolver /
  PackSolver2 shape (step/solved/failed/error/packedComponents) so
  the parent inner-partition packer can treat it interchangeably.

Default partitions still drive PackSolver2, so non-decap layouts are
untouched. Verified via dedicated regression test.

Tests (16 new):
- empty / single / multi-cap rows
- horizontal alignment on shared y-axis
- uniform x spacing between adjacent centers
- centering around origin
- explicit gap parameter wins over partition fallbacks
- decouplingCapsGap fallback used when gap is unset
- chipGap fallback used when decouplingCapsGap is missing
- non-uniform cap widths produce correct centered row
- chipId-based deterministic ordering (lex sort)
- rotation taken from first availableRotation, defaulting to 0
- packedComponents shape matches PackSolver2 consumer expectations
- single-step completion regardless of cap count
- idempotency
- visualize emits one rect per cap with correct dimensions
- integration: decoupling_caps partition routes through the row solver
- integration: default partitions still drive PackSolver2 (regression)

Suite: 16 new pass, no regressions in the 33 existing tests. Pre-
existing failures (1 import error, 1 baseline test failure) are
unrelated to this change.

/claim tscircuit#15
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 27, 2026

@solomonshalom is attempting to deploy a commit to the tscircuit Team on Vercel.

A member of the Team first needs to authorize it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant