-
Notifications
You must be signed in to change notification settings - Fork 71
Description
Environment
- Qiskit Algorithms version: 0.3.1
- Python version: 3.12.3
- Operating system: Ubuntu in WSL (Windows 11)
What is happening?
Operators containing controlled gates with parameters (e.g. CRXGate
) cause a KeyError
on qiskit_algorithms/gradients/utils.py#L348.
How can we reproduce the issue?
from qiskit.circuit import QuantumCircuit, Parameter
from qiskit.quantum_info import SparsePauliOp
import numpy as np
from qiskit.primitives import Estimator
from qiskit_algorithms.gradients import ReverseEstimatorGradient
a = Parameter("a")
qc = QuantumCircuit(2)
qc.h(0)
qc.crx(a, 0, 1)
print(qc.draw())
H = SparsePauliOp.from_list([("IX", 1)])
# Parameter list
params = [np.pi / 4]
# Define the estimator
estimator = Estimator()
exp_value = estimator.run(qc, H, params).result().values
print("Expectation value", exp_value)
# Define the gradient
gradient_estimator = ReverseEstimatorGradient(estimator)
# Evaluate the gradient of the circuits using parameter shift gradients
gradient = gradient_estimator.run([qc], [H], [params]).result().gradients
print("Gradient", gradient)
What should happen?
With the ParamShiftEstimatorGradient
, which transpiles the circuit into CX
and RX
gates, the result is as follows:
┌───┐
q_0: ┤ H ├────■────
└───┘┌───┴───┐
q_1: ─────┤ Rx(a) ├
└───────┘
Expectation value [0.92387953]
Gradient [array([-0.19134172])]
Any suggestions?
The problem is caused in the _assign_unique_parameters()
function in gradients.utils
: the check instruction.operation.is_parameterized()
on line qiskit_algorithms/gradients/utils.py#L302 returns False
if instruction.operation
is a ControlledGate
with a parameterised base_gate
.
This again happens because ControlledGate.params()
does not set the variable self._params
, which is read by the is_parameterized()
function.
A similar issue has been reported at Qiskit for another case, namely control flows: Qiskit/qiskit#12624
It looks like the Qiskit team is reluctant to change the API here.
The code runs successfully if I change instruction.operation.is_parameterized()
to instruction.is_parameterized()
. However, I do not know if that breaks any other cases.