Source code for qiskit.aqua.components.optimizers.nlopts.nloptimizer
# This code is part of Qiskit.
#
# (C) Copyright IBM 2018, 2020.
#
# 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.
""" Minimize using objective function """
from typing import List, Optional, Tuple, Callable
from enum import Enum
from abc import abstractmethod
import logging
import numpy as np
from qiskit.aqua import MissingOptionalLibraryError
from ..optimizer import Optimizer, OptimizerSupportLevel
logger = logging.getLogger(__name__)
try:
import nlopt
logger.info('NLopt version: %s.%s.%s', nlopt.version_major(),
nlopt.version_minor(), nlopt.version_bugfix())
_HAS_NLOPT = True
except ImportError:
_HAS_NLOPT = False
class NLoptOptimizerType(Enum):
""" NLopt Valid Optimizer """
GN_CRS2_LM = 1
GN_DIRECT_L_RAND = 2
GN_DIRECT_L = 3
GN_ESCH = 4
GN_ISRES = 5
class NLoptOptimizer(Optimizer):
"""
NLopt global optimizer base class
"""
_OPTIONS = ['max_evals']
def __init__(self, max_evals: int = 1000) -> None: # pylint: disable=unused-argument
"""
Args:
max_evals: Maximum allowed number of function evaluations.
Raises:
MissingOptionalLibraryError: NLopt library not installed.
"""
if not _HAS_NLOPT:
raise MissingOptionalLibraryError(
libname='nlopt',
name='NLoptOptimizer',
msg='See https://qiskit.org/documentation/apidoc/'
'qiskit.aqua.components.optimizers.nlopts.html'
' for installation information')
super().__init__()
for k, v in list(locals().items()):
if k in self._OPTIONS:
self._options[k] = v
self._optimizer_names = {
NLoptOptimizerType.GN_CRS2_LM: nlopt.GN_CRS2_LM,
NLoptOptimizerType.GN_DIRECT_L_RAND: nlopt.GN_DIRECT_L_RAND,
NLoptOptimizerType.GN_DIRECT_L: nlopt.GN_DIRECT_L,
NLoptOptimizerType.GN_ESCH: nlopt.GN_ESCH,
NLoptOptimizerType.GN_ISRES: nlopt.GN_ISRES,
}
@abstractmethod
def get_nlopt_optimizer(self) -> NLoptOptimizerType:
""" return NLopt optimizer enum type """
raise NotImplementedError
def get_support_level(self):
""" return support level dictionary """
return {
'gradient': OptimizerSupportLevel.ignored,
'bounds': OptimizerSupportLevel.supported,
'initial_point': OptimizerSupportLevel.required
}
def optimize(self, num_vars, objective_function, gradient_function=None,
variable_bounds=None, initial_point=None):
super().optimize(num_vars, objective_function,
gradient_function, variable_bounds, initial_point)
if variable_bounds is None:
variable_bounds = [(None, None)] * num_vars
return self._minimize(self._optimizer_names[self.get_nlopt_optimizer()],
objective_function,
variable_bounds,
initial_point, **self._options)
def _minimize(self,
name: str,
objective_function: Callable,
variable_bounds: Optional[List[Tuple[float, float]]],
initial_point: Optional[np.ndarray] = None,
max_evals: int = 1000) -> Tuple[float, float, int]:
"""Minimize using objective function
Args:
name: NLopt optimizer name
objective_function: handle to a function that
computes the objective function.
variable_bounds: list of variable
bounds, given as pairs (lower, upper). None means
unbounded.
initial_point: initial point.
max_evals: Maximum evaluations
Returns:
tuple(float, float, int): Solution at minimum found,
value at minimum found, num evaluations performed
"""
threshold = 3 * np.pi
low = [(l if l is not None else -threshold) for (l, u) in variable_bounds]
high = [(u if u is not None else threshold) for (l, u) in variable_bounds]
opt = nlopt.opt(name, len(low))
logger.debug(opt.get_algorithm_name())
opt.set_lower_bounds(low)
opt.set_upper_bounds(high)
eval_count = 0
def wrap_objfunc_global(x, _grad):
nonlocal eval_count
eval_count += 1
return objective_function(x)
opt.set_min_objective(wrap_objfunc_global)
opt.set_maxeval(max_evals)
xopt = opt.optimize(initial_point)
minf = opt.last_optimum_value()
logger.debug('Global minimize found %s eval count %s', minf, eval_count)
return xopt, minf, eval_count