Skip to content

Gradient parameter order mismatch in ParamShiftEstimatorGradient #987

@ParkYeong-hyeon

Description

@ParkYeong-hyeon

Environment

  • Qiskit Machine Learning version: 0.8.3
  • Python version: 3.12.3
  • Operating system: Windows11

What is happening?

I noticed that the gradient vector indices do not match the parameter order when using ParamShiftEstimatorGradient. I am not sure if this is intended behavior but I would greatly appreciate it if the team could confirm whether this is expected.

How can we reproduce the issue?

import numpy as np
from qiskit import QuantumCircuit
from qiskit.circuit import ParameterVector
from qiskit.primitives import BackendEstimatorV2
from qiskit_aer import Aer

# Create a simple parameterized circuit for testing.
def create_circuit(num_qubits, depth): 
    target = QuantumCircuit(num_qubits)
    params = ParameterVector("θ", length=num_qubits*depth)
    for i in range(num_qubits*depth):
        target.rx(params[i], i%4)
    return target

# --- Prepare test circuit and parameters ---
circuit = create_circuit(4, 4)
parameter_values = np.zeros(4*4)
parameters = circuit.parameters # try caculate grad for total parameters

backend = Aer.get_backend('aer_simulator')
test = ParamShiftEstimatorGradient(estimator=BackendEstimatorV2(backend=backend))

# _preprocess replicates the first step of gradient computation
# It builds gradient circuits and collects gradient parameters.
g_circuits, g_parameter_values, g_parameters = test._preprocess([circuit], [parameter_values], [parameters], test.SUPPORTED_GATES)

# --- Check alignment of indices ---
# In the actual implementation, postprocess uses g_parameters order
# to build an index map (g_parameter_indices).
# Here we mimic that logic and check against gradient_circuit.parameters order.

gradient_circuit = g_circuits[0]  # take the first gradient circuit and parameters
g_parameter = g_parameters[0]
g_parameter_indices = {param: i for i, param in enumerate(g_parameter)}

# Compare: do indices from g_parameters match gradient_circuit.parameters order?
for param, i in g_parameter_indices.items():
    print(
        param,
        " -> g_parameters index:", i,
        " | gradient_circuit index:",
        gradient_circuit.parameters.data.index(param),
        " | match:", i == gradient_circuit.parameters.data.index(param),
    )

What should happen?

In qiskit-machine-learning/qiskit_machine_learning/gradients/base/base_estimator_gradient.py lines 255, 271–274, the gradient is accumulated as follows:

 g_parameter_indices = {param: i for i, param in enumerate(g_parameters)}
gradient[i] += (
    float(bound_coeff)
    * results.gradients[idx][g_parameter_indices[g_parameter]]
)

This logic assumes that the order of entries in results.gradients[idx] matches the order of g_parameters (i.e., that the gradient vector is sequentially aligned with the parameter map).

However, in practice the order of shifted parameters produced and executed by the estimator is not sequential. In my minimal example, comparing g_parameters indices against gradient_circuit.parameters.data.index(param) shows that they do not all match (i.e., not all results are True).

This suggests that the code relies on an ordering assumption that does not hold in practice, causing gradients to be assigned to the wrong parameters.

Any suggestions?

I cannot be completely certain, but it seems that in qiskit-machine-learning/qiskit_machine_learning/gradients/utils.py, the _make_gradient_parameters function creates the unique g_parameters. At this step, the line list(dict.fromkeys(g_parameters)) is used to remove duplicates.

My understanding is that this may generate its own order of parameters, independent of the original order in which the circuit produced them. Could you please confirm if this interpretation is correct?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions