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
1 change: 1 addition & 0 deletions .github/workflows/benchmarks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ on:
pull_request:
paths:
- ".github/workflows/benchmarks.yml"
- "benchmarks/**"
- "bindings/**"
- "cmake/**"
- "CMakeLists.txt"
Expand Down
29 changes: 29 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,31 @@ releases may include breaking changes.

### Added

- ✨ Add `mqt-scpd plan`, which runs the planning steps into a run directory:
`--stop-after` and `[run] stop_after` end a run after a step, `--stage` runs
one step again on the copies the run carries, and `-v`, `-vv` and `-vvv` show
the steps, the items and the solver log. A run prints one block per stage with
a live progress line on a terminal, in the format of
`docs/terminal_output.md`. Add `list-algorithms`, and `plot` and `render` with
`--stage` and `--run-dir` for the planning stages; the assign and corridor
pictures show the feedline chains ([#139]) ([**@FeldmeierMichael**])
- ✨ Add the planning stages: the Capacity stage partitions the free space at
its bottlenecks and budgets the wires of every capacity chain, the Global
stage solves the inner circuit as a mixed-integer program on Hanan lattices,
the Assignment stage assigns the ring ports to launchers and feedline chains
with an integer program, and the Corridor stage routes every connection
through the partitions over border slots. They write the artifacts
`01-capacity.fb` to `04-corridor.fb` ([#139]) ([**@FeldmeierMichael**])
- ✨ Add `MQT::ScpdMilp`: a linear model, the HiGHS backend with a progress and
log observer, MPS output, and the choice of the backend through
`[stages.solver] backend` or `SCPD_SOLVER`; Gurobi is used through `gurobipy`
when it is installed and licensed ([#139]) ([**@FeldmeierMichael**])
- ✨ Add bridge pairs and components to the configuration: the `bridge_pair` and
`component` patterns, the `[[ports.bridge_pairs]]` rules, the stage sections
and `[run]` ([#139]) ([**@FeldmeierMichael**])
- ✨ Add the configurations of the eight benchmark chips in `benchmarks/`, and
the `--chip` option of `doctor`, `plot`, `render` and `plan` ([#139])
([**@FeldmeierMichael**])
- ✨ Add `MQT::ScpdRouting`: a curvature-constrained A* over eight-way Dubins
move primitives, with a distance-field heuristic, a bucket queue whose memory
is that of its largest search, one shared read-only obstacle mask and
Expand Down Expand Up @@ -49,6 +74,9 @@ releases may include breaking changes.

### Changed

- 🎨 Start the result line of `plot`, `render` and `inspect` with `✓` and an
error with `✗`, and show the `bridge_pair` pattern and the reachable solvers
in `doctor` ([#139]) ([**@FeldmeierMichael**])
- 🔧 Build the module libraries, the tests and the Python bindings with
floating-point contraction off (`-ffp-contract=off`, and
`/clang:-ffp-contract=off` for clang-cl), also inside a parent project that
Expand All @@ -72,6 +100,7 @@ releases may include breaking changes.

<!-- PR links -->

[#139]: https://github.com/munich-quantum-toolkit/scpd/pull/139
[#134]: https://github.com/munich-quantum-toolkit/scpd/pull/134
[#111]: https://github.com/munich-quantum-toolkit/scpd/pull/111
[#98]: https://github.com/munich-quantum-toolkit/scpd/pull/98
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,14 @@ mqt-scpd plot -c planar-superconducting-pd/inputs/9q/config.toml -o 9q.svg
mqt-scpd render -c planar-superconducting-pd/inputs/9q/config.toml -o 9q.gds
```

`plan` runs the planning steps of a chip into a run directory. The
configurations it needs are in the `benchmarks/` directory of this repository:

```bash
mqt-scpd plan -c benchmarks/9q/config.toml \
--chip planar-superconducting-pd/inputs/9q/routing_config.json -o runs/9q
```

The
[benchmark guide](https://mqt.readthedocs.io/projects/scpd/en/latest/benchmarks.html)
describes the chips and what the current release does with them.
Expand Down
30 changes: 30 additions & 0 deletions UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,36 @@ of changes including minor and patch releases, please refer to the

## [Unreleased]

### Planning a chip

`mqt-scpd plan` needs a few keys that a configuration for `doctor`, `plot` and
`render` does not:

- `[stages.assignment] launcher_target`: how many feedline ends the chip gives a
launcher. It is a figure of the chip and has no default.
- A `component` pattern, which groups the ports by component, and, for a chip
whose couplers carry a wire across, a `bridge_pair` pattern with the
`[[ports.bridge_pairs]]` rules that pair those ports.

The configurations in `benchmarks/<chip>/config.toml` carry these keys. Plan a
benchmark chip with the chip input of
[planar-superconducting-pd](https://github.com/cda-tum/planar-superconducting-pd):

```console
mqt-scpd plan -c benchmarks/17q/config.toml \
--chip planar-superconducting-pd/inputs/17q/routing_config.json -o runs/17q
```

The assignment expects the launcher ports to be numbered against the direction
of the port ring, as on the benchmark chips.

### Output of the commands

`plot`, `render` and `inspect -o` end with a line that starts with `✓`, and
every command reports an error on a line that starts with `✗`, both in the
format of `docs/terminal_output.md`. A script that looked for `wrote` or
`error:` looks for these instead.

<!-- Version links -->

[unreleased]: https://github.com/munich-quantum-toolkit/scpd
85 changes: 85 additions & 0 deletions benchmarks/17q/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Copyright (c) 2026 Chair for Design Automation, TUM
# Copyright (c) 2026 Munich Quantum Software Company GmbH
# All rights reserved.
#
# SPDX-License-Identifier: MIT
#
# Licensed under the MIT License

# The 17-qubit benchmark chip of the paper, as MQT SCPD plans it. The chip
# input is the routing_config.json of planar-superconducting-pd; pass it with
# --chip, as README.md in this directory shows. Every design rule is written
# out; every other key is present only when it differs from the default.

[chip]
input = "routing_config.json"

[ports.patterns]
launcher = '^Chip\.port\d+$'
resonator = '^Qb\d+\.port0$'
conventional = '^(Qb\d+\.port1|Coupler\d+_\d+\.port0)$'
bridge_pair = '^Coupler\d+_\d+\.port[1-4]$'
component = '^([^.]+)\.port\d+$'

[[ports.bridge_pairs]]
first = '^(Coupler\d+_\d+)\.port1$'
second = '^(Coupler\d+_\d+)\.port2$'

[[ports.bridge_pairs]]
first = '^(Coupler\d+_\d+)\.port3$'
second = '^(Coupler\d+_\d+)\.port4$'

[ports.sequences]
all_outer = [
"Qb15.port1", "Qb15.port0", "Coupler14_15.port3", "Coupler14_15.port0", "Coupler14_15.port1",
"Qb14.port1", "Qb14.port0", "Coupler13_14.port3", "Coupler13_14.port0", "Coupler13_14.port1",
"Qb13.port1", "Coupler13_17.port3", "Coupler13_17.port0", "Coupler13_17.port1", "Qb17.port0",
"Qb17.port1", "Coupler16_17.port1", "Coupler16_17.port0", "Coupler16_17.port3", "Qb16.port0",
"Qb16.port1", "Coupler12_16.port3", "Coupler12_16.port0", "Coupler12_16.port1", "Qb12.port0",
"Qb12.port1", "Coupler8_12.port1", "Coupler8_12.port0", "Coupler8_12.port3", "Qb8.port0",
"Coupler7_8.port3", "Coupler7_8.port0", "Coupler7_8.port1", "Qb7.port0", "Qb7.port1",
"Coupler3_7.port3", "Coupler3_7.port0", "Coupler3_7.port1", "Qb3.port1", "Qb3.port0",
"Coupler3_4.port3", "Coupler3_4.port0", "Coupler3_4.port1", "Qb4.port1", "Qb4.port0",
"Coupler4_5.port3", "Coupler4_5.port0", "Coupler4_5.port1", "Qb5.port1", "Coupler1_5.port3",
"Coupler1_5.port0", "Coupler1_5.port1", "Qb1.port0", "Qb1.port1", "Coupler1_2.port1",
"Coupler1_2.port0", "Coupler1_2.port3", "Qb2.port1", "Qb2.port0", "Coupler2_6.port1",
"Coupler2_6.port0", "Coupler2_6.port3", "Qb6.port0", "Qb6.port1", "Coupler6_10.port1",
"Coupler6_10.port0", "Coupler6_10.port3", "Qb10.port0", "Coupler10_11.port3",
"Coupler10_11.port0", "Coupler10_11.port1", "Qb11.port0", "Qb11.port1", "Coupler11_15.port3",
"Coupler11_15.port0", "Coupler11_15.port1",
]
fixed_outer = [
"Qb15.port0", "Coupler14_15.port0", "Qb14.port1", "Qb14.port0", "Coupler13_14.port0",
"Qb13.port1", "Coupler13_17.port0", "Qb17.port0", "Qb17.port1", "Coupler16_17.port0",
"Qb16.port0", "Qb16.port1", "Coupler12_16.port0", "Qb12.port0", "Qb12.port1",
"Coupler8_12.port0", "Qb8.port0", "Coupler7_8.port0", "Qb7.port0", "Qb7.port1",
"Coupler3_7.port0", "Qb3.port1", "Qb3.port0", "Coupler3_4.port0", "Qb4.port1", "Qb4.port0",
"Coupler4_5.port0", "Qb5.port1", "Coupler1_5.port0", "Qb1.port0", "Qb1.port1",
"Coupler1_2.port0", "Qb2.port1", "Qb2.port0", "Coupler2_6.port0", "Qb6.port0", "Qb6.port1",
"Coupler6_10.port0", "Qb10.port0", "Coupler10_11.port0", "Qb11.port0", "Qb11.port1",
"Coupler11_15.port0", "Qb15.port1",
]

[design_rules]
min_wire_spacing = 185.0
min_obstacle_spacing = 25.0
min_bend_radius = 50.0
min_straight_length = 100.0
target_resonator_length = 3000.0
resonator_length_tolerance = 100.0
max_feedline_utilization = 5
feedline_terminations = 1

[grid]
capacity_cells_x = 25
capacity_cells_y = 25
# The launcher slot sits on the launcher port, so the blocked border of the
# capacity grid must not cover it. A port inside the border is a freed cell in a
# wall that no capacity chain reaches, and the partitioning around it collapses.
launcher_offset_x = 0
launcher_offset_y = 0

[stages.assignment]
# How many launchers the assignment activates. A figure per chip with no
# default, taken from the prototype's driver of the same benchmark.
launcher_target = 7
94 changes: 94 additions & 0 deletions benchmarks/21q/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Copyright (c) 2026 Chair for Design Automation, TUM
# Copyright (c) 2026 Munich Quantum Software Company GmbH
# All rights reserved.
#
# SPDX-License-Identifier: MIT
#
# Licensed under the MIT License

# The 21-qubit benchmark chip of the paper, as MQT SCPD plans it. The chip
# input is the routing_config.json of planar-superconducting-pd; pass it with
# --chip, as README.md in this directory shows. Every design rule is written
# out; every other key is present only when it differs from the default.

[chip]
input = "routing_config.json"

[ports.patterns]
launcher = '^Chip\.port\d+$'
resonator = '^Qb\d+\.port0$'
conventional = '^(Qb\d+\.port1|Coupler\d+_\d+\.port0)$'
bridge_pair = '^Coupler\d+_\d+\.port[1-4]$'
component = '^([^.]+)\.port\d+$'

[[ports.bridge_pairs]]
first = '^(Coupler\d+_\d+)\.port1$'
second = '^(Coupler\d+_\d+)\.port2$'

[[ports.bridge_pairs]]
first = '^(Coupler\d+_\d+)\.port3$'
second = '^(Coupler\d+_\d+)\.port4$'

[ports.sequences]
all_outer = [
"Qb1.port1", "Qb1.port0", "Coupler1_2.port1", "Coupler1_2.port0", "Coupler1_2.port3",
"Qb2.port1", "Qb2.port0", "Coupler2_6.port1", "Coupler2_6.port0", "Coupler2_6.port3",
"Coupler6_7.port1", "Coupler6_7.port0", "Coupler6_7.port3", "Qb7.port1", "Qb7.port0",
"Coupler7_8.port3", "Coupler7_8.port0", "Coupler7_8.port1", "Qb8.port0", "Coupler3_8.port3",
"Coupler3_8.port0", "Coupler3_8.port1", "Qb3.port1", "Qb3.port0", "Coupler3_4.port3",
"Coupler3_4.port0", "Coupler3_4.port1", "Qb4.port0", "Qb4.port1", "Coupler4_9.port1",
"Coupler4_9.port0", "Coupler4_9.port3", "Qb9.port1", "Qb9.port0", "Coupler8_9.port1",
"Coupler8_9.port0", "Coupler8_9.port3", "Qb8.port1", "Coupler8_12.port1", "Coupler8_12.port0",
"Coupler8_12.port3", "Qb12.port1", "Qb12.port0", "Coupler12_16.port1", "Coupler12_16.port0",
"Coupler12_16.port3", "Qb16.port0", "Coupler16_17.port3", "Coupler16_17.port0",
"Coupler16_17.port1", "Qb17.port1", "Qb17.port0", "Coupler17_21.port1", "Coupler17_21.port0",
"Coupler17_21.port3", "Qb21.port0", "Qb21.port1", "Coupler20_21.port1", "Coupler20_21.port0",
"Coupler20_21.port3", "Qb20.port0", "Qb20.port1", "Coupler16_20.port1", "Coupler16_20.port0",
"Coupler16_20.port3", "Qb16.port1", "Coupler15_16.port1", "Coupler15_16.port0",
"Coupler15_16.port3", "Qb15.port0", "Qb15.port1", "Coupler14_15.port3", "Coupler14_15.port0",
"Coupler14_15.port1", "Coupler14_19.port3", "Coupler14_19.port0", "Coupler14_19.port1",
"Qb19.port0", "Qb19.port1", "Coupler18_19.port3", "Coupler18_19.port0", "Coupler18_19.port1",
"Qb18.port1", "Qb18.port0", "Coupler13_18.port1", "Coupler13_18.port0", "Coupler13_18.port3",
"Qb13.port0", "Qb13.port1", "Coupler13_14.port1", "Coupler13_14.port0", "Coupler13_14.port3",
"Qb14.port0", "Coupler10_14.port1", "Coupler10_14.port0", "Coupler10_14.port3", "Qb10.port0",
"Qb10.port1", "Coupler6_10.port3", "Coupler6_10.port0", "Coupler6_10.port1", "Qb6.port0",
"Coupler5_6.port3", "Coupler5_6.port0", "Coupler5_6.port1", "Qb5.port0", "Qb5.port1",
"Coupler1_5.port1", "Coupler1_5.port0", "Coupler1_5.port3",
]
fixed_outer = [
"Qb1.port1", "Qb1.port0", "Coupler1_2.port0", "Qb2.port1", "Qb2.port0", "Coupler2_6.port0",
"Coupler6_7.port0", "Qb7.port1", "Qb7.port0", "Coupler7_8.port0", "Qb8.port0",
"Coupler3_8.port0", "Qb3.port1", "Qb3.port0", "Coupler3_4.port0", "Qb4.port0", "Qb4.port1",
"Coupler4_9.port0", "Qb9.port1", "Qb9.port0", "Coupler8_9.port0", "Qb8.port1",
"Coupler8_12.port0", "Qb12.port1", "Qb12.port0", "Coupler12_16.port0", "Qb16.port0",
"Coupler16_17.port0", "Qb17.port1", "Qb17.port0", "Coupler17_21.port0", "Qb21.port0",
"Qb21.port1", "Coupler20_21.port0", "Qb20.port0", "Qb20.port1", "Coupler16_20.port0",
"Qb16.port1", "Coupler15_16.port0", "Qb15.port0", "Qb15.port1", "Coupler14_15.port0",
"Coupler14_19.port0", "Qb19.port0", "Qb19.port1", "Coupler18_19.port0", "Qb18.port1",
"Qb18.port0", "Coupler13_18.port0", "Qb13.port0", "Qb13.port1", "Coupler13_14.port0",
"Qb14.port0", "Coupler10_14.port0", "Qb10.port0", "Qb10.port1", "Coupler6_10.port0", "Qb6.port0",
"Coupler5_6.port0", "Qb5.port0", "Qb5.port1", "Coupler1_5.port0",
]

[design_rules]
min_wire_spacing = 185.0
min_obstacle_spacing = 25.0
min_bend_radius = 50.0
min_straight_length = 100.0
target_resonator_length = 4000.0
resonator_length_tolerance = 100.0
max_feedline_utilization = 5
feedline_terminations = 0

[grid]
capacity_cells_x = 20
# The launcher slot sits on the launcher port, so the blocked border of the
# capacity grid must not cover it. A port inside the border is a freed cell in a
# wall that no capacity chain reaches, and the partitioning around it collapses.
launcher_offset_x = 0
launcher_offset_y = 0

[stages.assignment]
# How many launchers the assignment activates. A figure per chip with no
# default, taken from the prototype's driver of the same benchmark.
launcher_target = 10
Loading
Loading