function.so

function.so

Analytical single-objective test functions for optimization benchmarking.

This module provides well-known analytical test functions commonly used for evaluating and benchmarking optimization algorithms.

Functions

Name Description
ackley N-dimensional Ackley function.
factor_quadratic Mixed continuous + nominal-factor benchmark with index-scrambled level structure.
lennard_jones Lennard-Jones Atomic Cluster Potential Energy.
michalewicz N-dimensional Michalewicz function.
noisy_sphere N-dimensional Sphere function with noise.
robot_arm_hard 10-Link Robot Arm with Maze-Like Hard Constraints.
robot_arm_obstacle 10-Link Planar Robot Arm Inverse Kinematics with Obstacle Avoidance.
rosenbrock N-dimensional Rosenbrock function.
sphere N-dimensional Sphere function.
wingwt Aircraft Wing Weight function.

ackley

function.so.ackley(X)

N-dimensional Ackley function.

The Ackley function is a widely used test function for optimization algorithms. It is characterized by a nearly flat outer region and a large hole at the center. The function is multimodal with many local minima but only one global minimum.

Mathematical formula

f(X) = -a * exp(-b * sqrt(sum(x_i^2) / n)) - exp(sum(cos(c * x_i)) / n) + a + e

where

  • a = 20 (default)
  • b = 0.2 (default)
  • c = 2π (default)
  • e = exp(1) ≈ 2.71828
  • n = number of dimensions

Parameters

Name Type Description Default
X array - like Input points with shape (n_samples, n_features) or (n_features,). Can be a 1D array for a single point or 2D array for multiple points. required

Returns

Name Type Description
np.ndarray np.ndarray: Function values at the input points with shape (n_samples,).

Note

  • Global minimum: f(0, 0, …, 0) = 0
  • Typical search domain: [-32.768, 32.768]^N
  • Characteristics: Non-convex, multimodal, separable

Examples

Single point evaluation at global minimum:

from spotoptim.function import ackley
import numpy as np
X = np.array([0.0, 0.0, 0.0])
ackley(X)
array([4.4408921e-16])

Multiple points evaluation:

from spotoptim.function import ackley
import numpy as np
X = np.array([[0.0, 0.0], [1.0, 1.0], [-1.0, 1.0]])
result = ackley(X)
result[0]  # Should be close to 0
result[1] > 0  # Should be positive
np.True_

References

Ackley, D. H. (1987). “A connectionist machine for genetic hillclimbing”. Kluwer Academic Publishers.

factor_quadratic

function.so.factor_quadratic(X, levels=FACTOR_QUADRATIC_LEVELS, amp=8.0)

Mixed continuous + nominal-factor benchmark with index-scrambled level structure.

A deliberately adversarial test function with 1 continuous dimension and 1 nominal (unordered) factor with many levels (16 by default). The continuous part is a simple bowl shared by all levels; each level adds a vertical offset drawn from a fixed index-scrambled permutation, so that adjacency in the integer level index carries no information about the objective value.

A surrogate that treats the factor as an ordinal/continuous integer (Euclidean or Canberra distance on the codes) wrongly assumes neighbouring indices behave similarly and is systematically misled — most strongly in the data-sparse regime typical of expensive black-box optimization, where most levels are observed only a few times. A nominal (Hamming) kernel treats all distinct levels as equidistant and learns each level’s contribution independently, so it builds a more accurate surrogate from the same budget.

Mathematical definition (with n = len(levels))::

offset = perm / (n - 1)          # perm = fixed permutation of {0, .., n-1}
f(x, c) = x**2 + amp * offset[idx(c)]

where idx maps a factor label to its integer index.

Parameters

Name Type Description Default
X array - like Input array of shape (n_samples, 2) or (2,). Column 0 is the continuous variable x ∈ [-3, 3]. Column 1 is the factor column, accepted as either string labels (the entries of levels) or numeric indices 0 .. n-1 — enabling both standalone unit testing and direct use by SpotOptim (which passes the factor column as string labels). required
levels tuple of str Ordered sequence of factor labels. Its length sets the number of levels. Defaults to :data:FACTOR_QUADRATIC_LEVELS (16 levels "c00" .. "c15"). FACTOR_QUADRATIC_LEVELS
amp float Scale of the per-level offset term. Defaults to 8.0. 8.0

Returns

Name Type Description
np.ndarray np.ndarray: Function values of shape (n_samples,) with dtype float.

Note

Global optimum (default 16 levels): f(x=0, c="c04") = 0.0. The optimal level is the index where the scrambled offset is 0.

Why ordinal encoding fails: with the default levels the optimum (index 4) is flanked in index space by a bad level (index 3, offset ≈0.67). An ordinal kernel interpolates between adjacent indices and therefore under-ranks the optimal level; a Hamming kernel does not. The benefit of the nominal kernel is largest when the number of levels is large relative to the evaluation budget — see scripts/factor_kernel_benchmark.py.

Examples

import numpy as np
from spotoptim.function import factor_quadratic
# global optimum: x=0 at level "c04"
print(factor_quadratic(np.array([[0.0, "c04"]], dtype=object)))
# a different level is worse
print(factor_quadratic(np.array([[0.0, "c15"]], dtype=object)))
[0.]
[8.]

lennard_jones

function.so.lennard_jones(X, n_atoms=13)

Lennard-Jones Atomic Cluster Potential Energy.

Calculates the potential energy of a cluster of N atoms interacting via the Lennard-Jones potential. The optimization problem involves finding the atomic coordinates that minimize the total potential energy. This is a classic benchmark problem known for its high difficulty due to the exponential growth of local minima with N.

Input Domain Handling

The function accepts inputs in the range [0, 1] and internally maps them to the search domain [-2, 2] for each coordinate.

Parameters

Name Type Description Default
X np.ndarray Input points. - Shape (n_samples, 3 * n_atoms) for batch evaluation. - Shape (3 * n_atoms,) for single evaluation. The input represents the flattened [x1, y1, z1, x2, y2, z2, …] coordinates. required
n_atoms int Number of atoms in the cluster. Defaults to 13. 13

Returns

Name Type Description
np.ndarray np.ndarray: Potential energy values. Shape (n_samples,).

Raises

Name Type Description
ValueError If input dimensions do not match 3 * n_atoms.

Note

  • Global minimum for N=13: E ≈ -44.3268
  • Search domain: [-2, 2]^(3N) (mapped from [0, 1])
  • Characteristics: Extremely rugged landscape, non-convex, many local minima.

Examples

Single point evaluation (random configuration):

from spotoptim.function import lennard_jones
import numpy as np
rng = np.random.default_rng(42)
X = rng.random(39)  # 13 atoms * 3 coords, in [0, 1]
lennard_jones(X)
array([74.35227958])

Batch evaluation:

from spotoptim.function import lennard_jones
import numpy as np
rng = np.random.default_rng(42)
X = rng.random((5, 39))
lennard_jones(X).shape
(5,)

References

Wales, D. J., & Doye, J. P. (1997). Global optimization by basin-hopping and the lowest energy structures of Lennard-Jones clusters containing up to 110 atoms. The Journal of Physical Chemistry A, 101(28), 5111-5116.

michalewicz

function.so.michalewicz(X, m=10)

N-dimensional Michalewicz function.

The Michalewicz function is a multimodal test function with steep ridges and valleys. The parameter m defines the steepness of the valleys and ridges. Larger values of m result in more difficult search problems. The number of local minima increases exponentially with the dimension.

Mathematical formula

f(X) = -sum_{i=1}^{n} sin(x_i) * [sin(i * x_i^2 / π)]^(2m)

Parameters

Name Type Description Default
X array - like Input points with shape (n_samples, n_features) or (n_features,). Can be a 1D array for a single point or 2D array for multiple points. required
m int Steepness parameter. Higher values make the function more difficult to optimize. Defaults to 10. 10

Returns

Name Type Description
np.ndarray np.ndarray: Function values at the input points with shape (n_samples,).

Note

  • Global minimum depends on dimension:
    • 2D: f(2.20, 1.57) ≈ -1.8013
    • 5D: f ≈ -4.687658
    • 10D: f ≈ -9.66015
  • Typical search domain: [0, π]^N
  • Characteristics: Non-convex, multimodal, non-separable

Examples

Single point evaluation:

from spotoptim.function import michalewicz
import numpy as np
X = np.array([2.20, 1.57])
result = michalewicz(X)
result[0]  # Should be close to -1.8013
np.float64(-1.801140718473825)

Multiple points evaluation:

from spotoptim.function import michalewicz
import numpy as np
X = np.array([[2.20, 1.57], [1.0, 1.0]])
michalewicz(X)
array([-1.80114072e+00, -2.55738728e-05])

Using different steepness parameter:

from spotoptim.function import michalewicz
import numpy as np
X = np.array([2.20, 1.57])
michalewicz(X, m=5)
array([-1.80481006])

References

Michalewicz, Z. (1996). “Genetic Algorithms + Data Structures = Evolution Programs”. Springer-Verlag.

noisy_sphere

function.so.noisy_sphere(X, sigma=0.1)

N-dimensional Sphere function with noise.

Parameters

Name Type Description Default
X array - like Input points with shape (n_samples, n_features) or (n_features,). Can be a 1D array for a single point or 2D array for multiple points. required
sigma float Standard deviation of the noise. Defaults to 0.1. 0.1

Returns

Name Type Description
np.ndarray np.ndarray: Function values at the input points with shape (n_samples,).

Raises

Name Type Description
ValueError If X has fewer than 1 dimension.

Note

  • Global minimum: f(0, 0, …, 0) = 0
  • Typical search domain: [-5, 10]^N or [-2, 2]^N
  • Characteristics: Convex, unimodal

Examples

from spotoptim.function import noisy_sphere
import numpy as np
X = np.array([1.0, 1.0])
noisy_sphere(X, sigma=0.1)
array([1.88543705])
from spotoptim.function import noisy_sphere
import numpy as np
X = np.array([[0.0, 0.0], [1.0, 1.0], [0.5, 0.5]])
noisy_sphere(X, sigma=0.1)
array([0.0606928 , 1.93382676, 0.51001547])

robot_arm_hard

function.so.robot_arm_hard(X)

10-Link Robot Arm with Maze-Like Hard Constraints.

A challenging constrained optimization problem where a 10-link planar robot arm must reach a target point (5.0, 5.0) while avoiding multiple obstacles forming a maze-like environment. This function tests an optimizer’s ability to handle hard constraints and navigate complex feasible regions.

The problem features three main difficulty factors: 1. ‘The Great Wall’: A vertical barrier at x=2.5 blocking direct paths 2. ‘The Ceiling’: A horizontal bar at y=8.5 preventing high loop strategies 3. ‘The Target Trap’: Obstacles surrounding the target, requiring precise approach

Mathematical formulation

f(X) = distance_cost + constraint_penalty + energy_regularization

where

  • distance_cost = (x_end - 5.0)^2 + (y_end - 5.0)^2
  • constraint_penalty = 10,000 * sum(max(0, r - d + 0.05)^2) for all joints and obstacles
  • energy_regularization = 0.01 * sum(angles^2)

Parameters

Name Type Description Default
X np.ndarray Input points with shape (n_samples, 10) or (10,). Each sample contains 10 joint angles normalized to [0, 1], which are internally mapped to [-1.2π, 1.2π] to allow looping strategies. Can be a 1D array for a single point or 2D array for multiple points. required

Returns

Name Type Description
np.ndarray np.ndarray: Function values at the input points with shape (n_samples,). Lower values indicate better solutions (closer to target with fewer constraint violations).

Note

  • Dimension: 10 (one angle per link)
  • Link length: L = 1.0 for all links
  • Target position: (5.0, 5.0)
  • Search domain: [0, 1]^10 (mapped internally to [-1.2π, 1.2π]^10)
  • Characteristics: Highly constrained, non-convex, multimodal
  • Constraint penalty: 10,000 per violation (effectively hard constraints)
  • Number of obstacles: ~30 forming walls and traps
  • Feasible region: Very small relative to search space

Examples

Single point evaluation with random configuration:

from spotoptim.function import robot_arm_hard
import numpy as np
X = np.random.rand(10) * 0.5  # Conservative random angles
result = robot_arm_hard(X)
result.shape
(1,)
(1,)

Multiple points evaluation:

from spotoptim.function import robot_arm_hard
import numpy as np
X = np.array([[0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5],
              [0.3, 0.4, 0.5, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0]])
robot_arm_hard(X)
array([269.77734305, 144.65586174])

Evaluating a straight configuration (all angles = 0.5, mapped to 0 radians):

from spotoptim.function import robot_arm_hard
import numpy as np
X_straight = np.full(10, 0.5)
cost_straight = robot_arm_hard(X_straight)
cost_straight[0] > 1000  # High cost due to obstacles
np.False_

References

This function is inspired by robot motion planning problems with obstacles, commonly studied in:

  • LaValle, S. M. (2006). “Planning Algorithms”. Cambridge University Press.
  • Choset, H., et al. (2005). “Principles of Robot Motion: Theory, Algorithms, and Implementations”. MIT Press.

robot_arm_obstacle

function.so.robot_arm_obstacle(X)

10-Link Planar Robot Arm Inverse Kinematics with Obstacle Avoidance.

The goal is to minimize the distance of the end-effector to a target point while avoiding collision with a set of circular obstacles. This problem mimics a real-world inverse kinematics solver for a redundant manipulator.

Input Domain Handling

The function accepts inputs in the range [0, 1] and internally maps them to the search domain [-pi, pi] for each joint angle (radians).

Parameters

Name Type Description Default
X np.ndarray Input angles (normalized). - Shape (n_samples, 10). The input contains the normalized relative angles for the 10 links. required

Returns

Name Type Description
np.ndarray np.ndarray: Cost values (Weighted sum of Distance + Penalty). Shape (n_samples,).

Raises

Name Type Description
ValueError If input dimensions do not match 10.

Note

  • Target: (5.0, 5.0)
  • Obstacles:
    • Order 1: (2,2), r=1
    • Order 2: (4,3), r=1.5
    • Order 3: (3,6), r=1
  • Dimensions: 10 (fixed)
  • Search domain: [-pi, pi]^10 (mapped from [0, 1])
  • Characteristics: Multimodal, disjoint feasible regions, constrained.

Examples

Single point evaluation:

from spotoptim.function.so import robot_arm_obstacle
import numpy as np
rng = np.random.default_rng(42)
X = rng.random(10)  # Random angles in [0, 1]
robot_arm_obstacle(X)
array([60.85746763])

Batch evaluation:

from spotoptim.function.so import robot_arm_obstacle
import numpy as np
X = rng.random((5, 10))
robot_arm_obstacle(X).shape
(5,)

rosenbrock

function.so.rosenbrock(X)

N-dimensional Rosenbrock function.

The Rosenbrock function is a classic test function for optimization algorithms. It is characterized by a long, narrow, parabolic-shaped valley. The global minimum is inside the valley and is hard to find for many algorithms.

For the 2D case

f(x, y) = (1 - x)^2 + 100 * (y - x2)2

The generalized form for N dimensions

f(X) = sum_{i=1}^{N-1} [100 * (x_{i+1} - x_i2)2 + (1 - x_i)^2]

Parameters

Name Type Description Default
X array - like Input points with shape (n_samples, n_features) or (n_features,). Can be a 1D array for a single point or 2D array for multiple points. required

Returns

Name Type Description
np.ndarray np.ndarray: Function values at the input points with shape (n_samples,).

Raises

Name Type Description
ValueError If X has fewer than 2 dimensions.

Note

  • Global minimum: f(1, 1, …, 1) = 0
  • Typical search domain: [-5, 10]^N or [-2, 2]^N
  • Characteristics: Non-convex, unimodal

Examples

Single point evaluation:

from spotoptim.function import rosenbrock
import numpy as np
X = np.array([1.0, 1.0])
rosenbrock(X)
array([0.])

Multiple points evaluation:

from spotoptim.function import rosenbrock
import numpy as np
X = np.array([[0.0, 0.0], [1.0, 1.0], [0.5, 0.5]])
rosenbrock(X)
array([1. , 0. , 6.5])

References

Rosenbrock, H.H. (1960). “An automatic method for finding the greatest or least value of a function”. The Computer Journal. 3 (3): 175–184.

sphere

function.so.sphere(X)

N-dimensional Sphere function.

The Sphere function is a simple test function for optimization algorithms. It is characterized by a parabolic-shaped valley. The global minimum is inside the valley and is easy to find for many algorithms.

For the 2D case

f(x, y) = x^2 + y^2

The generalized form for N dimensions

f(X) = sum_{i=1}^{N} x_i^2

Parameters

Name Type Description Default
X array - like Input points with shape (n_samples, n_features) or (n_features,). Can be a 1D array for a single point or 2D array for multiple points. required

Returns

Name Type Description
np.ndarray np.ndarray: Function values at the input points with shape (n_samples,).

Raises

Name Type Description
ValueError If X has fewer than 1 dimension.

Note

  • Global minimum: f(0, 0, …, 0) = 0
  • Typical search domain: [-5, 10]^N or [-2, 2]^N
  • Characteristics: Convex, unimodal

Examples

from spotoptim.function import sphere
import numpy as np
X = np.array([1.0, 1.0])
sphere(X)
array([2.])
from spotoptim.function import sphere
import numpy as np
X = np.array([[0.0, 0.0], [1.0, 1.0], [0.5, 0.5]])
sphere(X)
array([0. , 2. , 0.5])

wingwt

function.so.wingwt(X)

Aircraft Wing Weight function.

The example models the weight of an unpainted light aircraft wing. The function accepts inputs in the unit cube [0,1]^9 and returns the wing weight.

Parameters

Name Type Description Default
X array - like Input points with shape (n_samples, 9) or (9,) or (10,) or (n_samples, 10). Input variables order: [Sw, Wfw, A, L, q, l, Rtc, Nz, Wdg, Wp(optional)] required

Returns

Name Type Description
np.ndarray np.ndarray: Wing weight values at the input points with shape (n_samples,).

Examples

Single point evaluation (Baseline Cessna C172 - Unpainted):

from spotoptim.function.so import wingwt
import numpy as np
# Baseline configuration in unit cube
x_base = np.array([0.48, 0.4, 0.38, 0.5, 0.62, 0.344, 0.4, 0.37, 0.38])
wingwt(x_base)
array([233.90840542])

Batch evaluation:

from spotoptim.function.so import wingwt
import numpy as np
x_base = np.array([0.48, 0.4, 0.38, 0.5, 0.62, 0.344, 0.4, 0.37, 0.38])
X = np.vstack([x_base, x_base])
wingwt(X)
array([233.90840542, 233.90840542])

References

Forrester, A., Sobester, A., & Keane, A. (2008). Engineering design via surrogate modelling: a practical guide. John Wiley & Sons.