Skip to content

Commit

Permalink
Add NFT optimizer (qiskit-community/qiskit-aqua#729)
Browse files Browse the repository at this point in the history
* add NFT optimizer

* Add specific unit test for NFT

Co-authored-by: Manoel Marques <manoel@us.ibm.com>
Co-authored-by: Steve Wood <40241007+woodsp-ibm@users.noreply.github.com>
Co-authored-by: woodsp <woodsp@us.ibm.com>
  • Loading branch information
4 people authored Mar 25, 2020
1 parent 0468b95 commit 83a8b39
Show file tree
Hide file tree
Showing 2 changed files with 184 additions and 0 deletions.
3 changes: 3 additions & 0 deletions qiskit/aqua/components/optimizers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
COBYLA
L_BFGS_B
NELDER_MEAD
NFT
P_BFGS
POWELL
SLSQP
Expand Down Expand Up @@ -93,6 +94,7 @@
from .spsa import SPSA
from .tnc import TNC
from .aqgd import AQGD
from .nft import NFT
from .nlopts.crs import CRS
from .nlopts.direct_l import DIRECT_L
from .nlopts.direct_l_rand import DIRECT_L_RAND
Expand All @@ -106,6 +108,7 @@
'COBYLA',
'L_BFGS_B',
'NELDER_MEAD',
'NFT',
'P_BFGS',
'POWELL',
'SLSQP',
Expand Down
181 changes: 181 additions & 0 deletions qiskit/aqua/components/optimizers/nft.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
# -*- coding: utf-8 -*-

# This code is part of Qiskit.
#
# (C) Copyright IBM 2019, 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.

"""Nakanishi-Fujii-Todo algorithm."""

from typing import Optional
import logging

import numpy as np
from scipy.optimize import minimize
from scipy.optimize import OptimizeResult
from .optimizer import Optimizer


logger = logging.getLogger(__name__)


class NFT(Optimizer):
"""
Nakanishi-Fujii-Todo algorithm.
See https://arxiv.org/abs/1903.12166
"""

_OPTIONS = ['maxiter', 'maxfev', 'disp', 'reset_interval']

# pylint: disable=unused-argument
def __init__(self,
maxiter: Optional[int] = None,
maxfev: int = 1024,
disp: bool = False,
reset_interval: int = 32) -> None:
"""
Built out using scipy framework, for details, please refer to
https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html.
Args:
maxiter: Maximum number of iterations to perform.
maxfev: Maximum number of function evaluations to perform.
disp: disp
reset_interval: The minimum estimates directly once
in ``reset_interval`` times.
Notes:
In this optimization method, the optimization function have to satisfy
three conditions written in [1]_.
References:
.. [1] K. M. Nakanishi, K. Fujii, and S. Todo. 2019.
Sequential minimal optimization for quantum-classical hybrid algorithms.
arXiv preprint arXiv:1903.12166.
"""
super().__init__()
for k, v in locals().items():
if k in self._OPTIONS:
self._options[k] = v

def get_support_level(self):
""" return support level dictionary """
return {
'gradient': Optimizer.SupportLevel.ignored,
'bounds': Optimizer.SupportLevel.ignored,
'initial_point': Optimizer.SupportLevel.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)

res = minimize(objective_function, initial_point,
method=nakanishi_fujii_todo, options=self._options)
return res.x, res.fun, res.nfev


# pylint: disable=invalid-name
def nakanishi_fujii_todo(fun, x0, args=(), maxiter=None, maxfev=1024,
reset_interval=32, eps=1e-32, callback=None, **_):
"""
Find the global minimum of a function using the nakanishi_fujii_todo
algorithm [1].
Args:
fun (callable): ``f(x, *args)``
Function to be optimized. ``args`` can be passed as an optional item
in the dict ``minimizer_kwargs``.
This function must satisfy the three condition written in Ref. [1].
x0 (ndarray): shape (n,)
Initial guess. Array of real elements of size (n,),
where 'n' is the number of independent variables.
args (tuple, optional):
Extra arguments passed to the objective function.
maxiter (int):
Maximum number of iterations to perform.
Default: None.
maxfev (int):
Maximum number of function evaluations to perform.
Default: 1024.
reset_interval (int):
The minimum estimates directly once in ``reset_interval`` times.
Default: 32.
eps (float): eps
**_ : additional options
callback (callable, optional):
Called after each iteration.
Returns:
OptimizeResult:
The optimization result represented as a ``OptimizeResult`` object.
Important attributes are: ``x`` the solution array. See
`OptimizeResult` for a description of other attributes.
Notes:
In this optimization method, the optimization function have to satisfy
three conditions written in [1].
References:
.. [1] K. M. Nakanishi, K. Fujii, and S. Todo. 2019.
Sequential minimal optimization for quantum-classical hybrid algorithms.
arXiv preprint arXiv:1903.12166.
"""

x0 = np.asarray(x0)
recycle_z0 = None
niter = 0
funcalls = 0

while True:

idx = niter % x0.size

if reset_interval > 0:
if niter % reset_interval == 0:
recycle_z0 = None

if recycle_z0 is None:
z0 = fun(np.copy(x0), *args)
funcalls += 1
else:
z0 = recycle_z0

p = np.copy(x0)
p[idx] = x0[idx] + np.pi / 2
z1 = fun(p, *args)
funcalls += 1

p = np.copy(x0)
p[idx] = x0[idx] - np.pi / 2
z3 = fun(p, *args)
funcalls += 1

z2 = z1 + z3 - z0
c = (z1 + z3) / 2
a = np.sqrt((z0 - z2) ** 2 + (z1 - z3) ** 2) / 2
b = np.arctan((z1 - z3) / ((z0 - z2) + eps * (z0 == z2))) + x0[idx]
b += 0.5 * np.pi + 0.5 * np.pi * np.sign((z0 - z2) + eps * (z0 == z2))

x0[idx] = b
recycle_z0 = c - a

niter += 1

if callback is not None:
callback(np.copy(x0))

if maxfev is not None:
if funcalls >= maxfev:
break

if maxiter is not None:
if niter >= maxiter:
break

return OptimizeResult(fun=fun(np.copy(x0)), x=x0, nit=niter, nfev=funcalls, success=(niter > 1))

0 comments on commit 83a8b39

Please sign in to comment.