-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Add display of internal circuits for ControlFlowOps to text drawer #10414
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
One or more of the the following people are requested to review this:
|
Pull Request Test Coverage Report for Build 5860928068
💛 - Coveralls |
…a into display_text_flow
…a into display_text_flow
@jakelishman I updated the text drawer to deal with getting the circuits from |
Update: The #10601 issue for the mpl drawer has now been fixed for the text drawer as well. An additional test was added. |
…a into display_text_flow
@jakelishman This latest update incorporates the changes to the mpl drawer in #10602. This included expanding the use of the wire_map and refactoring the conditional section. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm super super excited to have this in, thanks so much for working on it!
We spoke about this offline, but for posterity for others: I noticed this edge case produces unexpected output for me - an empty control-flow op doesn't print at all, but I'd still expect to see the brackets appear.
from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister
cr = ClassicalRegister(2)
qc = QuantumCircuit(QuantumRegister(2), cr)
with qc.if_test((cr, 0)):
pass
qc.draw()
q3_0: ─
q3_1: ─
c6: 2/═
We then realised that this is because an empty control-flow block acts on zero qubits, so the problem is part of a larger issue around visualisation of zero-qubit instructions (#9962) and there's no action needed in this PR.
# Indicators for left, middle, and right of control flow gates | ||
CF_LEFT = 0 | ||
CF_MID = 1 | ||
CF_RIGHT = 2 | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Python's got a standard-library type enum.Enum
for things like this in general, but it's probably not worth bothering changing here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noted.
qiskit/visualization/circuit/text.py
Outdated
class FlowOnQuWire(DrawElement): | ||
"""Draws a box for a ControlFlowOp using a single qubit.""" | ||
|
||
def __init__(self, label="", top_connect="─", conditional=False, section=CF_LEFT): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor style: here and in the other new classes, it feels a bit weird to have section
be optional; I don't think there's any default value that makes sense and the outer context should always known whether it's left/mid/right.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in 9b82cd7.
if section == CF_RIGHT: | ||
self.top_format = " ─%s─┐" | ||
self.mid_format = " %s ├" | ||
self.bot_format = " ─%s─┘" | ||
else: | ||
self.top_format = "┌─%s─ " | ||
self.mid_format = "┤ %s " | ||
self.bot_format = "└─%s─ " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: how do you think it'd look if we had "mid" boxes display neither left nor right edge, so they appear more like a full continuation? At the moment it looks a shade unbalanced to me that we get more opening "brackets" than closing ones for if/else and switch constructs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After several tries, decided this is fraught with lots of formatting issues, so left it with left edges.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fine by me - it's all a bit of bike-shedding anyway.
qiskit/visualization/circuit/text.py
Outdated
# In case there is an exception, this prevents it from printing twice. | ||
self._single_string = " " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tbh I'd probably skip this; these exceptions aren't actionable by a user, and an exception here would always indicate either an invalid circuit or a problem in our code, and we don't need to be too worried about optimising the return speed in those cases. I'm worried that setting to the empty string implies there's some meaning to it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in 9b82cd7.
"""Test the wire_order option""" | ||
expected = "\n".join( | ||
[ | ||
" ", | ||
"q_2: |0>────────────", | ||
" ┌───┐ ", | ||
"q_1: |0>┤ X ├───────", | ||
" ├───┤ ┌───┐ ", | ||
"q_3: |0>┤ H ├─┤ X ├─", | ||
" ├───┤ └─╥─┘ ", | ||
"q_0: |0>┤ H ├───╫───", | ||
" └───┘┌──╨──┐", | ||
" c: 0 4/═════╡ 0xa ╞", | ||
" └─────┘", | ||
"ca: 0 2/════════════", | ||
" ", | ||
" ", | ||
"q_2: |0>──────────", | ||
" ┌───┐ ", | ||
"q_1: |0>┤ X ├─────", | ||
" ├───┤┌───┐", | ||
"q_3: |0>┤ H ├┤ X ├", | ||
" ├───┤└─╥─┘", | ||
"q_0: |0>┤ H ├──╫──", | ||
" └───┘ ║ ", | ||
" c_2: 0 ═══════o══", | ||
" ║ ", | ||
"ca_0: 0 ═══════╬══", | ||
" ║ ", | ||
"ca_1: 0 ═══════╬══", | ||
" ║ ", | ||
" c_1: 0 ═══════■══", | ||
" ║ ", | ||
" c_0: 0 ═══════o══", | ||
" ║ ", | ||
" c_3: 0 ═══════■══", | ||
" 0xa ", | ||
] | ||
) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test of wire_order
looks unrelated; how come it needs changing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right. I think I had an early problem with wire_order and cregbundle off, but that went away. I'll change it back.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, I think there is a fundamental problem with wire_order changes to clbits and cregbundle on. How do you display the order if you have 3 qubits, and two 2-clbit registers with a wire order of [0, 2, 1, 6, 3, 4, 5]? I noticed that the tests for wire_order that are done in test_circuit_visualization only reorder the qubits. The reason this is an issue now is that with the control flow changes, the wire_map is used much more to access bit position than for example, self.qubits or self.clbits.
My suggestion would be to force cregbundle off if clbits are reordered.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually (actually) I just realized this is that crazy problem with the fact that the text drawer tests unlike the other drawers bypass the call to circuit_drawer which is where all the checks to force cregbundle false are done.
The reality is that this is a bad test, since cregbundle would normally be forced off by circuit_drawer before the call to the text drawer. So I say, either ditch the test or do what I did here, which is explicitly make cregbundle false.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So left this with cregbundle false which is the only way it should be tested. To avoid problems in the future, I think it's worthwhile to switch to using circuit_drawer for text_drawer testing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, 100% agree. Let's make that change in a separate PR with no feature changes, though, since it's a large-scale change to the testing structure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great - I'm super keen to get this merged and in so we can start using it, if you're also happy with it.
def controlled_wires(node, layer): | ||
def controlled_wires(node, wire_map): | ||
""" | ||
Analyzes the node in the layer and checks if the controlled arguments are in | ||
the box or out of the box. | ||
|
||
Args: | ||
node (DAGNode): node to analyse | ||
layer (Layer): The layer in which the node is inserted. | ||
wire_map (dict): map of qubits/clbits to position |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, you managed to get this working? I'm pleased to see this - it looks generally more robust with the new idea of scopes.
…iskit#10414) * Update text.py * Update utils.py * Fix test using text * Lint * Lint * Fix if with body bug and first tests * Finish tests * Reno * Output=text * Cleanup * Fix repr and repr_html issue with jupyter * Cache _single_string to fix __repr__ and _repr_html__ issue * Get circuits from blocks and fix inner_wire_map * Fix gate on qubit issue and add test * Lint * First work on transpiled nested * Fix condition for flow ops * Intermediate flow_wire_map testing * Fix clbit bug * Finish transpiled bits bug * Final fix for conditions and transpiles * Fix review issues 1 * Revert wire_order test * Fix control gates with wire_map and test changes * Further case and else * Fix review items 2
Summary
Displays the circuits inside ControlFlowOps instead of just displaying a box.
Details and comments
This PR adds displays of internal circuits for ControlFlowOps to the circuit text drawer. This is similar to the capability in the mpl drawer in #10207. The main differences are,
If-1
,End-1
would appear insideIf-0
,End-0
.Otherwise all the previous functionality of the text drawer is intact. This PR incorporates the changes to
utils.py
that were made in #10207.