diff --git a/README.md b/README.md index 5e55d38ce..cedd16911 100644 --- a/README.md +++ b/README.md @@ -68,9 +68,9 @@ from docplex.mp.model import Model from qiskit_optimization.algorithms import MinimumEigenOptimizer from qiskit_optimization.translators import from_docplex_mp -from qiskit.utils import algorithm_globals, QuantumInstance -from qiskit import BasicAer -from qiskit.algorithms import QAOA +from qiskit.utils import algorithm_globals +from qiskit.primitives import Sampler +from qiskit.algorithms.minimum_eigensolvers import QAOA from qiskit.algorithms.optimizers import SPSA # Generate a graph of 4 nodes @@ -97,9 +97,8 @@ seed = 1234 algorithm_globals.random_seed = seed spsa = SPSA(maxiter=250) -backend = BasicAer.get_backend('qasm_simulator') -q_i = QuantumInstance(backend=backend, seed_simulator=seed, seed_transpiler=seed) -qaoa = QAOA(optimizer=spsa, reps=5, quantum_instance=q_i) +sampler = Sampler() +qaoa = QAOA(sampler=sampler, optimizer=spsa, reps=5) algorithm = MinimumEigenOptimizer(qaoa) result = algorithm.solve(problem) print(result.prettyprint()) # prints solution, x=[1, 0, 1, 0], the cost, fval=4 diff --git a/qiskit_optimization/algorithms/admm_optimizer.py b/qiskit_optimization/algorithms/admm_optimizer.py index 40c3911e7..881e05be7 100644 --- a/qiskit_optimization/algorithms/admm_optimizer.py +++ b/qiskit_optimization/algorithms/admm_optimizer.py @@ -17,21 +17,21 @@ from typing import List, Optional, Tuple, cast import numpy as np -from qiskit.algorithms import NumPyMinimumEigensolver +from qiskit.algorithms.minimum_eigensolvers import NumPyMinimumEigensolver +from ..converters import MaximizeToMinimize +from ..problems.constraint import Constraint +from ..problems.linear_constraint import LinearConstraint +from ..problems.linear_expression import LinearExpression +from ..problems.quadratic_program import QuadraticProgram +from ..problems.variable import Variable, VarType from .minimum_eigen_optimizer import MinimumEigenOptimizer from .optimization_algorithm import ( - OptimizationResultStatus, OptimizationAlgorithm, OptimizationResult, + OptimizationResultStatus, ) from .slsqp_optimizer import SlsqpOptimizer -from ..problems.constraint import Constraint -from ..problems.linear_constraint import LinearConstraint -from ..problems.linear_expression import LinearExpression -from ..problems.quadratic_program import QuadraticProgram -from ..problems.variable import VarType, Variable -from ..converters import MaximizeToMinimize UPDATE_RHO_BY_TEN_PERCENT = 0 UPDATE_RHO_BY_RESIDUALS = 1 diff --git a/qiskit_optimization/algorithms/grover_optimizer.py b/qiskit_optimization/algorithms/grover_optimizer.py index d6a75cde0..66dec73dd 100644 --- a/qiskit_optimization/algorithms/grover_optimizer.py +++ b/qiskit_optimization/algorithms/grover_optimizer.py @@ -16,6 +16,7 @@ import math from copy import deepcopy from typing import Optional, Dict, Union, List, cast +import warnings import numpy as np @@ -24,6 +25,7 @@ from qiskit.utils import QuantumInstance, algorithm_globals from qiskit.algorithms.amplitude_amplifiers.grover import Grover from qiskit.circuit.library import QuadraticForm +from qiskit.primitives import BaseSampler from qiskit.providers import Backend from qiskit.quantum_info import partial_trace from .optimization_algorithm import ( @@ -36,6 +38,7 @@ QuadraticProgramToQubo, QuadraticProgramConverter, ) +from ..exceptions import QiskitOptimizationError from ..problems import Variable from ..problems.quadratic_program import QuadraticProgram @@ -54,6 +57,7 @@ def __init__( Union[QuadraticProgramConverter, List[QuadraticProgramConverter]] ] = None, penalty: Optional[float] = None, + sampler: Optional[BaseSampler] = None, ) -> None: """ Args: @@ -66,20 +70,35 @@ def __init__( :class:`~qiskit_optimization.converters.QuadraticProgramToQubo` will be used. penalty: The penalty factor used in the default :class:`~qiskit_optimization.converters.QuadraticProgramToQubo` converter + sampler: A Sampler to use for sampling the results of the circuits. Raises: + ValueError: If both a quantum instance and sampler are set. TypeError: When there one of converters is an invalid type. """ self._num_value_qubits = num_value_qubits self._num_key_qubits = 0 self._n_iterations = num_iterations - self._quantum_instance = None # type: Optional[QuantumInstance] self._circuit_results = {} # type: dict + self._converters = self._prepare_converters(converters, penalty) - if quantum_instance is not None: - self.quantum_instance = quantum_instance + if quantum_instance is not None and sampler is not None: + raise ValueError("Only one of quantum_instance or sampler can be passed, not both!") - self._converters = self._prepare_converters(converters, penalty) + self._quantum_instance = None # type: Optional[QuantumInstance] + if quantum_instance is not None: + warnings.warn( + "The quantum_instance argument has been superseded by the sampler argument. " + "This argument will be deprecated in a future release and subsequently " + "removed after that.", + category=PendingDeprecationWarning, + stacklevel=2, + ) + with warnings.catch_warnings(): + warnings.simplefilter("ignore", category=PendingDeprecationWarning) + self.quantum_instance = quantum_instance + + self._sampler = sampler @property def quantum_instance(self) -> QuantumInstance: @@ -88,6 +107,13 @@ def quantum_instance(self) -> QuantumInstance: Returns: The quantum instance used in the algorithm. """ + warnings.warn( + "The quantum_instance argument has been superseded by the sampler argument. " + "This argument will be deprecated in a future release and subsequently " + "removed after that.", + category=PendingDeprecationWarning, + stacklevel=2, + ) return self._quantum_instance @quantum_instance.setter @@ -97,6 +123,13 @@ def quantum_instance(self, quantum_instance: Union[Backend, QuantumInstance]) -> Args: quantum_instance: The quantum instance to be used in the algorithm. """ + warnings.warn( + "The GroverOptimizer.quantum_instance setter is pending deprecation. " + "This property will be deprecated in a future release and subsequently " + "removed after that.", + category=PendingDeprecationWarning, + stacklevel=2, + ) if isinstance(quantum_instance, Backend): self._quantum_instance = QuantumInstance(quantum_instance) else: @@ -162,11 +195,16 @@ def solve(self, problem: QuadraticProgram) -> OptimizationResult: The result of the optimizer applied to the problem. Raises: + ValueError: If a quantum instance or a sampler has not been provided. + ValueError: If both a quantum instance and sampler are set. AttributeError: If the quantum instance has not been set. QiskitOptimizationError: If the problem is incompatible with the optimizer. """ - if self.quantum_instance is None: - raise AttributeError("The quantum instance or backend has not been set.") + if self._sampler is None and self._quantum_instance is None: + raise ValueError("A quantum instance or sampler must be provided.") + + if self._quantum_instance is not None and self._sampler is not None: + raise ValueError("Only one of quantum_instance or sampler can be passed, not both!") self._verify_compatibility(problem) @@ -199,7 +237,7 @@ def solve(self, problem: QuadraticProgram) -> OptimizationResult: # Initialize oracle helper object. qr_key_value = QuantumRegister(self._num_key_qubits + self._num_value_qubits) orig_constant = problem_.objective.constant - measurement = not self.quantum_instance.is_statevector + measurement = not (self._quantum_instance and self._quantum_instance.is_statevector) oracle, is_good_state = self._get_oracle(qr_key_value) while not optimum_found: @@ -246,15 +284,19 @@ def solve(self, problem: QuadraticProgram) -> OptimizationResult: threshold = optimum_value # trace out work qubits and store samples - if self._quantum_instance.is_statevector: - indices = list(range(n_key, len(outcome))) - rho = partial_trace(self._circuit_results, indices) - self._circuit_results = cast(Dict, np.diag(rho.data) ** 0.5) - else: + if self._sampler: self._circuit_results = { i[-1 * n_key :]: v for i, v in self._circuit_results.items() } - + else: + if self._quantum_instance.is_statevector: + indices = list(range(n_key, len(outcome))) + rho = partial_trace(self._circuit_results, indices) + self._circuit_results = cast(Dict, np.diag(rho.data) ** 0.5) + else: + self._circuit_results = { + i[-1 * n_key :]: v for i, v in self._circuit_results.items() + } raw_samples = self._eigenvector_to_solutions( self._circuit_results, problem_init ) @@ -312,33 +354,52 @@ def solve(self, problem: QuadraticProgram) -> OptimizationResult: def _measure(self, circuit: QuantumCircuit) -> str: """Get probabilities from the given backend, and picks a random outcome.""" - probs = self._get_probs(circuit) + probs = self._get_prob_dist(circuit) logger.info("Frequencies: %s", probs) # Pick a random outcome. return algorithm_globals.random.choice(list(probs.keys()), 1, p=list(probs.values()))[0] - def _get_probs(self, qc: QuantumCircuit) -> Dict[str, float]: + def _get_prob_dist(self, qc: QuantumCircuit) -> Dict[str, float]: """Gets probabilities from a given backend.""" # Execute job and filter results. - result = self.quantum_instance.execute(qc) - if self.quantum_instance.is_statevector: - state = result.get_statevector(qc) - if not isinstance(state, np.ndarray): - state = state.data - keys = [ - bin(i)[2::].rjust(int(np.log2(len(state))), "0")[::-1] for i in range(0, len(state)) - ] - probs = [abs(a) ** 2 for a in state] - total = math.fsum(probs) - probs = [p / total for p in probs] - hist = {key: prob for key, prob in zip(keys, probs) if prob > 0} - self._circuit_results = state + if self._sampler is not None: + job = self._sampler.run([qc]) + + try: + result = job.result() + except Exception as exc: + raise QiskitOptimizationError("Sampler job failed.") from exc + quasi_dist = result.quasi_dists[0] + bit_length = (len(quasi_dist) - 1).bit_length() + prob_dist = {f"{i:0{bit_length}b}"[::-1]: v for i, v in quasi_dist.items()} + self._circuit_results = { + f"{i:0{bit_length}b}": v**0.5 + for i, v in quasi_dist.items() + if not np.isclose(v, 0) + } else: - state = result.get_counts(qc) - shots = self.quantum_instance.run_config.shots - hist = {key[::-1]: val / shots for key, val in sorted(state.items()) if val > 0} - self._circuit_results = {b: (v / shots) ** 0.5 for (b, v) in state.items()} - return hist + result = self._quantum_instance.execute(qc) + if self._quantum_instance.is_statevector: + state = result.get_statevector(qc) + if not isinstance(state, np.ndarray): + state = state.data + keys = [ + bin(i)[2::].rjust(int(np.log2(len(state))), "0")[::-1] + for i in range(0, len(state)) + ] + probs = [abs(a) ** 2 for a in state] + total = math.fsum(probs) + probs = [p / total for p in probs] + prob_dist = {key: prob for key, prob in zip(keys, probs) if prob > 0} + self._circuit_results = state + else: + state = result.get_counts(qc) + shots = self._quantum_instance.run_config.shots + prob_dist = { + key[::-1]: val / shots for key, val in sorted(state.items()) if val > 0 + } + self._circuit_results = {b: (v / shots) ** 0.5 for (b, v) in state.items()} + return prob_dist @staticmethod def _bin_to_int(v: str, num_value_bits: int) -> int: diff --git a/qiskit_optimization/algorithms/minimum_eigen_optimizer.py b/qiskit_optimization/algorithms/minimum_eigen_optimizer.py index 0a86bba28..e8dc4b870 100644 --- a/qiskit_optimization/algorithms/minimum_eigen_optimizer.py +++ b/qiskit_optimization/algorithms/minimum_eigen_optimizer.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2020, 2021. +# (C) Copyright IBM 2020, 2022. # # 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 @@ -11,24 +11,38 @@ # that they have been altered from the originals. """A wrapper for minimum eigen solvers to be used within the optimization module.""" -from typing import Optional, Union, List, cast +from typing import List, Optional, Union, cast import numpy as np +from qiskit.algorithms.minimum_eigen_solvers import MinimumEigensolver as LegacyMinimumEigensolver +from qiskit.algorithms.minimum_eigen_solvers import ( + MinimumEigensolverResult as LegacyMinimumEigensolverResult, +) +from qiskit.algorithms.minimum_eigensolvers import ( + NumPyMinimumEigensolver, + NumPyMinimumEigensolverResult, + SamplingMinimumEigensolver, + SamplingMinimumEigensolverResult, +) +from qiskit.opflow import OperatorBase, PauliOp, PauliSumOp -from qiskit.algorithms import MinimumEigensolver, MinimumEigensolverResult -from qiskit.opflow import OperatorBase +from ..converters.quadratic_program_to_qubo import QuadraticProgramConverter, QuadraticProgramToQubo +from ..deprecation import DeprecatedType, warn_deprecated +from ..exceptions import QiskitOptimizationError +from ..problems.quadratic_program import QuadraticProgram, Variable from .optimization_algorithm import ( - OptimizationResultStatus, OptimizationAlgorithm, OptimizationResult, + OptimizationResultStatus, SolutionSample, ) -from ..exceptions import QiskitOptimizationError -from ..converters.quadratic_program_to_qubo import ( - QuadraticProgramToQubo, - QuadraticProgramConverter, -) -from ..problems.quadratic_program import QuadraticProgram, Variable + +MinimumEigensolver = Union[ + SamplingMinimumEigensolver, NumPyMinimumEigensolver, LegacyMinimumEigensolver +] +MinimumEigensolverResult = Union[ + SamplingMinimumEigensolverResult, NumPyMinimumEigensolverResult, LegacyMinimumEigensolverResult +] class MinimumEigenOptimizationResult(OptimizationResult): @@ -137,11 +151,18 @@ def __init__( TypeError: When one of converters has an invalid type. QiskitOptimizationError: When the minimum eigensolver does not return an eigenstate. """ - + if isinstance(min_eigen_solver, LegacyMinimumEigensolver): + warn_deprecated( + "0.5.0", + DeprecatedType.ARGUMENT, + f"min_eigen_solver as {LegacyMinimumEigensolver.__name__}", + new_name=f"min_eigen_solver as {SamplingMinimumEigensolver.__name__} " + f"or {NumPyMinimumEigensolver.__name__}", + ) if not min_eigen_solver.supports_aux_operators(): raise QiskitOptimizationError( "Given MinimumEigensolver does not return the eigenstate " - + "and is not supported by the MinimumEigenOptimizer." + "and is not supported by the MinimumEigenOptimizer." ) self._min_eigen_solver = min_eigen_solver self._penalty = penalty @@ -206,6 +227,9 @@ def _solve_internal( # only try to solve non-empty Ising Hamiltonians eigen_result: Optional[MinimumEigensolverResult] = None if operator.num_qubits > 0: + # NumPyEigensolver does not accept PauliOp but PauliSumOp + if isinstance(operator, PauliOp): + operator = PauliSumOp.from_list([(operator.primitive.to_label(), operator.coeff)]) # approximate ground state of operator using min eigen solver eigen_result = self._min_eigen_solver.compute_minimum_eigenvalue(operator) # analyze results diff --git a/qiskit_optimization/algorithms/optimization_algorithm.py b/qiskit_optimization/algorithms/optimization_algorithm.py index 050d78ca5..4b8fb3080 100644 --- a/qiskit_optimization/algorithms/optimization_algorithm.py +++ b/qiskit_optimization/algorithms/optimization_algorithm.py @@ -15,14 +15,16 @@ from abc import ABC, abstractmethod from dataclasses import dataclass from enum import Enum -from typing import List, Union, Any, Optional, Dict, Type, Tuple, cast +from typing import Any, Dict, List, Optional, Tuple, Type, Union, cast from warnings import warn import numpy as np +from qiskit.opflow import DictStateFn, StateFn +from qiskit.quantum_info import Statevector +from qiskit.result import QuasiDistribution -from qiskit.opflow import StateFn, DictStateFn +from ..converters.quadratic_program_to_qubo import QuadraticProgramConverter, QuadraticProgramToQubo from ..exceptions import QiskitOptimizationError -from ..converters.quadratic_program_to_qubo import QuadraticProgramToQubo, QuadraticProgramConverter from ..problems.quadratic_program import QuadraticProgram, Variable @@ -518,7 +520,7 @@ def _interpret_samples( @staticmethod def _eigenvector_to_solutions( - eigenvector: Union[dict, np.ndarray, StateFn], + eigenvector: Union[QuasiDistribution, Statevector, dict, np.ndarray, StateFn], qubo: QuadraticProgram, min_probability: float = 1e-6, ) -> List[SolutionSample]: @@ -566,7 +568,25 @@ def generate_solution(bitstr, qubo, probability): ) solutions = [] - if isinstance(eigenvector, dict): + if isinstance(eigenvector, QuasiDistribution): + probabilities = eigenvector.binary_probabilities() + # iterate over all samples + for bitstr, sampling_probability in probabilities.items(): + # add the bitstring, if the sampling probability exceeds the threshold + if sampling_probability >= min_probability: + solutions.append(generate_solution(bitstr, qubo, sampling_probability)) + + elif isinstance(eigenvector, Statevector): + probabilities = eigenvector.probabilities() + num_qubits = eigenvector.num_qubits + # iterate over all states and their sampling probabilities + for i, sampling_probability in enumerate(probabilities): + # add the i-th state if the sampling probability exceeds the threshold + if sampling_probability >= min_probability: + bitstr = f"{i:b}".rjust(num_qubits, "0") + solutions.append(generate_solution(bitstr, qubo, sampling_probability)) + + elif isinstance(eigenvector, dict): # When eigenvector is a dict, square the values since the values are normalized. # See https://github.com/Qiskit/qiskit-terra/pull/5496 for more details. probabilities = {bitstr: val**2 for (bitstr, val) in eigenvector.items()} @@ -579,7 +599,6 @@ def generate_solution(bitstr, qubo, probability): elif isinstance(eigenvector, np.ndarray): num_qubits = int(np.log2(eigenvector.size)) probabilities = np.abs(eigenvector * eigenvector.conj()) - # iterate over all states and their sampling probabilities for i, sampling_probability in enumerate(probabilities): # add the i-th state if the sampling probability exceeds the threshold @@ -588,6 +607,8 @@ def generate_solution(bitstr, qubo, probability): solutions.append(generate_solution(bitstr, qubo, sampling_probability)) else: - raise TypeError("Unsupported format of eigenvector. Provide a dict or numpy.ndarray.") - + raise TypeError( + f"Eigenvector should be QuasiDistribution, Statevector, dict or numpy.ndarray. " + f"But, it was {type(eigenvector)}." + ) return solutions diff --git a/qiskit_optimization/algorithms/recursive_minimum_eigen_optimizer.py b/qiskit_optimization/algorithms/recursive_minimum_eigen_optimizer.py index 26c1184a6..737fc56d9 100644 --- a/qiskit_optimization/algorithms/recursive_minimum_eigen_optimizer.py +++ b/qiskit_optimization/algorithms/recursive_minimum_eigen_optimizer.py @@ -14,28 +14,22 @@ from copy import deepcopy from enum import Enum -from typing import Optional, Union, List, Tuple, Dict, cast +from typing import Dict, List, Optional, Tuple, Union, cast import numpy as np -from qiskit.algorithms import NumPyMinimumEigensolver +from qiskit.algorithms.minimum_eigensolvers import NumPyMinimumEigensolver from qiskit.utils.validation import validate_min -from .minimum_eigen_optimizer import ( - MinimumEigenOptimizer, - MinimumEigenOptimizationResult, -) +from ..converters.quadratic_program_to_qubo import QuadraticProgramConverter, QuadraticProgramToQubo +from ..exceptions import QiskitOptimizationError +from ..problems import Variable +from ..problems.quadratic_program import QuadraticProgram +from .minimum_eigen_optimizer import MinimumEigenOptimizationResult, MinimumEigenOptimizer from .optimization_algorithm import ( - OptimizationResultStatus, OptimizationAlgorithm, OptimizationResult, + OptimizationResultStatus, ) -from ..converters.quadratic_program_to_qubo import ( - QuadraticProgramToQubo, - QuadraticProgramConverter, -) -from ..exceptions import QiskitOptimizationError -from ..problems import Variable -from ..problems.quadratic_program import QuadraticProgram class IntermediateResult(Enum): diff --git a/qiskit_optimization/algorithms/warm_start_qaoa_optimizer.py b/qiskit_optimization/algorithms/warm_start_qaoa_optimizer.py index 98016cbdd..62dbbe9a5 100644 --- a/qiskit_optimization/algorithms/warm_start_qaoa_optimizer.py +++ b/qiskit_optimization/algorithms/warm_start_qaoa_optimizer.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2021. +# (C) Copyright IBM 2021, 2022. # # 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 @@ -14,26 +14,19 @@ import copy from abc import ABC, abstractmethod -from typing import Optional, List, Union, Dict, Tuple, cast +from typing import Dict, List, Optional, Tuple, Union, cast import numpy as np from qiskit import QuantumCircuit -from qiskit.algorithms import QAOA +from qiskit.algorithms.minimum_eigensolvers import QAOA from qiskit.circuit import Parameter -from .minimum_eigen_optimizer import ( - MinimumEigenOptimizer, - MinimumEigenOptimizationResult, -) -from .optimization_algorithm import ( - OptimizationAlgorithm, - OptimizationResultStatus, - SolutionSample, -) from ..converters.quadratic_program_converter import QuadraticProgramConverter from ..exceptions import QiskitOptimizationError from ..problems.quadratic_program import QuadraticProgram from ..problems.variable import VarType +from .minimum_eigen_optimizer import MinimumEigenOptimizationResult, MinimumEigenOptimizer +from .optimization_algorithm import OptimizationAlgorithm, OptimizationResultStatus, SolutionSample class BaseAggregator(ABC): diff --git a/qiskit_optimization/deprecation.py b/qiskit_optimization/deprecation.py index c87ab4f7c..c14b7d72d 100644 --- a/qiskit_optimization/deprecation.py +++ b/qiskit_optimization/deprecation.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2021. +# (C) Copyright IBM 2021, 2022. # # 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 @@ -421,3 +421,12 @@ def deprecate_function( return _deprecate_object( version, DeprecatedType.FUNCTION, new_type, new_name, additional_msg, stack_level ) + + +def clear_deprecated_objects() -> None: + """Clear deprecated object cache + + Returns: + None + """ + _DEPRECATED_OBJECTS.clear() diff --git a/releasenotes/notes/grover-opt-primitive-de82d051d6cee2e4.yaml b/releasenotes/notes/grover-opt-primitive-de82d051d6cee2e4.yaml new file mode 100644 index 000000000..032867adf --- /dev/null +++ b/releasenotes/notes/grover-opt-primitive-de82d051d6cee2e4.yaml @@ -0,0 +1,9 @@ +--- +features: + - | + The :class:`~.GroverOptimizer` class has a new keyword argument, ``sampler`` which is + used to run the algorithm using an instance of the :class:`~.BaseSampler` + interface to calculate the results. This new argument supersedes the + the ``quantum_instance`` argument and accordingly, ``quantum_instance`` + is pending deprecation and will be deprecated and subsequently removed in + future releases. diff --git a/test/algorithms/legacy/test_min_eigen_optimizer.py b/test/algorithms/legacy/test_min_eigen_optimizer.py new file mode 100644 index 000000000..e4e7e529d --- /dev/null +++ b/test/algorithms/legacy/test_min_eigen_optimizer.py @@ -0,0 +1,397 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2018, 2022. +# +# 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 +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +""" Test Min Eigen Optimizer with the legacy MinimumEigensolver""" + +import unittest +from test.optimization_test_case import QiskitOptimizationTestCase + +from test.runtime.fake_vqeruntime import FakeVQERuntimeProvider, FakeQAOARuntimeProvider + +import numpy as np +from ddt import data, ddt +from qiskit import BasicAer +from qiskit.algorithms import QAOA, VQE, NumPyMinimumEigensolver +from qiskit.algorithms.optimizers import COBYLA, SPSA +from qiskit.circuit.library import TwoLocal +from qiskit.providers.basicaer import QasmSimulatorPy +from qiskit.utils import QuantumInstance, algorithm_globals +import qiskit_optimization.optionals as _optionals +from qiskit_optimization.algorithms import ( + CplexOptimizer, + MinimumEigenOptimizer, + MinimumEigenOptimizationResult, +) +from qiskit_optimization.algorithms.optimization_algorithm import ( + OptimizationResultStatus, +) +from qiskit_optimization.converters import ( + InequalityToEquality, + IntegerToBinary, + LinearEqualityToPenalty, + MaximizeToMinimize, + QuadraticProgramToQubo, +) +from qiskit_optimization.problems import QuadraticProgram +from qiskit_optimization.runtime import VQEProgram, QAOAProgram +from qiskit_optimization.deprecation import clear_deprecated_objects + + +@ddt +class TestMinEigenOptimizer(QiskitOptimizationTestCase): + """Min Eigen Optimizer Tests.""" + + def setUp(self): + super().setUp() + + # setup minimum eigen solvers + self.min_eigen_solvers = {} + + # exact eigen solver + self.min_eigen_solvers["exact"] = NumPyMinimumEigensolver() + + # QAOA + optimizer = COBYLA() + self.min_eigen_solvers["qaoa"] = QAOA(optimizer=optimizer) + # simulators + self.sv_simulator = QuantumInstance( + BasicAer.get_backend("statevector_simulator"), + seed_simulator=123, + seed_transpiler=123, + ) + self.qasm_simulator = QuantumInstance( + BasicAer.get_backend("qasm_simulator"), + seed_simulator=123, + seed_transpiler=123, + ) + # test minimize + self.op_minimize = QuadraticProgram() + self.op_minimize.integer_var(0, 3, "x") + self.op_minimize.binary_var("y") + self.op_minimize.minimize(linear={"x": 1, "y": 2}) + self.op_minimize.linear_constraint(linear={"x": 1, "y": 1}, sense=">=", rhs=1, name="xy") + + # test maximize + self.op_maximize = QuadraticProgram() + self.op_maximize.integer_var(0, 3, "x") + self.op_maximize.binary_var("y") + self.op_maximize.maximize(linear={"x": 1, "y": 2}) + self.op_maximize.linear_constraint(linear={"x": 1, "y": 1}, sense="<=", rhs=1, name="xy") + + # test bit ordering + self.op_ordering = QuadraticProgram("bit ordering") + self.op_ordering.binary_var("x") + self.op_ordering.binary_var("y") + self.op_ordering.minimize(linear={"x": 1, "y": -2}) + + @data( + ("exact", None, "op_ip1.lp"), + ("qaoa", "statevector_simulator", "op_ip1.lp"), + ("qaoa", "qasm_simulator", "op_ip1.lp"), + ) + @unittest.skipIf(not _optionals.HAS_CPLEX, "CPLEX not available.") + def test_min_eigen_optimizer(self, config): + """Min Eigen Optimizer Test""" + try: + # unpack configuration + min_eigen_solver_name, backend, filename = config + + # get minimum eigen solver + min_eigen_solver = self.min_eigen_solvers[min_eigen_solver_name] + if backend: + min_eigen_solver.quantum_instance = BasicAer.get_backend(backend) + + # construct minimum eigen optimizer + min_eigen_optimizer = MinimumEigenOptimizer(min_eigen_solver) + + # load optimization problem + problem = QuadraticProgram() + lp_file = self.get_resource_path(filename, "algorithms/resources") + problem.read_from_lp_file(lp_file) + + # solve problem with cplex + cplex = CplexOptimizer(cplex_parameters={"threads": 1, "randomseed": 1}) + cplex_result = cplex.solve(problem) + + # solve problem + result = min_eigen_optimizer.solve(problem) + self.assertIsNotNone(result) + + # analyze results + self.assertAlmostEqual(cplex_result.fval, result.fval) + + # check that eigensolver result is present + self.assertIsNotNone(result.min_eigen_solver_result) + except RuntimeError as ex: + self.fail(str(ex)) + + @data( + ("op_ip1.lp", -470, 12, OptimizationResultStatus.SUCCESS), + ("op_ip1.lp", np.inf, None, OptimizationResultStatus.FAILURE), + ) + @unittest.skipIf(not _optionals.HAS_CPLEX, "CPLEX not available.") + def test_min_eigen_optimizer_with_filter(self, config): + """Min Eigen Optimizer Test""" + try: + # unpack configuration + filename, lowerbound, fval, status = config + + # get minimum eigen solver + min_eigen_solver = NumPyMinimumEigensolver() + + # set filter + # pylint: disable=unused-argument + def filter_criterion(x, v, aux): + return v > lowerbound + + min_eigen_solver.filter_criterion = filter_criterion + + # construct minimum eigen optimizer + min_eigen_optimizer = MinimumEigenOptimizer(min_eigen_solver) + + # load optimization problem + problem = QuadraticProgram() + lp_file = self.get_resource_path(filename, "algorithms/resources") + problem.read_from_lp_file(lp_file) + + # solve problem + result = min_eigen_optimizer.solve(problem) + self.assertIsNotNone(result) + + # analyze results + self.assertAlmostEqual(fval, result.fval) + self.assertEqual(status, result.status) + + # check that eigensolver result is present + self.assertIsNotNone(result.min_eigen_solver_result) + except RuntimeError as ex: + self.fail(str(ex)) + + def test_converter_list(self): + """Test converter list""" + op = QuadraticProgram() + op.integer_var(0, 3, "x") + op.binary_var("y") + + op.maximize(linear={"x": 1, "y": 2}) + op.linear_constraint(linear={"x": 1, "y": 1}, sense="LE", rhs=3, name="xy_leq") + min_eigen_solver = NumPyMinimumEigensolver() + # a single converter + qp2qubo = QuadraticProgramToQubo() + min_eigen_optimizer = MinimumEigenOptimizer(min_eigen_solver, converters=qp2qubo) + result = min_eigen_optimizer.solve(op) + self.assertEqual(result.fval, 4) + # a list of converters + ineq2eq = InequalityToEquality() + int2bin = IntegerToBinary() + penalize = LinearEqualityToPenalty() + max2min = MaximizeToMinimize() + converters = [ineq2eq, int2bin, penalize, max2min] + min_eigen_optimizer = MinimumEigenOptimizer(min_eigen_solver, converters=converters) + result = min_eigen_optimizer.solve(op) + self.assertEqual(result.fval, 4) + with self.assertRaises(TypeError): + invalid = [qp2qubo, "invalid converter"] + MinimumEigenOptimizer(min_eigen_solver, converters=invalid) + + def test_samples_numpy_eigen_solver(self): + """Test samples for NumPyMinimumEigensolver""" + # test minimize + min_eigen_solver = NumPyMinimumEigensolver() + min_eigen_optimizer = MinimumEigenOptimizer(min_eigen_solver) + result = min_eigen_optimizer.solve(self.op_minimize) + opt_sol = 1 + success = OptimizationResultStatus.SUCCESS + self.assertEqual(result.fval, opt_sol) + self.assertEqual(len(result.samples), 1) + np.testing.assert_array_almost_equal(result.samples[0].x, [1, 0]) + self.assertAlmostEqual(result.samples[0].fval, opt_sol) + self.assertAlmostEqual(result.samples[0].probability, 1.0) + self.assertEqual(result.samples[0].status, success) + self.assertEqual(len(result.raw_samples), 1) + np.testing.assert_array_almost_equal(result.raw_samples[0].x, [1, 0, 0, 0, 0]) + self.assertAlmostEqual(result.raw_samples[0].fval, opt_sol) + self.assertAlmostEqual(result.raw_samples[0].probability, 1.0) + self.assertEqual(result.raw_samples[0].status, success) + # test maximize + min_eigen_solver = NumPyMinimumEigensolver() + min_eigen_optimizer = MinimumEigenOptimizer(min_eigen_solver) + result = min_eigen_optimizer.solve(self.op_maximize) + opt_sol = 2 + self.assertEqual(result.fval, opt_sol) + self.assertEqual(len(result.samples), 1) + np.testing.assert_array_almost_equal(result.samples[0].x, [0, 1]) + self.assertAlmostEqual(result.samples[0].fval, opt_sol) + self.assertAlmostEqual(result.samples[0].probability, 1.0) + self.assertEqual(result.samples[0].status, success) + self.assertEqual(len(result.raw_samples), 1) + np.testing.assert_array_almost_equal(result.raw_samples[0].x, [0, 0, 1, 0]) + # optimizer internally deals with minimization problem + self.assertAlmostEqual( + self.op_maximize.objective.sense.value * result.raw_samples[0].fval, opt_sol + ) + self.assertAlmostEqual(result.raw_samples[0].probability, 1.0) + self.assertEqual(result.raw_samples[0].status, success) + + @data("sv", "qasm") + def test_samples_qaoa(self, simulator): + """Test samples for QAOA""" + # test minimize + algorithm_globals.random_seed = 4 + quantum_instance = self.sv_simulator if simulator == "sv" else self.qasm_simulator + qaoa = QAOA(optimizer=COBYLA(), quantum_instance=quantum_instance, reps=2) + min_eigen_optimizer = MinimumEigenOptimizer(qaoa) + result = min_eigen_optimizer.solve(self.op_minimize) + success = OptimizationResultStatus.SUCCESS + opt_sol = 1 + self.assertAlmostEqual(sum(s.probability for s in result.samples), 1) + self.assertAlmostEqual(sum(s.probability for s in result.raw_samples), 1) + self.assertAlmostEqual(min(s.fval for s in result.samples), 0) + self.assertAlmostEqual(min(s.fval for s in result.samples if s.status == success), opt_sol) + self.assertAlmostEqual(min(s.fval for s in result.raw_samples), opt_sol) + for sample in result.raw_samples: + self.assertEqual(sample.status, success) + np.testing.assert_array_almost_equal(result.x, [1, 0]) + self.assertAlmostEqual(result.fval, result.samples[0].fval) + self.assertEqual(result.status, result.samples[0].status) + self.assertAlmostEqual(result.samples[0].fval, opt_sol) + self.assertEqual(result.samples[0].status, success) + np.testing.assert_array_almost_equal(result.raw_samples[0].x, [1, 0, 0, 0, 0]) + self.assertAlmostEqual(result.raw_samples[0].fval, opt_sol) + self.assertEqual(result.raw_samples[0].status, success) + # test maximize + opt_sol = 2 + qaoa = QAOA(optimizer=COBYLA(), quantum_instance=quantum_instance, reps=2) + min_eigen_optimizer = MinimumEigenOptimizer(qaoa) + result = min_eigen_optimizer.solve(self.op_maximize) + self.assertAlmostEqual(sum(s.probability for s in result.samples), 1) + self.assertAlmostEqual(sum(s.probability for s in result.raw_samples), 1) + self.assertAlmostEqual(max(s.fval for s in result.samples), 5) + self.assertAlmostEqual(max(s.fval for s in result.samples if s.status == success), opt_sol) + # optimizer internally deals with minimization problem + self.assertAlmostEqual( + max(self.op_maximize.objective.sense.value * s.fval for s in result.raw_samples), + opt_sol, + ) + for sample in result.raw_samples: + self.assertEqual(sample.status, success) + np.testing.assert_array_almost_equal(result.x, [0, 1]) + self.assertEqual(result.fval, opt_sol) + self.assertEqual(result.status, success) + np.testing.assert_array_almost_equal(result.samples[0].x, [0, 1]) + self.assertAlmostEqual(result.samples[0].fval, opt_sol) + self.assertEqual(result.samples[0].status, success) + np.testing.assert_array_almost_equal(result.raw_samples[0].x, [0, 0, 1, 0]) + # optimizer internally deals with minimization problem + self.assertAlmostEqual( + self.op_maximize.objective.sense.value * result.raw_samples[0].fval, opt_sol + ) + self.assertEqual(result.raw_samples[0].status, success) + # test bit ordering + opt_sol = -2 + qaoa = QAOA(optimizer=COBYLA(), quantum_instance=quantum_instance, reps=2) + min_eigen_optimizer = MinimumEigenOptimizer(qaoa) + result = min_eigen_optimizer.solve(self.op_ordering) + self.assertEqual(result.fval, opt_sol) + np.testing.assert_array_almost_equal(result.x, [0, 1]) + self.assertEqual(result.status, success) + result.raw_samples.sort(key=lambda x: x.probability, reverse=True) + np.testing.assert_array_almost_equal(result.x, result.raw_samples[0].x) + self.assertAlmostEqual(sum(s.probability for s in result.samples), 1, delta=1e-5) + self.assertAlmostEqual(sum(s.probability for s in result.raw_samples), 1, delta=1e-5) + self.assertAlmostEqual(min(s.fval for s in result.samples), -2) + self.assertAlmostEqual(min(s.fval for s in result.samples if s.status == success), opt_sol) + self.assertAlmostEqual(min(s.fval for s in result.raw_samples), opt_sol) + for sample in result.raw_samples: + self.assertEqual(sample.status, success) + np.testing.assert_array_almost_equal(result.samples[0].x, [0, 1]) + self.assertAlmostEqual(result.samples[0].fval, opt_sol) + self.assertEqual(result.samples[0].status, success) + np.testing.assert_array_almost_equal(result.raw_samples[0].x, [0, 1]) + self.assertAlmostEqual(result.raw_samples[0].fval, opt_sol) + self.assertEqual(result.raw_samples[0].status, success) + + @data("sv", "qasm") + def test_samples_vqe(self, simulator): + """Test samples for VQE""" + # test minimize + algorithm_globals.random_seed = 1 + quantum_instance = self.sv_simulator if simulator == "sv" else self.qasm_simulator + opt_sol = -2 + success = OptimizationResultStatus.SUCCESS + optimizer = SPSA(maxiter=100) + ry_ansatz = TwoLocal(5, "ry", "cz", reps=3, entanglement="full") + vqe_mes = VQE(ry_ansatz, optimizer=optimizer, quantum_instance=quantum_instance) + vqe = MinimumEigenOptimizer(vqe_mes) + results = vqe.solve(self.op_ordering) + self.assertEqual(results.fval, opt_sol) + np.testing.assert_array_almost_equal(results.x, [0, 1]) + self.assertEqual(results.status, success) + results.raw_samples.sort(key=lambda x: x.probability, reverse=True) + np.testing.assert_array_almost_equal(results.x, results.raw_samples[0].x) + self.assertAlmostEqual(sum(s.probability for s in results.samples), 1, delta=1e-5) + self.assertAlmostEqual(sum(s.probability for s in results.raw_samples), 1, delta=1e-5) + self.assertAlmostEqual(min(s.fval for s in results.samples), -2) + self.assertAlmostEqual(min(s.fval for s in results.samples if s.status == success), opt_sol) + self.assertAlmostEqual(min(s.fval for s in results.raw_samples), opt_sol) + for sample in results.raw_samples: + self.assertEqual(sample.status, success) + np.testing.assert_array_almost_equal(results.samples[0].x, [0, 1]) + self.assertAlmostEqual(results.samples[0].fval, opt_sol) + self.assertEqual(results.samples[0].status, success) + np.testing.assert_array_almost_equal(results.raw_samples[0].x, [0, 1]) + self.assertAlmostEqual(results.raw_samples[0].fval, opt_sol) + self.assertEqual(results.raw_samples[0].status, success) + + @data("vqe", "qaoa") + def test_runtime(self, subroutine): + """Test vqe and qaoa runtime""" + optimizer = {"name": "SPSA", "maxiter": 100} + backend = QasmSimulatorPy() + + if subroutine == "vqe": + ry_ansatz = TwoLocal(5, "ry", "cz", reps=3, entanglement="full") + initial_point = np.random.default_rng(42).random(ry_ansatz.num_parameters) + solver = VQEProgram( + ansatz=ry_ansatz, + optimizer=optimizer, + initial_point=initial_point, + backend=backend, + provider=FakeVQERuntimeProvider(), + ) + else: + reps = 2 + initial_point = np.random.default_rng(42).random(2 * reps) + solver = QAOAProgram( + optimizer=optimizer, + reps=reps, + initial_point=initial_point, + backend=backend, + provider=FakeQAOARuntimeProvider(), + ) + + opt = MinimumEigenOptimizer(solver) + result = opt.solve(self.op_ordering) + self.assertIsInstance(result, MinimumEigenOptimizationResult) + + def test_deprecation(self): + """Test deprecation warning""" + clear_deprecated_objects() + optimizer = SPSA(maxiter=100) + ry_ansatz = TwoLocal(5, "ry", "cz", reps=3, entanglement="full") + vqe_mes = VQE(ry_ansatz, optimizer=optimizer, quantum_instance=QasmSimulatorPy()) + with self.assertWarns(DeprecationWarning): + _ = MinimumEigenOptimizer(vqe_mes) + + +if __name__ == "__main__": + unittest.main() diff --git a/test/algorithms/legacy/test_recursive_optimization.py b/test/algorithms/legacy/test_recursive_optimization.py new file mode 100644 index 000000000..efe8399e6 --- /dev/null +++ b/test/algorithms/legacy/test_recursive_optimization.py @@ -0,0 +1,201 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2018, 2022. +# +# 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 +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +"""Test Recursive Min Eigen Optimizer with legacy MinimumEigensolver.""" + +import unittest +from test import QiskitOptimizationTestCase + +import numpy as np + +from qiskit import BasicAer +from qiskit.utils import algorithm_globals, QuantumInstance + +from qiskit.algorithms import NumPyMinimumEigensolver, QAOA + +import qiskit_optimization.optionals as _optionals +from qiskit_optimization.algorithms import ( + MinimumEigenOptimizer, + CplexOptimizer, + RecursiveMinimumEigenOptimizer, + WarmStartQAOAOptimizer, + SlsqpOptimizer, +) +from qiskit_optimization.algorithms.recursive_minimum_eigen_optimizer import ( + IntermediateResult, +) +from qiskit_optimization.problems import QuadraticProgram +from qiskit_optimization.converters import ( + IntegerToBinary, + InequalityToEquality, + LinearEqualityToPenalty, + QuadraticProgramToQubo, +) + + +class TestRecursiveMinEigenOptimizer(QiskitOptimizationTestCase): + """Recursive Min Eigen Optimizer Tests.""" + + @unittest.skipIf(not _optionals.HAS_CPLEX, "CPLEX not available.") + def test_recursive_min_eigen_optimizer(self): + """Test the recursive minimum eigen optimizer.""" + filename = "op_ip1.lp" + # get minimum eigen solver + min_eigen_solver = NumPyMinimumEigensolver() + + # construct minimum eigen optimizer + min_eigen_optimizer = MinimumEigenOptimizer(min_eigen_solver) + recursive_min_eigen_optimizer = RecursiveMinimumEigenOptimizer( + min_eigen_optimizer, min_num_vars=4 + ) + + # load optimization problem + problem = QuadraticProgram() + lp_file = self.get_resource_path(filename, "algorithms/resources") + problem.read_from_lp_file(lp_file) + + # solve problem with cplex + cplex = CplexOptimizer() + cplex_result = cplex.solve(problem) + + # solve problem + result = recursive_min_eigen_optimizer.solve(problem) + + # analyze results + np.testing.assert_array_almost_equal(cplex_result.x, result.x, 4) + self.assertAlmostEqual(cplex_result.fval, result.fval) + + @unittest.skipIf(not _optionals.HAS_CPLEX, "CPLEX not available.") + def test_recursive_history(self): + """Tests different options for history.""" + filename = "op_ip1.lp" + # load optimization problem + problem = QuadraticProgram() + lp_file = self.get_resource_path(filename, "algorithms/resources") + problem.read_from_lp_file(lp_file) + + # get minimum eigen solver + min_eigen_solver = NumPyMinimumEigensolver() + + # construct minimum eigen optimizer + min_eigen_optimizer = MinimumEigenOptimizer(min_eigen_solver) + + # no history + recursive_min_eigen_optimizer = RecursiveMinimumEigenOptimizer( + min_eigen_optimizer, + min_num_vars=4, + history=IntermediateResult.NO_ITERATIONS, + ) + result = recursive_min_eigen_optimizer.solve(problem) + self.assertIsNotNone(result.replacements) + self.assertIsNotNone(result.history) + self.assertIsNotNone(result.history[0]) + self.assertEqual(len(result.history[0]), 0) + self.assertIsNone(result.history[1]) + + # only last iteration in the history + recursive_min_eigen_optimizer = RecursiveMinimumEigenOptimizer( + min_eigen_optimizer, + min_num_vars=4, + history=IntermediateResult.LAST_ITERATION, + ) + result = recursive_min_eigen_optimizer.solve(problem) + self.assertIsNotNone(result.replacements) + self.assertIsNotNone(result.history) + self.assertIsNotNone(result.history[0]) + self.assertEqual(len(result.history[0]), 0) + self.assertIsNotNone(result.history[1]) + + # full history + recursive_min_eigen_optimizer = RecursiveMinimumEigenOptimizer( + min_eigen_optimizer, + min_num_vars=4, + history=IntermediateResult.ALL_ITERATIONS, + ) + result = recursive_min_eigen_optimizer.solve(problem) + self.assertIsNotNone(result.replacements) + self.assertIsNotNone(result.history) + self.assertIsNotNone(result.history[0]) + self.assertGreater(len(result.history[0]), 1) + self.assertIsNotNone(result.history[1]) + + @unittest.skipIf(not _optionals.HAS_CPLEX, "CPLEX not available.") + def test_recursive_warm_qaoa(self): + """Test the recursive optimizer with warm start qaoa.""" + seed = 1234 + algorithm_globals.random_seed = seed + backend = BasicAer.get_backend("statevector_simulator") + qaoa = QAOA( + quantum_instance=QuantumInstance( + backend=backend, seed_simulator=seed, seed_transpiler=seed + ), + reps=1, + ) + warm_qaoa = WarmStartQAOAOptimizer( + pre_solver=SlsqpOptimizer(), relax_for_pre_solver=True, qaoa=qaoa + ) + + recursive_min_eigen_optimizer = RecursiveMinimumEigenOptimizer(warm_qaoa, min_num_vars=4) + + # load optimization problem + problem = QuadraticProgram() + lp_file = self.get_resource_path("op_ip1.lp", "algorithms/resources") + problem.read_from_lp_file(lp_file) + + # solve problem with cplex + cplex = CplexOptimizer(cplex_parameters={"threads": 1, "randomseed": 1}) + cplex_result = cplex.solve(problem) + + # solve problem + result = recursive_min_eigen_optimizer.solve(problem) + + # analyze results + np.testing.assert_array_almost_equal(cplex_result.x, result.x, 4) + self.assertAlmostEqual(cplex_result.fval, result.fval) + + def test_converter_list(self): + """Test converter list""" + op = QuadraticProgram() + op.integer_var(0, 3, "x") + op.binary_var("y") + + op.maximize(linear={"x": 1, "y": 2}) + op.linear_constraint(linear={"y": 1, "x": 1}, sense="LE", rhs=3, name="xy_leq") + + # construct minimum eigen optimizer + min_eigen_solver = NumPyMinimumEigensolver() + min_eigen_optimizer = MinimumEigenOptimizer(min_eigen_solver) + # a single converter + qp2qubo = QuadraticProgramToQubo() + recursive_min_eigen_optimizer = RecursiveMinimumEigenOptimizer( + min_eigen_optimizer, min_num_vars=2, converters=qp2qubo + ) + result = recursive_min_eigen_optimizer.solve(op) + self.assertEqual(result.fval, 4) + # a list of converters + ineq2eq = InequalityToEquality() + int2bin = IntegerToBinary() + penalize = LinearEqualityToPenalty() + converters = [ineq2eq, int2bin, penalize] + recursive_min_eigen_optimizer = RecursiveMinimumEigenOptimizer( + min_eigen_optimizer, min_num_vars=2, converters=converters + ) + result = recursive_min_eigen_optimizer.solve(op) + self.assertEqual(result.fval, 4) + # invalid converters + with self.assertRaises(TypeError): + invalid = [qp2qubo, "invalid converter"] + RecursiveMinimumEigenOptimizer(min_eigen_optimizer, min_num_vars=2, converters=invalid) + + +if __name__ == "__main__": + unittest.main() diff --git a/test/algorithms/legacy/test_warm_start_qaoa.py b/test/algorithms/legacy/test_warm_start_qaoa.py new file mode 100644 index 000000000..550cf0cc8 --- /dev/null +++ b/test/algorithms/legacy/test_warm_start_qaoa.py @@ -0,0 +1,134 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021, 2022. +# +# 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 +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +""" Test warm start QAOA optimizer with legacy MinimumEigensolver. """ + +import unittest +from test import QiskitOptimizationTestCase + +import numpy as np + +from docplex.mp.model import Model +from qiskit import BasicAer +from qiskit.algorithms import QAOA + +import qiskit_optimization.optionals as _optionals +from qiskit_optimization.algorithms import SlsqpOptimizer +from qiskit_optimization.algorithms.goemans_williamson_optimizer import ( + GoemansWilliamsonOptimizer, +) +from qiskit_optimization.algorithms.warm_start_qaoa_optimizer import ( + MeanAggregator, + WarmStartQAOAOptimizer, +) +from qiskit_optimization.applications.max_cut import Maxcut +from qiskit_optimization.translators import from_docplex_mp + + +class TestWarmStartQAOAOptimizer(QiskitOptimizationTestCase): + """Tests for the warm start QAOA optimizer.""" + + @unittest.skipIf(not _optionals.HAS_CVXPY, "CVXPY not available.") + def test_max_cut(self): + """Basic test on the max cut problem.""" + graph = np.array( + [ + [0.0, 1.0, 2.0, 0.0], + [1.0, 0.0, 1.0, 0.0], + [2.0, 1.0, 0.0, 1.0], + [0.0, 0.0, 1.0, 0.0], + ] + ) + + presolver = GoemansWilliamsonOptimizer(num_cuts=10) + problem = Maxcut(graph).to_quadratic_program() + + backend = BasicAer.get_backend("statevector_simulator") + qaoa = QAOA(quantum_instance=backend, reps=1) + aggregator = MeanAggregator() + optimizer = WarmStartQAOAOptimizer( + pre_solver=presolver, + relax_for_pre_solver=False, + qaoa=qaoa, + epsilon=0.25, + num_initial_solutions=10, + aggregator=aggregator, + ) + result_warm = optimizer.solve(problem) + + self.assertIsNotNone(result_warm) + self.assertIsNotNone(result_warm.x) + np.testing.assert_almost_equal([0, 0, 1, 0], result_warm.x, 3) + self.assertIsNotNone(result_warm.fval) + np.testing.assert_almost_equal(4, result_warm.fval, 3) + + def test_constrained_binary(self): + """Constrained binary optimization problem.""" + model = Model() + v = model.binary_var(name="v") + w = model.binary_var(name="w") + # pylint:disable=invalid-name + t = model.binary_var(name="t") + + model.minimize(v + w + t) + model.add_constraint(2 * v + 10 * w + t <= 3, "cons1") + model.add_constraint(v + w + t >= 2, "cons2") + + problem = from_docplex_mp(model) + + backend = BasicAer.get_backend("statevector_simulator") + qaoa = QAOA(quantum_instance=backend, reps=1) + aggregator = MeanAggregator() + optimizer = WarmStartQAOAOptimizer( + pre_solver=SlsqpOptimizer(), + relax_for_pre_solver=True, + qaoa=qaoa, + epsilon=0.25, + aggregator=aggregator, + ) + result_warm = optimizer.solve(problem) + + self.assertIsNotNone(result_warm) + self.assertIsNotNone(result_warm.x) + np.testing.assert_almost_equal([1, 0, 1], result_warm.x, 3) + self.assertIsNotNone(result_warm.fval) + np.testing.assert_almost_equal(2, result_warm.fval, 3) + + def test_simple_qubo(self): + """Test on a simple QUBO problem.""" + model = Model() + # pylint:disable=invalid-name + u = model.binary_var(name="u") + v = model.binary_var(name="v") + + model.minimize((u - v + 2) ** 2) + problem = from_docplex_mp(model) + + backend = BasicAer.get_backend("statevector_simulator") + qaoa = QAOA(quantum_instance=backend, reps=1) + optimizer = WarmStartQAOAOptimizer( + pre_solver=SlsqpOptimizer(), + relax_for_pre_solver=True, + qaoa=qaoa, + epsilon=0.25, + ) + result_warm = optimizer.solve(problem) + + self.assertIsNotNone(result_warm) + self.assertIsNotNone(result_warm.x) + np.testing.assert_almost_equal([0, 1], result_warm.x, 3) + self.assertIsNotNone(result_warm.fval) + np.testing.assert_almost_equal(1, result_warm.fval, 3) + + +if __name__ == "__main__": + unittest.main() diff --git a/test/algorithms/test_grover_optimizer.py b/test/algorithms/test_grover_optimizer.py index a029590fa..6edff0d5b 100644 --- a/test/algorithms/test_grover_optimizer.py +++ b/test/algorithms/test_grover_optimizer.py @@ -20,6 +20,7 @@ from docplex.mp.model import Model from qiskit.utils import QuantumInstance, algorithm_globals, optionals from qiskit.algorithms import NumPyMinimumEigensolver +from qiskit.primitives import Sampler from qiskit_optimization.algorithms import ( GroverOptimizer, MinimumEigenOptimizer, @@ -58,6 +59,35 @@ def setUp(self): ) self.n_iter = 8 + def _prepare_grover_optimizer( + self, num_value_qubits, num_iterations, simulator, converters=None + ): + """Prepare GroverOptimizer.""" + if simulator == "statevector": + with self.assertWarns(PendingDeprecationWarning): + grover_optimizer = GroverOptimizer( + num_value_qubits=num_value_qubits, + num_iterations=num_iterations, + converters=converters, + quantum_instance=self.sv_simulator, + ) + elif simulator == "qasm": + with self.assertWarns(PendingDeprecationWarning): + grover_optimizer = GroverOptimizer( + num_value_qubits=num_value_qubits, + num_iterations=num_iterations, + converters=converters, + quantum_instance=self.qasm_simulator, + ) + else: + grover_optimizer = GroverOptimizer( + num_value_qubits=num_value_qubits, + num_iterations=num_iterations, + converters=converters, + sampler=Sampler(), + ) + return grover_optimizer + def validate_results(self, problem, results): """Validate the results object returned by GroverOptimizer.""" # Get expected value. @@ -71,7 +101,8 @@ def validate_results(self, problem, results): results.fval, problem.objective.sense.value * results.intermediate_fval ) - def test_qubo_gas_int_zero(self): + @data("statevector", "qasm", "sampler") + def test_qubo_gas_int_zero(self, simulator): """Test for when the answer is zero.""" # Input. @@ -82,13 +113,16 @@ def test_qubo_gas_int_zero(self): op = from_docplex_mp(model) # Will not find a negative, should return 0. - gmf = GroverOptimizer(1, num_iterations=1, quantum_instance=self.sv_simulator) - results = gmf.solve(op) + grover_optimizer = self._prepare_grover_optimizer( + num_value_qubits=1, num_iterations=1, simulator=simulator + ) + results = grover_optimizer.solve(op) np.testing.assert_array_almost_equal(results.x, [0, 0]) self.assertEqual(results.fval, 0.0) self.assertAlmostEqual(results.fval, results.intermediate_fval) - def test_qubo_gas_int_simple(self): + @data("statevector", "qasm", "sampler") + def test_qubo_gas_int_simple(self, simulator): """Test for simple case, with 2 linear coeffs and no quadratic coeffs or constants.""" # Input. @@ -99,15 +133,18 @@ def test_qubo_gas_int_simple(self): op = from_docplex_mp(model) # Get the optimum key and value. - gmf = GroverOptimizer(4, num_iterations=self.n_iter, quantum_instance=self.sv_simulator) - results = gmf.solve(op) + grover_optimizer = self._prepare_grover_optimizer( + num_value_qubits=4, num_iterations=self.n_iter, simulator=simulator + ) + results = grover_optimizer.solve(op) self.validate_results(op, results) self.assertIsNotNone(results.operation_counts) self.assertEqual(results.n_input_qubits, 2) self.assertEqual(results.n_output_qubits, 4) - def test_qubo_gas_int_simple_maximize(self): + @data("statevector", "qasm", "sampler") + def test_qubo_gas_int_simple_maximize(self, simulator): """Test for simple case, but with maximization.""" # Input. @@ -118,11 +155,13 @@ def test_qubo_gas_int_simple_maximize(self): op = from_docplex_mp(model) # Get the optimum key and value. - gmf = GroverOptimizer(4, num_iterations=self.n_iter, quantum_instance=self.sv_simulator) - results = gmf.solve(op) + grover_optimizer = self._prepare_grover_optimizer( + num_value_qubits=4, num_iterations=self.n_iter, simulator=simulator + ) + results = grover_optimizer.solve(op) self.validate_results(op, results) - @data("sv", "qasm") + @data("statevector", "qasm", "sampler") def test_qubo_gas_int_paper_example(self, simulator): """ Test the example from https://arxiv.org/abs/1912.04088 using the state vector simulator @@ -138,12 +177,14 @@ def test_qubo_gas_int_paper_example(self, simulator): op = from_docplex_mp(model) # Get the optimum key and value. - q_instance = self.sv_simulator if simulator == "sv" else self.qasm_simulator - gmf = GroverOptimizer(6, num_iterations=self.n_iter, quantum_instance=q_instance) - results = gmf.solve(op) + grover_optimizer = self._prepare_grover_optimizer( + num_value_qubits=6, num_iterations=self.n_iter, simulator=simulator + ) + results = grover_optimizer.solve(op) self.validate_results(op, results) - def test_converter_list(self): + @data("statevector", "qasm", "sampler") + def test_converter_list(self, simulator): """Test converters list""" # Input. @@ -156,13 +197,10 @@ def test_converter_list(self): # Get the optimum key and value. # a single converter. qp2qubo = QuadraticProgramToQubo() - gmf = GroverOptimizer( - 4, - num_iterations=self.n_iter, - quantum_instance=self.sv_simulator, - converters=qp2qubo, + grover_optimizer = self._prepare_grover_optimizer( + num_value_qubits=4, num_iterations=self.n_iter, simulator=simulator ) - results = gmf.solve(op) + results = grover_optimizer.solve(op) self.validate_results(op, results) # a list of converters @@ -171,25 +209,22 @@ def test_converter_list(self): penalize = LinearEqualityToPenalty() max2min = MaximizeToMinimize() converters = [ineq2eq, int2bin, penalize, max2min] - gmf = GroverOptimizer( - 4, + grover_optimizer = self._prepare_grover_optimizer( + num_value_qubits=4, num_iterations=self.n_iter, - quantum_instance=self.sv_simulator, + simulator=simulator, converters=converters, ) - results = gmf.solve(op) + results = grover_optimizer.solve(op) self.validate_results(op, results) # invalid converters with self.assertRaises(TypeError): invalid = [qp2qubo, "invalid converter"] - GroverOptimizer( - 4, - num_iterations=self.n_iter, - quantum_instance=self.sv_simulator, - converters=invalid, + grover_optimizer = self._prepare_grover_optimizer( + 4, num_iterations=self.n_iter, simulator=simulator, converters=invalid ) - @data("sv", "qasm") + @data("statevector", "qasm", "sampler") def test_samples_and_raw_samples(self, simulator): """Test samples and raw_samples""" algorithm_globals.random_seed = 2 @@ -198,9 +233,8 @@ def test_samples_and_raw_samples(self, simulator): op.binary_var("y") op.minimize(linear={"x": 1, "y": 2}) op.linear_constraint(linear={"x": 1, "y": 1}, sense=">=", rhs=1, name="xy") - q_instance = self.sv_simulator if simulator == "sv" else self.qasm_simulator - grover_optimizer = GroverOptimizer( - 8, num_iterations=self.n_iter, quantum_instance=q_instance + grover_optimizer = self._prepare_grover_optimizer( + num_value_qubits=8, num_iterations=self.n_iter, simulator=simulator ) opt_sol = 1 success = OptimizationResultStatus.SUCCESS @@ -221,12 +255,11 @@ def test_samples_and_raw_samples(self, simulator): self.assertEqual(results.status, results.raw_samples[0].status) np.testing.assert_array_almost_equal([1, 0, 0, 0, 0], results.raw_samples[0].x) - @data("sv", "qasm") + @data("statevector", "qasm", "sampler") def test_bit_ordering(self, simulator): """Test bit ordering""" # test minimize algorithm_globals.random_seed = 2 - q_instance = self.sv_simulator if simulator == "sv" else self.qasm_simulator mdl = Model("docplex model") x = mdl.binary_var("x") y = mdl.binary_var("y") @@ -234,8 +267,8 @@ def test_bit_ordering(self, simulator): op = from_docplex_mp(mdl) opt_sol = -2 success = OptimizationResultStatus.SUCCESS - grover_optimizer = GroverOptimizer( - 3, num_iterations=self.n_iter, quantum_instance=q_instance + grover_optimizer = self._prepare_grover_optimizer( + num_value_qubits=3, num_iterations=self.n_iter, simulator=simulator ) results = grover_optimizer.solve(op) self.assertEqual(results.fval, opt_sol) diff --git a/test/algorithms/test_min_eigen_optimizer.py b/test/algorithms/test_min_eigen_optimizer.py index 257fe7fe4..a5b518e78 100644 --- a/test/algorithms/test_min_eigen_optimizer.py +++ b/test/algorithms/test_min_eigen_optimizer.py @@ -10,30 +10,28 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -""" Test Min Eigen Optimizer """ +""" Test Min Eigen Optimizer with the primitive-based minimum eigensolver """ import unittest from test.optimization_test_case import QiskitOptimizationTestCase - -from test.runtime.fake_vqeruntime import FakeVQERuntimeProvider, FakeQAOARuntimeProvider +from test.runtime.fake_vqeruntime import FakeQAOARuntimeProvider, FakeVQERuntimeProvider import numpy as np -from ddt import data, ddt -from qiskit import BasicAer -from qiskit.algorithms import QAOA, VQE, NumPyMinimumEigensolver +from ddt import data, ddt, unpack +from qiskit.algorithms.minimum_eigensolvers import QAOA, NumPyMinimumEigensolver, SamplingVQE from qiskit.algorithms.optimizers import COBYLA, SPSA from qiskit.circuit.library import TwoLocal +from qiskit.primitives import Sampler from qiskit.providers.basicaer import QasmSimulatorPy -from qiskit.utils import QuantumInstance, algorithm_globals +from qiskit.utils import algorithm_globals + import qiskit_optimization.optionals as _optionals from qiskit_optimization.algorithms import ( CplexOptimizer, - MinimumEigenOptimizer, MinimumEigenOptimizationResult, + MinimumEigenOptimizer, ) -from qiskit_optimization.algorithms.optimization_algorithm import ( - OptimizationResultStatus, -) +from qiskit_optimization.algorithms.optimization_algorithm import OptimizationResultStatus from qiskit_optimization.converters import ( InequalityToEquality, IntegerToBinary, @@ -42,7 +40,7 @@ QuadraticProgramToQubo, ) from qiskit_optimization.problems import QuadraticProgram -from qiskit_optimization.runtime import VQEProgram, QAOAProgram +from qiskit_optimization.runtime import QAOAClient, VQEClient @ddt @@ -52,26 +50,14 @@ class TestMinEigenOptimizer(QiskitOptimizationTestCase): def setUp(self): super().setUp() + self._seed = 123 + # setup minimum eigen solvers - self.min_eigen_solvers = {} - - # exact eigen solver - self.min_eigen_solvers["exact"] = NumPyMinimumEigensolver() - - # QAOA - optimizer = COBYLA() - self.min_eigen_solvers["qaoa"] = QAOA(optimizer=optimizer) - # simulators - self.sv_simulator = QuantumInstance( - BasicAer.get_backend("statevector_simulator"), - seed_simulator=123, - seed_transpiler=123, - ) - self.qasm_simulator = QuantumInstance( - BasicAer.get_backend("qasm_simulator"), - seed_simulator=123, - seed_transpiler=123, - ) + self.min_eigen_solvers = { + "exact": NumPyMinimumEigensolver(), + "qaoa": QAOA(sampler=Sampler(), optimizer=COBYLA()), + } + # test minimize self.op_minimize = QuadraticProgram() self.op_minimize.integer_var(0, 3, "x") @@ -94,20 +80,19 @@ def setUp(self): @data( ("exact", None, "op_ip1.lp"), - ("qaoa", "statevector_simulator", "op_ip1.lp"), - ("qaoa", "qasm_simulator", "op_ip1.lp"), + ("qaoa", None, "op_ip1.lp"), + ("qaoa", 10000, "op_ip1.lp"), ) + @unpack @unittest.skipIf(not _optionals.HAS_CPLEX, "CPLEX not available.") - def test_min_eigen_optimizer(self, config): + def test_min_eigen_optimizer(self, min_eigen_solver_name, shots, filename): """Min Eigen Optimizer Test""" try: - # unpack configuration - min_eigen_solver_name, backend, filename = config - # get minimum eigen solver min_eigen_solver = self.min_eigen_solvers[min_eigen_solver_name] - if backend: - min_eigen_solver.quantum_instance = BasicAer.get_backend(backend) + if min_eigen_solver_name == "qaoa": + min_eigen_solver.sampler.options.shots = shots + min_eigen_solver.sampler.options.seed = self._seed # construct minimum eigen optimizer min_eigen_optimizer = MinimumEigenOptimizer(min_eigen_solver) @@ -137,13 +122,11 @@ def test_min_eigen_optimizer(self, config): ("op_ip1.lp", -470, 12, OptimizationResultStatus.SUCCESS), ("op_ip1.lp", np.inf, None, OptimizationResultStatus.FAILURE), ) + @unpack @unittest.skipIf(not _optionals.HAS_CPLEX, "CPLEX not available.") - def test_min_eigen_optimizer_with_filter(self, config): + def test_min_eigen_optimizer_with_filter(self, filename, lowerbound, fval, status): """Min Eigen Optimizer Test""" try: - # unpack configuration - filename, lowerbound, fval, status = config - # get minimum eigen solver min_eigen_solver = NumPyMinimumEigensolver() @@ -241,13 +224,12 @@ def test_samples_numpy_eigen_solver(self): self.assertAlmostEqual(result.raw_samples[0].probability, 1.0) self.assertEqual(result.raw_samples[0].status, success) - @data("sv", "qasm") - def test_samples_qaoa(self, simulator): + def test_samples_qaoa(self): """Test samples for QAOA""" # test minimize algorithm_globals.random_seed = 4 - quantum_instance = self.sv_simulator if simulator == "sv" else self.qasm_simulator - qaoa = QAOA(optimizer=COBYLA(), quantum_instance=quantum_instance, reps=2) + sampler = Sampler() + qaoa = QAOA(sampler=sampler, optimizer=COBYLA(), reps=2) min_eigen_optimizer = MinimumEigenOptimizer(qaoa) result = min_eigen_optimizer.solve(self.op_minimize) success = OptimizationResultStatus.SUCCESS @@ -269,7 +251,7 @@ def test_samples_qaoa(self, simulator): self.assertEqual(result.raw_samples[0].status, success) # test maximize opt_sol = 2 - qaoa = QAOA(optimizer=COBYLA(), quantum_instance=quantum_instance, reps=2) + qaoa = QAOA(sampler=sampler, optimizer=COBYLA(), reps=2) min_eigen_optimizer = MinimumEigenOptimizer(qaoa) result = min_eigen_optimizer.solve(self.op_maximize) self.assertAlmostEqual(sum(s.probability for s in result.samples), 1) @@ -297,7 +279,7 @@ def test_samples_qaoa(self, simulator): self.assertEqual(result.raw_samples[0].status, success) # test bit ordering opt_sol = -2 - qaoa = QAOA(optimizer=COBYLA(), quantum_instance=quantum_instance, reps=2) + qaoa = QAOA(sampler=sampler, optimizer=COBYLA(), reps=2) min_eigen_optimizer = MinimumEigenOptimizer(qaoa) result = min_eigen_optimizer.solve(self.op_ordering) self.assertEqual(result.fval, opt_sol) @@ -319,17 +301,16 @@ def test_samples_qaoa(self, simulator): self.assertAlmostEqual(result.raw_samples[0].fval, opt_sol) self.assertEqual(result.raw_samples[0].status, success) - @data("sv", "qasm") - def test_samples_vqe(self, simulator): + def test_samples_vqe(self): """Test samples for VQE""" # test minimize algorithm_globals.random_seed = 1 - quantum_instance = self.sv_simulator if simulator == "sv" else self.qasm_simulator opt_sol = -2 success = OptimizationResultStatus.SUCCESS optimizer = SPSA(maxiter=100) ry_ansatz = TwoLocal(5, "ry", "cz", reps=3, entanglement="full") - vqe_mes = VQE(ry_ansatz, optimizer=optimizer, quantum_instance=quantum_instance) + sampler = Sampler() + vqe_mes = SamplingVQE(sampler, ry_ansatz, optimizer=optimizer) vqe = MinimumEigenOptimizer(vqe_mes) results = vqe.solve(self.op_ordering) self.assertEqual(results.fval, opt_sol) @@ -360,7 +341,7 @@ def test_runtime(self, subroutine): if subroutine == "vqe": ry_ansatz = TwoLocal(5, "ry", "cz", reps=3, entanglement="full") initial_point = np.random.default_rng(42).random(ry_ansatz.num_parameters) - solver = VQEProgram( + solver = VQEClient( ansatz=ry_ansatz, optimizer=optimizer, initial_point=initial_point, @@ -370,7 +351,7 @@ def test_runtime(self, subroutine): else: reps = 2 initial_point = np.random.default_rng(42).random(2 * reps) - solver = QAOAProgram( + solver = QAOAClient( optimizer=optimizer, reps=reps, initial_point=initial_point, diff --git a/test/algorithms/test_recursive_optimization.py b/test/algorithms/test_recursive_optimization.py old mode 100755 new mode 100644 index 53e206b7b..ec8c6d9cc --- a/test/algorithms/test_recursive_optimization.py +++ b/test/algorithms/test_recursive_optimization.py @@ -10,36 +10,33 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -"""Test Recursive Min Eigen Optimizer.""" +"""Test Recursive Min Eigen Optimizer with the primitive-based minimum eigensolver.""" import unittest from test import QiskitOptimizationTestCase import numpy as np - -from qiskit import BasicAer -from qiskit.utils import algorithm_globals, QuantumInstance - -from qiskit.algorithms import NumPyMinimumEigensolver, QAOA +from qiskit.algorithms.minimum_eigensolvers import QAOA, NumPyMinimumEigensolver +from qiskit.algorithms.optimizers import SLSQP +from qiskit.primitives import Sampler +from qiskit.utils import algorithm_globals import qiskit_optimization.optionals as _optionals from qiskit_optimization.algorithms import ( - MinimumEigenOptimizer, CplexOptimizer, + MinimumEigenOptimizer, RecursiveMinimumEigenOptimizer, - WarmStartQAOAOptimizer, SlsqpOptimizer, + WarmStartQAOAOptimizer, ) -from qiskit_optimization.algorithms.recursive_minimum_eigen_optimizer import ( - IntermediateResult, -) -from qiskit_optimization.problems import QuadraticProgram +from qiskit_optimization.algorithms.recursive_minimum_eigen_optimizer import IntermediateResult from qiskit_optimization.converters import ( - IntegerToBinary, InequalityToEquality, + IntegerToBinary, LinearEqualityToPenalty, QuadraticProgramToQubo, ) +from qiskit_optimization.problems import QuadraticProgram class TestRecursiveMinEigenOptimizer(QiskitOptimizationTestCase): @@ -133,11 +130,9 @@ def test_recursive_warm_qaoa(self): """Test the recursive optimizer with warm start qaoa.""" seed = 1234 algorithm_globals.random_seed = seed - backend = BasicAer.get_backend("statevector_simulator") qaoa = QAOA( - quantum_instance=QuantumInstance( - backend=backend, seed_simulator=seed, seed_transpiler=seed - ), + sampler=Sampler(), + optimizer=SLSQP(), reps=1, ) warm_qaoa = WarmStartQAOAOptimizer( diff --git a/test/algorithms/test_warm_start_qaoa.py b/test/algorithms/test_warm_start_qaoa.py index 39f0dba0c..be83a392b 100644 --- a/test/algorithms/test_warm_start_qaoa.py +++ b/test/algorithms/test_warm_start_qaoa.py @@ -10,22 +10,20 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -""" Test warm start QAOA optimizer. """ +""" Test warm start QAOA optimizer with the primitive-based minimum eigensolver. """ import unittest from test import QiskitOptimizationTestCase import numpy as np - from docplex.mp.model import Model -from qiskit import BasicAer -from qiskit.algorithms import QAOA +from qiskit.algorithms.minimum_eigensolvers import QAOA +from qiskit.algorithms.optimizers import SLSQP +from qiskit.primitives.sampler import Sampler import qiskit_optimization.optionals as _optionals from qiskit_optimization.algorithms import SlsqpOptimizer -from qiskit_optimization.algorithms.goemans_williamson_optimizer import ( - GoemansWilliamsonOptimizer, -) +from qiskit_optimization.algorithms.goemans_williamson_optimizer import GoemansWilliamsonOptimizer from qiskit_optimization.algorithms.warm_start_qaoa_optimizer import ( MeanAggregator, WarmStartQAOAOptimizer, @@ -52,8 +50,7 @@ def test_max_cut(self): presolver = GoemansWilliamsonOptimizer(num_cuts=10) problem = Maxcut(graph).to_quadratic_program() - backend = BasicAer.get_backend("statevector_simulator") - qaoa = QAOA(quantum_instance=backend, reps=1) + qaoa = QAOA(sampler=Sampler(), optimizer=SLSQP(), reps=1) aggregator = MeanAggregator() optimizer = WarmStartQAOAOptimizer( pre_solver=presolver, @@ -85,8 +82,7 @@ def test_constrained_binary(self): problem = from_docplex_mp(model) - backend = BasicAer.get_backend("statevector_simulator") - qaoa = QAOA(quantum_instance=backend, reps=1) + qaoa = QAOA(sampler=Sampler(), optimizer=SLSQP(), reps=1) aggregator = MeanAggregator() optimizer = WarmStartQAOAOptimizer( pre_solver=SlsqpOptimizer(), @@ -113,8 +109,7 @@ def test_simple_qubo(self): model.minimize((u - v + 2) ** 2) problem = from_docplex_mp(model) - backend = BasicAer.get_backend("statevector_simulator") - qaoa = QAOA(quantum_instance=backend, reps=1) + qaoa = QAOA(sampler=Sampler(), optimizer=SLSQP(), reps=1) optimizer = WarmStartQAOAOptimizer( pre_solver=SlsqpOptimizer(), relax_for_pre_solver=True, diff --git a/test/converters/test_converters.py b/test/converters/test_converters.py index 7290f3877..8086166b0 100644 --- a/test/converters/test_converters.py +++ b/test/converters/test_converters.py @@ -17,15 +17,12 @@ import numpy as np from docplex.mp.model import Model -from qiskit.algorithms import NumPyMinimumEigensolver -from qiskit.opflow import Z, I +from qiskit.algorithms.minimum_eigensolvers import NumPyMinimumEigensolver +from qiskit.opflow import I, Z + import qiskit_optimization.optionals as _optionals -from qiskit_optimization import QuadraticProgram, QiskitOptimizationError -from qiskit_optimization.algorithms import ( - MinimumEigenOptimizer, - CplexOptimizer, - ADMMOptimizer, -) +from qiskit_optimization import QiskitOptimizationError, QuadraticProgram +from qiskit_optimization.algorithms import ADMMOptimizer, CplexOptimizer, MinimumEigenOptimizer from qiskit_optimization.algorithms.admm_optimizer import ADMMParameters from qiskit_optimization.converters import ( InequalityToEquality, @@ -36,7 +33,6 @@ from qiskit_optimization.problems import Constraint, Variable from qiskit_optimization.translators import from_docplex_mp - QUBIT_OP_MAXIMIZE_SAMPLE = ( -199999.5 * (I ^ I ^ I ^ Z) + -399999.5 * (I ^ I ^ Z ^ I)