Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update optimizers to allow new primitives-based algorithms #436

Merged
merged 22 commits into from
Nov 30, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
16 changes: 8 additions & 8 deletions qiskit_optimization/algorithms/admm_optimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
50 changes: 37 additions & 13 deletions qiskit_optimization/algorithms/minimum_eigen_optimizer.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
t-imamichi marked this conversation as resolved.
Show resolved Hide resolved
]
MinimumEigensolverResult = Union[
SamplingMinimumEigensolverResult, NumPyMinimumEigensolverResult, LegacyMinimumEigensolverResult
]


class MinimumEigenOptimizationResult(OptimizationResult):
Expand Down Expand Up @@ -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):
t-imamichi marked this conversation as resolved.
Show resolved Hide resolved
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."
)
t-imamichi marked this conversation as resolved.
Show resolved Hide resolved
self._min_eigen_solver = min_eigen_solver
self._penalty = penalty
Expand Down Expand Up @@ -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
Expand Down
37 changes: 29 additions & 8 deletions qiskit_optimization/algorithms/optimization_algorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down Expand Up @@ -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]:
Expand Down Expand Up @@ -566,7 +568,25 @@ def generate_solution(bitstr, qubo, probability):
)

solutions = []
if isinstance(eigenvector, dict):
if isinstance(eigenvector, QuasiDistribution):
t-imamichi marked this conversation as resolved.
Show resolved Hide resolved
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()}
Expand All @@ -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
Expand All @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
17 changes: 5 additions & 12 deletions qiskit_optimization/algorithms/warm_start_qaoa_optimizer.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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):
Expand Down
11 changes: 10 additions & 1 deletion qiskit_optimization/deprecation.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2021.
# (C) Copyright IBM 2021, 2022.
manoelmarques marked this conversation as resolved.
Show resolved Hide resolved
#
# 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
Expand Down Expand Up @@ -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()
Loading