/
bbob.py
137 lines (109 loc) · 5.11 KB
/
bbob.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# This file is part of DEAP.
#
# DEAP is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
#
# DEAP is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with DEAP. If not, see <http://www.gnu.org/licenses/>.
import array
import math
import random
import time
from itertools import chain
from deap import base
from deap import creator
from deap import benchmarks
import fgeneric
import bbobbenchmarks as bn
creator.create("FitnessMin", base.Fitness, weights=(-1.0,))
creator.create("Individual", array.array, typecode="d", fitness=creator.FitnessMin)
def update(individual, mu, sigma):
"""Update the current *individual* with values from a gaussian centered on
*mu* and standard deviation *sigma*.
"""
for i, mu_i in enumerate(mu):
individual[i] = random.gauss(mu_i, sigma)
def tupleize(func):
"""A decorator that tuple-ize the result of a function. This is useful
when the evaluation function returns a single value.
"""
def wrapper(*args, **kargs):
return func(*args, **kargs),
return wrapper
def main(func, dim, maxfuncevals, ftarget=None):
toolbox = base.Toolbox()
toolbox.register("update", update)
toolbox.register("evaluate", func)
toolbox.decorate("evaluate", tupleize)
# Create the desired optimal function value as a Fitness object
# for later comparison
opt = creator.FitnessMin((ftarget,))
# Interval in which to initialize the optimizer
interval = -5, 5
sigma = (interval[1] - interval[0])/2.0
alpha = 2.0**(1.0/dim)
# Initialize best randomly and worst as a place holder
best = creator.Individual(random.uniform(interval[0], interval[1]) for _ in range(dim))
worst = creator.Individual([0.0] * dim)
# Evaluate the first individual
best.fitness.values = toolbox.evaluate(best)
# Evolve until ftarget is reached or the number of evaluation
# is exausted (maxfuncevals)
for g in range(1, maxfuncevals):
toolbox.update(worst, best, sigma)
worst.fitness.values = toolbox.evaluate(worst)
if best.fitness <= worst.fitness:
# Incease mutation strength and swap the individual
sigma = sigma * alpha
best, worst = worst, best
else:
# Decrease mutation strength
sigma = sigma * alpha**(-0.25)
# Test if we reached the optimum of the function
# Remember that ">" for fitness means better (not greater)
if best.fitness > opt:
return best
return best
if __name__ == "__main__":
# Maximum number of restart for an algorithm that detects stagnation
maxrestarts = 1000
# Create a COCO experiment that will log the results under the
# ./output directory
e = fgeneric.LoggingFunction("output")
# Iterate over all desired test dimensions
for dim in (2, 3, 5, 10, 20, 40):
# Set the maximum number function evaluation granted to the algorithm
# This is usually function of the dimensionality of the problem
maxfuncevals = 100 * dim**2
minfuncevals = dim + 2
# Iterate over a set of benchmarks (noise free benchmarks here)
for f_name in bn.nfreeIDs:
# Iterate over all the instance of a single problem
# Rotation, translation, etc.
for instance in chain(range(1, 6), range(21, 31)):
# Set the function to be used (problem) in the logger
e.setfun(*bn.instantiate(f_name, iinstance=instance))
# Independent restarts until maxfunevals or ftarget is reached
for restarts in range(0, maxrestarts + 1):
if restarts > 0:
# Signal the experiment that the algorithm restarted
e.restart('independent restart') # additional info
# Run the algorithm with the remaining number of evaluations
revals = int(math.ceil(maxfuncevals - e.evaluations))
main(e.evalfun, dim, revals, e.ftarget)
# Stop if ftarget is reached
if e.fbest < e.ftarget or e.evaluations + minfuncevals > maxfuncevals:
break
e.finalizerun()
print('f%d in %d-D, instance %d: FEs=%d with %d restarts, '
'fbest-ftarget=%.4e'
% (f_name, dim, instance, e.evaluations, restarts,
e.fbest - e.ftarget))
print('date and time: %s' % time.asctime())