CMA-ES, Covariance Matrix Adaptation Evolution Strategy for non-linear numerical optimization in Python
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Comprehensive collection of test functions, benchmark problems, and fitness transformations for algorithm testing, validation, and performance evaluation.
The ff module provides a rich collection of test functions commonly used in optimization research and algorithm benchmarking. All functions are accessible via cma.ff.<function_name>.
# Complete list of available test functions in cma.ff module
import cma
# Basic quadratic functions
cma.ff.sphere # Sphere function: sum(x**2)
cma.ff.elli # Ellipsoid function with conditioning
cma.ff.cigar # Cigar function: x[0]**2 + 1e6*sum(x[1:]**2)
cma.ff.tablet # Tablet function: 1e6*x[0]**2 + sum(x[1:]**2)
cma.ff.twoaxes # Two-axes function with group separability
cma.ff.ellirot # Rotated ellipsoid function
# Multi-modal functions
cma.ff.rosen # Rosenbrock function
cma.ff.diffpowell # Different powers function
cma.ff.rastrigin # Rastrigin function with many local minima
cma.ff.schwefel # Schwefel function
cma.ff.griewank # Griewank function
cma.ff.ackley # Ackley function
# Noise and randomness
cma.ff.noise # Add Gaussian noise to any function
cma.ff.noisysphere # Noisy sphere function
cma.ff.spherenoise # Sphere with added noise
# Step functions and plateaus
cma.ff.step # Step function
cma.ff.parab # Parabolic ridge function
# Composition functions
cma.ff.composed # Composition of multiple functions
# Special test cases
cma.ff.optprob # Optimization problem wrapper
cma.ff.warped # Warped/transformed function space# Access test functions through cma.ff
import cma
# Basic quadratic functions
def sphere(x):
"""
Sphere function - simplest quadratic test function.
Global minimum: f(0, ..., 0) = 0
Properties: Unimodal, separable, quadratic
"""
return sum(x**2)
def elli(x, cond=1e6):
"""
Ellipsoid function - ill-conditioned quadratic.
Parameters:
-----------
x : array-like
Input vector.
cond : float, optional
Condition number (default 1e6).
Global minimum: f(0, ..., 0) = 0
Properties: Unimodal, separable, ill-conditioned
"""
N = len(x)
return sum(cond**(np.arange(N) / (N - 1 + 1e-9)) * np.asarray(x)**2)
# Usage examples
>>> import cma
>>>
>>> # Sphere function
>>> f_val = cma.ff.sphere([1, 2, 3]) # Returns 14.0
>>>
>>> # Ellipsoid with different condition numbers
>>> f_val = cma.ff.elli([1, 1, 1]) # Default condition 1e6
>>> f_val = cma.ff.elli([1, 1, 1], cond=100) # Condition number 100
>>>
>>> # Use in optimization
>>> x, es = cma.fmin2(cma.ff.sphere, [1, 2, 3], 0.5)
>>> x, es = cma.fmin2(cma.ff.elli, [1, 2, 3], 0.5)# Non-separable functions available through cma.ff
import cma
# Cigar function - one dominant direction
>>> def cigar_example():
... """Cigar function: x[0]^2 + cond * sum(x[1:]^2)"""
... x, es = cma.fmin2(cma.ff.cigar, [1, 2, 3, 4], 0.5)
... print(f"Cigar result: {x}")
... return x, es
# Tablet function - one weak direction
>>> def tablet_example():
... """Tablet function: cond * x[0]^2 + sum(x[1:]^2)"""
... x, es = cma.fmin2(cma.ff.tablet, [1, 2, 3, 4], 0.5)
... print(f"Tablet result: {x}")
... return x, es
# Two-axes function - group separability
>>> def twoaxes_example():
... """Two-axes function with different conditioning"""
... x, es = cma.fmin2(cma.ff.twoaxes, 6 * [0.5], 0.3)
... print(f"Two-axes result: {x}")
... return x, es
# Rotated ellipsoid - no separability
>>> def ellirot_example():
... """Rotated ellipsoid - tests rotation invariance"""
... x, es = cma.fmin2(cma.ff.ellirot, [1, 2, 3], 0.5)
... print(f"Rotated ellipsoid result: {x}")
... return x, es# Multi-modal and difficult functions
import cma
import numpy as np
# Rosenbrock function - classic benchmark
>>> def rosenbrock_example():
... """Rosenbrock function - narrow curved valley"""
... # The Rosenbrock function is available as cma.ff.rosen
... x, es = cma.fmin2(cma.ff.rosen, 4 * [0], 0.5)
... print(f"Rosenbrock result: {x}") # Should be close to [1, 1, 1, 1]
... return x, es
# Rastrigin function - many local minima
>>> def rastrigin_example():
... """Rastrigin function - highly multi-modal"""
... # Note: Rastrigin may be in BBOB collection
... def rastrigin(x):
... A = 10
... n = len(x)
... return A * n + sum(xi**2 - A * np.cos(2 * np.pi * xi) for xi in x)
...
... x, es = cma.fmin2(rastrigin, 5 * [2.0], 1.0,
... options={'maxfevals': 10000})
... print(f"Rastrigin result: {x}")
... return x, es
# Ackley function - many local minima with global structure
>>> def ackley_example():
... """Ackley function - exponential multi-modal"""
... def ackley(x):
... x = np.asarray(x)
... n = len(x)
... return (-20 * np.exp(-0.2 * np.sqrt(sum(x**2) / n)) -
... np.exp(sum(np.cos(2 * np.pi * xi) for xi in x) / n) +
... 20 + np.e)
...
... x, es = cma.fmin2(ackley, 3 * [1.0], 0.5)
... print(f"Ackley result: {x}")
... return x, es# Special test functions with constraints or unusual properties
import cma
import numpy as np
# Functions with constraints built-in
>>> def constrained_sphere_example():
... """Sphere function with constraint x[0] > 1"""
... x, es = cma.fmin2(cma.ff.spherewithoneconstraint, [2, 1, 1], 0.3)
... print(f"Constrained sphere result: {x}")
... return x, es
# Asymmetric functions
>>> def sectorsphere_example():
... """Asymmetric sphere - different scaling for negative values"""
... x, es = cma.fmin2(cma.ff.sectorsphere, [1, -1, 0], 0.5)
... print(f"Sector sphere result: {x}")
... return x, es
# Functions with corners/boundaries
>>> def cornersphere_example():
... """Sphere function constrained to corner x >= 1"""
... x, es = cma.fmin2(cma.ff.cornersphere, [1.5, 1.5, 1.5], 0.2)
... print(f"Corner sphere result: {x}")
... return x, es
# Noisy functions
>>> def noisy_sphere_example():
... """Sphere function with multiplicative noise"""
... x, es = cma.fmin2(cma.ff.noisysphere, [1, 1, 1], 0.5,
... noise_handler=cma.NoiseHandler(3))
... print(f"Noisy sphere result: {x}")
... return x, es
# Functions with different dimensions of influence
>>> def subspace_sphere_example():
... """Sphere function in random subspace"""
... x, es = cma.fmin2(cma.ff.subspace_sphere, 10 * [0.5], 0.3)
... print(f"Subspace sphere result: {x}")
... return x, es# Complete list of available test functions in cma.ff
import cma
# Get all available functions
ff_functions = {
# Basic unimodal functions
'sphere': cma.ff.sphere, # sum(x^2)
'elli': cma.ff.elli, # Ellipsoid with condition number
'cigar': cma.ff.cigar, # One large eigenvalue
'tablet': cma.ff.tablet, # One small eigenvalue
'twoaxes': cma.ff.twoaxes, # Two groups of eigenvalues
'ellirot': cma.ff.ellirot, # Rotated ellipsoid
'hyperelli': cma.ff.hyperelli, # Hyperellipsoid
# Multi-modal functions
'rosen': cma.ff.rosen, # Rosenbrock function
# Functions with constraints/boundaries
'spherewithoneconstraint': cma.ff.spherewithoneconstraint,
'cornersphere': cma.ff.cornersphere,
'cornerelli': cma.ff.cornerelli,
'sectorsphere': cma.ff.sectorsphere,
# Noisy functions
'noisysphere': cma.ff.noisysphere,
# Special/research functions
'subspace_sphere': cma.ff.subspace_sphere,
'partsphere': cma.ff.partsphere,
'linear': cma.ff.linear,
'rand': cma.ff.rand,
# Gradient functions (for testing)
'grad_sphere': cma.ff.grad_sphere,
'grad_cigar': cma.ff.grad_cigar,
'grad_tablet': cma.ff.grad_tablet,
}
# Usage pattern for testing multiple functions
def test_multiple_functions():
"""Test CMA-ES on multiple benchmark functions."""
results = {}
for name, func in ff_functions.items():
if name.startswith('grad_'): # Skip gradient functions
continue
try:
print(f"Testing {name}...")
x, es = cma.fmin2(func, 3 * [0.5], 0.3,
options={'maxfevals': 1000, 'verbose': -9})
results[name] = {
'success': es.result.fbest < 1e-6,
'evaluations': es.result.evaluations,
'final_value': es.result.fbest,
'solution': es.result.xbest
}
except Exception as e:
results[name] = {'error': str(e)}
return results
# Run comprehensive test
results = test_multiple_functions()
for func_name, result in results.items():
if 'error' not in result:
print(f"{func_name}: {'✓' if result['success'] else '✗'} "
f"({result['evaluations']} evals, f = {result['final_value']:.2e})")The Black-Box Optimization Benchmarking (BBOB) test suite provides standardized benchmark problems.
import cma
# Access BBOB functions
bbob = cma.ff.BBOB # or cma.bbobbenchmarks
# BBOB provides 24 test functions in various problem dimensions
# Functions are grouped by properties:
# Group 1: Separable functions (f1-f5)
separable_functions = {
1: "Sphere",
2: "Ellipsoid separable",
3: "Rastrigin separable",
4: "Skew Rastrigin-Bueche separable",
5: "Linear slope"
}
# Group 2: Functions with low or moderate conditioning (f6-f9)
moderate_functions = {
6: "Attractive sector",
7: "Step-ellipsoid",
8: "Rosenbrock original",
9: "Rosenbrock rotated"
}
# Group 3: Functions with high conditioning and unimodal (f10-f14)
unimodal_functions = {
10: "Ellipsoid",
11: "Discus",
12: "Bent cigar",
13: "Sharp ridge",
14: "Different powers"
}
# Group 4: Multi-modal functions with adequate global structure (f15-f19)
multimodal_adequate = {
15: "Rastrigin",
16: "Weierstrass",
17: "Schaffers F7, condition 10",
18: "Schaffers F7, condition 1000",
19: "Griewank-Rosenbrock F8F2"
}
# Group 5: Multi-modal functions with weak global structure (f20-f24)
multimodal_weak = {
20: "Schwefel",
21: "Gallagher 101 peaks",
22: "Gallagher 21 peaks",
23: "Katsuuras",
24: "Lunacek bi-Rastrigin"
}
# Example usage
def bbob_function_example():
"""Example using BBOB benchmark functions."""
try:
# Test multiple BBOB functions
for func_id in [1, 8, 15, 20]: # Representative from each group
# Create function instance
f = bbob.F(func_id, instance=1, dimension=5)
print(f"Testing F{func_id} ({separable_functions.get(func_id, 'Other')})")
# Optimize with CMA-ES
x, es = cma.fmin2(f, 5 * [0], 0.5,
options={'maxfevals': 2000, 'verbose': -9})
print(f" Result: f = {es.result.fbest:.2e} in {es.result.evaluations} evals")
except ImportError:
print("BBOB benchmarks not available. Install with: pip install cma[bbob]")
return
bbob_function_example()import cma
def bbob_systematic_testing():
"""Systematic testing on BBOB benchmark suite."""
try:
bbob = cma.bbobbenchmarks
# Test configuration
dimensions = [2, 5, 10]
function_ids = range(1, 25) # All BBOB functions
instances = [1, 2, 3] # Multiple instances per function
results = {}
for dim in dimensions:
results[dim] = {}
for fid in function_ids:
results[dim][fid] = {}
for inst in instances:
# Create BBOB function
f = bbob.F(fid, instance=inst, dimension=dim)
# Optimize with CMA-ES
x, es = cma.fmin2(
f, dim * [0], 0.5,
options={
'maxfevals': 100 * dim**2, # Budget scales with dimension
'ftarget': 1e-8,
'verbose': -9
}
)
# Record result
results[dim][fid][inst] = {
'fbest': es.result.fbest,
'evaluations': es.result.evaluations,
'success': es.result.fbest < 1e-8
}
print(f"F{fid:2d} D{dim:2d} I{inst}: "
f"{'✓' if results[dim][fid][inst]['success'] else '✗'} "
f"({results[dim][fid][inst]['evaluations']} evals)")
return results
except ImportError:
print("BBOB not available. Use: pip install cma[bbob]")
return None
# Run systematic test (comment out for large-scale testing)
# results = bbob_systematic_testing()Tools for modifying and composing objective functions to create more challenging or realistic optimization problems.
class ScaleCoordinates:
"""
Scale and shift coordinate systems for fitness functions.
Allows transformation of variables to create ill-conditioned problems
or to adapt functions to specific domains.
"""
def __init__(self, function, multipliers=None, zero=None,
upper=None, lower=None):
"""
Create coordinate-scaled function wrapper.
Parameters:
-----------
function : callable
Original fitness function to transform.
multipliers : array-like, optional
Scaling factors per coordinate. If shorter than input dimension,
last value is recycled.
zero : array-like, optional
Offset in original coordinate system (preimage space).
upper, lower : array-like, optional
Domain bounds. Creates scaling: f(lower + (upper-lower) * x).
Examples:
---------
>>> import cma
>>> from cma.fitness_transformations import ScaleCoordinates
>>>
>>> # Scale coordinates with different factors
>>> scaled_sphere = ScaleCoordinates(
... cma.ff.sphere,
... multipliers=[1, 10, 100] # Different scales per coordinate
... )
>>>
>>> # Result: f([x0, x1, x2]) = x0^2 + (10*x1)^2 + (100*x2)^2
>>> result = scaled_sphere([1, 1, 1]) # = 1 + 100 + 10000 = 10101
>>>
>>> # Domain transformation [0,1]^n -> [lower, upper]^n
>>> domain_sphere = ScaleCoordinates(
... cma.ff.sphere,
... lower=[-5, -10],
... upper=[5, 10]
... )
>>>
>>> # Now x in [0,1] maps to [-5,5] x [-10,10] domain
>>> x, es = cma.fmin2(domain_sphere, [0.5, 0.5], 0.2)
>>>
>>> # Ill-conditioned problem creation
>>> ill_conditioned = ScaleCoordinates(
... cma.ff.sphere,
... multipliers=[1, 1e3, 1e6] # Condition number 1e12
... )
>>>
>>> x, es = cma.fmin2(ill_conditioned, [1, 1, 1], 0.1)
"""
pass
# Usage examples
def scaling_examples():
"""Examples of coordinate scaling transformations."""
from cma.fitness_transformations import ScaleCoordinates
import cma
# Example 1: Create ill-conditioned sphere
def ill_conditioned_example():
"""Create highly ill-conditioned optimization problem."""
# Original sphere function
def sphere(x):
return sum(x**2)
# Scale with exponentially increasing factors
scales = [10**(i/2) for i in range(5)] # [1, ~3.16, 10, ~31.6, 100]
scaled_sphere = ScaleCoordinates(sphere, multipliers=scales)
print(f"Scales: {scales}")
# Optimize scaled version
x, es = cma.fmin2(scaled_sphere, 5 * [1], 0.3,
options={'maxfevals': 3000})
print(f"Scaled sphere result: {x}")
print(f"Condition number effect visible in solution scaling")
return x, es
# Example 2: Domain mapping
def domain_mapping_example():
"""Map optimization to specific domain."""
# Want to optimize in domain x1 ∈ [-10, 10], x2 ∈ [0, 100]
domain_sphere = ScaleCoordinates(
cma.ff.sphere,
lower=[-10, 0],
upper=[10, 100]
)
# Optimize in [0,1]^2 space
x_unit, es = cma.fmin2(domain_sphere, [0.5, 0.5], 0.2)
# Transform back to original domain
x_original = [-10 + 20*x_unit[0], 0 + 100*x_unit[1]]
print(f"Unit domain result: {x_unit}")
print(f"Original domain result: {x_original}")
return x_unit, x_original
# Example 3: Different scales per coordinate group
def grouped_scaling_example():
"""Scale different groups of coordinates differently."""
# 6D problem: scale first 2 coordinates x1, last 4 coordinates x1000
scales = [1, 1, 1000, 1000, 1000, 1000]
grouped_sphere = ScaleCoordinates(cma.ff.sphere, multipliers=scales)
x, es = cma.fmin2(grouped_sphere, 6 * [0.1], 0.3)
print(f"Grouped scaling result: {x}")
print(f"Notice different scales in solution components")
return x, es
ill_conditioned_example()
domain_mapping_example()
grouped_scaling_example()
scaling_examples()class GlueArguments:
"""
DEPRECATED: Use functools.partial instead.
Bind additional arguments to fitness functions.
"""
def __init__(self, fitness_function, *args, **kwargs):
"""
Create function with bound arguments.
Parameters:
-----------
fitness_function : callable
Function to wrap.
*args : tuple
Positional arguments to append.
**kwargs : dict
Keyword arguments to bind.
Examples:
---------
>>> import cma
>>> from cma.fitness_transformations import GlueArguments
>>>
>>> # Create ellipsoid with specific condition number
>>> elli_1e4 = GlueArguments(cma.ff.elli, cond=1e4)
>>> result = elli_1e4([1, 1, 1]) # Uses cond=1e4
>>>
>>> # Better: use functools.partial (recommended)
>>> import functools
>>> elli_1e4_better = functools.partial(cma.ff.elli, cond=1e4)
>>> result = elli_1e4_better([1, 1, 1])
"""
pass
# Modern alternative using functools.partial
def function_binding_examples():
"""Examples of binding arguments to fitness functions."""
import functools
import cma
# Example 1: Create specialized test functions
def specialized_functions():
"""Create specialized versions of test functions."""
# Ellipsoids with different condition numbers
elli_easy = functools.partial(cma.ff.elli, cond=100)
elli_hard = functools.partial(cma.ff.elli, cond=1e8)
# Test both versions
x1, es1 = cma.fmin2(elli_easy, [1, 1, 1], 0.5,
options={'maxfevals': 1000, 'verbose': -9})
x2, es2 = cma.fmin2(elli_hard, [1, 1, 1], 0.5,
options={'maxfevals': 1000, 'verbose': -9})
print(f"Easy ellipsoid (cond=100): {es1.result.evaluations} evals")
print(f"Hard ellipsoid (cond=1e8): {es2.result.evaluations} evals")
return (x1, es1), (x2, es2)
# Example 2: Parametric function families
def parametric_functions():
"""Create parametric function families."""
# Generalized sphere function: sum((x - center)^p)
def generalized_sphere(x, center=None, p=2):
x = np.asarray(x)
if center is not None:
x = x - np.asarray(center)
return sum(np.abs(x)**p)
# Create family of functions
functions = {
'sphere_origin_L2': functools.partial(generalized_sphere, center=[0, 0], p=2),
'sphere_shifted_L2': functools.partial(generalized_sphere, center=[1, 1], p=2),
'sphere_origin_L1': functools.partial(generalized_sphere, center=[0, 0], p=1),
'sphere_origin_L4': functools.partial(generalized_sphere, center=[0, 0], p=4),
}
# Test all variants
results = {}
for name, func in functions.items():
x, es = cma.fmin2(func, [2, 2], 0.5,
options={'maxfevals': 1500, 'verbose': -9})
results[name] = (x, es.result.fbest, es.result.evaluations)
print(f"{name}: x={x}, f={es.result.fbest:.2e}, evals={es.result.evaluations}")
return results
# Example 3: Noisy function variants
def noisy_function_variants():
"""Create functions with different noise characteristics."""
def noisy_sphere(x, noise_std=0.1, noise_type='additive'):
base_value = sum(x**2)
if noise_type == 'additive':
return base_value + noise_std * np.random.randn()
elif noise_type == 'multiplicative':
return base_value * (1 + noise_std * np.random.randn())
else:
return base_value
# Create noise variants
noise_variants = {
'clean': functools.partial(noisy_sphere, noise_std=0),
'low_noise': functools.partial(noisy_sphere, noise_std=0.01),
'high_noise': functools.partial(noisy_sphere, noise_std=0.1),
'multiplicative': functools.partial(noisy_sphere, noise_std=0.05,
noise_type='multiplicative')
}
# Test with noise handling
for name, func in noise_variants.items():
noise_handler = cma.NoiseHandler(3, maxevals=[1, 2, 10]) if 'noise' in name else None
x, es = cma.fmin2(func, [1, 1, 1], 0.3,
noise_handler=noise_handler,
options={'maxfevals': 2000, 'verbose': -9})
print(f"{name}: final f = {es.result.fbest:.2e}")
specialized_functions()
parametric_functions()
noisy_function_variants()
function_binding_examples()# Advanced function transformations and compositions
import cma
import numpy as np
from cma.fitness_transformations import ScaleCoordinates
import functools
def advanced_transformations():
"""Advanced fitness function transformations and compositions."""
# Example 1: Rotation + Scaling composition
def rotation_scaling_composition():
"""Combine rotation and scaling transformations."""
from cma.transformations import Rotation
# Create rotated and scaled function
def rotated_scaled_sphere(x, rotation_matrix=None, scales=None):
x = np.asarray(x)
# Apply rotation
if rotation_matrix is not None:
x = rotation_matrix @ x
# Apply scaling
if scales is not None:
x = x * np.asarray(scales)
return sum(x**2)
# Create rotation matrix
np.random.seed(42) # For reproducibility
rotation = Rotation()
R = rotation(len=3) # 3D rotation matrix
# Create composed function
composed_func = functools.partial(
rotated_scaled_sphere,
rotation_matrix=R,
scales=[1, 10, 100]
)
# Optimize
x, es = cma.fmin2(composed_func, [1, 1, 1], 0.5)
print(f"Rotation+scaling result: {x}")
return x, es
# Example 2: Multi-objective to single-objective
def multiobjective_scalarization():
"""Convert multi-objective to single-objective via scalarization."""
def multiobjective_function(x):
"""Example multi-objective function returning [f1, f2]."""
f1 = sum(x**2) # Minimize distance from origin
f2 = sum((x - 1)**2) # Minimize distance from [1,1,...]
return [f1, f2]
# Weighted sum scalarization
def weighted_sum_scalarization(x, weights=[0.5, 0.5]):
objectives = multiobjective_function(x)
return sum(w * f for w, f in zip(weights, objectives))
# Different weight combinations
weight_sets = [
[1.0, 0.0], # Focus on f1
[0.0, 1.0], # Focus on f2
[0.5, 0.5], # Equal weights
[0.8, 0.2], # Prefer f1
]
results = {}
for i, weights in enumerate(weight_sets):
scalarized = functools.partial(weighted_sum_scalarization, weights=weights)
x, es = cma.fmin2(scalarized, [0.5, 0.5, 0.5], 0.3,
options={'maxfevals': 1000, 'verbose': -9})
# Evaluate both objectives at solution
objectives = multiobjective_function(x)
results[f"weights_{weights}"] = {
'solution': x,
'f1': objectives[0],
'f2': objectives[1],
'weighted_sum': scalarized(x)
}
print(f"Weights {weights}: x={x}, f1={objectives[0]:.3f}, f2={objectives[1]:.3f}")
return results
# Example 3: Time-varying fitness landscape
def time_varying_function():
"""Create time-varying fitness function."""
evaluation_counter = [0] # Mutable counter
def dynamic_sphere(x, period=100, amplitude=1.0):
"""Sphere function with moving optimum."""
evaluation_counter[0] += 1
# Moving optimum based on evaluation count
t = evaluation_counter[0] / period
optimum = amplitude * np.array([np.sin(t), np.cos(t), 0])
return sum((x - optimum)**2)
# Optimize dynamic function
x, es = cma.fmin2(dynamic_sphere, [0, 0, 0], 0.5,
options={'maxfevals': 2000, 'verb_disp': 100})
print(f"Dynamic function result: {x}")
print(f"Total evaluations: {evaluation_counter[0]}")
return x, es
# Example 4: Constraint violation penalty
def penalty_method_transformation():
"""Transform constrained to unconstrained via penalty method."""
def constrained_objective(x):
"""Original objective: minimize x^2."""
return sum(x**2)
def constraints(x):
"""Constraints: g(x) <= 0."""
return [
x[0] + x[1] - 1, # x[0] + x[1] <= 1
x[0]**2 + x[1]**2 - 4 # x[0]^2 + x[1]^2 <= 4
]
def penalty_function(x, penalty_factor=1000):
"""Unconstrained function with penalty for violations."""
obj_val = constrained_objective(x)
# Add penalty for constraint violations
g_vals = constraints(x)
penalty = sum(max(0, g)**2 for g in g_vals)
return obj_val + penalty_factor * penalty
# Optimize with different penalty factors
penalty_factors = [10, 100, 1000, 10000]
for pf in penalty_factors:
penalized = functools.partial(penalty_function, penalty_factor=pf)
x, es = cma.fmin2(penalized, [0.5, 0.5], 0.3,
options={'maxfevals': 2000, 'verbose': -9})
# Check constraint satisfaction
g_vals = constraints(x)
feasible = all(g <= 1e-6 for g in g_vals)
print(f"Penalty {pf}: x={x}, feasible={feasible}, "
f"obj={constrained_objective(x):.4f}")
rotation_scaling_composition()
multiobjective_scalarization()
time_varying_function()
penalty_method_transformation()
advanced_transformations()Tools for systematic testing and algorithm validation.
import cma
import numpy as np
import time
def algorithm_testing_suite():
"""Comprehensive testing suite for CMA-ES validation."""
class OptimizationTester:
"""Systematic testing framework for optimization algorithms."""
def __init__(self):
self.results = {}
def test_function_suite(self, algorithm_func, test_functions,
dimensions=[2, 5, 10], repetitions=5):
"""Test algorithm on suite of functions."""
for func_name, func in test_functions.items():
self.results[func_name] = {}
for dim in dimensions:
self.results[func_name][dim] = {
'successes': 0,
'evaluations': [],
'final_values': [],
'times': []
}
for rep in range(repetitions):
start_time = time.time()
try:
# Run optimization
x, es = algorithm_func(func, dim * [0.5], 0.3)
elapsed = time.time() - start_time
# Record results
success = es.result.fbest < 1e-6
if success:
self.results[func_name][dim]['successes'] += 1
self.results[func_name][dim]['evaluations'].append(
es.result.evaluations)
self.results[func_name][dim]['final_values'].append(
es.result.fbest)
self.results[func_name][dim]['times'].append(elapsed)
except Exception as e:
print(f"Error on {func_name} D{dim} rep{rep}: {e}")
def print_summary(self):
"""Print summary of test results."""
print("\nOptimization Test Summary")
print("=" * 50)
for func_name in self.results:
print(f"\nFunction: {func_name}")
for dim in sorted(self.results[func_name].keys()):
result = self.results[func_name][dim]
success_rate = result['successes'] / len(result['evaluations'])
avg_evals = np.mean(result['evaluations']) if result['evaluations'] else 0
avg_time = np.mean(result['times']) if result['times'] else 0
print(f" D{dim:2d}: {success_rate:4.1%} success, "
f"{avg_evals:6.0f} evals, {avg_time:5.2f}s")
# Define test function suite
test_functions = {
'sphere': cma.ff.sphere,
'elli': cma.ff.elli,
'cigar': cma.ff.cigar,
'tablet': cma.ff.tablet,
'rosen': cma.ff.rosen,
'ellirot': cma.ff.ellirot
}
# Test CMA-ES with different configurations
def test_cmaes_basic(func, x0, sigma0):
"""Basic CMA-ES test."""
return cma.fmin2(func, x0, sigma0,
options={'maxfevals': 1000 * len(x0)**2, 'verbose': -9})
def test_cmaes_large_pop(func, x0, sigma0):
"""CMA-ES with large population."""
return cma.fmin2(func, x0, sigma0,
options={'maxfevals': 1000 * len(x0)**2,
'popsize_factor': 2, 'verbose': -9})
# Run tests
tester = OptimizationTester()
print("Testing basic CMA-ES...")
tester.test_function_suite(test_cmaes_basic, test_functions,
dimensions=[2, 5], repetitions=3)
tester.print_summary()
return tester
def performance_profiling():
"""Profile performance characteristics of different functions."""
import time
functions_to_profile = {
'sphere': cma.ff.sphere,
'elli': functools.partial(cma.ff.elli, cond=1e6),
'rosen': cma.ff.rosen,
'noisy_sphere': functools.partial(cma.ff.noisysphere, noise=0.01)
}
dimensions = [2, 5, 10, 20]
print("Performance Profiling Results")
print("=" * 40)
for func_name, func in functions_to_profile.items():
print(f"\nFunction: {func_name}")
for dim in dimensions:
# Time single evaluation
x = np.random.randn(dim)
start_time = time.time()
for _ in range(1000): # 1000 evaluations
_ = func(x)
elapsed = time.time() - start_time
evals_per_sec = 1000 / elapsed
print(f" D{dim:2d}: {evals_per_sec:8.0f} evals/sec")
# Run testing suite (comment out for large-scale testing)
# tester = algorithm_testing_suite()
performance_profiling()This comprehensive fitness functions documentation covers:
The documentation provides complete API references with practical usage examples for algorithm testing, benchmarking, and validation.
Install with Tessl CLI
npx tessl i tessl/pypi-cma