-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
Remove method qasm
from Instruction
and all of its subclasses
#10399
Conversation
Pull Request Test Coverage Report for Build 5595206875
💛 - Coveralls |
qasm
from Instruction
and all of its subclasses
* Deprecate all `qasm` methods for Instruction and subclasses. * Move code for generating OpenQASM 2 strings to `QuantumCircuit`. * Test that deprecation warnings are raised. * Add release note.
0b961b3
to
26a3ec6
Compare
qasm
from Instruction
and all of its subclassesqasm
from Instruction
and all of its subclasses
One or more of the the following people are requested to review this:
|
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'll be glad to see the backs of these methods - one more place ticked off the list of instructions examining their params
state. Thanks for looking at it.
qiskit/circuit/quantumcircuit.py
Outdated
operation = _qasm2_define_custom_operation( | ||
operation, existing_gate_names, gates_to_define | ||
) | ||
|
||
# Insert qasm representation of the original instruction | ||
if operation.name == "c3sx": | ||
operation.name = "c3sqrtx" | ||
name_param = _instruction_qasm2(operation) | ||
if operation.name == "c3sqrtx": | ||
operation.name = "c3sx" | ||
bits_qasm = ",".join( | ||
bit_labels[j] for j in itertools.chain(instruction.qubits, instruction.clbits) | ||
) | ||
instruction_qasm = f"{operation.qasm()} {bits_qasm};" | ||
instruction_qasm = f"{name_param} {bits_qasm};" |
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.
The ordering of these calls doesn't look right - _qasm2_define_custom_operation
is what actually defines the operation and it's true recursive. The special handling should be in there if anything - it already has logic to transform one operation into another for use as the definition and call point.
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.
See #10399 (review) .
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.
The ordering problem I meant in this comment was that there was logic to handle the rename of c3sx
that only occurred at the top level QuantumCircuit.qasm
, and it didn't appear in _qasm2_define_custom_operation
, which meant that there was a discrepancy.
I think mostly I'm realising that the current system is pretty broken, and it's just that your refactor makes that fact a lot more obvious because the code's much clearer to follow. For example, this code results in a duplicate definition of c3sqrtx
:
from qiskit import QuantumCircuit
from qiskit.circuit.library import C3SXGate
gate = QuantumCircuit(4, name="c3sqrtx").to_gate()
outer = QuantumCircuit(4)
outer.append(gate, [0, 1, 2, 3], [])
print(outer.qasm())
OPENQASM 2.0;
include "qelib1.inc";
gate c3sqrtx q0,q1,q2,q3 { }
qreg q[4];
c3sqrtx q[0],q[1],q[2],q[3];
since c3sqrtx
is defined in Terra's custom qelib1.inc
.
That's a pre-existing problem, though, so let's leave it during this refactor, and fix it separately.
In x.py in class C3SXGate the method `qasm` has been deprecated. It's ok and simpler to deprecated code in this method. The two deprecated pieces will be removed together.
`for (param, value) in ...` was replaced with `for param, value in ...`. This commit reverts that change.
…on message * The method has_qasm2 was added in a previous commit (not in main). It is removed with this commit. * An additional message was added to the deprecation warning for HamiltonianGate.qasm. It is removed with this commit * A test has been updated to reflect these changes.
c3sqrtx is the name we need to use with OpenQASM2 for qiskit's c3sx. This makes the hack a bit less wordy and perhaps more palatble. The gate's name is no longer changed before calling a function on it, then changed back.
PR 10399 (not merged) changed a method call inside a Python f-string statement into a call outside, introducing a variable, and use of that variable inside the f-string. This commit makes a more minimal change. Now we only replace the method call with an ordinary function call.
qiskit/circuit/quantumcircuit.py
Outdated
@@ -5085,7 +5088,7 @@ def _qasm2_define_custom_operation(operation, existing_gate_names, gates_to_defi | |||
instruction.operation, existing_gate_names, gates_to_define | |||
) | |||
bits_qasm = ",".join(qubit_labels[q] for q in instruction.qubits) | |||
statements.append(f"{new_operation.qasm()} {bits_qasm};") | |||
statements.append(f"{_instruction_qasm2(new_operation)} {bits_qasm};") | |||
body_qasm = " ".join(statements) |
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.
Regarding "The ordering of these calls doesn't look right...". I made a couple of commits to simplify the code that show that all I've done is exchange a method call for a plain function call. However, I think this makes it clear that the call to _instruction_qasm2
could be moved inside _qasm2_define_custom_operation
. This would the code a bit less complex and add a bit more encapsulation. I think this may be what you are suggesting.
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.
Yeah, your new commits make the structure much clearer. More importantly (with regard to the "ordering" comment), they also ensure that the c3sx -> c3sqrtx
also happens when the gate appears during nested gates that need definitions as well, whereas in the version I'd commented on, it didn't.
Given:
from qiskit import QuantumCircuit
from qiskit.circuit.library import C3SXGate
gate = QuantumCircuit(4, name="my_gate")
gate.append(C3SXGate(), [0, 1, 2, 3], [])
outer = QuantumCircuit(4)
outer.append(gate.to_gate(), [0, 1, 2, 3], [])
print(outer.qasm())
the output from where I commented (a2e2041) is:
OPENQASM 2.0;
include "qelib1.inc";
gate my_gate q0,q1,q2,q3 { c3sx q0,q1,q2,q3; }
qreg q[4];
my_gate q[0],q[1],q[2],q[3];
and from 6875e17, which is the current PR head, it's the correct:
OPENQASM 2.0;
include "qelib1.inc";
gate my_gate q0,q1,q2,q3 { c3sqrtx q0,q1,q2,q3; }
qreg q[4];
my_gate q[0],q[1],q[2],q[3];
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.
Moving the hack down to a lower level feels worse in a sense. But, it is simpler and temporarily mutating something that should not change is distasteful. I didn't realize that it is more correct in the sense of your example. It's useful to make this clear
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 changes, John. I think once this is brought up to date with the current state of main
, this will be ready to go, give or take a variable renaming which isn't even very important.
qiskit/circuit/quantumcircuit.py
Outdated
operation = _qasm2_define_custom_operation( | ||
operation, existing_gate_names, gates_to_define | ||
) | ||
|
||
# Insert qasm representation of the original instruction | ||
if operation.name == "c3sx": | ||
operation.name = "c3sqrtx" | ||
name_param = _instruction_qasm2(operation) | ||
if operation.name == "c3sqrtx": | ||
operation.name = "c3sx" | ||
bits_qasm = ",".join( | ||
bit_labels[j] for j in itertools.chain(instruction.qubits, instruction.clbits) | ||
) | ||
instruction_qasm = f"{operation.qasm()} {bits_qasm};" | ||
instruction_qasm = f"{name_param} {bits_qasm};" |
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.
The ordering problem I meant in this comment was that there was logic to handle the rename of c3sx
that only occurred at the top level QuantumCircuit.qasm
, and it didn't appear in _qasm2_define_custom_operation
, which meant that there was a discrepancy.
I think mostly I'm realising that the current system is pretty broken, and it's just that your refactor makes that fact a lot more obvious because the code's much clearer to follow. For example, this code results in a duplicate definition of c3sqrtx
:
from qiskit import QuantumCircuit
from qiskit.circuit.library import C3SXGate
gate = QuantumCircuit(4, name="c3sqrtx").to_gate()
outer = QuantumCircuit(4)
outer.append(gate, [0, 1, 2, 3], [])
print(outer.qasm())
OPENQASM 2.0;
include "qelib1.inc";
gate c3sqrtx q0,q1,q2,q3 { }
qreg q[4];
c3sqrtx q[0],q[1],q[2],q[3];
since c3sqrtx
is defined in Terra's custom qelib1.inc
.
That's a pre-existing problem, though, so let's leave it during this refactor, and fix it separately.
qiskit/circuit/quantumcircuit.py
Outdated
@@ -5085,7 +5088,7 @@ def _qasm2_define_custom_operation(operation, existing_gate_names, gates_to_defi | |||
instruction.operation, existing_gate_names, gates_to_define | |||
) | |||
bits_qasm = ",".join(qubit_labels[q] for q in instruction.qubits) | |||
statements.append(f"{new_operation.qasm()} {bits_qasm};") | |||
statements.append(f"{_instruction_qasm2(new_operation)} {bits_qasm};") | |||
body_qasm = " ".join(statements) |
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.
Yeah, your new commits make the structure much clearer. More importantly (with regard to the "ordering" comment), they also ensure that the c3sx -> c3sqrtx
also happens when the gate appears during nested gates that need definitions as well, whereas in the version I'd commented on, it didn't.
Given:
from qiskit import QuantumCircuit
from qiskit.circuit.library import C3SXGate
gate = QuantumCircuit(4, name="my_gate")
gate.append(C3SXGate(), [0, 1, 2, 3], [])
outer = QuantumCircuit(4)
outer.append(gate.to_gate(), [0, 1, 2, 3], [])
print(outer.qasm())
the output from where I commented (a2e2041) is:
OPENQASM 2.0;
include "qelib1.inc";
gate my_gate q0,q1,q2,q3 { c3sx q0,q1,q2,q3; }
qreg q[4];
my_gate q[0],q[1],q[2],q[3];
and from 6875e17, which is the current PR head, it's the correct:
OPENQASM 2.0;
include "qelib1.inc";
gate my_gate q0,q1,q2,q3 { c3sqrtx q0,q1,q2,q3; }
qreg q[4];
my_gate q[0],q[1],q[2],q[3];
I think it's worth making the small changes you mentioned @jakelishman. I refactored a bit more in 275f9b3
|
The docstring states that a CircuitError is raised if a gate cannot be converted to qasm2. But this is now handled ultimately by the qasm2 exporter.
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.
One rogue import aside, this looks good to merge. Thanks for sticking with it and getting the whole thing written on short notice!
This PR deprecates all methods named
qasm
forInstruction
and subclasses. Instead the OpenQASM 2 strings are produced inQuantumCircuit.qasm
.This does little more than remove the methodInstruction.qasm
and fix up all the places that call it to preserve existing behavior.Note that this method has been removed, rather than deprecated. In fact this new code relies onhasattr
not finding this method. When deprecating, this would have to be fixed up.EDIT: The items below have been added to this PR
Looking at
Instruction.qasm
and friends underQuantumCircuit.qasm
#10361and related discussion, it seems that what we really want is to push this PR further by removing all methods called
qasm
from subclasses ofInstruction
.