[Circuit renderer] Compact rendering of classically controlled gate - #3637
[Circuit renderer] Compact rendering of classically controlled gate#3637Dima Fedoriaka (fedimser) wants to merge 11 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Adds first-class support for “compact” classically controlled gates across the Rust circuit model, rendering pipeline, and circuit-to-Q# conversion, so simple if (result == One/Zero) branches can be visualized as gates annotated with classical controls (rather than expanded conditional groups).
Changes:
- Extend the circuit JSON/schema and Rust circuit model with
classicalControlsfor unitary operations. - Update circuit tracing/lowering and renderer logic to emit and draw compact classically controlled gates (including inverted/“anti” controls).
- Add/adjust Rust, JS/TS, Python, and snapshot tests to cover compact classical control behavior and updated output sizes.
Reviewed changes
Copilot reviewed 26 out of 27 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| source/samples_test/src/tests/OpenQASM.rs | Update expected circuit-length snapshot for teleportation due to compact rendering. |
| source/samples_test/src/tests/getting_started.rs | Update expected circuit-length snapshot due to compact rendering. |
| source/samples_test/src/tests/algorithms.rs | Update multiple expected circuit-length snapshots due to compact rendering. |
| source/qdk_package/tests/test_qsharp.py | Update expected ASCII circuit strings for compact classical control rendering. |
| source/qdk_package/tests/test_qasm.py | Update expected ASCII circuit strings for compact classical control rendering. |
| source/npm/qsharp/ux/qsharp-circuit.css | Add styling for inverted (anti-) classical control dots. |
| source/npm/qsharp/ux/circuit-vis/utils.ts | Include classicalControls registers in register collection for sizing/renumbering. |
| source/npm/qsharp/ux/circuit-vis/renderer/process.ts | Map classicalControls into render data and ensure they’re included in classical-control register tracking. |
| source/npm/qsharp/ux/circuit-vis/renderer/gateRenderData.ts | Add render-data shape for compact classical controls on a gate. |
| source/npm/qsharp/ux/circuit-vis/renderer/formatters/gateFormatter.ts | Render compact classical control connectors/dots alongside gates. |
| source/npm/qsharp/ux/circuit-vis/actions/circuit-actions/classicalRefs.ts | Treat classicalControls as classical consumers for cascade/move/delete logic. |
| source/npm/qsharp/test/circuits-cases/if-else.qs.snapshot.html | Update SVG snapshot to reflect compact classical control rendering. |
| source/npm/qsharp/test/circuit-editor/utils.test.mjs | Add coverage ensuring compact classical controls affect wire extent calculations. |
| source/npm/qsharp/test/circuit-editor/process.test.mjs | Add coverage ensuring processOperations maps compact classical controls into render data. |
| source/npm/qsharp/test/circuit-editor/gateFormatter.test.mjs | Add coverage ensuring compact classical controls render connectors and (anti-)dots. |
| source/npm/qsharp/test/circuit-editor/circuit-actions/measurementCascade.test.mjs | Extend cascade tests to include compact classical control consumers. |
| source/npm/qsharp/src/data-structures/circuit.ts | Add ClassicalControl type + runtime validation and wire into Unitary. |
| source/compiler/qsc/src/interpret/circuit_classical_ctl_tests.rs | Update expected interpreter circuit output to reflect compact classical controls. |
| source/compiler/qsc_circuit/src/rir_to_circuit/tests/logical_stack_trace.rs | Update/add logical trace expectations for compact classical control behavior (+ negative cases). |
| source/compiler/qsc_circuit/src/rir_to_circuit.rs | Emit compact classical controls for simple if branches when safe (single-qubit, uncontrolled gates). |
| source/compiler/qsc_circuit/src/circuit/tests.rs | Add circuit layout/string rendering test for direct classical control wire range. |
| source/compiler/qsc_circuit/src/circuit.rs | Add classical_controls to the Rust circuit model + include in display/layout and serialization. |
| source/compiler/qsc_circuit/src/circuit_to_qsharp/tests.rs | Add test coverage for circuit-to-Q# conversion of compact classical controls. |
| source/compiler/qsc_circuit/src/circuit_to_qsharp.rs | Generate Q# if wrappers for unitaries with compact classical controls; disable Ctl+Adj when present. |
| source/compiler/qsc_circuit/src/builder/tests.rs | Add test ensuring classical control result-ids are converted to classical registers. |
| source/compiler/qsc_circuit/src/builder.rs | Thread classical control inputs through gate building into circuit operations. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| let classical_controls = match &op { | ||
| Operation::Unitary(u) => &u.classical_controls, | ||
| Operation::Measurement(_) | Operation::Ket(_) => &vec![], | ||
| }; |
| /** Control registers the gate acts on. */ | ||
| controls?: Register[]; | ||
| /** Classical controls that determine whether the gate is applied. */ | ||
| classicalControls?: ClassicalControl[]; |
There was a problem hiding this comment.
I wonder if we could have a more general approach and have all controls fall under the controls field. The type of that field would be modified to be (Register | ControlValue)[] with ControlValue being the rename for ClassicalControl. That would leave open the ability to specify inverted quantum controls also.
There was a problem hiding this comment.
Or better yet, for the type, it would be a Control[] with
export interface Control extends Register {
inverted?: boolean;
}
| /** The qubit registers the gate measures. */ | ||
| qubits: Register[]; | ||
| /** The classical registers the gate writes to. */ | ||
| results: Register[]; |
There was a problem hiding this comment.
Since this is a change to the data contract for circuits, we should consider bumping the circuit version number and making sure we have a plan to auto-update old circuit files for backwards compatibility.
1b2a6b5 to
2dbbabd
Compare
Example 1 - teleportation
Before:

After:

Example 2
Example 3 - negative cases (controlled gate, complex condition, 2-qubit gate).