"""Online documentation:
https://pypop.readthedocs.io/en/latest/benchmarks.html#base-functions
"""
import numpy as np # engine for numerical computing
import math
# helper function
def squeeze_and_check(x, size_gt_1=False):
"""Squeeze the input `x` into 1-d `numpy.ndarray`.
And check whether its number of dimensions == 1. If not, raise a TypeError.
Optionally, check whether its size > 1. If not, raise a TypeError.
"""
x = np.squeeze(x)
if (x.ndim == 0) and (x.size == 1):
x = np.array([x])
if x.ndim != 1:
raise TypeError(f'The number of dimensions should == 1 (not {x.ndim}) after numpy.squeeze(x).')
if size_gt_1 and not (x.size > 1):
raise TypeError(f'The size should > 1 (not {x.size}) after numpy.squeeze(x).')
if x.size == 0:
raise TypeError(f'the size should != 0.')
return x
# helper class
class BaseFunction(object):
"""Class for all base functions.
"""
def __init__(self):
pass
[docs]def sphere(x):
"""**Sphere** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
y = np.sum(np.square(squeeze_and_check(x)))
return y
class Sphere(BaseFunction):
def __call__(self, x):
"""Class of **Sphere** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
return sphere(x)
[docs]def cigar(x):
"""**Cigar** test function.
.. note:: Its dimensionality should `> 1`.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
x = np.square(squeeze_and_check(x, True))
y = x[0] + (10.0 ** 6) * np.sum(x[1:])
return y
class Cigar(BaseFunction):
def __call__(self, x):
"""Class of **Cigar** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
return cigar(x)
[docs]def discus(x):
"""**Discus** (also called **Tablet**) test function.
.. note:: Its dimensionality should `> 1`.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
x = np.square(squeeze_and_check(x, True))
y = (10.0 ** 6) * x[0] + np.sum(x[1:])
return y
class Discus(BaseFunction): # also called Tablet
def __call__(self, x):
"""Class of **Discus** (also called **Tablet**) test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
return discus(x)
[docs]def cigar_discus(x):
"""**Cigar-Discus** test function.
.. note:: Its dimensionality should `> 1`.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
x = np.square(squeeze_and_check(x, True))
if x.size == 2:
y = x[0] + (10.0 ** 4) * np.sum(x) + (10.0 ** 6) * x[-1]
else:
y = x[0] + (10.0 ** 4) * np.sum(x[1:-1]) + (10.0 ** 6) * x[-1]
return y
class CigarDiscus(BaseFunction):
def __call__(self, x):
"""Class of **Cigar-Discus** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
return cigar_discus(x)
[docs]def ellipsoid(x):
"""**Ellipsoid** test function.
.. note:: Its dimensionality should `> 1`.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
x = np.square(squeeze_and_check(x, True))
y = np.dot(np.power(10.0, 6.0 * np.linspace(0.0, 1.0, x.size)), x)
return y
class Ellipsoid(BaseFunction):
def __call__(self, x):
"""Class of **Ellipsoid** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
return ellipsoid(x)
[docs]def different_powers(x):
"""**Different-Powers** test function.
.. note:: Its dimensionality should `> 1`.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
x = np.abs(squeeze_and_check(x, True))
y = np.sum(np.power(x, 2.0 + 4.0 * np.linspace(0.0, 1.0, x.size)))
return y
class DifferentPowers(BaseFunction):
def __call__(self, x):
"""Class of **Different-Powers** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
return different_powers(x)
[docs]def schwefel221(x):
"""**Schwefel221** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
y = np.max(np.abs(squeeze_and_check(x)))
return y
class Schwefel221(BaseFunction):
def __call__(self, x):
"""Class of **Schwefel221** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
return schwefel221(x)
[docs]def step(x):
"""**Step** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
y = np.sum(np.square(np.floor(squeeze_and_check(x) + 0.5)))
return y
class Step(BaseFunction):
def __call__(self, x):
"""Class of **Step** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
return step(x)
[docs]def schwefel222(x):
"""**Schwefel222** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
x = np.abs(squeeze_and_check(x))
y = np.sum(x) + np.prod(x)
return y
class Schwefel222(BaseFunction):
def __call__(self, x):
"""Class of **Schwefel222** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
return schwefel222(x)
[docs]def rosenbrock(x):
"""**Rosenbrock** test function.
.. note:: Its dimensionality should `> 1`.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
x = squeeze_and_check(x, True)
y = 100.0 * np.sum(np.square(x[1:] - np.square(x[:-1]))) + np.sum(np.square(x[:-1] - 1.0))
return y
class Rosenbrock(BaseFunction):
def __call__(self, x):
"""Class of **Rosenbrock** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
return rosenbrock(x)
[docs]def schwefel12(x):
"""**Schwefel12** test function.
.. note:: Its dimensionality should `> 1`.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
x = squeeze_and_check(x, True)
x = [np.sum(x[:i + 1]) for i in range(x.size)]
y = np.sum(np.square(x))
return y
class Schwefel12(BaseFunction):
def __call__(self, x):
"""Class of **Schwefel12** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
return schwefel12(x)
[docs]def exponential(x):
"""**Exponential** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
x = squeeze_and_check(x)
y = -np.exp(-0.5 * np.sum(np.square(x)))
return y
class Exponential(BaseFunction):
def __call__(self, x):
"""Class of **Exponential** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
return exponential(x)
[docs]def griewank(x):
"""**Griewank** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
x = squeeze_and_check(x)
y = np.sum(np.square(x)) / 4000.0 - np.prod(np.cos(x / np.sqrt(np.arange(1, x.size + 1)))) + 1.0
return y
class Griewank(BaseFunction):
def __call__(self, x):
"""Class of **Griewank** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
return griewank(x)
[docs]def bohachevsky(x):
"""**Bohachevsky** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
x, y = squeeze_and_check(x), 0.0
for i in range(x.size - 1):
y += np.square(x[i]) + 2.0 * np.square(x[i + 1]) - 0.3 * np.cos(3.0 * np.pi * x[i]) - \
0.4 * np.cos(4.0 * np.pi * x[i + 1]) + 0.7
return y
class Bohachevsky(BaseFunction):
def __call__(self, x):
"""
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
return bohachevsky(x)
[docs]def ackley(x):
"""**Ackley** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
x = squeeze_and_check(x)
y = -20.0 * np.exp(-0.2 * np.sqrt(np.sum(np.square(x)) / x.size)) - \
np.exp(np.sum(np.cos(2.0 * np.pi * x)) / x.size) + 20.0 + np.exp(1)
return y
class Ackley(BaseFunction):
def __call__(self, x):
"""Class of **Ackley** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
return ackley(x)
[docs]def rastrigin(x):
"""**Rastrigin** test function.
.. note:: It's LaTeX formulation is `$10 n + \sum_{i = 1}^{n} (x_i^2 - 10 \cos(2 \pi x_i))$`.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
x = squeeze_and_check(x)
y = 10.0 * x.size + np.sum(np.square(x) - 10.0 * np.cos(2.0 * np.pi * x))
return y
class Rastrigin(BaseFunction):
def __call__(self, x):
"""
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
return rastrigin(x)
[docs]def scaled_rastrigin(x):
"""**Scaled-Rastrigin** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
x, w = squeeze_and_check(x), np.power(10.0, np.linspace(0.0, 1.0, len(x)))
x *= w
y = 10.0 * len(x) + np.sum(np.square(x) - 10.0 * np.cos(2.0 * np.pi * x))
return y
class ScaledRastrigin(BaseFunction):
def __call__(self, x):
"""Class of **Scaled-Rastrigin** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
return scaled_rastrigin(x)
[docs]def skew_rastrigin(x):
"""**Skew-Rastrigin** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
x = squeeze_and_check(x)
for i in range(x.size):
if x[i] > 0.0:
x[i] *= 10.0
y = rastrigin(x)
return y
class SkewRastrigin(BaseFunction):
def __call__(self, x):
"""Class of **Skew-Rastrigin** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
return skew_rastrigin(x)
[docs]def levy_montalvo(x):
"""**Levy-Montalvo** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
x, y = 1.0 + 0.25 * (squeeze_and_check(x) + 1.0), 0.0
for i in range(x.size - 1):
y += np.square(x[i] - 1.0) * (1.0 + 10.0 * np.square(np.sin(np.pi * x[i + 1])))
y += 10.0 * np.square(np.sin(np.pi * x[0])) + np.square(x[-1] - 1.0)
return (np.pi / x.size) * y
class LevyMontalvo(BaseFunction):
def __call__(self, x):
"""Class of **Levy-Montalvo** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
return levy_montalvo(x)
[docs]def michalewicz(x):
"""**Michalewicz** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
x, y = squeeze_and_check(x), 0.0
for i in range(x.size):
y -= np.sin(x[i]) * np.power(np.sin((i + 1) * np.square(x[i]) / np.pi), 20)
return y
class Michalewicz(BaseFunction):
def __call__(self, x):
"""Class of **Michalewicz** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
return michalewicz(x)
[docs]def salomon(x):
"""**Salomon** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
x = np.sqrt(np.sum(np.square(squeeze_and_check(x))))
return 1.0 - np.cos(2.0 * np.pi * x) + 0.1 * x
class Salomon(BaseFunction):
def __call__(self, x):
"""Class of **Salomon** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
return salomon(x)
[docs]def shubert(x):
"""**Shubert** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
x, y = squeeze_and_check(x), 1.0
for i in range(x.size):
yy = 0.0
for j in range(1, 6):
yy += j * np.cos((j + 1) * x[i] + j)
y *= yy
return y
class Shubert(BaseFunction):
def __call__(self, x):
"""Class of **Shubert** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
return shubert(x)
[docs]def schaffer(x):
"""**Schaffer** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
x, y = squeeze_and_check(x), 0.0
for i in range(x.size - 1):
xx = np.power(x[i], 2) + np.power(x[i + 1], 2)
y += np.power(xx, 0.25) * (np.power(np.sin(50.0 * np.power(xx, 0.1)), 2) + 1.0)
return y
class Schaffer(BaseFunction):
def __call__(self, x):
"""Class of **Schaffer** test function.
Parameters
----------
x : ndarray
input vector.
Returns
-------
y : float
scalar fitness.
"""
return schaffer(x)
# all of the following functions are only for visualization purpose
def cosine(x):
"""**Cosine** test function.
Parameters
----------
x: ndarray
input vector.
Returns
-------
y: float
scalar fitness.
"""
y = 10.0 * x[0] ** 2 * (1.0 + 0.75 * math.cos(70.0 * x[0]) / 12.0) + math.cos(100.0 * x[0]) ** 2 / 24.0 + \
2.0 * x[1] ** 2 * (1.0 + 0.75 * math.cos(70.0 * x[1]) / 12.0) + math.cos(100.0 * x[1]) ** 2 / 24.0 + \
4.0 * x[0] * x[1]
return y
def dennis_woods(x):
"""**Dennis-Woods** test function.
Parameters
----------
x: ndarray
input vector.
Returns
-------
y: float
scalar fitness.
References
----------
Dennis, J. E., Daniel J. Woods, 1987.
Optimization on microcomputers: The Nelder-Mead simplex algorithm.
New computing environments: microcomputers in large-scale computing, 11, p. 6-122.
"""
c_1 = np.array([1.0, -1.0])
y = 0.5 * max(np.linalg.norm(x - c_1) ** 2, np.linalg.norm(x + c_1) ** 2)
return y