spotoptim ships with a collection of well-known test functions for optimization benchmarking. All functions accept a 2-D array of shape (n_samples, n_features) and return a 1-D array of shape (n_samples,). They live in spotoptim.function.
Single-Objective Functions
Sphere
The simplest test function: \(f(\mathbf{x}) = \sum_{i=1}^{d} x_i^2\) . Global minimum at the origin.
import numpy as np
from spotoptim.function import sphere
X = np.array([[0.0 , 0.0 ], [1.0 , 2.0 ], [- 3.0 , 4.0 ]])
y = sphere(X)
print (f"sphere([0,0]) = { y[0 ]:.1f} " )
print (f"sphere([1,2]) = { y[1 ]:.1f} " )
print (f"sphere([-3,4]) = { y[2 ]:.1f} " )
sphere([0,0]) = 0.0
sphere([1,2]) = 5.0
sphere([-3,4]) = 25.0
Noisy Sphere
Sphere with additive Gaussian noise: \(f(\mathbf{x}) = \sum x_i^2 + \mathcal{N}(0, \sigma^2)\) . Useful for testing noise-handling strategies (repeats, OCBA).
import numpy as np
from spotoptim.function import noisy_sphere
np.random.seed(0 )
X = np.array([[0.0 , 0.0 ], [0.0 , 0.0 ], [0.0 , 0.0 ]])
y = noisy_sphere(X, sigma= 0.1 )
print (f"Three evaluations at origin: { y} " )
print (f"Mean: { y. mean():.4f} , Std: { y. std():.4f} " )
Three evaluations at origin: [0.17640523 0.04001572 0.0978738 ]
Mean: 0.1048, Std: 0.0559
Rosenbrock
A classic non-convex function with a narrow curved valley: \(f(x, y) = (1 - x)^2 + 100(y - x^2)^2\) . Global minimum at \((1, 1, \ldots, 1)\) .
import numpy as np
from spotoptim.function import rosenbrock
X = np.array([[1.0 , 1.0 ], [0.0 , 0.0 ], [- 1.0 , 2.0 ]])
y = rosenbrock(X)
print (f"rosenbrock([1,1]) = { y[0 ]:.1f} (global min)" )
print (f"rosenbrock([0,0]) = { y[1 ]:.1f} " )
print (f"rosenbrock([-1,2]) = { y[2 ]:.1f} " )
rosenbrock([1,1]) = 0.0 (global min)
rosenbrock([0,0]) = 1.0
rosenbrock([-1,2]) = 104.0
Ackley
Multi-modal function with many local minima: global minimum \(f(\mathbf{0}) = 0\) .
import numpy as np
from spotoptim.function import ackley
X = np.array([[0.0 , 0.0 ], [1.0 , 1.0 ]])
y = ackley(X)
print (f"ackley([0,0]) = { y[0 ]:.4f} (global min)" )
print (f"ackley([1,1]) = { y[1 ]:.4f} " )
ackley([0,0]) = 0.0000 (global min)
ackley([1,1]) = 3.6254
Michalewicz
A function with steep valleys whose depth increases with the steepness parameter \(m\) . The 2-D minimum is approximately \(-1.8013\) .
import numpy as np
from spotoptim.function import michalewicz
X = np.array([[2.20 , 1.57 ]])
y = michalewicz(X, m= 10 )
print (f"michalewicz([2.20, 1.57]) = { y[0 ]:.4f} " )
michalewicz([2.20, 1.57]) = -1.8011
Engineering Functions
spotoptim also includes engineering benchmark functions:
wingwt — Wing weight estimation (9 or 10 dimensions, unit-cube domain)
robot_arm_hard — 10-link robot arm maze navigation (10 dimensions)
robot_arm_obstacle — 10-link robot arm with obstacle avoidance
lennard_jones — Lennard-Jones atomic cluster potential (39 dimensions for 13 atoms)
import numpy as np
from spotoptim.function import robot_arm_hard
X = np.random.default_rng(0 ).uniform(0 , 1 , size= (3 , 10 ))
y = robot_arm_hard(X)
print (f"robot_arm_hard evaluations: { y} " )
robot_arm_hard evaluations: [2449.04444121 77.46661349 52.03648314]
Optimizing a Built-in Function
from spotoptim import SpotOptim
from spotoptim.function import ackley
opt = SpotOptim(
fun= ackley,
bounds= [(- 5 , 5 ), (- 5 , 5 )],
acquisition= "ei" ,
max_iter= 25 ,
n_initial= 10 ,
seed= 0 ,
)
result = opt.optimize()
print (f"Best x : { result. x} " )
print (f"Best f(x) : { result. fun:.6f} " )
Best x : [-0.02052553 0.01131928]
Best f(x) : 0.080871
Writing a Custom Objective
Your objective function must accept a 2-D array X of shape (n_samples, n_features) and return a 1-D array of shape (n_samples,):
import numpy as np
from spotoptim import SpotOptim
def my_objective(X):
X = np.atleast_2d(X)
x, y = X[:, 0 ], X[:, 1 ]
return np.sin(x) * np.cos(y) + 0.1 * (x** 2 + y** 2 )
opt = SpotOptim(
fun= my_objective,
bounds= [(- 3 , 3 ), (- 3 , 3 )],
max_iter= 20 ,
n_initial= 10 ,
seed= 0 ,
)
result = opt.optimize()
print (f"Best x : { result. x} " )
print (f"Best f(x) : { result. fun:.6f} " )
Best x : [-1.30649014e+00 3.36801544e-04]
Best f(x) : -0.794582
Multi-Objective Functions
Multi-objective functions return arrays of shape (n_samples, n_objectives). They live in spotoptim.function alongside the single-objective functions.
import numpy as np
from spotoptim.function import fonseca_fleming
X = np.array([[0.0 , 0.0 ], [0.5 , 0.5 ], [- 1.0 , 1.0 ]])
y = fonseca_fleming(X)
print (f"Shape: { y. shape} " )
print (f"fonseca_fleming([0, 0]) = { y[0 ]} " )
print (f"fonseca_fleming([0.5, 0.5]) = { y[1 ]} " )
Shape: (3, 2)
fonseca_fleming([0, 0]) = [0.63212056 0.63212056]
fonseca_fleming([0.5, 0.5]) = [0.08220978 0.94575332]
Available multi-objective functions include zdt1 through zdt6, dtlz1, dtlz2, fonseca_fleming, schaffer_n1, and kursawe. See Multi-Objective Optimization for details on optimizing these.