From 31e73599c1fbdb1e8432c920f337d34896e7834b Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 29 Jul 2021 14:36:16 -0400 Subject: [PATCH] Allow `Optimizer`s as input to `VQEProgram` (#290) (#291) * allow Optimizers as optimizer inputs * Update releasenotes/notes/vqeprogram-optimizers-cd23307c10fcd15b.yaml Co-authored-by: Panagiotis Barkoutsos (cherry picked from commit e6a2dfd3c5039cb1c00c10540c2d76ca026f281c) Co-authored-by: Julien Gacon --- qiskit_nature/runtime/vqe_program.py | 37 +++++++++++-------- ...qeprogram-optimizers-cd23307c10fcd15b.yaml | 6 +++ test/runtime/fake_vqeruntime.py | 3 +- test/runtime/test_vqeprogram.py | 7 +++- 4 files changed, 34 insertions(+), 19 deletions(-) create mode 100644 releasenotes/notes/vqeprogram-optimizers-cd23307c10fcd15b.yaml diff --git a/qiskit_nature/runtime/vqe_program.py b/qiskit_nature/runtime/vqe_program.py index ece8a6aa98..b46c52ce90 100644 --- a/qiskit_nature/runtime/vqe_program.py +++ b/qiskit_nature/runtime/vqe_program.py @@ -13,7 +13,7 @@ """The Qiskit Nature VQE Quantum Program.""" -from typing import List, Callable, Optional, Any, Dict +from typing import List, Callable, Optional, Any, Dict, Union import numpy as np from qiskit import QuantumCircuit @@ -21,6 +21,7 @@ from qiskit.providers import Provider from qiskit.providers.backend import Backend from qiskit.algorithms import MinimumEigensolver, MinimumEigensolverResult, VQEResult +from qiskit.algorithms.optimizers import Optimizer, SPSA from qiskit.opflow import OperatorBase, PauliSumOp from qiskit.quantum_info import SparsePauliOp @@ -31,7 +32,7 @@ class VQEProgram(MinimumEigensolver): def __init__( self, ansatz: QuantumCircuit, - optimizer: Optional[Dict[str, Any]] = None, + optimizer: Optional[Union[Optimizer, Dict[str, Any]]] = None, initial_point: Optional[np.ndarray] = None, provider: Optional[Provider] = None, backend: Optional[Backend] = None, @@ -43,11 +44,11 @@ def __init__( """ Args: ansatz: A parameterized circuit used as Ansatz for the wave function. - optimizer: A dictionary specifying a classical optimizer. - Currently only SPSA and QN-SPSA are supported. Per default, SPSA is used. - The dictionary must contain a key ``name`` for the name of the optimizer and may - contain additional keys for the settings. - E.g. ``{'name': 'SPSA', 'maxiter': 100}``. + optimizer: An optimizer or dictionary specifying a classical optimizer. + If a dictionary, only SPSA and QN-SPSA are supported. The dictionary must contain a + key ``name`` for the name of the optimizer and may contain additional keys for the + settings. E.g. ``{'name': 'SPSA', 'maxiter': 100}``. + Per default, SPSA is used. backend: The backend to run the circuits on. initial_point: An optional initial point (i.e. initial parameter values) for the optimizer. If ``None`` a random vector is used. @@ -62,7 +63,7 @@ def __init__( steps. Per default False. """ if optimizer is None: - optimizer = {"name": "SPSA"} + optimizer = SPSA(maxiter=300) # define program name self._program_id = "vqe" @@ -116,21 +117,25 @@ def ansatz(self, ansatz: QuantumCircuit) -> None: self._ansatz = ansatz @property - def optimizer(self) -> Dict[str, Any]: + def optimizer(self) -> Union[Optimizer, Dict[str, Any]]: """Return the dictionary describing the optimizer.""" return self._optimizer @optimizer.setter - def optimizer(self, settings: Dict[str, Any]) -> None: + def optimizer(self, optimizer: Union[Optimizer, Dict[str, Any]]) -> None: """Set the optimizer.""" - if "name" not in settings.keys(): - raise ValueError( - "The settings must contain a ``name`` key specifying the type of " "the optimizer." - ) + if isinstance(optimizer, Optimizer): + self._optimizer = optimizer + else: + if "name" not in optimizer.keys(): + raise ValueError( + "The optimizer dictionary must contain a ``name`` key specifying the type " + "of the optimizer." + ) - _validate_optimizer_settings(settings) + _validate_optimizer_settings(optimizer) - self._optimizer = settings + self._optimizer = optimizer @property def backend(self) -> Optional[Backend]: diff --git a/releasenotes/notes/vqeprogram-optimizers-cd23307c10fcd15b.yaml b/releasenotes/notes/vqeprogram-optimizers-cd23307c10fcd15b.yaml new file mode 100644 index 0000000000..47cbc25fa6 --- /dev/null +++ b/releasenotes/notes/vqeprogram-optimizers-cd23307c10fcd15b.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + Allow Qiskit's :class:`~qiskit.algorithms.optimizers.Optimizer` classes as input for + the ``optimizer`` in the :class:`~qiskit_nature.runtime.VQEProgram` instead of only + dictionaries. diff --git a/test/runtime/fake_vqeruntime.py b/test/runtime/fake_vqeruntime.py index 892ae19959..b098f1190d 100644 --- a/test/runtime/fake_vqeruntime.py +++ b/test/runtime/fake_vqeruntime.py @@ -14,6 +14,7 @@ from typing import Dict, Any import numpy as np +from qiskit.algorithms.optimizers import Optimizer from qiskit.circuit import QuantumCircuit from qiskit.opflow import PauliSumOp from qiskit.providers import Provider @@ -59,7 +60,7 @@ def run(self, program_id, inputs, options, callback=None): "aux_operators": (list, type(None)), "ansatz": QuantumCircuit, "initial_point": (np.ndarray, str), - "optimizer": dict, + "optimizer": (Optimizer, dict), "shots": int, "measurement_error_mitigation": bool, "store_intermediate": bool, diff --git a/test/runtime/test_vqeprogram.py b/test/runtime/test_vqeprogram.py index 946bd0559d..762537d4c5 100644 --- a/test/runtime/test_vqeprogram.py +++ b/test/runtime/test_vqeprogram.py @@ -15,9 +15,11 @@ from test import QiskitNatureTestCase import unittest +from ddt import ddt, data import numpy as np from qiskit.providers.basicaer import QasmSimulatorPy from qiskit.algorithms import VQEResult +from qiskit.algorithms.optimizers import SPSA from qiskit.circuit.library import RealAmplitudes from qiskit.opflow import I, Z @@ -26,6 +28,7 @@ from .fake_vqeruntime import FakeRuntimeProvider +@ddt class TestVQEProgram(QiskitNatureTestCase): """Test the VQE program.""" @@ -33,12 +36,12 @@ def setUp(self): super().setUp() self.provider = FakeRuntimeProvider() - def test_standard_case(self): + @data({"name": "SPSA", "maxiter": 100}, SPSA(maxiter=100)) + def test_standard_case(self, optimizer): """Test a standard use case.""" circuit = RealAmplitudes(3) operator = Z ^ I ^ Z initial_point = np.random.random(circuit.num_parameters) - optimizer = {"name": "SPSA", "maxiter": 100} backend = QasmSimulatorPy() vqe = VQEProgram(