-
Notifications
You must be signed in to change notification settings - Fork 60
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
Circuit viewer #308
Circuit viewer #308
Conversation
Codecov Report
@@ Coverage Diff @@
## master #308 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 59 59
Lines 11209 11290 +81
=========================================
+ Hits 11209 11290 +81
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
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.
Thanks for implementing this, I believe it is simple and provides a good visualization. Some comments regarding appearance:
- Multi-control gates (eg.
gates.X(0).controlled_by(1, 2, 3, 4)
) do not appear properly. Specifically only the first control qubit is considered while the rest are ignored. - We could consider using capital letters for the gate representation (eg.
X
,Y
,Z
,H
,I
,U1
, etc.), simlar to Cirq. - The controlled gate dot/bullet symbol appears a bit weird in my case:
so we may want to check compatibility with different terminal versions. - Although it may complicate the code slightly, I believe it will be better intuitively if we remove the
c
from the controlled gate names for the visualization. Since we explicitly show the control qubits using the dot symbols, we don't need thec
in the target qubit symbol. - Currently the
|
symbol that connects the dot with the gate for controlled gates is not used when the control and target qubits are neighbors (for example see secondcx
in my figure). Again this would complicate the code, but it could look better if we used empty lines between qubits and use the|
symbol for neighboring qubits too. In this case thematrix
would have2 * nqubits - 1
rows where every other row is empty or has|
symbols.
src/qibo/abstractions/gates.py
Outdated
@@ -12,7 +12,7 @@ | |||
"cx": "CNOT", "swap": "SWAP", "cz": "CZ", | |||
"crx": "CRX", "cry": "CRY", "crz": "CRZ", | |||
"cu1": "CU1", "cu3": "CU3", | |||
"ccx": "TOFFOLI"} | |||
"ccx": "TOFFOLI", "id": "identity"} |
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.
If I remember correctly QASM_GATES
is a map from the Qasm name of the gate to the corresponding Qibo class name, so this should be "id": "I"
. However I think that "id"
is not a valid Qasm gate anyway so this entry probably should not be 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.
I did a quick check and id seems to work, at least using the ibm q editor.
@@ -169,7 +169,7 @@ class I(Gate): | |||
|
|||
def __init__(self, *q): | |||
super(I, self).__init__() | |||
self.name = "identity" | |||
self.name = "id" |
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.
We could also use the name I
to be compatible with X
, Y
, Z
and H
.
src/qibo/abstractions/circuit.py
Outdated
else: | ||
t1 = targets[0] | ||
matrix[t1][idx[t1]] = f"{gate.name}" | ||
idx[t1] += 1 |
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.
A small technical remark: The matrix
that is created here is almost the "transpose" of self.queue.moments
that already exists in the circuit, so there is a chance to simplify this with something like:
matrix = [[moment[i].name if moment[i] is not None else ""
for moment in self.queue.moments]
for i in range(self.nqubits)]
The issue is that for controlled gates this will put the gate.name
for both the control and the target qubit so we would still need a mechanism to replace the control qubit name with the dot. Perhaps this could be handled in a gate method to simplify things here.
src/qibo/abstractions/circuit.py
Outdated
if iq in (qi, qf): | ||
if gate.name in ('id', 'collapse'): | ||
matrix[iq][column] = f"{gate.name}" | ||
elif gate.name in ('swap', 'fsim', 'generalizedfsim'): |
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 will use the X--X
symbol for the fSim gate which is not correct as the fSim is not a SWAP. Perhaps we should include fSim and GenarlizedfSim to the previous if
case where matrix[iq][column] = f'{gate.name}'
.
Thanks for the comments, I agree with all of them, except for the "|" for neighbours, I think the plot is cleaner/more compact if we avoid an extra empty line with these connections, what do you think? |
Personally I am fine with either approach, I just proposed the other one because it is what Cirq uses. They also use |
Looks good to me. Having I am not sure if using @ instead of dots might make it more universal, but we can look into that if that would fix the issue on Stavros' device. I also agree with Stavros that only Does it work with all gates from Qibo or it only supports QASM gates? Overall I think this is useful. |
@stavros11 @igres26 I have implemented the features we have discussed last week, could you please have a look/test the code? @stavros11 for simplicity, I decided to avoid the moments construction, I believe the current version is much more readable and easy to follow, let me know. |
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.
Thanks for the updates, it looks good to me. No problem about not using the moments, I agree that the code is easy to follow as it is. The only two points I noticed are the following:
- Perhaps we could expand the testing of this a bit, for example the case where
line_wrap
is notNone
is not tested. That being said, I played with various gate cases and combinations as well as theline_wrap
and everything seems to work as expected. - When using the
line_wrap
, every chunk gets appended with...
in the beginning and the end. This also happens for the last chunk, however I believe we do not need...
at the end for the last chunk.
Some additional comments which are probably less important:
- Although as I said it is easy to follow, it may be easier to test (if we extend tests) if we split this to a few auxiliary functions, instead of a big function as it is now. This point may require additional work and won't change anything in practice so I don't believe it is mandatory for now.
- Depending on the
line_wrap
one selects, some gates that involve more than one character (eg.NOT
) may get split in different chunks (eg.N
andOT
) which looks weird. Personally, I don't think we should do anything about this, just leave it up to the user to play and select a goodline_wrap
for each case. Most gates are single character anyway so this is not a big issue.
idx = [0] * self.nqubits | ||
|
||
for gate in self.queue: | ||
gate_name = labels.get(gate.name) |
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.
There are some gates such as the CallbackGate
, Flatten
and the channels which are not included in labels
. In this case using labels.get
here will return a None
which will raise some errors later which may be hard for the user to understand. I would suggest to include a check like:
if gate.name not in labels:
raise_error(NotImplementedError, f"{gate.name} gate is not supported by `circuit.draw`")
src/qibo/abstractions/circuit.py
Outdated
labels = {"h": "H", "x": "X", "y": "Y", "z": "Z", | ||
"rx": "RX", "ry": "RY", "rz": "RZ", | ||
"u1": "U1", "u2": "U2", "u3": "U3", | ||
"cx": "NOT", "swap": "x", "cz": "Z", |
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.
"cx": "NOT", "swap": "x", "cz": "Z", | |
"cx": "X", "swap": "x", "cz": "Z", |
I believe X
is more commonly used than NOT
when plotting quantum circuits, even for the CNOT
gate (despite calling it CNOT
). If we use X
we are also more consistent with how we plot TOFFOLI
and multi-control X
.
src/qibo/abstractions/circuit.py
Outdated
|
||
# extend matrix | ||
for iq in range(self.nqubits): | ||
matrix[iq] += [ '' for _ in range(1 + col - len(matrix[iq]))] |
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 believe the following is slightly more efficient because it doesn't recreate the list:
matrix[iq] += [ '' for _ in range(1 + col - len(matrix[iq]))] | |
matrix[iq].extend((1 + col - len(matrix[iq]))* ['']) |
@stavros11, thanks for the comments, please let me know if you agree with the current changes. Concerning the line_wrap, I also think that the user can check what is better for his circuit setup, now, concerning the split in multiple function, I think we can avoid that with the current tests, but let me know your opinion. |
Thanks for the update. The tests are okay and I don't think splitting the function is really needed, I just observed that there is still a problem with circuit = QFT(5)
print(circuit.draw(line_wrap=30)) gives
which is okay, but with
which is wrong because the second chunk does not have |
@stavros11 many thanks, this should be fixed now! |
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.
@stavros11 many thanks, this should be fixed now!
Yes, everything seems to work as expected now.
Provides a text based circuit viewer, closes #145.
Example:
@stavros11 @igres26 before polishing the code could you please let me know your opinion?