CUGate's params getter does not comply with circuit's assign_parameters
See original GitHub issueEnvironment
- Qiskit Terra version: 0a10008
- Python version: 3.8.10 64-bit
- Operating system: windows 10 64-bit
What is happening?
This issue is proposed based on the discussion under #7283, especially the insight of @jakelishman.
CUGate
is the controlled version of UGate
, a generic single-qubit rotation gate with 3 Euler angles. Most controlled gates have the same parameters as the base gate, but CUGate
has an extra one: the global phase Ξ³
. To cope with this, CUGate
uses a @property
decorator to define a getter for the property params
. This getter function creates a new array and returns it. It leads to problems that following operations may be applied to this newly created array instead of the real parameters of the CUGate
object. For example, that happens in the function QuantumCircuit.assign_parameters
, which is demonstrated in the following section.
The failure of assign_parameters
on CUGate
leads to another problem. Currently, a line is missing below line 652 in qiskit/circuit/library/standard_gates/equivalence_library.py.
q = QuantumRegister(2, "q")
theta = Parameter("theta")
phi = Parameter("phi")
lam = Parameter("lam")
cu3_to_cu = QuantumCircuit(q)
cu3_to_cu.cu(theta, phi, lam, 0, 0, 1)
# should have another line:
# _sel.add_equivalence(CU3Gate(theta, phi, lam), cu3_to_cu)
If the add_equivalence
function is added, the test test_equivalence_phase would report a TypeError
exception. QuantumCircuit.assign_parameters
is called during the test,
How can we reproduce the issue?
from qiskit.circuit import QuantumCircuit, Parameter
ps = [Parameter("t"), Parameter("p"), Parameter("l"), Parameter("g")]
qc = QuantumCircuit(2)
qc.cu(*ps, 0, 1)
qc.cu3(*ps[:3], 0, 1)
print(qc)
print(qc.assign_parameters(dict(zip(ps, [0.1, 0.2, 0.3, 0.4])), inplace=False))
The output is
q_0: βββββββ ββββββββββββββ ββββββ
βββββββ΄ββββββββββββββ΄ββββββ
q_1: β€ U(t,p,l,g) ββ€ U3(t,p,l) β
βββββββββββββββββββββββββββ
q_0: βββββββ βββββββββββββββββ βββββββββ
βββββββ΄βββββββββββββββββ΄βββββββββ
q_1: β€ U(t,p,l,g) ββ€ U3(0.1,0.2,0.3) β
βββββββββββββββββββββββββββββββββ
suggesting the assignment of CUGate is failed. Note that the parameters of the U3Gate
have been assigned.
What should happen?
The second circuit should be
q_0: βββββββββββ βββββββββββββββββββββ βββββββββ
βββββββββββ΄βββββββββββββββββββββ΄βββββββββ
q_1: β€ U(0.1,0.2,0.3,0.4) ββ€ U3(0.1,0.2,0.3) β
βββββββββββββββββββββββββββββββββββββββββ
Any suggestions?
Maybe remove the Ξ³
parameter from CUGate. The global phase is a property of quantum circuits. It is not a property of other gates. Adding this parameter to CUGate makes it different from the general cases and requires special processing, e.g., here and here.
Issue Analytics
- State:
- Created 2 years ago
- Comments:7 (7 by maintainers)
Top GitHub Comments
Yeah, itβs the same issue -
assign_parameters
/bind_parameter
tries to mutate indices in theCUGate.params
field, but the gate has a getter that produces a new list, not the actual array. Julien at one point had a PR that addedassign_parameter
toInstruction
instances so it could be overridden, but I donβt know what happened to that.Perhaps calling it βglobalβ phase is a bit misleading here (itβs the phase of the controlled gate), but yeah, the gamma parameter needs to stay for now. The main issue is [again π¦] that we donβt have a contract for what
Instruction.params
should contain, and how it should behave with respect to mutability.QuantumCircuit
assumes that itβs a βtrueβ attribute, and tries to write to it as if it is guaranteed to be a list, but thatβs probably not something it can assume.The βbugβ could either be that
CUGate
must return a list-like object that backs all its parameters (in which case we need to do what Julien said), or other places in Terra need to stop assuming that they can mutate the object. They can write wholesale, perhaps (so theyβll trigger the setter method), but they canβt mutate. This second form is more safe, but it likely has some performance implications, because weβd need to be reconstructing several lists/tuples each time.