Qiskit / qiskit

Qiskit is an open-source SDK for working with quantum computers at the level of extended quantum circuits, operators, and primitives.
https://www.ibm.com/quantum/qiskit
Apache License 2.0
5.04k stars 2.32k forks source link

`quantum_info.Operator` constructor raises an unexpected unbound parameter error #10002

Closed SimoneGasperini closed 11 months ago

SimoneGasperini commented 1 year ago

Environment

What is happening?

The quantum_info.Operator constructor fails because of an unbound parameter while all the free parameters of the circuit seem to be properly bound.

How can we reproduce the issue?

from qiskit import QuantumCircuit
from qiskit.circuit import ParameterVector
from qiskit.circuit.library import RGate

pqc = QuantumCircuit(2)
xs = ParameterVector(name='x', length=2)
gate = RGate(*xs).control(num_ctrl_qubits=1)
pqc.append(gate, [0, 1])

pqc.draw('mpl')

Capture

from qiskit.quantum_info import Operator

qc = pqc.assign_parameters([2.34, 0.98])
op = Operator(qc)

TypeError: ParameterExpression with unbound parameters ({ParameterVectorElement(x[0])}) cannot be cast to a float.

What should happen?

The code above should work correctly. For other very similar parameterized quantum circuit (see the pqc instance defined below), it runs as expected without any problem.

pqc = QuantumCircuit(3)
xs = ParameterVector(name='x', length=2)
gate = RGate(*xs).control(num_ctrl_qubits=2)
pqc.append(gate, [0, 1, 2])

Any suggestions?

I actually have no idea about why this is happening but it looks like a problem only related to controlled-gates with more than one parameter (e.g. CRGate, CUGate).

jakelishman commented 1 year ago

Thanks for this report. I poked into the code a little bit, and it turns out that eventually this is reduces to the bug reported by #7326, because RGate gets controlled into something containing a CUGate. That said, we could potentially have headed that off by having an __array__ method defined on ControlledGate, but I'm not fully convinced that that's a good idea, since we don't require that general Gate instances have an __array__ method, so it's not clear how it should work well.

Fixing CUGate's bad behaviour around parameters would be the cleanest way to cause this to work. PR #9118 should do that, which I need to revisit.