Skip to content
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

Add drawer support for AnnotatedOperations #11202

Merged
merged 14 commits into from
Dec 24, 2023

Conversation

enavarro51
Copy link
Contributor

@enavarro51 enavarro51 commented Nov 6, 2023

Summary

Fixes #11087

Details and comments

This PR adds support for displaying the details of an AnnotatedOperation in the circuit drawers. If the ControlModifier is used, it displays as a controlled gate would. If InverseModifier or PowerModifier is used, this is appended to the name of the base_op. The power value is rounded to 1 decimal.

This also fixes a bug in the 'text' drawer that would cause it to fail if an AnnotatedOperation was in the circuit.
To do:

  • Tests
  • Reno
from qiskit import QuantumCircuit
from qiskit.quantum_info import Clifford, random_clifford 
from qiskit.circuit.annotated_operation import AnnotatedOperation, InverseModifier, ControlModifier, PowerModifier 
from qiskit.circuit.library import SGate, SXGate, ZGate

qc = QuantumCircuit(3) 
cliff = random_clifford(2) 
qc.append(cliff, [0, 1])
qc.x(0) 
qc.h(1) 
qc.append(SGate().control(2, ctrl_state=1), [0, 2, 1]) 
qc.ccx(0, 1, 2) 
op1 = AnnotatedOperation(SGate(), [InverseModifier(), ControlModifier(2, 1), PowerModifier(3.29)]) 
qc.append(op1, [0, 1, 2]) 
qc.append(SXGate(), [1]) 
qc.draw('text', style="iqp")

image

     ┌───────────┐┌───┐                                     
q_0: ┤0          ├┤ X ├──■────■────────────■────────────────
     │  Clifford │├───┤┌─┴─┐  │            │          ┌────┐
q_1: ┤1          ├┤ H ├┤ S ├──■────────────o──────────┤ √X ├
     └───────────┘└───┘└─┬─┘┌─┴─┐┌─────────┴─────────┐└────┘
q_2: ────────────────────o──┤ X ├┤ S - Inv, Pow(3.3) ├──────
                            └───┘└───────────────────┘      

@enavarro51 enavarro51 requested review from nonhermitian and a team as code owners November 6, 2023 17:49
@qiskit-bot
Copy link
Collaborator

One or more of the the following people are requested to review this:

@coveralls
Copy link

coveralls commented Nov 6, 2023

Pull Request Test Coverage Report for Build 7316922398

  • 42 of 50 (84.0%) changed or added relevant lines in 3 files are covered.
  • 4 unchanged lines in 3 files lost coverage.
  • Overall coverage increased (+0.03%) to 87.542%

Changes Missing Coverage Covered Lines Changed/Added Lines %
qiskit/visualization/circuit/matplotlib.py 5 13 38.46%
Files with Coverage Reduction New Missed Lines %
crates/qasm2/src/expr.rs 1 93.76%
qiskit/visualization/circuit/matplotlib.py 1 48.07%
crates/qasm2/src/lex.rs 2 92.93%
Totals Coverage Status
Change from base Build 7302309139: 0.03%
Covered Lines: 59203
Relevant Lines: 67628

💛 - Coveralls

Copy link
Contributor

@alexanderivrii alexanderivrii left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many thanks @enavarro51, this looks amazing! And sorry for the late response.

The only small problem is that there could be multiple control modifiers in the list, for example we may have

op1 = AnnotatedOperation(SGate(), [InverseModifier(), ControlModifier(2, 1), ControlModifier(2)])
qc.append(op1, [0, 1, 2, 3, 4])

This can be easily fixed by combining multiple control modifiers into one and displaying that (please see one of the review comments for detail).

Technically we would not be able to see the number of control modifiers or understand which of the control qubits belong to which modifier, but I think it's completely adequate for displaying purposes. To be pedantic, even when we have a single control modifier and some other modifier, say inverse modifier, we can't know from the picture whether the inverse modifier is applied first and the control modifier is applied second, or the other way around, but it does not really matter since both are semantically equivalent, and again I feel it's completely adequate for displaying purposes.

Comment on lines 1136 to 1143
# AnnotatedOperation with ControlModifier
mod_control = None
if getattr(op, "modifiers", None):
for modifier in op.modifiers:
if isinstance(modifier, ControlModifier):
mod_control = modifier
break

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would not work correctly when there are multiple ControlModifiers in the list. The simplest fix would be to use the function _canonicalize_modifiers from annotated_operation.py which would combine multiple control modifiers into one, as follows:

if getattr(op, "modifiers", None):
    canonical_modifiers = _canonicalize_modifiers(op.modifiers)
    for modifier in canonical_modifiers:
        if isinstance(modifier, ControlModifier):
            mod_control = modifier
            break

Comment on lines 1062 to 1069
# AnnotatedOperation with ControlModifier
mod_control = None
if getattr(op, "modifiers", None):
for modifier in op.modifiers:
if isinstance(modifier, ControlModifier):
mod_control = modifier
break

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see the comment in text.py.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it. I understand that displays are sometimes 'best efforts'. Changes done in 0c79f18.

@alexanderivrii alexanderivrii added this to the 1.0.0 milestone Dec 24, 2023
@alexanderivrii alexanderivrii added mod: visualization qiskit.visualization Changelog: Bugfix Include in the "Fixed" section of the changelog labels Dec 24, 2023
Copy link
Contributor

@alexanderivrii alexanderivrii left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many thanks for the quick updates!

@alexanderivrii alexanderivrii added this pull request to the merge queue Dec 24, 2023
Merged via the queue into Qiskit:main with commit 8e5ecb5 Dec 24, 2023
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Changelog: Bugfix Include in the "Fixed" section of the changelog mod: visualization qiskit.visualization
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add drawer support for Operations that are not subclasses of Instruction
4 participants