0
# Fitness Functions and Testing
1
2
Comprehensive collection of test functions, benchmark problems, and fitness transformations for algorithm testing, validation, and performance evaluation.
3
4
## Test Function Collection (ff module)
5
6
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>`.
7
8
### Complete Function List
9
10
```python { .api }
11
# Complete list of available test functions in cma.ff module
12
import cma
13
14
# Basic quadratic functions
15
cma.ff.sphere # Sphere function: sum(x**2)
16
cma.ff.elli # Ellipsoid function with conditioning
17
cma.ff.cigar # Cigar function: x[0]**2 + 1e6*sum(x[1:]**2)
18
cma.ff.tablet # Tablet function: 1e6*x[0]**2 + sum(x[1:]**2)
19
cma.ff.twoaxes # Two-axes function with group separability
20
cma.ff.ellirot # Rotated ellipsoid function
21
22
# Multi-modal functions
23
cma.ff.rosen # Rosenbrock function
24
cma.ff.diffpowell # Different powers function
25
cma.ff.rastrigin # Rastrigin function with many local minima
26
cma.ff.schwefel # Schwefel function
27
cma.ff.griewank # Griewank function
28
cma.ff.ackley # Ackley function
29
30
# Noise and randomness
31
cma.ff.noise # Add Gaussian noise to any function
32
cma.ff.noisysphere # Noisy sphere function
33
cma.ff.spherenoise # Sphere with added noise
34
35
# Step functions and plateaus
36
cma.ff.step # Step function
37
cma.ff.parab # Parabolic ridge function
38
39
# Composition functions
40
cma.ff.composed # Composition of multiple functions
41
42
# Special test cases
43
cma.ff.optprob # Optimization problem wrapper
44
cma.ff.warped # Warped/transformed function space
45
```
46
47
### Basic Test Functions
48
49
```python { .api }
50
# Access test functions through cma.ff
51
import cma
52
53
# Basic quadratic functions
54
def sphere(x):
55
"""
56
Sphere function - simplest quadratic test function.
57
58
Global minimum: f(0, ..., 0) = 0
59
Properties: Unimodal, separable, quadratic
60
"""
61
return sum(x**2)
62
63
def elli(x, cond=1e6):
64
"""
65
Ellipsoid function - ill-conditioned quadratic.
66
67
Parameters:
68
-----------
69
x : array-like
70
Input vector.
71
cond : float, optional
72
Condition number (default 1e6).
73
74
Global minimum: f(0, ..., 0) = 0
75
Properties: Unimodal, separable, ill-conditioned
76
"""
77
N = len(x)
78
return sum(cond**(np.arange(N) / (N - 1 + 1e-9)) * np.asarray(x)**2)
79
80
# Usage examples
81
>>> import cma
82
>>>
83
>>> # Sphere function
84
>>> f_val = cma.ff.sphere([1, 2, 3]) # Returns 14.0
85
>>>
86
>>> # Ellipsoid with different condition numbers
87
>>> f_val = cma.ff.elli([1, 1, 1]) # Default condition 1e6
88
>>> f_val = cma.ff.elli([1, 1, 1], cond=100) # Condition number 100
89
>>>
90
>>> # Use in optimization
91
>>> x, es = cma.fmin2(cma.ff.sphere, [1, 2, 3], 0.5)
92
>>> x, es = cma.fmin2(cma.ff.elli, [1, 2, 3], 0.5)
93
```
94
95
### Non-Separable Test Functions
96
97
```python { .api }
98
# Non-separable functions available through cma.ff
99
import cma
100
101
# Cigar function - one dominant direction
102
>>> def cigar_example():
103
... """Cigar function: x[0]^2 + cond * sum(x[1:]^2)"""
104
... x, es = cma.fmin2(cma.ff.cigar, [1, 2, 3, 4], 0.5)
105
... print(f"Cigar result: {x}")
106
... return x, es
107
108
# Tablet function - one weak direction
109
>>> def tablet_example():
110
... """Tablet function: cond * x[0]^2 + sum(x[1:]^2)"""
111
... x, es = cma.fmin2(cma.ff.tablet, [1, 2, 3, 4], 0.5)
112
... print(f"Tablet result: {x}")
113
... return x, es
114
115
# Two-axes function - group separability
116
>>> def twoaxes_example():
117
... """Two-axes function with different conditioning"""
118
... x, es = cma.fmin2(cma.ff.twoaxes, 6 * [0.5], 0.3)
119
... print(f"Two-axes result: {x}")
120
... return x, es
121
122
# Rotated ellipsoid - no separability
123
>>> def ellirot_example():
124
... """Rotated ellipsoid - tests rotation invariance"""
125
... x, es = cma.fmin2(cma.ff.ellirot, [1, 2, 3], 0.5)
126
... print(f"Rotated ellipsoid result: {x}")
127
... return x, es
128
```
129
130
### Multi-Modal Test Functions
131
132
```python { .api }
133
# Multi-modal and difficult functions
134
import cma
135
import numpy as np
136
137
# Rosenbrock function - classic benchmark
138
>>> def rosenbrock_example():
139
... """Rosenbrock function - narrow curved valley"""
140
... # The Rosenbrock function is available as cma.ff.rosen
141
... x, es = cma.fmin2(cma.ff.rosen, 4 * [0], 0.5)
142
... print(f"Rosenbrock result: {x}") # Should be close to [1, 1, 1, 1]
143
... return x, es
144
145
# Rastrigin function - many local minima
146
>>> def rastrigin_example():
147
... """Rastrigin function - highly multi-modal"""
148
... # Note: Rastrigin may be in BBOB collection
149
... def rastrigin(x):
150
... A = 10
151
... n = len(x)
152
... return A * n + sum(xi**2 - A * np.cos(2 * np.pi * xi) for xi in x)
153
...
154
... x, es = cma.fmin2(rastrigin, 5 * [2.0], 1.0,
155
... options={'maxfevals': 10000})
156
... print(f"Rastrigin result: {x}")
157
... return x, es
158
159
# Ackley function - many local minima with global structure
160
>>> def ackley_example():
161
... """Ackley function - exponential multi-modal"""
162
... def ackley(x):
163
... x = np.asarray(x)
164
... n = len(x)
165
... return (-20 * np.exp(-0.2 * np.sqrt(sum(x**2) / n)) -
166
... np.exp(sum(np.cos(2 * np.pi * xi) for xi in x) / n) +
167
... 20 + np.e)
168
...
169
... x, es = cma.fmin2(ackley, 3 * [1.0], 0.5)
170
... print(f"Ackley result: {x}")
171
... return x, es
172
```
173
174
### Constrained and Special Test Functions
175
176
```python { .api }
177
# Special test functions with constraints or unusual properties
178
import cma
179
import numpy as np
180
181
# Functions with constraints built-in
182
>>> def constrained_sphere_example():
183
... """Sphere function with constraint x[0] > 1"""
184
... x, es = cma.fmin2(cma.ff.spherewithoneconstraint, [2, 1, 1], 0.3)
185
... print(f"Constrained sphere result: {x}")
186
... return x, es
187
188
# Asymmetric functions
189
>>> def sectorsphere_example():
190
... """Asymmetric sphere - different scaling for negative values"""
191
... x, es = cma.fmin2(cma.ff.sectorsphere, [1, -1, 0], 0.5)
192
... print(f"Sector sphere result: {x}")
193
... return x, es
194
195
# Functions with corners/boundaries
196
>>> def cornersphere_example():
197
... """Sphere function constrained to corner x >= 1"""
198
... x, es = cma.fmin2(cma.ff.cornersphere, [1.5, 1.5, 1.5], 0.2)
199
... print(f"Corner sphere result: {x}")
200
... return x, es
201
202
# Noisy functions
203
>>> def noisy_sphere_example():
204
... """Sphere function with multiplicative noise"""
205
... x, es = cma.fmin2(cma.ff.noisysphere, [1, 1, 1], 0.5,
206
... noise_handler=cma.NoiseHandler(3))
207
... print(f"Noisy sphere result: {x}")
208
... return x, es
209
210
# Functions with different dimensions of influence
211
>>> def subspace_sphere_example():
212
... """Sphere function in random subspace"""
213
... x, es = cma.fmin2(cma.ff.subspace_sphere, 10 * [0.5], 0.3)
214
... print(f"Subspace sphere result: {x}")
215
... return x, es
216
```
217
218
### Complete Test Function Reference
219
220
```python { .api }
221
# Complete list of available test functions in cma.ff
222
import cma
223
224
# Get all available functions
225
ff_functions = {
226
# Basic unimodal functions
227
'sphere': cma.ff.sphere, # sum(x^2)
228
'elli': cma.ff.elli, # Ellipsoid with condition number
229
'cigar': cma.ff.cigar, # One large eigenvalue
230
'tablet': cma.ff.tablet, # One small eigenvalue
231
'twoaxes': cma.ff.twoaxes, # Two groups of eigenvalues
232
'ellirot': cma.ff.ellirot, # Rotated ellipsoid
233
'hyperelli': cma.ff.hyperelli, # Hyperellipsoid
234
235
# Multi-modal functions
236
'rosen': cma.ff.rosen, # Rosenbrock function
237
238
# Functions with constraints/boundaries
239
'spherewithoneconstraint': cma.ff.spherewithoneconstraint,
240
'cornersphere': cma.ff.cornersphere,
241
'cornerelli': cma.ff.cornerelli,
242
'sectorsphere': cma.ff.sectorsphere,
243
244
# Noisy functions
245
'noisysphere': cma.ff.noisysphere,
246
247
# Special/research functions
248
'subspace_sphere': cma.ff.subspace_sphere,
249
'partsphere': cma.ff.partsphere,
250
'linear': cma.ff.linear,
251
'rand': cma.ff.rand,
252
253
# Gradient functions (for testing)
254
'grad_sphere': cma.ff.grad_sphere,
255
'grad_cigar': cma.ff.grad_cigar,
256
'grad_tablet': cma.ff.grad_tablet,
257
}
258
259
# Usage pattern for testing multiple functions
260
def test_multiple_functions():
261
"""Test CMA-ES on multiple benchmark functions."""
262
263
results = {}
264
265
for name, func in ff_functions.items():
266
if name.startswith('grad_'): # Skip gradient functions
267
continue
268
269
try:
270
print(f"Testing {name}...")
271
x, es = cma.fmin2(func, 3 * [0.5], 0.3,
272
options={'maxfevals': 1000, 'verbose': -9})
273
274
results[name] = {
275
'success': es.result.fbest < 1e-6,
276
'evaluations': es.result.evaluations,
277
'final_value': es.result.fbest,
278
'solution': es.result.xbest
279
}
280
281
except Exception as e:
282
results[name] = {'error': str(e)}
283
284
return results
285
286
# Run comprehensive test
287
results = test_multiple_functions()
288
for func_name, result in results.items():
289
if 'error' not in result:
290
print(f"{func_name}: {'✓' if result['success'] else '✗'} "
291
f"({result['evaluations']} evals, f = {result['final_value']:.2e})")
292
```
293
294
## BBOB Benchmark Functions
295
296
The Black-Box Optimization Benchmarking (BBOB) test suite provides standardized benchmark problems.
297
298
### BBOB Function Access
299
300
```python { .api }
301
import cma
302
303
# Access BBOB functions
304
bbob = cma.ff.BBOB # or cma.bbobbenchmarks
305
306
# BBOB provides 24 test functions in various problem dimensions
307
# Functions are grouped by properties:
308
309
# Group 1: Separable functions (f1-f5)
310
separable_functions = {
311
1: "Sphere",
312
2: "Ellipsoid separable",
313
3: "Rastrigin separable",
314
4: "Skew Rastrigin-Bueche separable",
315
5: "Linear slope"
316
}
317
318
# Group 2: Functions with low or moderate conditioning (f6-f9)
319
moderate_functions = {
320
6: "Attractive sector",
321
7: "Step-ellipsoid",
322
8: "Rosenbrock original",
323
9: "Rosenbrock rotated"
324
}
325
326
# Group 3: Functions with high conditioning and unimodal (f10-f14)
327
unimodal_functions = {
328
10: "Ellipsoid",
329
11: "Discus",
330
12: "Bent cigar",
331
13: "Sharp ridge",
332
14: "Different powers"
333
}
334
335
# Group 4: Multi-modal functions with adequate global structure (f15-f19)
336
multimodal_adequate = {
337
15: "Rastrigin",
338
16: "Weierstrass",
339
17: "Schaffers F7, condition 10",
340
18: "Schaffers F7, condition 1000",
341
19: "Griewank-Rosenbrock F8F2"
342
}
343
344
# Group 5: Multi-modal functions with weak global structure (f20-f24)
345
multimodal_weak = {
346
20: "Schwefel",
347
21: "Gallagher 101 peaks",
348
22: "Gallagher 21 peaks",
349
23: "Katsuuras",
350
24: "Lunacek bi-Rastrigin"
351
}
352
353
# Example usage
354
def bbob_function_example():
355
"""Example using BBOB benchmark functions."""
356
357
try:
358
# Test multiple BBOB functions
359
for func_id in [1, 8, 15, 20]: # Representative from each group
360
361
# Create function instance
362
f = bbob.F(func_id, instance=1, dimension=5)
363
364
print(f"Testing F{func_id} ({separable_functions.get(func_id, 'Other')})")
365
366
# Optimize with CMA-ES
367
x, es = cma.fmin2(f, 5 * [0], 0.5,
368
options={'maxfevals': 2000, 'verbose': -9})
369
370
print(f" Result: f = {es.result.fbest:.2e} in {es.result.evaluations} evals")
371
372
except ImportError:
373
print("BBOB benchmarks not available. Install with: pip install cma[bbob]")
374
375
return
376
377
bbob_function_example()
378
```
379
380
### BBOB Usage Patterns
381
382
```python { .api }
383
import cma
384
385
def bbob_systematic_testing():
386
"""Systematic testing on BBOB benchmark suite."""
387
388
try:
389
bbob = cma.bbobbenchmarks
390
391
# Test configuration
392
dimensions = [2, 5, 10]
393
function_ids = range(1, 25) # All BBOB functions
394
instances = [1, 2, 3] # Multiple instances per function
395
396
results = {}
397
398
for dim in dimensions:
399
results[dim] = {}
400
401
for fid in function_ids:
402
results[dim][fid] = {}
403
404
for inst in instances:
405
# Create BBOB function
406
f = bbob.F(fid, instance=inst, dimension=dim)
407
408
# Optimize with CMA-ES
409
x, es = cma.fmin2(
410
f, dim * [0], 0.5,
411
options={
412
'maxfevals': 100 * dim**2, # Budget scales with dimension
413
'ftarget': 1e-8,
414
'verbose': -9
415
}
416
)
417
418
# Record result
419
results[dim][fid][inst] = {
420
'fbest': es.result.fbest,
421
'evaluations': es.result.evaluations,
422
'success': es.result.fbest < 1e-8
423
}
424
425
print(f"F{fid:2d} D{dim:2d} I{inst}: "
426
f"{'✓' if results[dim][fid][inst]['success'] else '✗'} "
427
f"({results[dim][fid][inst]['evaluations']} evals)")
428
429
return results
430
431
except ImportError:
432
print("BBOB not available. Use: pip install cma[bbob]")
433
return None
434
435
# Run systematic test (comment out for large-scale testing)
436
# results = bbob_systematic_testing()
437
```
438
439
## Fitness Transformations
440
441
Tools for modifying and composing objective functions to create more challenging or realistic optimization problems.
442
443
### ScaleCoordinates - Coordinate Scaling
444
445
```python { .api }
446
class ScaleCoordinates:
447
"""
448
Scale and shift coordinate systems for fitness functions.
449
450
Allows transformation of variables to create ill-conditioned problems
451
or to adapt functions to specific domains.
452
"""
453
454
def __init__(self, function, multipliers=None, zero=None,
455
upper=None, lower=None):
456
"""
457
Create coordinate-scaled function wrapper.
458
459
Parameters:
460
-----------
461
function : callable
462
Original fitness function to transform.
463
464
multipliers : array-like, optional
465
Scaling factors per coordinate. If shorter than input dimension,
466
last value is recycled.
467
468
zero : array-like, optional
469
Offset in original coordinate system (preimage space).
470
471
upper, lower : array-like, optional
472
Domain bounds. Creates scaling: f(lower + (upper-lower) * x).
473
474
Examples:
475
---------
476
>>> import cma
477
>>> from cma.fitness_transformations import ScaleCoordinates
478
>>>
479
>>> # Scale coordinates with different factors
480
>>> scaled_sphere = ScaleCoordinates(
481
... cma.ff.sphere,
482
... multipliers=[1, 10, 100] # Different scales per coordinate
483
... )
484
>>>
485
>>> # Result: f([x0, x1, x2]) = x0^2 + (10*x1)^2 + (100*x2)^2
486
>>> result = scaled_sphere([1, 1, 1]) # = 1 + 100 + 10000 = 10101
487
>>>
488
>>> # Domain transformation [0,1]^n -> [lower, upper]^n
489
>>> domain_sphere = ScaleCoordinates(
490
... cma.ff.sphere,
491
... lower=[-5, -10],
492
... upper=[5, 10]
493
... )
494
>>>
495
>>> # Now x in [0,1] maps to [-5,5] x [-10,10] domain
496
>>> x, es = cma.fmin2(domain_sphere, [0.5, 0.5], 0.2)
497
>>>
498
>>> # Ill-conditioned problem creation
499
>>> ill_conditioned = ScaleCoordinates(
500
... cma.ff.sphere,
501
... multipliers=[1, 1e3, 1e6] # Condition number 1e12
502
... )
503
>>>
504
>>> x, es = cma.fmin2(ill_conditioned, [1, 1, 1], 0.1)
505
"""
506
pass
507
508
# Usage examples
509
def scaling_examples():
510
"""Examples of coordinate scaling transformations."""
511
512
from cma.fitness_transformations import ScaleCoordinates
513
import cma
514
515
# Example 1: Create ill-conditioned sphere
516
def ill_conditioned_example():
517
"""Create highly ill-conditioned optimization problem."""
518
519
# Original sphere function
520
def sphere(x):
521
return sum(x**2)
522
523
# Scale with exponentially increasing factors
524
scales = [10**(i/2) for i in range(5)] # [1, ~3.16, 10, ~31.6, 100]
525
526
scaled_sphere = ScaleCoordinates(sphere, multipliers=scales)
527
528
print(f"Scales: {scales}")
529
530
# Optimize scaled version
531
x, es = cma.fmin2(scaled_sphere, 5 * [1], 0.3,
532
options={'maxfevals': 3000})
533
534
print(f"Scaled sphere result: {x}")
535
print(f"Condition number effect visible in solution scaling")
536
537
return x, es
538
539
# Example 2: Domain mapping
540
def domain_mapping_example():
541
"""Map optimization to specific domain."""
542
543
# Want to optimize in domain x1 ∈ [-10, 10], x2 ∈ [0, 100]
544
domain_sphere = ScaleCoordinates(
545
cma.ff.sphere,
546
lower=[-10, 0],
547
upper=[10, 100]
548
)
549
550
# Optimize in [0,1]^2 space
551
x_unit, es = cma.fmin2(domain_sphere, [0.5, 0.5], 0.2)
552
553
# Transform back to original domain
554
x_original = [-10 + 20*x_unit[0], 0 + 100*x_unit[1]]
555
556
print(f"Unit domain result: {x_unit}")
557
print(f"Original domain result: {x_original}")
558
559
return x_unit, x_original
560
561
# Example 3: Different scales per coordinate group
562
def grouped_scaling_example():
563
"""Scale different groups of coordinates differently."""
564
565
# 6D problem: scale first 2 coordinates x1, last 4 coordinates x1000
566
scales = [1, 1, 1000, 1000, 1000, 1000]
567
568
grouped_sphere = ScaleCoordinates(cma.ff.sphere, multipliers=scales)
569
570
x, es = cma.fmin2(grouped_sphere, 6 * [0.1], 0.3)
571
572
print(f"Grouped scaling result: {x}")
573
print(f"Notice different scales in solution components")
574
575
return x, es
576
577
ill_conditioned_example()
578
domain_mapping_example()
579
grouped_scaling_example()
580
581
scaling_examples()
582
```
583
584
### GlueArguments - Function Argument Binding
585
586
```python { .api }
587
class GlueArguments:
588
"""
589
DEPRECATED: Use functools.partial instead.
590
591
Bind additional arguments to fitness functions.
592
"""
593
594
def __init__(self, fitness_function, *args, **kwargs):
595
"""
596
Create function with bound arguments.
597
598
Parameters:
599
-----------
600
fitness_function : callable
601
Function to wrap.
602
*args : tuple
603
Positional arguments to append.
604
**kwargs : dict
605
Keyword arguments to bind.
606
607
Examples:
608
---------
609
>>> import cma
610
>>> from cma.fitness_transformations import GlueArguments
611
>>>
612
>>> # Create ellipsoid with specific condition number
613
>>> elli_1e4 = GlueArguments(cma.ff.elli, cond=1e4)
614
>>> result = elli_1e4([1, 1, 1]) # Uses cond=1e4
615
>>>
616
>>> # Better: use functools.partial (recommended)
617
>>> import functools
618
>>> elli_1e4_better = functools.partial(cma.ff.elli, cond=1e4)
619
>>> result = elli_1e4_better([1, 1, 1])
620
"""
621
pass
622
623
# Modern alternative using functools.partial
624
def function_binding_examples():
625
"""Examples of binding arguments to fitness functions."""
626
627
import functools
628
import cma
629
630
# Example 1: Create specialized test functions
631
def specialized_functions():
632
"""Create specialized versions of test functions."""
633
634
# Ellipsoids with different condition numbers
635
elli_easy = functools.partial(cma.ff.elli, cond=100)
636
elli_hard = functools.partial(cma.ff.elli, cond=1e8)
637
638
# Test both versions
639
x1, es1 = cma.fmin2(elli_easy, [1, 1, 1], 0.5,
640
options={'maxfevals': 1000, 'verbose': -9})
641
642
x2, es2 = cma.fmin2(elli_hard, [1, 1, 1], 0.5,
643
options={'maxfevals': 1000, 'verbose': -9})
644
645
print(f"Easy ellipsoid (cond=100): {es1.result.evaluations} evals")
646
print(f"Hard ellipsoid (cond=1e8): {es2.result.evaluations} evals")
647
648
return (x1, es1), (x2, es2)
649
650
# Example 2: Parametric function families
651
def parametric_functions():
652
"""Create parametric function families."""
653
654
# Generalized sphere function: sum((x - center)^p)
655
def generalized_sphere(x, center=None, p=2):
656
x = np.asarray(x)
657
if center is not None:
658
x = x - np.asarray(center)
659
return sum(np.abs(x)**p)
660
661
# Create family of functions
662
functions = {
663
'sphere_origin_L2': functools.partial(generalized_sphere, center=[0, 0], p=2),
664
'sphere_shifted_L2': functools.partial(generalized_sphere, center=[1, 1], p=2),
665
'sphere_origin_L1': functools.partial(generalized_sphere, center=[0, 0], p=1),
666
'sphere_origin_L4': functools.partial(generalized_sphere, center=[0, 0], p=4),
667
}
668
669
# Test all variants
670
results = {}
671
for name, func in functions.items():
672
x, es = cma.fmin2(func, [2, 2], 0.5,
673
options={'maxfevals': 1500, 'verbose': -9})
674
results[name] = (x, es.result.fbest, es.result.evaluations)
675
print(f"{name}: x={x}, f={es.result.fbest:.2e}, evals={es.result.evaluations}")
676
677
return results
678
679
# Example 3: Noisy function variants
680
def noisy_function_variants():
681
"""Create functions with different noise characteristics."""
682
683
def noisy_sphere(x, noise_std=0.1, noise_type='additive'):
684
base_value = sum(x**2)
685
686
if noise_type == 'additive':
687
return base_value + noise_std * np.random.randn()
688
elif noise_type == 'multiplicative':
689
return base_value * (1 + noise_std * np.random.randn())
690
else:
691
return base_value
692
693
# Create noise variants
694
noise_variants = {
695
'clean': functools.partial(noisy_sphere, noise_std=0),
696
'low_noise': functools.partial(noisy_sphere, noise_std=0.01),
697
'high_noise': functools.partial(noisy_sphere, noise_std=0.1),
698
'multiplicative': functools.partial(noisy_sphere, noise_std=0.05,
699
noise_type='multiplicative')
700
}
701
702
# Test with noise handling
703
for name, func in noise_variants.items():
704
noise_handler = cma.NoiseHandler(3, maxevals=[1, 2, 10]) if 'noise' in name else None
705
706
x, es = cma.fmin2(func, [1, 1, 1], 0.3,
707
noise_handler=noise_handler,
708
options={'maxfevals': 2000, 'verbose': -9})
709
710
print(f"{name}: final f = {es.result.fbest:.2e}")
711
712
specialized_functions()
713
parametric_functions()
714
noisy_function_variants()
715
716
function_binding_examples()
717
```
718
719
### Function Composition and Advanced Transformations
720
721
```python { .api }
722
# Advanced function transformations and compositions
723
import cma
724
import numpy as np
725
from cma.fitness_transformations import ScaleCoordinates
726
import functools
727
728
def advanced_transformations():
729
"""Advanced fitness function transformations and compositions."""
730
731
# Example 1: Rotation + Scaling composition
732
def rotation_scaling_composition():
733
"""Combine rotation and scaling transformations."""
734
735
from cma.transformations import Rotation
736
737
# Create rotated and scaled function
738
def rotated_scaled_sphere(x, rotation_matrix=None, scales=None):
739
x = np.asarray(x)
740
741
# Apply rotation
742
if rotation_matrix is not None:
743
x = rotation_matrix @ x
744
745
# Apply scaling
746
if scales is not None:
747
x = x * np.asarray(scales)
748
749
return sum(x**2)
750
751
# Create rotation matrix
752
np.random.seed(42) # For reproducibility
753
rotation = Rotation()
754
R = rotation(len=3) # 3D rotation matrix
755
756
# Create composed function
757
composed_func = functools.partial(
758
rotated_scaled_sphere,
759
rotation_matrix=R,
760
scales=[1, 10, 100]
761
)
762
763
# Optimize
764
x, es = cma.fmin2(composed_func, [1, 1, 1], 0.5)
765
766
print(f"Rotation+scaling result: {x}")
767
return x, es
768
769
# Example 2: Multi-objective to single-objective
770
def multiobjective_scalarization():
771
"""Convert multi-objective to single-objective via scalarization."""
772
773
def multiobjective_function(x):
774
"""Example multi-objective function returning [f1, f2]."""
775
f1 = sum(x**2) # Minimize distance from origin
776
f2 = sum((x - 1)**2) # Minimize distance from [1,1,...]
777
return [f1, f2]
778
779
# Weighted sum scalarization
780
def weighted_sum_scalarization(x, weights=[0.5, 0.5]):
781
objectives = multiobjective_function(x)
782
return sum(w * f for w, f in zip(weights, objectives))
783
784
# Different weight combinations
785
weight_sets = [
786
[1.0, 0.0], # Focus on f1
787
[0.0, 1.0], # Focus on f2
788
[0.5, 0.5], # Equal weights
789
[0.8, 0.2], # Prefer f1
790
]
791
792
results = {}
793
for i, weights in enumerate(weight_sets):
794
scalarized = functools.partial(weighted_sum_scalarization, weights=weights)
795
796
x, es = cma.fmin2(scalarized, [0.5, 0.5, 0.5], 0.3,
797
options={'maxfevals': 1000, 'verbose': -9})
798
799
# Evaluate both objectives at solution
800
objectives = multiobjective_function(x)
801
results[f"weights_{weights}"] = {
802
'solution': x,
803
'f1': objectives[0],
804
'f2': objectives[1],
805
'weighted_sum': scalarized(x)
806
}
807
808
print(f"Weights {weights}: x={x}, f1={objectives[0]:.3f}, f2={objectives[1]:.3f}")
809
810
return results
811
812
# Example 3: Time-varying fitness landscape
813
def time_varying_function():
814
"""Create time-varying fitness function."""
815
816
evaluation_counter = [0] # Mutable counter
817
818
def dynamic_sphere(x, period=100, amplitude=1.0):
819
"""Sphere function with moving optimum."""
820
evaluation_counter[0] += 1
821
822
# Moving optimum based on evaluation count
823
t = evaluation_counter[0] / period
824
optimum = amplitude * np.array([np.sin(t), np.cos(t), 0])
825
826
return sum((x - optimum)**2)
827
828
# Optimize dynamic function
829
x, es = cma.fmin2(dynamic_sphere, [0, 0, 0], 0.5,
830
options={'maxfevals': 2000, 'verb_disp': 100})
831
832
print(f"Dynamic function result: {x}")
833
print(f"Total evaluations: {evaluation_counter[0]}")
834
835
return x, es
836
837
# Example 4: Constraint violation penalty
838
def penalty_method_transformation():
839
"""Transform constrained to unconstrained via penalty method."""
840
841
def constrained_objective(x):
842
"""Original objective: minimize x^2."""
843
return sum(x**2)
844
845
def constraints(x):
846
"""Constraints: g(x) <= 0."""
847
return [
848
x[0] + x[1] - 1, # x[0] + x[1] <= 1
849
x[0]**2 + x[1]**2 - 4 # x[0]^2 + x[1]^2 <= 4
850
]
851
852
def penalty_function(x, penalty_factor=1000):
853
"""Unconstrained function with penalty for violations."""
854
obj_val = constrained_objective(x)
855
856
# Add penalty for constraint violations
857
g_vals = constraints(x)
858
penalty = sum(max(0, g)**2 for g in g_vals)
859
860
return obj_val + penalty_factor * penalty
861
862
# Optimize with different penalty factors
863
penalty_factors = [10, 100, 1000, 10000]
864
865
for pf in penalty_factors:
866
penalized = functools.partial(penalty_function, penalty_factor=pf)
867
868
x, es = cma.fmin2(penalized, [0.5, 0.5], 0.3,
869
options={'maxfevals': 2000, 'verbose': -9})
870
871
# Check constraint satisfaction
872
g_vals = constraints(x)
873
feasible = all(g <= 1e-6 for g in g_vals)
874
875
print(f"Penalty {pf}: x={x}, feasible={feasible}, "
876
f"obj={constrained_objective(x):.4f}")
877
878
rotation_scaling_composition()
879
multiobjective_scalarization()
880
time_varying_function()
881
penalty_method_transformation()
882
883
advanced_transformations()
884
```
885
886
## Testing and Validation Utilities
887
888
Tools for systematic testing and algorithm validation.
889
890
```python { .api }
891
import cma
892
import numpy as np
893
import time
894
895
def algorithm_testing_suite():
896
"""Comprehensive testing suite for CMA-ES validation."""
897
898
class OptimizationTester:
899
"""Systematic testing framework for optimization algorithms."""
900
901
def __init__(self):
902
self.results = {}
903
904
def test_function_suite(self, algorithm_func, test_functions,
905
dimensions=[2, 5, 10], repetitions=5):
906
"""Test algorithm on suite of functions."""
907
908
for func_name, func in test_functions.items():
909
self.results[func_name] = {}
910
911
for dim in dimensions:
912
self.results[func_name][dim] = {
913
'successes': 0,
914
'evaluations': [],
915
'final_values': [],
916
'times': []
917
}
918
919
for rep in range(repetitions):
920
start_time = time.time()
921
922
try:
923
# Run optimization
924
x, es = algorithm_func(func, dim * [0.5], 0.3)
925
926
elapsed = time.time() - start_time
927
928
# Record results
929
success = es.result.fbest < 1e-6
930
if success:
931
self.results[func_name][dim]['successes'] += 1
932
933
self.results[func_name][dim]['evaluations'].append(
934
es.result.evaluations)
935
self.results[func_name][dim]['final_values'].append(
936
es.result.fbest)
937
self.results[func_name][dim]['times'].append(elapsed)
938
939
except Exception as e:
940
print(f"Error on {func_name} D{dim} rep{rep}: {e}")
941
942
def print_summary(self):
943
"""Print summary of test results."""
944
945
print("\nOptimization Test Summary")
946
print("=" * 50)
947
948
for func_name in self.results:
949
print(f"\nFunction: {func_name}")
950
951
for dim in sorted(self.results[func_name].keys()):
952
result = self.results[func_name][dim]
953
954
success_rate = result['successes'] / len(result['evaluations'])
955
avg_evals = np.mean(result['evaluations']) if result['evaluations'] else 0
956
avg_time = np.mean(result['times']) if result['times'] else 0
957
958
print(f" D{dim:2d}: {success_rate:4.1%} success, "
959
f"{avg_evals:6.0f} evals, {avg_time:5.2f}s")
960
961
# Define test function suite
962
test_functions = {
963
'sphere': cma.ff.sphere,
964
'elli': cma.ff.elli,
965
'cigar': cma.ff.cigar,
966
'tablet': cma.ff.tablet,
967
'rosen': cma.ff.rosen,
968
'ellirot': cma.ff.ellirot
969
}
970
971
# Test CMA-ES with different configurations
972
def test_cmaes_basic(func, x0, sigma0):
973
"""Basic CMA-ES test."""
974
return cma.fmin2(func, x0, sigma0,
975
options={'maxfevals': 1000 * len(x0)**2, 'verbose': -9})
976
977
def test_cmaes_large_pop(func, x0, sigma0):
978
"""CMA-ES with large population."""
979
return cma.fmin2(func, x0, sigma0,
980
options={'maxfevals': 1000 * len(x0)**2,
981
'popsize_factor': 2, 'verbose': -9})
982
983
# Run tests
984
tester = OptimizationTester()
985
986
print("Testing basic CMA-ES...")
987
tester.test_function_suite(test_cmaes_basic, test_functions,
988
dimensions=[2, 5], repetitions=3)
989
990
tester.print_summary()
991
992
return tester
993
994
def performance_profiling():
995
"""Profile performance characteristics of different functions."""
996
997
import time
998
999
functions_to_profile = {
1000
'sphere': cma.ff.sphere,
1001
'elli': functools.partial(cma.ff.elli, cond=1e6),
1002
'rosen': cma.ff.rosen,
1003
'noisy_sphere': functools.partial(cma.ff.noisysphere, noise=0.01)
1004
}
1005
1006
dimensions = [2, 5, 10, 20]
1007
1008
print("Performance Profiling Results")
1009
print("=" * 40)
1010
1011
for func_name, func in functions_to_profile.items():
1012
print(f"\nFunction: {func_name}")
1013
1014
for dim in dimensions:
1015
# Time single evaluation
1016
x = np.random.randn(dim)
1017
1018
start_time = time.time()
1019
for _ in range(1000): # 1000 evaluations
1020
_ = func(x)
1021
elapsed = time.time() - start_time
1022
1023
evals_per_sec = 1000 / elapsed
1024
1025
print(f" D{dim:2d}: {evals_per_sec:8.0f} evals/sec")
1026
1027
# Run testing suite (comment out for large-scale testing)
1028
# tester = algorithm_testing_suite()
1029
performance_profiling()
1030
```
1031
1032
This comprehensive fitness functions documentation covers:
1033
1034
1. **Basic Test Functions** - Fundamental functions like sphere, ellipsoid, and cigar
1035
2. **Multi-Modal Functions** - Rosenbrock, Rastrigin, Ackley for challenging optimization
1036
3. **BBOB Benchmark Suite** - Standardized benchmark functions for algorithm comparison
1037
4. **Fitness Transformations** - ScaleCoordinates, GlueArguments for function modification
1038
5. **Advanced Transformations** - Complex compositions and multi-objective handling
1039
6. **Testing Utilities** - Systematic testing and validation frameworks
1040
1041
The documentation provides complete API references with practical usage examples for algorithm testing, benchmarking, and validation.