Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export function applyDecouplingCapsLinearLayout(
chips: Array<{
chipId: string
center: { x: number; y: number }
ccwRotationDegrees: number
}>,
opts?: { decouplingCapsGap?: number; chipGap?: number },
) {
if (chips.length === 0) return

const gap = opts?.decouplingCapsGap ?? opts?.chipGap ?? 0.2
const chipWidth = 1
const totalWidth = chips.length * chipWidth + (chips.length - 1) * gap

const sorted = [...chips].sort((a, b) => a.chipId.localeCompare(b.chipId))
let x = -totalWidth / 2 + chipWidth / 2

for (const chip of sorted) {
chip.center.x = x
chip.center.y = 0
chip.ccwRotationDegrees = 0
x += chipWidth + gap
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import type {
import { visualizeInputProblem } from "../LayoutPipelineSolver/visualizeInputProblem"
import { createFilteredNetworkMapping } from "../../utils/networkFiltering"
import { getPadsBoundingBox } from "./getPadsBoundingBox"
import { applyDecouplingCapsLinearLayout } from "./DecouplingCapsLinearLayoutSolver"
import { doBasicInputProblemLayout } from "../LayoutPipelineSolver/doBasicInputProblemLayout"

const PIN_SIZE = 0.1
Expand All @@ -38,6 +39,32 @@ export class SingleInnerPartitionPackingSolver extends BaseSolver {
}

override _step() {
// Fast path: decoupling cap partitions get a clean linear layout
if (this.partitionInputProblem.partitionType === "decoupling_caps") {
const chips = Object.entries(this.partitionInputProblem.chipMap).map(
([chipId]) => ({
chipId,
center: { x: 0, y: 0 },
ccwRotationDegrees: 0,
}),
)
applyDecouplingCapsLinearLayout(chips, {
decouplingCapsGap: this.partitionInputProblem.decouplingCapsGap,
chipGap: this.partitionInputProblem.chipGap,
})
this.layout = {
chipPlacements: Object.fromEntries(
chips.map(({ chipId, center, ccwRotationDegrees }) => [
chipId,
{ x: center.x, y: center.y, ccwRotationDegrees },
]),
),
groupPlacements: {},
}
this.solved = true
return
}

// Initialize PackSolver2 if not already created
if (!this.activeSubSolver) {
const packInput = this.createPackInput()
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,8 @@
},
"peerDependencies": {
"typescript": "^5"
},
"dependencies": {
"circuit-to-svg": "^0.0.343"
}
}
47 changes: 47 additions & 0 deletions tests/PackInnerPartitionsSolver/DecouplingCapsLayout.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { describe, it, expect } from "bun:test"
import { applyDecouplingCapsLinearLayout } from "../../lib/solvers/PackInnerPartitionsSolver/DecouplingCapsLinearLayoutSolver"

describe("applyDecouplingCapsLinearLayout", () => {
it("places a single cap at origin", () => {
const chips = [
{ chipId: "C1", center: { x: 99, y: 99 }, ccwRotationDegrees: 45 },
]
applyDecouplingCapsLinearLayout(chips)
expect(chips[0]!.center!.x).toBeCloseTo(0)
expect(chips[0]!.center!.y).toBeCloseTo(0)
expect(chips[0]!.ccwRotationDegrees).toBe(0)
})

it("centers multiple caps in a horizontal row", () => {
const chips = [
{ chipId: "C1", center: { x: 0, y: 0 }, ccwRotationDegrees: 0 },
{ chipId: "C2", center: { x: 0, y: 0 }, ccwRotationDegrees: 0 },
{ chipId: "C3", center: { x: 0, y: 0 }, ccwRotationDegrees: 0 },
]
applyDecouplingCapsLinearLayout(chips, { decouplingCapsGap: 0.2 })

// total width = 3*1 + 2*0.2 = 3.4, centered → x in [-1.2, 0, 1.2]
const xs = chips.map((c) => c.center!.x).sort((a, b) => a - b)
expect(xs[0]).toBeCloseTo(-1.2)
expect(xs[1]).toBeCloseTo(0)
expect(xs[2]).toBeCloseTo(1.2)

chips.forEach((c) => expect(c.center!.y).toBeCloseTo(0))
})

it("does nothing for empty array", () => {
expect(() => applyDecouplingCapsLinearLayout([])).not.toThrow()
})

it("sorts chips by chipId before laying out", () => {
const chips = [
{ chipId: "C3", center: { x: 0, y: 0 }, ccwRotationDegrees: 0 },
{ chipId: "C1", center: { x: 0, y: 0 }, ccwRotationDegrees: 0 },
]
applyDecouplingCapsLinearLayout(chips, { decouplingCapsGap: 0 })
// C1 should be leftmost after sort
const c1 = chips.find((c) => c.chipId === "C1")!
const c3 = chips.find((c) => c.chipId === "C3")!
expect(c1.center!.x).toBeLessThan(c3.center!.x)
})
})
Loading