-
Couldn't load subscription status.
- Fork 70
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.