- Add the Capacity, Global, Assignment and Corridor stages, ported from
the development branch onto the grid of main; they write the artifacts
01-capacity.fb to 04-corridor.fb
- Add port bands, the Voronoi medial axis, bottlenecks, partitions and
chamber moves to the grid module, and bridge pairs and components to
the design module
- Add MQT::ScpdMilp: a linear model, a HiGHS 1.11.0 backend, MPS output
and an external backend that reaches Gurobi through gurobipy
- Add the stage interfaces, the algorithm registry and the stage report
to the pipeline module
- Add mqt-scpd plan with a run directory, --stop-after, --stage, -v to
-vvv and a live progress line through rich, list-algorithms, and
--run-dir and --stage for plot and render
- Define the terminal output in docs/terminal_output.md and test it
- Add the configurations of the eight benchmark chips and the --chip
option
- Leave labels below the first partition label out of the partition
outlines, so the cells reserved for a port approach form no partition
- Negate the objective of a maximization that an external backend solves
through MPS
- Build HiGHS without link-time optimization, so a solve does not depend
on how often the build directory was configured
Assisted-by: Claude Opus 5.5 via Claude Code
🤖 AI text below 🤖
Description
Until now the tool could read, check, draw and export a chip, and the grid and router modules of #134 could route one wire. Nothing decided yet which wire goes where. This pull request adds the four planning steps of the pipeline and the command that runs them. Each step writes one artifact:
01-capacity.fb02-global.fb03-assign.fb04-corridor.fbmqt-scpd planruns the steps into a run directory. On the 17-qubit chip, a run prints:The detail and final routing follow in the next phase.
The steps were built and measured on the development branch. This pull request ports them onto the reviewed grid of main. On seven of the eight benchmark chips, the four artifacts equal those of the development branch in every field. The 4-qubit chip differs by one bug fix (see "Differences from the development branch").
The planning steps
watershed). The step rasterizes the chip and takes the distance transform of the free space. It finds the bottlenecks along the medial axis of the free space, which a Voronoi diagram over the boundary cells of the obstacles gives (Boost.Polygon). From each target it walks the bottlenecks outward into capacity chains. The chambers that the chains cross become partitions, and the rest of the free space grows into partitions from the middle of every clear capacity cell. Every partition border gets a budget: the number of wires that may cross it. A band in front of every port keeps the straight approach of its wire clear.hanan-milp). The step routes the inner circuit: the wires to the ports that the configured ring does not carry. It solves a binary flow model on the Hanan lattice of each capacity chain as one mixed-integer program. The bridge rules of the configuration name the two ports of a coupler that a wire passes between. The result includes the ring of outer ports that the assignment works on.ordered-milp). One mixed-integer program assigns the ring ports to launchers and feedline chains and keeps the feedlines from crossing.partition-astar). The router searches the partition graph instead of the cells. A node is a crossing slot on a partition border. A connection therefore learns which partitions it runs through and where it crosses from one into the next. The detail routing of the next phase draws the wire inside each partition. No two wires take the same slot, and no two wires cross inside one partition. The router works in rounds that sweep forward and backward over the connections. A slot that a wire wanted and could not have gets dearer for the wire on it, so two wires do not trade one slot back and forth.The global step runs before the assignment, because the inner circuit decides at which coupler ports its wires surface, and the assignment works on the ring that those ports extend. The roadmap lists the two steps the other way round.
The MILP module (
MQT::ScpdMilp)Modelholds variables, linear constraints and one linear objective.toMpswrites a model as MPS text, and an external backend solves that text. The Python package registers Gurobi this way whengurobipyis installed and licensed.[stages.solver] backendorSCPD_SOLVERchoosesauto,highsorgurobi.SolveObserverreceives the solver log and the progress of the search (objective, bound, gap and nodes). An exception that the observer throws stops HiGHS through its interrupt flag and is thrown again after the solve, so it never passes through HiGHS.The pipeline module (
MQT::ScpdPipeline)mqt-scpd list-algorithmslists them, and the configuration can choose one per step.Reportcarries what a step reports: free lines, entries such as one round, the result and the progress, each at one of four levels. The core never prints; the Python package renders the report.Command line
mqt-scpd plan -c <config> -o <run directory>copies the configuration and the chip input into the run directory and runs the steps.--stop-after <step>, or[run] stop_after, ends the run after a step.--stage <step>runs one step again on the copies in the run directory and deletes the artifacts of the later steps. Each artifact is written to a temporary file and then renamed, so a run never leaves half a file. A run that ends with fails exits with code 1. Ctrl-C stops a running solve and exits with code 130.-v,-vvand-vvvadd the parameters and sub-steps, one line per item, and the solver log. On a terminal, a live line throughrichshows the running step.docs/terminal_output.mdfixes this format for the steps of later phases, and tests hold it: a golden output ofplanon the test fixture, a grammar test of every line at-vvv, and a test that every step has a mark, an ASCII form and a colour.plotandrenderdraw a planning step of a run with--run-dirand--stage. In GDS, the planning shapes use the layers 20 to 31.--chipreplaces the chip input of the configuration fordoctor,plot,renderandplan.benchmarks/<chip>/config.tomlholds a configuration for each of the eight benchmark chips; the chip inputs stay in planar-superconducting-pd.Configuration
componentpattern groups the ports by component. Thebridge_pairpattern and the[[ports.bridge_pairs]]rules pair the two ports of a coupler that a wire passes between.[stages.capacity],[stages.global],[stages.assignment],[stages.corridor]and[stages.solver]hold the parameters of the steps.[run]holdsstop_after.[stages.assignment] launcher_targethas no default, because it is a figure of the chip.UPGRADING.mdlists what a configuration needs forplan.Differences from the development branch
The reference was the development branch at commit
712cf7a, with fix 1 applied.01-capacity.fband04-corridor.fb. The other chips have no such cells.toMpsnegates a maximization. The external backend now negates the objective that it gets back. Both planning models minimize, so no artifact changes.The grid of main also differs from the development branch in three rules from the review of #134: a watershed tie goes to the lower seed, the border smoothing keeps every seed cell, and the polygon fill computes each crossing from the nearer end of an edge. None of these rules changes an artifact of the eight benchmark chips.
Known limits
std::unordered_map. The shapes are the same everywhere, but the start corner and the order of the rings in01-capacity.fbcan differ between standard libraries. Every later use of the outlines ignores that order. A sorted order would change the artifact on every chip, so this pull request keeps the order of the development branch.UPGRADING.mdstates the rule; a check indoctorcould follow.launcher_targetor an unknown algorithm name fails only when its step runs. On the 69-qubit chip, that can be a minute into the run.gurobipyis not installed on the test machine. Withauto, a licensedgurobipytakes precedence over HiGHS.planneeds the configurations inbenchmarks/.docs/terminal_output.mddocuments warnings, but no step produces one yet.Determinism
The same input gives the same artifacts within one build, and a resumed run equals an uninterrupted one. The project targets build without floating-point contraction, as since #134. HiGHS keeps the compiler defaults and is always built without link-time optimization. Main configures the dependencies before the project settings, so HiGHS used to get link-time optimization only on a second configure, and that changed the last bits of the assignment objectives on the 45- and 69-qubit chips. The comparisons with the development branch ran on macOS arm64.
Notes for review
SCP1identifier and the same union order, withCorridorRoutingas the seventh member. The later stages of the development branch therefore read them, and the acceptance check below relies on that.rich>=14is a new runtime dependency of the Python package.plantakes about 1.5 minutes, 56 seconds of it in the Capacity step.test/fixtures/minigets launcher offsets of 0, a launcher target of 1 and one feedline termination, and its launchers are numbered clockwise. With the old values, the assignment of the fixture has no solution.NOLINTs: two implicit conversions toLinearExpr, which keep model expressions short; a copy in a test that checks that a copied report shares its state; andsetenvandunsetenvin a test, which include-cleaner does not map to a header.Verification
mqt-scpd plan --stop-after corridorran on the eight benchmark chips, and a script compared the artifacts with those of the development branch field by field, floating-point values bit for bit. All four artifacts are equal on the chips with 9 to 69 qubits. On the 4-qubit chip, only fix 2 makes a difference.MQT_SCPD_BENCHMARKS. The benchmark checks plan every chip and test what the later stages rely on: every inner port is reached, every ring port has a launcher, every connection has a corridor, a crossing slot carries one wire, and no two wires meet inside a partition. Every planning step also draws an SVG under 10 MB and a GDS file. The benchmarks workflow runs these checks.uvx nox -s lintpasses. The Python stubs and the schema code are regenerated.AI assistance. The port, the tests, the documentation and this description were written with Claude Opus 5.5 via Claude Code. The author reviewed them.
Checklist
If PR contains AI-assisted content:
🤖 *AI text below* 🤖(titles are exempt).🤖 Generated with Claude Code