From c303c2ddafb5115cbb01940b7d67aa66b0e25150 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elena=20Pe=C3=B1a=20Tapia?= Date: Tue, 24 Oct 2023 14:03:07 +0200 Subject: [PATCH 1/8] Add alternative and deprecation warning --- qiskit/transpiler/synthesis/aqc/aqc.py | 114 +++++++++++++++--- qiskit/transpiler/synthesis/aqc/aqc_plugin.py | 8 +- test/python/transpiler/aqc/test_aqc.py | 69 ++++++++++- test/python/transpiler/aqc/test_aqc_plugin.py | 8 +- 4 files changed, 167 insertions(+), 32 deletions(-) diff --git a/qiskit/transpiler/synthesis/aqc/aqc.py b/qiskit/transpiler/synthesis/aqc/aqc.py index e90fd5612f97..66dbe123131a 100644 --- a/qiskit/transpiler/synthesis/aqc/aqc.py +++ b/qiskit/transpiler/synthesis/aqc/aqc.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2022. +# (C) Copyright IBM 2022, 2023. # # This code is licensed under the Apache License, Version 2.0. You may # obtain a copy of this license in the LICENSE.txt file in the root directory @@ -10,30 +10,85 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. """A generic implementation of Approximate Quantum Compiler.""" -from typing import Optional +from __future__ import annotations + +from functools import partial + +from collections.abc import Callable +from typing import Protocol import numpy as np +from scipy.optimize import OptimizeResult, minimize -from qiskit.algorithms.optimizers import L_BFGS_B, Optimizer +from qiskit.algorithms.optimizers import Optimizer from qiskit.quantum_info import Operator +from qiskit.utils.deprecation import deprecate_arg + from .approximate import ApproximateCircuit, ApproximatingObjective +class Minimizer(Protocol): + """Callable Protocol for minimizer. + + This interface is based on `SciPy's optimize module + `__. + + This protocol defines a callable taking the following parameters: + + fun + The objective function to minimize. + x0 + The initial point for the optimization. + jac + The gradient of the objective function. + bounds + Parameters bounds for the optimization. Note that these might not be supported + by all optimizers. + + and which returns a SciPy minimization result object. + """ + + # pylint: disable=invalid-name + def __call__( + self, + fun: Callable[[np.ndarray], float], + x0: np.ndarray, + jac: Callable[[np.ndarray], np.ndarray] | None, + bounds: list[tuple[float, float]] | None, + ) -> OptimizeResult: + """Minimize the objective function. + + This interface is based on `SciPy's optimize module `__. + + Args: + fun: The objective function to minimize. + x0: The initial point for the optimization. + jac: The gradient of the objective function. + bounds: Parameters bounds for the optimization. Note that these might not be supported + by all optimizers. + + Returns: + The SciPy minimization result object. + """ + ... # pylint: disable=unnecessary-ellipsis + + class AQC: """ - A generic implementation of Approximate Quantum Compiler. This implementation is agnostic of + A generic implementation of the Approximate Quantum Compiler. This implementation is agnostic of the underlying implementation of the approximate circuit, objective, and optimizer. Users may pass corresponding implementations of the abstract classes: - * Optimizer is an instance of :class:`~qiskit.algorithms.optimizers.Optimizer` and used to run - the optimization process. A choice of optimizer may affect overall convergence, required time + * The *optimizer* is an implementation of the :class:`~.Minimizer` protocol, a callable used to run + the optimization process. The choice of optimizer may affect overall convergence, required time for the optimization process and achieved objective value. - * Approximate circuit represents a template which parameters we want to optimize. Currently, + * The *approximate circuit* represents a template which parameters we want to optimize. Currently, there's only one implementation based on 4-rotations CNOT unit blocks: :class:`.CNOTUnitCircuit`. See the paper for more details. - * Approximate objective is tightly coupled with the approximate circuit implementation and + * The *approximate objective* is tightly coupled with the approximate circuit implementation and provides two methods for computing objective function and gradient with respect to approximate circuit parameters. This objective is passed to the optimizer. Currently, there are two implementations based on 4-rotations CNOT unit blocks: :class:`.DefaultCNOTUnitObjective` and @@ -48,17 +103,27 @@ class AQC: also allocates a number of temporary memory buffers comparable in size to the target matrix. """ + @deprecate_arg( + "optimizer", + deprecation_description=( + "Setting the `optimizer` argument to an instance " + "of `qiskit.algorithms.optimizers.Optimizer` " + ), + additional_msg=("Please, submit a callable that follows the `Minimizer` protocol instead."), + predicate=lambda optimizer: isinstance(optimizer, Optimizer), + since="0.45.0", + ) def __init__( self, - optimizer: Optional[Optimizer] = None, - seed: Optional[int] = None, + optimizer: Minimizer | Optimizer | None = None, + seed: int | None = None, ): """ Args: optimizer: an optimizer to be used in the optimization procedure of the search for - the best approximate circuit. By default, :obj:`.L_BFGS_B` is used with max - iterations set to 1000. - seed: a seed value to be user by a random number generator. + the best approximate circuit. By default, the scipy minimizer with the + ``L-BFGS-B`` method is used with max iterations set to 1000. + seed: a seed value to be used by a random number generator. """ super().__init__() self._optimizer = optimizer @@ -69,7 +134,7 @@ def compile_unitary( target_matrix: np.ndarray, approximate_circuit: ApproximateCircuit, approximating_objective: ApproximatingObjective, - initial_point: Optional[np.ndarray] = None, + initial_point: np.ndarray | None = None, ) -> None: """ Approximately compiles a circuit represented as a unitary matrix by solving an optimization @@ -96,17 +161,26 @@ def compile_unitary( # set the matrix to approximate in the algorithm approximating_objective.target_matrix = su_matrix - optimizer = self._optimizer or L_BFGS_B(maxiter=1000) + optimizer = self._optimizer or partial( + minimize, args=(), method="L-BFGS-B", options={"maxiter": 1000} + ) if initial_point is None: np.random.seed(self._seed) initial_point = np.random.uniform(0, 2 * np.pi, approximating_objective.num_thetas) - opt_result = optimizer.minimize( - fun=approximating_objective.objective, - x0=initial_point, - jac=approximating_objective.gradient, - ) + if isinstance(optimizer, Optimizer): + opt_result = optimizer.minimize( + fun=approximating_objective.objective, + x0=initial_point, + jac=approximating_objective.gradient, + ) + else: + opt_result = optimizer( + fun=approximating_objective.objective, + x0=initial_point, + jac=approximating_objective.gradient, + ) approximate_circuit.build(opt_result.x) diff --git a/qiskit/transpiler/synthesis/aqc/aqc_plugin.py b/qiskit/transpiler/synthesis/aqc/aqc_plugin.py index 0138d8e7b97a..93403a64f81c 100644 --- a/qiskit/transpiler/synthesis/aqc/aqc_plugin.py +++ b/qiskit/transpiler/synthesis/aqc/aqc_plugin.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2021. +# (C) Copyright IBM 2021, 2023. # # This code is licensed under the Apache License, Version 2.0. You may # obtain a copy of this license in the LICENSE.txt file in the root directory @@ -12,6 +12,7 @@ """ An AQC synthesis plugin to Qiskit's transpiler. """ +from functools import partial import numpy as np from qiskit.converters import circuit_to_dag @@ -104,7 +105,7 @@ def run(self, unitary, **options): # Runtime imports to avoid the overhead of these imports for # plugin discovery and only use them if the plugin is run/used - from qiskit.algorithms.optimizers import L_BFGS_B + from scipy.optimize import minimize from qiskit.transpiler.synthesis.aqc.aqc import AQC from qiskit.transpiler.synthesis.aqc.cnot_structures import make_cnot_network from qiskit.transpiler.synthesis.aqc.cnot_unit_circuit import CNOTUnitCircuit @@ -125,7 +126,8 @@ def run(self, unitary, **options): depth=depth, ) - optimizer = config.get("optimizer", L_BFGS_B(maxiter=1000)) + default_optimizer = partial(minimize, args=(), method="L-BFGS-B", options={"maxiter": 1000}) + optimizer = config.get("optimizer", default_optimizer) seed = config.get("seed") aqc = AQC(optimizer, seed) diff --git a/test/python/transpiler/aqc/test_aqc.py b/test/python/transpiler/aqc/test_aqc.py index 45b1a5ea51ee..fc13acb991b7 100644 --- a/test/python/transpiler/aqc/test_aqc.py +++ b/test/python/transpiler/aqc/test_aqc.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2022. +# (C) Copyright IBM 2022, 2023. # # This code is licensed under the Apache License, Version 2.0. You may # obtain a copy of this license in the LICENSE.txt file in the root directory @@ -12,10 +12,14 @@ """ Tests AQC framework using hardcoded and randomly generated circuits. """ +from functools import partial + import unittest from test.python.transpiler.aqc.sample_data import ORIGINAL_CIRCUIT, INITIAL_THETAS + import numpy as np -from qiskit.algorithms.optimizers import L_BFGS_B +from scipy.optimize import minimize + from qiskit.quantum_info import Operator from qiskit.test import QiskitTestCase from qiskit.transpiler.synthesis.aqc.aqc import AQC @@ -38,8 +42,7 @@ def test_aqc(self): num_qubits=num_qubits, network_layout="spin", connectivity_type="full", depth=0 ) - optimizer = L_BFGS_B(maxiter=200) - + optimizer = partial(minimize, args=(), method="L-BFGS-B", options={"maxiter": 200}) aqc = AQC(optimizer=optimizer, seed=seed) target_matrix = ORIGINAL_CIRCUIT @@ -57,6 +60,60 @@ def test_aqc(self): error = 0.5 * (np.linalg.norm(approx_matrix - ORIGINAL_CIRCUIT, "fro") ** 2) self.assertTrue(error < 1e-3) + def test_aqc_default_optimizer(self): + """Tests AQC on a hardcoded circuit/matrix without providing an optimizer.""" + + seed = 12345 + + num_qubits = int(round(np.log2(ORIGINAL_CIRCUIT.shape[0]))) + cnots = make_cnot_network( + num_qubits=num_qubits, network_layout="spin", connectivity_type="full", depth=0 + ) + + aqc = AQC(seed=seed) + + target_matrix = ORIGINAL_CIRCUIT + approximate_circuit = CNOTUnitCircuit(num_qubits, cnots) + approximating_objective = DefaultCNOTUnitObjective(num_qubits, cnots) + + aqc.compile_unitary( + target_matrix=target_matrix, + approximate_circuit=approximate_circuit, + approximating_objective=approximating_objective, + initial_point=INITIAL_THETAS, + ) + + approx_matrix = Operator(approximate_circuit).data + error = 0.5 * (np.linalg.norm(approx_matrix - ORIGINAL_CIRCUIT, "fro") ** 2) + self.assertTrue(error < 1e-3) + + def test_aqc_deprecation(self): + """Tests that AQC raises deprecation warning.""" + + seed = 12345 + + num_qubits = int(round(np.log2(ORIGINAL_CIRCUIT.shape[0]))) + cnots = make_cnot_network( + num_qubits=num_qubits, network_layout="spin", connectivity_type="full", depth=0 + ) + + aqc = AQC(seed=seed) + + target_matrix = ORIGINAL_CIRCUIT + approximate_circuit = CNOTUnitCircuit(num_qubits, cnots) + approximating_objective = DefaultCNOTUnitObjective(num_qubits, cnots) + + aqc.compile_unitary( + target_matrix=target_matrix, + approximate_circuit=approximate_circuit, + approximating_objective=approximating_objective, + initial_point=INITIAL_THETAS, + ) + + approx_matrix = Operator(approximate_circuit).data + error = 0.5 * (np.linalg.norm(approx_matrix - ORIGINAL_CIRCUIT, "fro") ** 2) + self.assertTrue(error < 1e-3) + def test_aqc_fastgrad(self): """ Tests AQC on a MCX circuit/matrix with random initial guess using @@ -70,7 +127,7 @@ def test_aqc_fastgrad(self): num_qubits=num_qubits, network_layout="spin", connectivity_type="full", depth=0 ) - optimizer = L_BFGS_B(maxiter=200) + optimizer = partial(minimize, args=(), method="L-BFGS-B", options={"maxiter": 200}) aqc = AQC(optimizer=optimizer, seed=seed) # Make multi-control CNOT gate matrix. @@ -103,7 +160,7 @@ def test_aqc_determinant_minus_one(self): num_qubits=num_qubits, network_layout="spin", connectivity_type="full", depth=0 ) - optimizer = L_BFGS_B(maxiter=200) + optimizer = partial(minimize, args=(), method="L-BFGS-B", options={"maxiter": 200}) aqc = AQC(optimizer=optimizer, seed=seed) target_matrix = np.eye(2**num_qubits, dtype=int) diff --git a/test/python/transpiler/aqc/test_aqc_plugin.py b/test/python/transpiler/aqc/test_aqc_plugin.py index 0ad2742a1195..b5f3bf1858f4 100644 --- a/test/python/transpiler/aqc/test_aqc_plugin.py +++ b/test/python/transpiler/aqc/test_aqc_plugin.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2021. +# (C) Copyright IBM 2021, 2023. # # This code is licensed under the Apache License, Version 2.0. You may # obtain a copy of this license in the LICENSE.txt file in the root directory @@ -12,11 +12,12 @@ """ Tests AQC plugin. """ +from functools import partial import numpy as np +from scipy.optimize import minimize from qiskit import QuantumCircuit -from qiskit.algorithms.optimizers import SLSQP from qiskit.converters import dag_to_circuit, circuit_to_dag from qiskit.quantum_info import Operator from qiskit.test import QiskitTestCase @@ -68,12 +69,13 @@ def test_plugin_setup(self): def test_plugin_configuration(self): """Tests plugin with a custom configuration.""" + optimizer = partial(minimize, args=(), method="SLSQP") config = { "network_layout": "sequ", "connectivity_type": "full", "depth": 0, "seed": 12345, - "optimizer": SLSQP(), + "optimizer": optimizer, } transpiler_pass = UnitarySynthesis( basis_gates=["rx", "ry", "rz", "cx"], method="aqc", plugin_config=config From c4b2f8fb6be6f3d5bcb777907921438a5464b531 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elena=20Pe=C3=B1a=20Tapia?= Date: Tue, 24 Oct 2023 14:10:38 +0200 Subject: [PATCH 2/8] Add deprecation test --- test/python/transpiler/aqc/test_aqc.py | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/test/python/transpiler/aqc/test_aqc.py b/test/python/transpiler/aqc/test_aqc.py index fc13acb991b7..798df50e4d5e 100644 --- a/test/python/transpiler/aqc/test_aqc.py +++ b/test/python/transpiler/aqc/test_aqc.py @@ -20,6 +20,7 @@ import numpy as np from scipy.optimize import minimize +from qiskit.algorithms.optimizers import L_BFGS_B from qiskit.quantum_info import Operator from qiskit.test import QiskitTestCase from qiskit.transpiler.synthesis.aqc.aqc import AQC @@ -91,28 +92,10 @@ def test_aqc_deprecation(self): """Tests that AQC raises deprecation warning.""" seed = 12345 + optimizer = L_BFGS_B(maxiter=200) - num_qubits = int(round(np.log2(ORIGINAL_CIRCUIT.shape[0]))) - cnots = make_cnot_network( - num_qubits=num_qubits, network_layout="spin", connectivity_type="full", depth=0 - ) - - aqc = AQC(seed=seed) - - target_matrix = ORIGINAL_CIRCUIT - approximate_circuit = CNOTUnitCircuit(num_qubits, cnots) - approximating_objective = DefaultCNOTUnitObjective(num_qubits, cnots) - - aqc.compile_unitary( - target_matrix=target_matrix, - approximate_circuit=approximate_circuit, - approximating_objective=approximating_objective, - initial_point=INITIAL_THETAS, - ) - - approx_matrix = Operator(approximate_circuit).data - error = 0.5 * (np.linalg.norm(approx_matrix - ORIGINAL_CIRCUIT, "fro") ** 2) - self.assertTrue(error < 1e-3) + with self.assertRaises(DeprecationWarning): + _ = AQC(optimizer=optimizer, seed=seed) def test_aqc_fastgrad(self): """ From 053b3786cd23573d969b25a3a28b886dc0908a68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elena=20Pe=C3=B1a=20Tapia?= <57907331+ElePT@users.noreply.github.com> Date: Wed, 25 Oct 2023 14:18:33 +0200 Subject: [PATCH 3/8] Apply Julien's suggestion Co-authored-by: Julien Gacon --- test/python/transpiler/aqc/test_aqc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/python/transpiler/aqc/test_aqc.py b/test/python/transpiler/aqc/test_aqc.py index 798df50e4d5e..12c78ff538b9 100644 --- a/test/python/transpiler/aqc/test_aqc.py +++ b/test/python/transpiler/aqc/test_aqc.py @@ -86,7 +86,7 @@ def test_aqc_default_optimizer(self): approx_matrix = Operator(approximate_circuit).data error = 0.5 * (np.linalg.norm(approx_matrix - ORIGINAL_CIRCUIT, "fro") ** 2) - self.assertTrue(error < 1e-3) + self.assertLess(error, 1e-3) def test_aqc_deprecation(self): """Tests that AQC raises deprecation warning.""" From 63ec7ab0bb49da0152fbd0692beff51d7a55cb40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elena=20Pe=C3=B1a=20Tapia?= Date: Wed, 25 Oct 2023 14:28:15 +0200 Subject: [PATCH 4/8] Apply suggestions from Julien's code review --- qiskit/transpiler/synthesis/aqc/aqc.py | 25 +++++++---------- test/python/transpiler/aqc/test_aqc.py | 39 ++++++-------------------- 2 files changed, 19 insertions(+), 45 deletions(-) diff --git a/qiskit/transpiler/synthesis/aqc/aqc.py b/qiskit/transpiler/synthesis/aqc/aqc.py index 66dbe123131a..4f47f47efed8 100644 --- a/qiskit/transpiler/synthesis/aqc/aqc.py +++ b/qiskit/transpiler/synthesis/aqc/aqc.py @@ -48,13 +48,12 @@ class Minimizer(Protocol): and which returns a SciPy minimization result object. """ - # pylint: disable=invalid-name def __call__( self, fun: Callable[[np.ndarray], float], - x0: np.ndarray, - jac: Callable[[np.ndarray], np.ndarray] | None, - bounds: list[tuple[float, float]] | None, + x0: np.ndarray, # pylint: disable=invalid-name + jac: Callable[[np.ndarray], np.ndarray] | None = None, + bounds: list[tuple[float, float]] | None = None, ) -> OptimizeResult: """Minimize the objective function. @@ -170,17 +169,13 @@ def compile_unitary( initial_point = np.random.uniform(0, 2 * np.pi, approximating_objective.num_thetas) if isinstance(optimizer, Optimizer): - opt_result = optimizer.minimize( - fun=approximating_objective.objective, - x0=initial_point, - jac=approximating_objective.gradient, - ) - else: - opt_result = optimizer( - fun=approximating_objective.objective, - x0=initial_point, - jac=approximating_objective.gradient, - ) + optimizer = optimizer.minimize + + opt_result = optimizer( + fun=approximating_objective.objective, + x0=initial_point, + jac=approximating_objective.gradient, + ) approximate_circuit.build(opt_result.x) diff --git a/test/python/transpiler/aqc/test_aqc.py b/test/python/transpiler/aqc/test_aqc.py index 798df50e4d5e..c5472985ac66 100644 --- a/test/python/transpiler/aqc/test_aqc.py +++ b/test/python/transpiler/aqc/test_aqc.py @@ -17,6 +17,7 @@ import unittest from test.python.transpiler.aqc.sample_data import ORIGINAL_CIRCUIT, INITIAL_THETAS +import ddt import numpy as np from scipy.optimize import minimize @@ -30,10 +31,12 @@ from qiskit.transpiler.synthesis.aqc.fast_gradient.fast_gradient import FastCNOTUnitObjective +@ddt class TestAqc(QiskitTestCase): """Main tests of approximate quantum compiler.""" - def test_aqc(self): + @ddt.data(True, False) + def test_aqc(self, uses_default): """Tests AQC on a hardcoded circuit/matrix.""" seed = 12345 @@ -43,35 +46,11 @@ def test_aqc(self): num_qubits=num_qubits, network_layout="spin", connectivity_type="full", depth=0 ) - optimizer = partial(minimize, args=(), method="L-BFGS-B", options={"maxiter": 200}) - aqc = AQC(optimizer=optimizer, seed=seed) - - target_matrix = ORIGINAL_CIRCUIT - approximate_circuit = CNOTUnitCircuit(num_qubits, cnots) - approximating_objective = DefaultCNOTUnitObjective(num_qubits, cnots) - - aqc.compile_unitary( - target_matrix=target_matrix, - approximate_circuit=approximate_circuit, - approximating_objective=approximating_objective, - initial_point=INITIAL_THETAS, - ) - - approx_matrix = Operator(approximate_circuit).data - error = 0.5 * (np.linalg.norm(approx_matrix - ORIGINAL_CIRCUIT, "fro") ** 2) - self.assertTrue(error < 1e-3) - - def test_aqc_default_optimizer(self): - """Tests AQC on a hardcoded circuit/matrix without providing an optimizer.""" - - seed = 12345 - - num_qubits = int(round(np.log2(ORIGINAL_CIRCUIT.shape[0]))) - cnots = make_cnot_network( - num_qubits=num_qubits, network_layout="spin", connectivity_type="full", depth=0 - ) - - aqc = AQC(seed=seed) + if uses_default: + aqc = AQC(seed=seed) + else: + optimizer = partial(minimize, args=(), method="L-BFGS-B", options={"maxiter": 200}) + aqc = AQC(optimizer=optimizer, seed=seed) target_matrix = ORIGINAL_CIRCUIT approximate_circuit = CNOTUnitCircuit(num_qubits, cnots) From 9a78904a0ca1f41942f8b2548f28f61f9f41947a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elena=20Pe=C3=B1a=20Tapia?= Date: Wed, 25 Oct 2023 14:30:32 +0200 Subject: [PATCH 5/8] Move optimizer setting to init --- qiskit/transpiler/synthesis/aqc/aqc.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/qiskit/transpiler/synthesis/aqc/aqc.py b/qiskit/transpiler/synthesis/aqc/aqc.py index 4f47f47efed8..905116cd2a6c 100644 --- a/qiskit/transpiler/synthesis/aqc/aqc.py +++ b/qiskit/transpiler/synthesis/aqc/aqc.py @@ -125,7 +125,13 @@ def __init__( seed: a seed value to be used by a random number generator. """ super().__init__() - self._optimizer = optimizer + self._optimizer = optimizer or partial( + minimize, args=(), method="L-BFGS-B", options={"maxiter": 1000} + ) + # temporary fix -> remove after deprecation period of Optimizer + if isinstance(self._optimizer, Optimizer): + self._optimizer = self._optimizer.minimize + self._seed = seed def compile_unitary( @@ -160,18 +166,11 @@ def compile_unitary( # set the matrix to approximate in the algorithm approximating_objective.target_matrix = su_matrix - optimizer = self._optimizer or partial( - minimize, args=(), method="L-BFGS-B", options={"maxiter": 1000} - ) - if initial_point is None: np.random.seed(self._seed) initial_point = np.random.uniform(0, 2 * np.pi, approximating_objective.num_thetas) - if isinstance(optimizer, Optimizer): - optimizer = optimizer.minimize - - opt_result = optimizer( + opt_result = self._optimizer( fun=approximating_objective.objective, x0=initial_point, jac=approximating_objective.gradient, From 42c608bb72553ca77fb4bcf21939fef33c50f82f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elena=20Pe=C3=B1a=20Tapia?= Date: Wed, 25 Oct 2023 14:48:44 +0200 Subject: [PATCH 6/8] Fix ddt import --- test/python/transpiler/aqc/test_aqc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/python/transpiler/aqc/test_aqc.py b/test/python/transpiler/aqc/test_aqc.py index c67708d01c34..6bdbc6320b2b 100644 --- a/test/python/transpiler/aqc/test_aqc.py +++ b/test/python/transpiler/aqc/test_aqc.py @@ -17,7 +17,7 @@ import unittest from test.python.transpiler.aqc.sample_data import ORIGINAL_CIRCUIT, INITIAL_THETAS -import ddt +from ddt import ddt, data, unpack import numpy as np from scipy.optimize import minimize @@ -35,7 +35,7 @@ class TestAqc(QiskitTestCase): """Main tests of approximate quantum compiler.""" - @ddt.data(True, False) + @data(True, False) def test_aqc(self, uses_default): """Tests AQC on a hardcoded circuit/matrix.""" From b169d3fb3c4d98151886bf0fab139368f2076ef4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elena=20Pe=C3=B1a=20Tapia?= Date: Wed, 25 Oct 2023 15:51:23 +0200 Subject: [PATCH 7/8] Fix lint --- test/python/transpiler/aqc/test_aqc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/python/transpiler/aqc/test_aqc.py b/test/python/transpiler/aqc/test_aqc.py index 6bdbc6320b2b..885fe4c1fc13 100644 --- a/test/python/transpiler/aqc/test_aqc.py +++ b/test/python/transpiler/aqc/test_aqc.py @@ -17,7 +17,7 @@ import unittest from test.python.transpiler.aqc.sample_data import ORIGINAL_CIRCUIT, INITIAL_THETAS -from ddt import ddt, data, unpack +from ddt import ddt, data import numpy as np from scipy.optimize import minimize From d5d7ffc05c76be92f599b595f7cbc321c65380b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elena=20Pe=C3=B1a=20Tapia?= Date: Wed, 25 Oct 2023 18:05:22 +0200 Subject: [PATCH 8/8] Add reno --- ...c-optimizer-typehint-34b54c6278d23f79.yaml | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 releasenotes/notes/fix-aqc-optimizer-typehint-34b54c6278d23f79.yaml diff --git a/releasenotes/notes/fix-aqc-optimizer-typehint-34b54c6278d23f79.yaml b/releasenotes/notes/fix-aqc-optimizer-typehint-34b54c6278d23f79.yaml new file mode 100644 index 000000000000..bca717c18745 --- /dev/null +++ b/releasenotes/notes/fix-aqc-optimizer-typehint-34b54c6278d23f79.yaml @@ -0,0 +1,21 @@ +--- +fixes: + - | + The use of the (deprecated) ``Optimizer`` class on :class:`~.AQC` did not have a + non-deprecated alternative path, which should have been introduced in + the original ``qiskit-algorithms`` deprecation PR + [#10406](https://github.com/Qiskit/qiskit/pull/10406). + It now accepts a callable that implements the :class:`~.Minimizer` protocol, + as explicitly stated in the deprecation warning. The callable can look like the + following example: + + .. code-block:: python + + from scipy.optimize import minimize + from qiskit.transpiler.synthesis.aqc.aqc import AQC + + optimizer = partial(minimize, args=(), method="L-BFGS-B", options={"maxiter": 200}) + aqc = AQC(optimizer=optimizer) + + +