Source code for lbfgsb.benchmarks

# SPDX-License-Identifier: BSD-3-Clause
# Copyright (c) 2025 Antoine COLLET

"""
Provide the following benchmark functions and their gradients.
- ackley
- griewank
- quadratic
- rastrigin
- rosenbrook
- sphere
- styblinski_tang
"""

import numpy as np

from lbfgsb.types import NDArrayFloat


[docs] def ackley(x: NDArrayFloat) -> float: """ The Ackley function. Parameters ---------- x : array_like 1-D array of points at which the Ackley function is to be computed. Returns ------- float The value of the Ackley function. """ x = np.asarray(x) ndim = x.size e = 2.7182818284590451 sum1 = np.sqrt(1.0 / ndim * np.square(x).sum()) sum2 = 1.0 / ndim * np.cos(2.0 * np.pi * x).sum() return 20.0 + e - 20.0 * np.exp(-0.2 * sum1) - np.exp(sum2)
[docs] def ackley_grad(x: NDArrayFloat) -> NDArrayFloat: """ The gradient of the Ackley function. Parameters ---------- x : array_like 1-D array of points at which the Ackley function is to be derivated. Returns ------- NDArrayFloat The gradient of the Ackley function. """ x = np.asarray(x) ndim = x.size square_sum = np.square(x).sum() return ( 4.0 * x * np.sqrt(square_sum / ndim) * np.exp(-0.2 * np.sqrt(square_sum / ndim)) / square_sum ) - 2.0 * np.pi / ndim * np.sin(2.0 * np.pi * x)
[docs] def beale(x: NDArrayFloat) -> float: """ The Beale function. Parameters ---------- x : array_like 1-D array of points at which the Beale function is to be computed. Returns ------- float The value of the Griewank function. """ x = np.asarray(x) return ( (1.5 - x[:-1] + x[:-1] * x[1:]) ** 2 + (2.25 - x[:-1] + x[:-1] * x[1:] ** 2) ** 2 + (2.625 - x[:-1] + x[:-1] * x[1:] ** 3) ** 2 ).sum()
[docs] def beale_grad(x: NDArrayFloat) -> NDArrayFloat: """ The gradient of the Quartic function. Parameters ---------- x : array_like 1-D array of points at which the Beale function is to be derivated. Returns ------- NDArrayFloat The gradient of the Beale function. """ x = np.asarray(x) y1 = x[1:] y2 = y1 * y1 y3 = y2 * y1 f1 = 1.5 - x[:-1] + x[:-1] * y1 f2 = 2.25 - x[:-1] + x[:-1] * y2 f3 = 2.625 - x[:-1] + x[:-1] * y3 grad = np.zeros_like(x) grad[:-1] += 2 * (y1 - 1) * f1 + 2 * (y2 - 1) * f2 + 2 * (y3 - 1) * f3 grad[1:] += 2 * x[:-1] * f1 + 4 * x[:-1] * y1 * f2 + 6 * x[:-1] * y2 * f3 return grad
[docs] def griewank(x: NDArrayFloat) -> float: """ The Griewank function. Parameters ---------- x : array_like 1-D array of points at which the Griewank function is to be computed. Returns ------- float The value of the Griewank function. """ x = np.asarray(x) ndim = x.size sum1 = np.square(x).sum() / 4000.0 prod1 = np.prod(np.cos(x / np.sqrt(np.arange(1, ndim + 1)))) return 1.0 + sum1 - prod1
[docs] def griewank_grad(x: NDArrayFloat) -> NDArrayFloat: """ The gradient of the Griewank function. Parameters ---------- x : array_like 1-D array of points at which the Griewank function is to be derivated. Returns ------- NDArrayFloat The gradient of the Griewank function. """ x = np.asarray(x) ndim = x.size den = np.sqrt(np.arange(1, ndim + 1)) return ( x / 2000.0 + np.sin(x / den) * np.prod(np.cos(x / den)) / np.cos(x / den) / den )
[docs] def quartic(x: NDArrayFloat) -> float: """ The Quartic function. Parameters ---------- x : array_like 1-D array of points at which the Quartic function is to be computed. Returns ------- float The value of the Quartic function. """ x = np.asarray(x) ndim = x.size return (np.arange(1, ndim + 1) * np.power(x, 4)).sum()
[docs] def quartic_grad(x: NDArrayFloat) -> NDArrayFloat: """ The gradient of the Quartic function. Parameters ---------- x : array_like 1-D array of points at which the Quartic function is to be derivated. Returns ------- NDArrayFloat The gradient of the Quartic function. """ x = np.asarray(x) ndim = x.size return np.arange(1, ndim + 1) * 4 * np.power(x, 3)
[docs] def rastrigin(x: NDArrayFloat) -> float: """ The Rastrigin function. Parameters ---------- x : array_like 1-D array of points at which the Rastrigin function is to be computed. Returns ------- float The value of the Rastrigin function. """ x = np.asarray(x) ndim = x.size sum1 = (np.square(x) - 10.0 * np.cos(2.0 * np.pi * x)).sum() return 10.0 * ndim + sum1
[docs] def rastrigin_grad(x: NDArrayFloat) -> NDArrayFloat: """ The gradient of the Rastrigin function. Parameters ---------- x : array_like 1-D array of points at which the Rastrigin function is to be derivated. Returns ------- NDArrayFloat The gradient of the Rastrigin function. """ x = np.asarray(x) return 2.0 * x + 20.0 * np.pi * np.sin(2.0 * np.pi * x)
[docs] def rosenbrock(x: NDArrayFloat) -> float: """ The Rosenbrock function. Parameters ---------- x : array_like Array of of points at which the Rosenbrock function is to be computed. It can be of shape (m,) or (m, n), m being the number of variables per vector of parameters and n the number of different vectors. Returns ------- float The gradient of the Rosenbrock function with size (n,). """ x = np.asarray(x) sum1 = ((x[1:] - x[:-1] ** 2.0) ** 2.0).sum(axis=0) sum2 = np.square(1.0 - x[:-1]).sum(axis=0) return 100.0 * sum1 + sum2
[docs] def rosenbrock_grad(x: NDArrayFloat) -> NDArrayFloat: """ The gradient of the Rosenbrock function. Parameters ---------- x : array_like Array of of points at which the Rosenbrock function is to be computed. It can be of shape (m,) or (m, n), m being the number of variables per vector of parameters and n the number of different vectors. Returns ------- NDArrayFloat The gradient(s) of the Rosenbrock function with the same shapes as the input x. """ x = np.asarray(x) g = np.zeros(x.shape) # derivation of sum1 g[1:] += 100.0 * (2.0 * x[1:] - 2.0 * x[:-1] ** 2.0) g[:-1] += 100.0 * (-4.0 * x[1:] * x[:-1] + 4.0 * x[:-1] ** 3.0) # derivation of sum2 g[:-1] += 2.0 * (x[:-1] - 1.0) return g
[docs] def sphere(x: NDArrayFloat) -> float: """ The Sphere function. Parameters ---------- x : array_like 1-D array of points at which the Sphere function is to be computed. Returns ------- float The value of the Sphere function. """ return np.square(x).sum()
[docs] def sphere_grad(x: NDArrayFloat) -> NDArrayFloat: """ The gradient of the Sphere function. Parameters ---------- x : array_like 1-D array of points at which the Sphere function is to be derivated. Returns ------- NDArrayFloat The gradient of the Rosenbrock function. """ return 2 * np.asarray(x)
[docs] def styblinski_tang(x: NDArrayFloat) -> float: """ The Styblinski-Tang function. Parameters ---------- x : array_like 1-D array of points at which the Styblinski-Tang function is to be computed. Returns ------- float The value of the Styblinski-Tang function. """ x = np.asarray(x) sum1 = (np.power(x, 4) - 16.0 * np.square(x) + 5.0 * x).sum() return 0.5 * sum1 + 39.16599 * x.size
[docs] def styblinski_tang_grad(x: NDArrayFloat) -> NDArrayFloat: """ The gradient of the Styblinski-Tang function. Parameters ---------- x : array_like 1-D array of points at which the Styblinski-Tang function is to be derivated. Returns ------- NDArrayFloat The gradient of the Styblinski-Tang function. """ x = np.asarray(x) return 2.0 * np.power(x, 3) - 16.0 * x + 2.5