diff --git a/qiskit/algorithms/optimizers/qnspsa.py b/qiskit/algorithms/optimizers/qnspsa.py index 39e60090a8..b7ba297962 100644 --- a/qiskit/algorithms/optimizers/qnspsa.py +++ b/qiskit/algorithms/optimizers/qnspsa.py @@ -311,8 +311,18 @@ class QNSPSA(SPSA): fid = ComputeUncompute(sampler) + num_parameters = circuit.num_parameters + def fidelity(values_x, values_y): - result = fid.run(circuit, circuit, values_x, values_y).result() + values_x = np.reshape(values_x, (-1, num_parameters)).tolist() + batch_size_x = len(values_x) + + values_y = np.reshape(values_y, (-1, num_parameters)).tolist() + batch_size_y = len(values_y) + + result = fid.run( + batch_size_x * [circuit], batch_size_y * [circuit], values_x, values_y + ).result() return np.asarray(result.fidelities) return fidelity diff --git a/releasenotes/notes/fix-qnspsa-max-evals-grouped-52eb462fa6c82079.yaml b/releasenotes/notes/fix-qnspsa-max-evals-grouped-52eb462fa6c82079.yaml new file mode 100644 index 0000000000..3b8209946f --- /dev/null +++ b/releasenotes/notes/fix-qnspsa-max-evals-grouped-52eb462fa6c82079.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - | + Fixes a bug causing QNSPSA to fail when ``max_evals_grouped`` was set to a + value larger than 1. diff --git a/test/python/algorithms/optimizers/test_spsa.py b/test/python/algorithms/optimizers/test_spsa.py index ad1c605a66..c18d498291 100644 --- a/test/python/algorithms/optimizers/test_spsa.py +++ b/test/python/algorithms/optimizers/test_spsa.py @@ -19,7 +19,7 @@ import numpy as np from qiskit.algorithms.optimizers import SPSA, QNSPSA from qiskit.circuit.library import PauliTwoDesign -from qiskit.primitives import Sampler +from qiskit.primitives import Estimator, Sampler from qiskit.providers.basicaer import StatevectorSimulatorPy from qiskit.opflow import I, Z, StateFn, MatrixExpectation from qiskit.utils import algorithm_globals @@ -222,3 +222,36 @@ class TestSPSA(QiskitAlgorithmsTestCase): result = fidelity(initial_point, initial_point) self.assertAlmostEqual(result[0], 1) + + def test_qnspsa_max_evals_grouped(self): + """Test using max_evals_grouped with QNSPSA.""" + circuit = PauliTwoDesign(3, reps=1, seed=1) + num_parameters = circuit.num_parameters + obs = Z ^ Z ^ I + + estimator = Estimator(options={"seed": 12}) + + initial_point = np.array( + [0.82311034, 0.02611798, 0.21077064, 0.61842177, 0.09828447, 0.62013131] + ) + + def objective(x): + x = np.reshape(x, (-1, num_parameters)).tolist() + n = len(x) + return estimator.run(n * [circuit], n * [obs.primitive], x).result().values.real + + fidelity = QNSPSA.get_fidelity(circuit) + optimizer = QNSPSA(fidelity) + optimizer.maxiter = 1 + optimizer.learning_rate = 0.05 + optimizer.perturbation = 0.05 + optimizer.set_max_evals_grouped(50) # greater than 1 + + result = optimizer.minimize(objective, initial_point) + + with self.subTest("check final accuracy"): + self.assertAlmostEqual(result.fun[0], 0.473, places=3) + + with self.subTest("check number of function calls"): + expected_nfev = 8 # 7 * maxiter + 1 + self.assertEqual(result.nfev, expected_nfev)