from abc import abstractmethod
from typing import Any, List, Optional
from qiskit.circuit.library import TwoLocal
from qiskit.primitives import Sampler
from qiskit_algorithms import QAOA, SamplingVQE
from qiskit_algorithms.optimizers import SPSA
from qiskit_optimization.algorithms import MinimumEigenOptimizer
from discrete_optimization.generic_tools.callbacks.callback import Callback
from discrete_optimization.generic_tools.do_problem import (
ParamsObjectiveFunction,
Problem,
Solution,
)
from discrete_optimization.generic_tools.do_solver import SolverDO
from discrete_optimization.generic_tools.result_storage.result_storage import (
ResultStorage,
)
[docs]
class QiskitQAOASolver(SolverDO):
def __init__(
self,
problem: Problem,
params_objective_function: Optional[ParamsObjectiveFunction] = None,
**kwargs: Any
):
super().__init__(problem, params_objective_function)
self.quadratic_programm = None
[docs]
def solve(
self, callbacks: Optional[List[Callback]] = None, **kwargs: Any
) -> ResultStorage:
optimizer = kwargs.get("optimizer", SPSA(maxiter=250))
reps = kwargs.get("reps", 5)
if self.quadratic_programm is None:
self.init_model(**kwargs)
if self.quadratic_programm is None:
raise RuntimeError(
"self.quadratic_programm must not be None after self.init_model()."
)
sampler = Sampler()
qaoa = QAOA(sampler=sampler, optimizer=optimizer, reps=reps)
algorithm = MinimumEigenOptimizer(qaoa)
result = algorithm.solve(self.quadratic_programm)
sol = self.retrieve_current_solution(result)
fit = self.aggreg_from_sol(sol)
return ResultStorage(
[(sol, fit)], mode_optim=self.params_objective_function.sense_function
)
[docs]
@abstractmethod
def init_model(self, **kwargs: Any) -> None:
...
[docs]
@abstractmethod
def retrieve_current_solution(self, result) -> Solution:
"""Retrieve current solution from qiskit result.
Args:
result: list of value for each binary variable of the problem
Returns:
the converted solution at d-o format
"""
...
[docs]
class QiskitVQESolver(SolverDO):
def __init__(
self,
problem: Problem,
params_objective_function: Optional[ParamsObjectiveFunction] = None,
**kwargs: Any
):
super().__init__(problem, params_objective_function)
self.quadratic_programm = None
self.nb_variable = 0
[docs]
def solve(
self, callbacks: Optional[List[Callback]] = None, **kwargs: Any
) -> ResultStorage:
optimizer = kwargs.get("optimizer", SPSA(maxiter=300))
reps = kwargs.get("reps", 5)
if self.quadratic_programm is None or self.nb_variable == 0:
self.init_model(**kwargs)
if self.quadratic_programm is None:
raise RuntimeError(
"self.quadratic_programm must not be None after self.init_model()."
)
if self.nb_variable == 0:
raise RuntimeError(
"self.variable must not be 0 after self.init_model()."
)
ry = TwoLocal(self.nb_variable, "ry", "cz", reps=reps, entanglement="linear")
vqe = SamplingVQE(sampler=Sampler(), ansatz=ry, optimizer=optimizer)
algorithm = MinimumEigenOptimizer(vqe)
result = algorithm.solve(self.quadratic_programm)
sol = self.retrieve_current_solution(result)
fit = self.aggreg_from_sol(sol)
return ResultStorage(
[(sol, fit)], mode_optim=self.params_objective_function.sense_function
)
[docs]
@abstractmethod
def init_model(self, **kwargs: Any) -> None:
...
[docs]
@abstractmethod
def retrieve_current_solution(self, result) -> Solution:
"""Retrieve current solution from qiskit result.
Args:
result: list of value for each binary variable of the problem
Returns:
the converted solution at d-o format
"""
...