This is an expansion of item no. 6 in #15849, containing a proposal about how to visualize control flow instructions and a general discussion about the major changes required to support them in the Rust circuit drawer.
First, regarding visualization, I think it would be nice if we had a way to render control flow items in a slicker way than the multi-wire empty boxes used in the Python text drawer today. Taking inspiration from the MPL drawer, I experimented a bit with manual Unicode drawing and achieved something which IMO looks much better than the textually-rendered output today:
This is the corresponding character rendering, for reference:
╭┄If┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┬┄Else┄╮╭┄Switch┄┬┄Case(0)┄┬┄Case(1,2)┄┬┄Default┄╮
┆┌───┐ ┆ ┆┆ ┆ ┌───┐ ┆ ┌───┐ ┆ ┆
q0_0: ─────────────────────────┼┤ H ├───────────────┼──────┼┼────────┼──┤ X ├──┼───┤ H ├───┼─────────┼─
╭┄Box┄┄┄┄┄┄╮ ┆└───┘ ╭┄While┄╮┆ ┆┆ ┆ └───┘ ┆ └───┘ ┆ ┆
┆┌───┐ ┆ ┆ ┆ ┌───┐ ┆┆┌───┐ ┆┆ │ ┆ ┆ ┌───┐ ┆
q0_1: ┼┤ H ├──■──┼─────────────┼──■────────┼─┤ X ├─┼┼┤ S ├─┼┼────────┼─────────┼───────────┼──┤ Z ├──┼─
┆└───┘ │ ┆╭┄If┄┄┄┄┄┄┄┄╮┆ │ ┆ └─┬─┘ ┆┆└───┘ ┆┆ ┆ ┆ ┆ └───┘ ┆
┆ ┌─┴─┐┆┆┌─────────┐┆┆ │ ┆ │ ┆┆┌───┐ ┆╰┄╥┄┄┄┄┄┄┴┄┄┄┄┄┄┄┄┄┴┄┄┄┄┄┄┄┄┄┄┄┴┄┄┄┄┄┄┄┄┄╯
q0_2: ┼─────┤ X ├┼┼┤ Rz(0.3) ├┼┼──■────────┼───■───┼┼┤ T ├─┼──╫────────────────────────────────────────
┆ └───┘┆┆└─────────┘┆┆ │ ╰┄╥┄┄┄┄┄╯┆└───┘ ┆ ║
┆┌───┐ ┆╰┄╥┄┄┄┄┄┄┄┄┄╯┆┌─┴─┐ ║ ┆ ┆ ║
q0_3: ┼┤ Z ├─────┼──╫──────────┼┤ X ├────────╫──────┼──────┼──╫────────────────────────────────────────
┆└───┘ ┆ ║ ┆└───┘ ║ ┆ ┆ ║
╰┄┄┄┄┄┄┄┄┄┄╯ ║ ╰┄╥┄┄┄┄┄┄┄┄┄┄┄╫┄┄┄┄┄┄┴┄┄┄┄┄┄╯ ║
┌─╨────────┐ ┌─╨────────┐┌─╨────────┐ ┌─╨───┐
c0: 2/════════════╡ c0_0=0x1 ╞═╡ c0_0=0x0 ╞╡ c0_1=0x1 ╞═════╡ 0x3 ╞════════════════════════════════════
└──────────┘ └──────────┘└──────────┘ └─────┘
And this is the Python output, for comparison:
┌────── ┌───┐ ┌──────── »
q0_0: ────────────────────────────────────────────────────────────────┤ ──┤ H ├───────────────────────────┤ ─────»
│ └───┘ │ »
┌─────── ┌───┐ ───────┐ │ ┌───────── ┌───┐ ───────┐ │ ┌───┐»
q0_1: ┤ ┤ H ├──■── ├────────────────────────────────────┤ ────■──┤ ─┤ X ├ ├─┤ ┤ S ├»
│ └───┘ │ │ │ │ │ └─┬─┘ │ │ └───┘»
│ ┌─┴─┐ │ ┌────── ┌─────────┐ ───────┐ │ If-0 │ │ While-1 │ End-1 │ │ Else-0 ┌───┐»
q0_2: ┤ Box-0 ─────┤ X ├ End-0 ├───┤ If-0 ──┤ Rz(0.3) ├ End-0 ├───┤ ────■──┤ ───■── ├─┤ ┤ T ├»
│ └───┘ │ └──╥─── └─────────┘ ───────┘ │ │ └────╥──── ───────┘ │ └───┘»
│ ┌───┐ │ ║ │ ┌─┴─┐ ║ │ »
q0_3: ┤ ┤ Z ├───── ├──────╫─────────────────────────────┤ ──┤ X ├─────╫─────────────────────┤ ─────»
└─────── └───┘ ───────┘ ║ └──╥─── └───┘ ║ └──────── »
┌────╨─────┐ ┌────╨─────┐ ┌────╨─────┐ »
c0: 2/═════════════════════════════╡ c0_0=0x1 ╞═════════════════════╡ c0_0=0x0 ╞═════╡ c0_1=0x1 ╞══════════════════════════════»
└──────────┘ └──────────┘ └──────────┘ »
« ───────┐ ┌────────── ┌──────────── ┌───┐┌─────────────── ┌───┐┌──────────────── ───────┐
«q0_0: ├─┤ ┤ ┤ X ├┤ ┤ H ├┤ ───── ├─
« │ │ │ └───┘│ └───┘│ │
« │ │ Switch-0 │ Case-0 (0) │ Case-0 (1, 2) │ Case-0 default ┌───┐ End-0 │
«q0_1: ├─┤ ┤ ─────┤ ─────┤ ┤ Z ├ ├─
« │ └────╥───── └──────────── └─────────────── └──────────────── └───┘ ───────┘
« End-0 │ ║
«q0_2: ├──────╫────────────────────────────────────────────────────────────────────────────────
« │ ║
« │ ║
«q0_3: ├──────╫────────────────────────────────────────────────────────────────────────────────
« ───────┘ ║
« ┌──╨──┐
«c0: 2/════════════╡ 0x3 ╞═════════════════════════════════════════════════════════════════════════════
« └─────┘
P
Implementation-wise, here are some initial thoughts about the required changes:
- Visualization matrix: this is a 2D representation of the circuit, kind of an internal IR between
CircuitData and TextDrawer. To continue the design philosophy whereby every visible element has an entry in the visualization matrix, we'll need to introduce a new element for representing control flow frames. For this we should add a new variant to the VisualizationElement enum, called Frame. The new variant should probably hold a reference to the ControlFlowInstruction object of the corresponding PackedInstruction.
- Layers:
build_layers should become aware of the nesting in control flow instructions. Furthermore, I think it could be helpful if build_layers will produce a flattened output, so that all PackedInstruction references, including those inside inner control flow blocks, are already assigned to layers.
- Conditions: The
Boxed variant in VisualizationElement is meant to represent visualization elements on qubit wires only. We should probably not change that but add a new variable, say called Condition, to represent the control flow condition boxes drawn on classical bits.
This is an expansion of item no. 6 in #15849, containing a proposal about how to visualize control flow instructions and a general discussion about the major changes required to support them in the Rust circuit drawer.
First, regarding visualization, I think it would be nice if we had a way to render control flow items in a slicker way than the multi-wire empty boxes used in the Python text drawer today. Taking inspiration from the MPL drawer, I experimented a bit with manual Unicode drawing and achieved something which IMO looks much better than the textually-rendered output today:
This is the corresponding character rendering, for reference:
And this is the Python output, for comparison:
Implementation-wise, here are some initial thoughts about the required changes:
CircuitDataandTextDrawer. To continue the design philosophy whereby every visible element has an entry in the visualization matrix, we'll need to introduce a new element for representing control flow frames. For this we should add a new variant to theVisualizationElementenum, calledFrame. The new variant should probably hold a reference to theControlFlowInstructionobject of the correspondingPackedInstruction.build_layersshould become aware of the nesting in control flow instructions. Furthermore, I think it could be helpful ifbuild_layerswill produce a flattened output, so that allPackedInstructionreferences, including those inside inner control flow blocks, are already assigned to layers.Boxedvariant inVisualizationElementis meant to represent visualization elements on qubit wires only. We should probably not change that but add a new variable, say calledCondition, to represent the control flow condition boxes drawn on classical bits.