Skip to content

Commit 62334fc

Browse files
committed
let MinimumEigenOptimizer allow new primitive-based algorithms
1 parent 3dfa511 commit 62334fc

File tree

4 files changed

+497
-75
lines changed

4 files changed

+497
-75
lines changed

qiskit_optimization/algorithms/minimum_eigen_optimizer.py

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# This code is part of Qiskit.
22
#
3-
# (C) Copyright IBM 2020, 2021.
3+
# (C) Copyright IBM 2020, 2022.
44
#
55
# This code is licensed under the Apache License, Version 2.0. You may
66
# obtain a copy of this license in the LICENSE.txt file in the root directory
@@ -11,24 +11,38 @@
1111
# that they have been altered from the originals.
1212

1313
"""A wrapper for minimum eigen solvers to be used within the optimization module."""
14-
from typing import Optional, Union, List, cast
14+
from typing import List, Optional, Union, cast
1515

1616
import numpy as np
17+
from qiskit.algorithms.minimum_eigen_solvers import MinimumEigensolver as LegacyMinimumEigensolver
18+
from qiskit.algorithms.minimum_eigen_solvers import (
19+
MinimumEigensolverResult as LegacyMinimumEigensolverResult,
20+
)
21+
from qiskit.algorithms.minimum_eigensolvers import (
22+
NumPyMinimumEigensolver,
23+
NumPyMinimumEigensolverResult,
24+
SamplingMinimumEigensolver,
25+
SamplingMinimumEigensolverResult,
26+
)
27+
from qiskit.opflow import OperatorBase, PauliOp, PauliSumOp
1728

18-
from qiskit.algorithms import MinimumEigensolver, MinimumEigensolverResult
19-
from qiskit.opflow import OperatorBase
29+
from ..converters.quadratic_program_to_qubo import QuadraticProgramConverter, QuadraticProgramToQubo
30+
from ..deprecation import DeprecatedType, warn_deprecated
31+
from ..exceptions import QiskitOptimizationError
32+
from ..problems.quadratic_program import QuadraticProgram, Variable
2033
from .optimization_algorithm import (
21-
OptimizationResultStatus,
2234
OptimizationAlgorithm,
2335
OptimizationResult,
36+
OptimizationResultStatus,
2437
SolutionSample,
2538
)
26-
from ..exceptions import QiskitOptimizationError
27-
from ..converters.quadratic_program_to_qubo import (
28-
QuadraticProgramToQubo,
29-
QuadraticProgramConverter,
30-
)
31-
from ..problems.quadratic_program import QuadraticProgram, Variable
39+
40+
MinimumEigensolver = Union[
41+
SamplingMinimumEigensolver, NumPyMinimumEigensolver, LegacyMinimumEigensolver
42+
]
43+
MinimumEigensolverResult = Union[
44+
SamplingMinimumEigensolverResult, NumPyMinimumEigensolverResult, LegacyMinimumEigensolverResult
45+
]
3246

3347

3448
class MinimumEigenOptimizationResult(OptimizationResult):
@@ -137,11 +151,18 @@ def __init__(
137151
TypeError: When one of converters has an invalid type.
138152
QiskitOptimizationError: When the minimum eigensolver does not return an eigenstate.
139153
"""
140-
154+
if isinstance(min_eigen_solver, LegacyMinimumEigensolver):
155+
warn_deprecated(
156+
"0.5.0",
157+
DeprecatedType.ARGUMENT,
158+
f"min_eigen_solver as {LegacyMinimumEigensolver.__name__}",
159+
new_name=f"min_eigen_solver as {SamplingMinimumEigensolver.__name__} "
160+
f"or {NumPyMinimumEigensolver.__name__}",
161+
)
141162
if not min_eigen_solver.supports_aux_operators():
142163
raise QiskitOptimizationError(
143164
"Given MinimumEigensolver does not return the eigenstate "
144-
+ "and is not supported by the MinimumEigenOptimizer."
165+
"and is not supported by the MinimumEigenOptimizer."
145166
)
146167
self._min_eigen_solver = min_eigen_solver
147168
self._penalty = penalty
@@ -206,6 +227,9 @@ def _solve_internal(
206227
# only try to solve non-empty Ising Hamiltonians
207228
eigen_result: Optional[MinimumEigensolverResult] = None
208229
if operator.num_qubits > 0:
230+
# NumPyEigensolver does not accept PauliOp but PauliSumOp
231+
if isinstance(operator, PauliOp):
232+
operator = PauliSumOp.from_list([(operator.primitive.to_label(), operator.coeff)])
209233
# approximate ground state of operator using min eigen solver
210234
eigen_result = self._min_eigen_solver.compute_minimum_eigenvalue(operator)
211235
# analyze results

qiskit_optimization/algorithms/optimization_algorithm.py

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,16 @@
1515
from abc import ABC, abstractmethod
1616
from dataclasses import dataclass
1717
from enum import Enum
18-
from typing import List, Union, Any, Optional, Dict, Type, Tuple, cast
18+
from typing import Any, Dict, List, Optional, Tuple, Type, Union, cast
1919
from warnings import warn
2020

2121
import numpy as np
22+
from qiskit.opflow import DictStateFn, StateFn
23+
from qiskit.quantum_info import Statevector
24+
from qiskit.result import QuasiDistribution
2225

23-
from qiskit.opflow import StateFn, DictStateFn
26+
from ..converters.quadratic_program_to_qubo import QuadraticProgramConverter, QuadraticProgramToQubo
2427
from ..exceptions import QiskitOptimizationError
25-
from ..converters.quadratic_program_to_qubo import QuadraticProgramToQubo, QuadraticProgramConverter
2628
from ..problems.quadratic_program import QuadraticProgram, Variable
2729

2830

@@ -518,7 +520,7 @@ def _interpret_samples(
518520

519521
@staticmethod
520522
def _eigenvector_to_solutions(
521-
eigenvector: Union[dict, np.ndarray, StateFn],
523+
eigenvector: Union[QuasiDistribution, Statevector, dict, np.ndarray, StateFn],
522524
qubo: QuadraticProgram,
523525
min_probability: float = 1e-6,
524526
) -> List[SolutionSample]:
@@ -566,7 +568,25 @@ def generate_solution(bitstr, qubo, probability):
566568
)
567569

568570
solutions = []
569-
if isinstance(eigenvector, dict):
571+
if isinstance(eigenvector, QuasiDistribution):
572+
probabilities = eigenvector.binary_probabilities()
573+
# iterate over all samples
574+
for bitstr, sampling_probability in probabilities.items():
575+
# add the bitstring, if the sampling probability exceeds the threshold
576+
if sampling_probability >= min_probability:
577+
solutions.append(generate_solution(bitstr, qubo, sampling_probability))
578+
579+
elif isinstance(eigenvector, Statevector):
580+
probabilities = eigenvector.probabilities()
581+
num_qubits = eigenvector.num_qubits
582+
# iterate over all states and their sampling probabilities
583+
for i, sampling_probability in enumerate(probabilities):
584+
# add the i-th state if the sampling probability exceeds the threshold
585+
if sampling_probability >= min_probability:
586+
bitstr = f"{i:b}".rjust(num_qubits, "0")
587+
solutions.append(generate_solution(bitstr, qubo, sampling_probability))
588+
589+
elif isinstance(eigenvector, dict):
570590
# When eigenvector is a dict, square the values since the values are normalized.
571591
# See https://github.com/Qiskit/qiskit-terra/pull/5496 for more details.
572592
probabilities = {bitstr: val**2 for (bitstr, val) in eigenvector.items()}
@@ -579,7 +599,6 @@ def generate_solution(bitstr, qubo, probability):
579599
elif isinstance(eigenvector, np.ndarray):
580600
num_qubits = int(np.log2(eigenvector.size))
581601
probabilities = np.abs(eigenvector * eigenvector.conj())
582-
583602
# iterate over all states and their sampling probabilities
584603
for i, sampling_probability in enumerate(probabilities):
585604
# add the i-th state if the sampling probability exceeds the threshold
@@ -588,6 +607,8 @@ def generate_solution(bitstr, qubo, probability):
588607
solutions.append(generate_solution(bitstr, qubo, sampling_probability))
589608

590609
else:
591-
raise TypeError("Unsupported format of eigenvector. Provide a dict or numpy.ndarray.")
592-
610+
raise TypeError(
611+
f"Eigenvector should be QuasiDistribution, Statevector, dict or numpy.ndarray. "
612+
f"But, it was {type(eigenvector)}."
613+
)
593614
return solutions

0 commit comments

Comments
 (0)