fcmaes 1.1.3__py3-none-any.whl → 1.6.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fcmaes/__init__.py +12 -2
- fcmaes/advretry.py +217 -159
- fcmaes/astro.py +143 -27
- fcmaes/bitecpp.py +107 -0
- fcmaes/cmaes.py +204 -173
- fcmaes/cmaescpp.py +253 -87
- fcmaes/crfmnes.py +339 -0
- fcmaes/crfmnescpp.py +273 -0
- fcmaes/dacpp.py +39 -51
- fcmaes/de.py +472 -0
- fcmaes/decpp.py +222 -64
- fcmaes/diversifier.py +357 -0
- fcmaes/evaluator.py +297 -14
- fcmaes/lib/libacmalib.dll +0 -0
- fcmaes/lib/libacmalib.dylib +0 -0
- fcmaes/lib/libacmalib.so +0 -0
- fcmaes/lib/libhbv.so +0 -0
- fcmaes/lib/liblrgv.so +0 -0
- fcmaes/lib/librw_top_trumps.dll +0 -0
- fcmaes/lib/librw_top_trumps.so +0 -0
- fcmaes/mapelites.py +737 -0
- fcmaes/mode.py +719 -0
- fcmaes/modecpp.py +470 -0
- fcmaes/moretry.py +270 -0
- fcmaes/multiretry.py +195 -0
- fcmaes/optimizer.py +883 -112
- fcmaes/pgpecpp.py +340 -0
- fcmaes/pygmoretry.py +10 -19
- fcmaes/retry.py +248 -121
- fcmaes/test_cma.py +207 -30
- fcmaes/testfun.py +38 -1
- {fcmaes-1.1.3.dist-info → fcmaes-1.6.9.dist-info}/METADATA +22 -12
- fcmaes-1.6.9.dist-info/RECORD +36 -0
- {fcmaes-1.1.3.dist-info → fcmaes-1.6.9.dist-info}/WHEEL +1 -1
- fcmaes/hhcpp.py +0 -114
- fcmaes/lib/libgtoplib.dll +0 -0
- fcmaes/lib/libgtoplib.so +0 -0
- fcmaes-1.1.3.dist-info/RECORD +0 -23
- {fcmaes-1.1.3.dist-info → fcmaes-1.6.9.dist-info}/LICENSE +0 -0
- {fcmaes-1.1.3.dist-info → fcmaes-1.6.9.dist-info}/top_level.txt +0 -0
fcmaes/retry.py
CHANGED
|
@@ -2,48 +2,52 @@
|
|
|
2
2
|
#
|
|
3
3
|
# This source code is licensed under the MIT license found in the
|
|
4
4
|
# LICENSE file in the root directory.
|
|
5
|
+
from __future__ import annotations
|
|
5
6
|
|
|
6
|
-
import random
|
|
7
7
|
import time
|
|
8
8
|
import math
|
|
9
9
|
import os
|
|
10
10
|
import sys
|
|
11
|
+
import threadpoolctl
|
|
11
12
|
import ctypes as ct
|
|
13
|
+
from scipy import interpolate
|
|
12
14
|
import numpy as np
|
|
13
|
-
from numpy.random import Generator,
|
|
15
|
+
from numpy.random import Generator, PCG64DXSM, SeedSequence
|
|
14
16
|
from scipy.optimize._constraints import new_bounds_to_old
|
|
15
17
|
from scipy.optimize import OptimizeResult, Bounds
|
|
16
18
|
import multiprocessing as mp
|
|
17
19
|
from multiprocessing import Process
|
|
18
|
-
from fcmaes.optimizer import de_cma, dtime,
|
|
20
|
+
from fcmaes.optimizer import de_cma, dtime, Optimizer
|
|
21
|
+
from fcmaes.evaluator import is_debug_active, is_trace_active
|
|
22
|
+
from loguru import logger
|
|
23
|
+
from typing import Optional, Callable, List
|
|
24
|
+
from numpy.typing import ArrayLike
|
|
19
25
|
|
|
20
26
|
os.environ['MKL_DEBUG_CPU_TYPE'] = '5'
|
|
21
27
|
os.environ['MKL_NUM_THREADS'] = '1'
|
|
22
28
|
os.environ['OPENBLAS_NUM_THREADS'] = '1'
|
|
23
29
|
|
|
24
|
-
def minimize(fun,
|
|
25
|
-
bounds
|
|
26
|
-
value_limit =
|
|
27
|
-
num_retries =
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
):
|
|
30
|
+
def minimize(fun: Callable[[ArrayLike], float],
|
|
31
|
+
bounds: Bounds,
|
|
32
|
+
value_limit: Optional[float] = np.inf,
|
|
33
|
+
num_retries: Optional[int] = 1024,
|
|
34
|
+
workers: Optional[int] = mp.cpu_count(),
|
|
35
|
+
popsize: Optional[int] = 31,
|
|
36
|
+
max_evaluations: Optional[int] = 50000,
|
|
37
|
+
capacity: Optional[int] = 500,
|
|
38
|
+
stop_fitness: Optional[float] = -np.inf,
|
|
39
|
+
optimizer: Optional[Optimizer] = None,
|
|
40
|
+
statistic_num: Optional[int] = 0,
|
|
41
|
+
) -> OptimizeResult:
|
|
36
42
|
"""Minimization of a scalar function of one or more variables using parallel
|
|
37
|
-
|
|
43
|
+
optimization retry.
|
|
38
44
|
|
|
39
45
|
Parameters
|
|
40
46
|
----------
|
|
41
47
|
fun : callable
|
|
42
48
|
The objective function to be minimized.
|
|
43
|
-
``fun(x
|
|
44
|
-
where ``x`` is an 1-D array with shape (n,)
|
|
45
|
-
is a tuple of the fixed parameters needed to completely
|
|
46
|
-
specify the function.
|
|
49
|
+
``fun(x) -> float``
|
|
50
|
+
where ``x`` is an 1-D array with shape (n,)
|
|
47
51
|
bounds : sequence or `Bounds`, optional
|
|
48
52
|
Bounds on variables. There are two ways to specify the bounds:
|
|
49
53
|
1. Instance of the `scipy.Bounds` class.
|
|
@@ -53,10 +57,6 @@ def minimize(fun,
|
|
|
53
57
|
Upper limit for optimized function values to be stored.
|
|
54
58
|
num_retries : int, optional
|
|
55
59
|
Number of optimization retries.
|
|
56
|
-
logger : logger, optional
|
|
57
|
-
logger for log output of the retry mechanism. If None, logging
|
|
58
|
-
is switched off. Default is a logger which logs both to stdout and
|
|
59
|
-
appends to a file ``optimizer.log``.
|
|
60
60
|
workers : int, optional
|
|
61
61
|
number of parallel processes used. Default is mp.cpu_count()
|
|
62
62
|
popsize = int, optional
|
|
@@ -69,10 +69,12 @@ def minimize(fun,
|
|
|
69
69
|
this setting is defined in the optimizer.
|
|
70
70
|
capacity : int, optional
|
|
71
71
|
capacity of the evaluation store.
|
|
72
|
-
|
|
72
|
+
stop_fitness : float, optional
|
|
73
73
|
Limit for fitness value. optimization runs terminate if this value is reached.
|
|
74
74
|
optimizer : optimizer.Optimizer, optional
|
|
75
75
|
optimizer to use. Default is a sequence of differential evolution and CMA-ES.
|
|
76
|
+
statistic_num: int, optional
|
|
77
|
+
if > 0 stores the progress of the optimization. Defines the size of this store.
|
|
76
78
|
|
|
77
79
|
Returns
|
|
78
80
|
-------
|
|
@@ -83,33 +85,151 @@ def minimize(fun,
|
|
|
83
85
|
``success`` a Boolean flag indicating if the optimizer exited successfully. """
|
|
84
86
|
|
|
85
87
|
if optimizer is None:
|
|
86
|
-
optimizer = de_cma(max_evaluations, popsize,
|
|
87
|
-
store = Store(bounds, capacity = capacity,
|
|
88
|
-
return retry(
|
|
89
|
-
|
|
90
|
-
def retry(
|
|
88
|
+
optimizer = de_cma(max_evaluations, popsize, stop_fitness)
|
|
89
|
+
store = Store(fun, bounds, capacity = capacity, statistic_num = statistic_num)
|
|
90
|
+
return retry(store, optimizer.minimize, num_retries, value_limit, workers, stop_fitness)
|
|
91
|
+
|
|
92
|
+
def retry(store: Store,
|
|
93
|
+
optimize: Callable,
|
|
94
|
+
num_retries: int,
|
|
95
|
+
value_limit: Optional[float] = np.inf,
|
|
96
|
+
workers: Optional[int] = mp.cpu_count(),
|
|
97
|
+
stop_fitness: Optional[float] = -np.inf) -> OptimizeResult:
|
|
98
|
+
|
|
91
99
|
sg = SeedSequence()
|
|
92
|
-
rgs = [Generator(
|
|
100
|
+
rgs = [Generator(PCG64DXSM(s)) for s in sg.spawn(workers)]
|
|
93
101
|
proc=[Process(target=_retry_loop,
|
|
94
|
-
args=(pid, rgs,
|
|
102
|
+
args=(pid, rgs, store, optimize, num_retries, value_limit, stop_fitness)) for pid in range(workers)]
|
|
95
103
|
[p.start() for p in proc]
|
|
96
104
|
[p.join() for p in proc]
|
|
97
105
|
store.sort()
|
|
98
106
|
store.dump()
|
|
99
107
|
return OptimizeResult(x=store.get_x_best(), fun=store.get_y_best(),
|
|
100
108
|
nfev=store.get_count_evals(), success=True)
|
|
109
|
+
|
|
110
|
+
def minimize_plot(name: str,
|
|
111
|
+
optimizer: Optimizer,
|
|
112
|
+
fun: Callable[[ArrayLike], float],
|
|
113
|
+
bounds: Bounds,
|
|
114
|
+
value_limit: Optional[float] = np.inf,
|
|
115
|
+
plot_limit: Optional[float] = np.inf,
|
|
116
|
+
num_retries: Optional[int] = 1024,
|
|
117
|
+
workers: Optional[int] = mp.cpu_count(),
|
|
118
|
+
stop_fitness: Optional[float] = -np.inf,
|
|
119
|
+
statistic_num: Optional[int] = 5000) -> OptimizeResult:
|
|
120
|
+
|
|
121
|
+
time0 = time.perf_counter() # optimization start time
|
|
122
|
+
name += '_' + optimizer.name
|
|
123
|
+
logger.info('optimize ' + name)
|
|
124
|
+
store = Store(fun, bounds, capacity = 500, statistic_num = statistic_num)
|
|
125
|
+
ret = retry(store, optimizer.minimize, num_retries, value_limit, workers, stop_fitness)
|
|
126
|
+
impr = store.get_improvements()
|
|
127
|
+
np.savez_compressed(name, ys=impr)
|
|
128
|
+
for _ in range(10):
|
|
129
|
+
filtered = np.array([imp for imp in impr if imp[1] < plot_limit])
|
|
130
|
+
if len(filtered) > 0:
|
|
131
|
+
impr = filtered
|
|
132
|
+
break
|
|
133
|
+
else:
|
|
134
|
+
plot_limit *= 3
|
|
135
|
+
logger.info(name + ' time ' + str(dtime(time0)))
|
|
136
|
+
plot(impr, 'progress_ret.' + name + '.png', label = name,
|
|
137
|
+
xlabel = 'time in sec', ylabel = r'$f$')
|
|
138
|
+
return ret
|
|
139
|
+
|
|
140
|
+
def plot(front: ArrayLike, fname: str, interp: Optional[bool] = True,
|
|
141
|
+
label: Optional[str] = r'$\chi$',
|
|
142
|
+
xlabel: Optional[str] = r'$f_1$', ylabel:Optional[str] = r'$f_2$',
|
|
143
|
+
zlabel: Optional[str] = r'$f_3$', plot3d: Optional[bool] = False,
|
|
144
|
+
s = 1, dpi=300):
|
|
145
|
+
if len(front[0]) == 3 and plot3d:
|
|
146
|
+
plot3(front, fname, label, xlabel, ylabel, zlabel)
|
|
147
|
+
return
|
|
148
|
+
if len(front[0]) >= 3:
|
|
149
|
+
for i in range(1, len(front[0])):
|
|
150
|
+
plot(front.T[np.array([0,i])].T, str(i) + '_' + fname,
|
|
151
|
+
interp=interp, ylabel = r'$f_{0}$'.format(i+1))
|
|
152
|
+
return
|
|
153
|
+
if len(front[0]) == 1:
|
|
154
|
+
ys = np.array(list(zip(range(100), [front[0][0]]*100)))
|
|
155
|
+
plot(ys, str(1) + '_' + fname,
|
|
156
|
+
interp=interp, xlabel = '', ylabel = r'$f_{0}$'.format(1))
|
|
157
|
+
return
|
|
158
|
+
import matplotlib.pyplot as pl
|
|
159
|
+
fig, ax = pl.subplots(1, 1)
|
|
160
|
+
x = front[:, 0]; y = front[:, 1]
|
|
161
|
+
if interp and len(x) > 2:
|
|
162
|
+
xa = np.argsort(x)
|
|
163
|
+
xs = x[xa]; ys = y[xa]
|
|
164
|
+
x = []; y = []
|
|
165
|
+
for i in range(len(xs)): # filter equal x values
|
|
166
|
+
if i == 0 or xs[i] > xs[i-1] + 1E-5:
|
|
167
|
+
x.append(xs[i]); y.append(ys[i])
|
|
168
|
+
tck = interpolate.InterpolatedUnivariateSpline(x,y,k=1)
|
|
169
|
+
x = np.linspace(min(x),max(x),1000)
|
|
170
|
+
y = [tck(xi) for xi in x]
|
|
171
|
+
ax.scatter(x, y, label=label, s=s)
|
|
172
|
+
ax.grid()
|
|
173
|
+
ax.set_xlabel(xlabel)
|
|
174
|
+
ax.set_ylabel(ylabel)
|
|
175
|
+
ax.legend()
|
|
176
|
+
fig.savefig(fname, dpi=dpi)
|
|
177
|
+
pl.close('all')
|
|
178
|
+
|
|
179
|
+
def plot3(front: ArrayLike, fname: str, label: Optional[str] =r'$\chi$',
|
|
180
|
+
xlabel: Optional[str] = r'$f_1$', ylabel: Optional[str] = r'$f_2$',
|
|
181
|
+
zlabel: Optional[str] = r'$f_3$'):
|
|
182
|
+
import matplotlib.pyplot as pl
|
|
183
|
+
fig = pl.figure()
|
|
184
|
+
ax = fig.add_subplot(projection='3d')
|
|
185
|
+
x = front[:, 0]; y = front[:, 1]; z = front[:, 2]
|
|
186
|
+
ax.scatter(x, y, z, label=label, s=1)
|
|
187
|
+
ax.grid()
|
|
188
|
+
ax.set_xlabel(xlabel)
|
|
189
|
+
ax.set_ylabel(ylabel)
|
|
190
|
+
ax.set_zlabel(zlabel)
|
|
191
|
+
ax.legend()
|
|
192
|
+
#pl.show()
|
|
193
|
+
fig.savefig(fname, dpi=300)
|
|
194
|
+
pl.close('all')
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
dtype_map = {
|
|
198
|
+
'int32': ct.c_int32,
|
|
199
|
+
'int64': ct.c_int64,
|
|
200
|
+
'float32': ct.c_float,
|
|
201
|
+
'float64': ct.c_double,
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
class Shared2d():
|
|
205
|
+
|
|
206
|
+
def __init__(self, xs):
|
|
207
|
+
self.rows, self.cols = xs.shape
|
|
208
|
+
self.dtype = xs.dtype
|
|
209
|
+
self.ra = mp.RawArray(dtype_map[str(xs.dtype)], self.rows*self.cols)
|
|
210
|
+
self.set(xs)
|
|
211
|
+
|
|
212
|
+
def set_i(self, i, x):
|
|
213
|
+
self.view()[i, :] = x
|
|
214
|
+
|
|
215
|
+
def view(self):
|
|
216
|
+
return np.frombuffer(self.ra, dtype=self.dtype).reshape((self.rows, self.cols))
|
|
217
|
+
|
|
218
|
+
def set(self, xs):
|
|
219
|
+
np.copyto(self.view(), xs)
|
|
101
220
|
|
|
102
221
|
class Store(object):
|
|
103
222
|
"""thread safe storage for optimization retry results."""
|
|
104
223
|
|
|
105
224
|
def __init__(self,
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
225
|
+
fun: Callable[[ArrayLike], float], # fitness function
|
|
226
|
+
bounds: Bounds, # bounds of the objective function arguments
|
|
227
|
+
check_interval: Optional[int] = 10, # sort evaluation memory after check_interval iterations
|
|
228
|
+
capacity: Optional[int] = 500, # capacity of the evaluation store
|
|
229
|
+
statistic_num: Optional[int] = 0
|
|
110
230
|
):
|
|
231
|
+
self.fun = fun
|
|
111
232
|
self.lower, self.upper = _convertBounds(bounds)
|
|
112
|
-
self.logger = logger
|
|
113
233
|
self.capacity = capacity
|
|
114
234
|
self.check_interval = check_interval
|
|
115
235
|
self.dim = len(self.lower)
|
|
@@ -119,131 +239,142 @@ class Store(object):
|
|
|
119
239
|
|
|
120
240
|
#shared between processes
|
|
121
241
|
self.add_mutex = mp.Lock()
|
|
122
|
-
self.xs =
|
|
242
|
+
self.xs = Shared2d(np.empty((self.capacity, self.dim), dtype = np.float64))
|
|
243
|
+
self.create_xs_view()
|
|
123
244
|
self.ys = mp.RawArray(ct.c_double, self.capacity)
|
|
124
245
|
self.count_evals = mp.RawValue(ct.c_long, 0)
|
|
125
246
|
self.count_runs = mp.RawValue(ct.c_int, 0)
|
|
126
|
-
self.num_stored = mp.RawValue(ct.c_int, 0)
|
|
127
|
-
self.num_sorted = mp.RawValue(ct.c_int, 0)
|
|
247
|
+
self.num_stored = mp.RawValue(ct.c_int, 0)
|
|
128
248
|
self.count_stat_runs = mp.RawValue(ct.c_int, 0)
|
|
129
249
|
self.t0 = time.perf_counter()
|
|
130
250
|
self.mean = mp.RawValue(ct.c_double, 0)
|
|
131
251
|
self.qmean = mp.RawValue(ct.c_double, 0)
|
|
132
|
-
self.best_y = mp.RawValue(ct.c_double,
|
|
252
|
+
self.best_y = mp.RawValue(ct.c_double, np.inf)
|
|
133
253
|
self.best_x = mp.RawArray(ct.c_double, self.dim)
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
self.
|
|
137
|
-
|
|
138
|
-
|
|
254
|
+
self.statistic_num = statistic_num
|
|
255
|
+
# statistics
|
|
256
|
+
self.statistic_num = statistic_num
|
|
257
|
+
if statistic_num > 0: # enable statistics
|
|
258
|
+
self.time = mp.RawArray(ct.c_double, self.statistic_num)
|
|
259
|
+
self.val = mp.RawArray(ct.c_double, self.statistic_num)
|
|
260
|
+
self.si = mp.RawValue(ct.c_int, 0)
|
|
261
|
+
self.sevals = mp.RawValue(ct.c_long, 0)
|
|
262
|
+
self.bval = mp.RawValue(ct.c_double, np.inf)
|
|
139
263
|
|
|
140
|
-
#
|
|
141
|
-
def
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
264
|
+
# register improvement - time and value
|
|
265
|
+
def wrapper(self, x: ArrayLike):
|
|
266
|
+
y = self.fun(x)
|
|
267
|
+
self.sevals.value += 1
|
|
268
|
+
if y < self.bval.value:
|
|
269
|
+
self.bval.value = y
|
|
270
|
+
si = self.si.value
|
|
271
|
+
if si < self.statistic_num - 1:
|
|
272
|
+
self.si.value = si + 1
|
|
273
|
+
self.time[si] = dtime(self.t0)
|
|
274
|
+
self.val[si] = y
|
|
275
|
+
logger.trace(str(self.time[si]) + ' ' +
|
|
276
|
+
str(self.sevals.value) + ' ' +
|
|
277
|
+
str(int(self.sevals.value / self.time[si])) + ' ' +
|
|
278
|
+
str(y) + ' ' +
|
|
279
|
+
str(list(x)))
|
|
280
|
+
return y
|
|
281
|
+
|
|
148
282
|
def get_improvements(self):
|
|
149
|
-
return zip(self.time[:self.si.value], self.val[:self.si.value])
|
|
150
|
-
|
|
283
|
+
return np.array(list(zip(self.time[:self.si.value], self.val[:self.si.value])))
|
|
284
|
+
|
|
151
285
|
# get num best values at evenly distributed times
|
|
152
|
-
def get_statistics(self, num):
|
|
286
|
+
def get_statistics(self, num: int) -> List:
|
|
153
287
|
ts = self.time[:self.si.value]
|
|
154
|
-
|
|
288
|
+
ys = self.val[:self.si.value]
|
|
155
289
|
mt = ts[-1]
|
|
156
290
|
dt = 0.9999999 * mt / num
|
|
157
291
|
conv = []
|
|
158
292
|
ti = 0
|
|
159
|
-
val =
|
|
293
|
+
val = ys[0]
|
|
160
294
|
for i in range(num):
|
|
161
295
|
while ts[ti] < (i+1) * dt:
|
|
162
296
|
ti += 1
|
|
163
|
-
val =
|
|
297
|
+
val = ys[ti]
|
|
164
298
|
conv.append(val)
|
|
165
299
|
return conv
|
|
166
300
|
|
|
167
|
-
def eval_num(self, max_evals):
|
|
301
|
+
def eval_num(self, max_evals: int) -> int:
|
|
168
302
|
return max_evals
|
|
169
303
|
|
|
170
|
-
def replace(self, i, y, xs):
|
|
304
|
+
def replace(self, i: int, y: float, xs: ArrayLike):
|
|
171
305
|
self.set_y(i, y)
|
|
172
306
|
self.set_x(i, xs)
|
|
173
307
|
|
|
174
|
-
def sort(self): # sort all entries to make room for new ones, determine best and worst
|
|
308
|
+
def sort(self) -> int: # sort all entries to make room for new ones, determine best and worst
|
|
175
309
|
"""sorts all store entries, keep only the 90% best to make room for new ones."""
|
|
176
310
|
ns = self.num_stored.value
|
|
177
311
|
ys = np.asarray(self.ys[:ns])
|
|
178
312
|
yi = ys.argsort()
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
xs = self.get_x(yi[i])
|
|
183
|
-
sortRuns.append((y, xs))
|
|
184
|
-
numStored = min(len(sortRuns),int(0.9*self.capacity)) # keep 90% best
|
|
185
|
-
for i in range(numStored):
|
|
186
|
-
self.replace(i, sortRuns[i][0], sortRuns[i][1])
|
|
187
|
-
self.num_sorted.value = numStored
|
|
313
|
+
numStored = min(ns, int(0.9*self.capacity)) # keep 90% best
|
|
314
|
+
self.xs_view[:numStored] = self.xs_view[yi][:numStored]
|
|
315
|
+
self.ys[:numStored] = ys[yi][:numStored]
|
|
188
316
|
self.num_stored.value = numStored
|
|
189
317
|
return numStored
|
|
190
318
|
|
|
191
|
-
def add_result(self, y,
|
|
192
|
-
"""registers an optimization result at the
|
|
319
|
+
def add_result(self, y: float, x: ArrayLike, evals: int, limit=np.inf):
|
|
320
|
+
"""registers an optimization result at the store."""
|
|
193
321
|
with self.add_mutex:
|
|
194
322
|
self.incr_count_evals(evals)
|
|
195
323
|
if y < limit:
|
|
196
324
|
self.count_stat_runs.value += 1
|
|
197
325
|
if y < self.best_y.value:
|
|
198
326
|
self.best_y.value = y
|
|
199
|
-
self.best_x[:] =
|
|
200
|
-
self.add_statistics()
|
|
327
|
+
self.best_x[:] = x[:]
|
|
201
328
|
self.dump()
|
|
202
329
|
if self.num_stored.value >= self.capacity-1:
|
|
203
330
|
self.sort()
|
|
204
331
|
cnt = self.count_stat_runs.value
|
|
205
|
-
diff = y - self.mean.value
|
|
206
|
-
self.qmean.value += (cnt - 1) * diff*diff
|
|
332
|
+
diff = min(1E20, y - self.mean.value) # avoid overflow
|
|
333
|
+
self.qmean.value += (cnt - 1)/ cnt * diff*diff ;
|
|
207
334
|
self.mean.value += diff / cnt
|
|
208
335
|
ns = self.num_stored.value
|
|
209
336
|
self.num_stored.value = ns + 1
|
|
210
|
-
self.
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
337
|
+
self.xs_view[self.num_stored.value, :] = x
|
|
338
|
+
self.ys[self.num_stored.value] = y
|
|
339
|
+
if is_debug_active():
|
|
340
|
+
dt = dtime(self.t0)
|
|
341
|
+
message = '{0} {1} {2} {3} {4:.6f} {5:.6f} {6:.2f} {7:.2f}'.format(
|
|
342
|
+
dt, int(self.count_evals.value / dt), self.count_runs.value, self.count_evals.value, \
|
|
343
|
+
y, self.best_y.value, self.get_y_mean(), self.get_y_standard_dev())
|
|
344
|
+
logger.debug(message)
|
|
214
345
|
|
|
215
|
-
def get_x_best(self):
|
|
216
|
-
return self.best_x[:]
|
|
346
|
+
def get_x_best(self) -> np.ndarray:
|
|
347
|
+
return np.array(self.best_x[:])
|
|
217
348
|
|
|
218
|
-
def
|
|
349
|
+
def create_xs_view(self): # needs to be called in the target process
|
|
350
|
+
self.xs_view = self.xs.view()
|
|
351
|
+
|
|
352
|
+
def get_xs(self) -> np.ndarray:
|
|
353
|
+
return self.xs.view()[:self.num_stored.value]
|
|
354
|
+
|
|
355
|
+
def get_y(self, pid: int) -> float:
|
|
219
356
|
return self.ys[pid]
|
|
220
357
|
|
|
221
|
-
def get_y_best(self):
|
|
358
|
+
def get_y_best(self) -> float:
|
|
222
359
|
return self.best_y.value
|
|
223
360
|
|
|
224
|
-
def get_ys(self):
|
|
225
|
-
return self.ys[:self.num_stored.value]
|
|
361
|
+
def get_ys(self) -> np.ndarray:
|
|
362
|
+
return np.array(self.ys[:self.num_stored.value])
|
|
226
363
|
|
|
227
|
-
def get_y_mean(self):
|
|
364
|
+
def get_y_mean(self) -> float:
|
|
228
365
|
return self.mean.value
|
|
229
366
|
|
|
230
|
-
def get_y_standard_dev(self):
|
|
231
|
-
cnt = self.
|
|
367
|
+
def get_y_standard_dev(self) -> float:
|
|
368
|
+
cnt = self.count_stat_runs.value
|
|
232
369
|
return 0 if cnt <= 0 else math.sqrt(self.qmean.value / cnt)
|
|
233
370
|
|
|
234
|
-
def get_count_evals(self):
|
|
371
|
+
def get_count_evals(self) -> int:
|
|
235
372
|
return self.count_evals.value
|
|
236
373
|
|
|
237
|
-
def get_count_runs(self):
|
|
374
|
+
def get_count_runs(self) -> int:
|
|
238
375
|
return self.count_runs.value
|
|
239
|
-
|
|
240
|
-
def
|
|
241
|
-
self.xs[pid*self.dim:(pid+1)*self.dim] = xs[:]
|
|
242
|
-
|
|
243
|
-
def set_y(self, pid, y):
|
|
244
|
-
self.ys[pid] = y
|
|
245
|
-
|
|
246
|
-
def get_runs_compare_incr(self, limit):
|
|
376
|
+
|
|
377
|
+
def get_runs_compare_incr(self, limit: float):
|
|
247
378
|
with self.add_mutex:
|
|
248
379
|
if self.count_runs.value < limit:
|
|
249
380
|
self.count_runs.value += 1
|
|
@@ -258,36 +389,32 @@ class Store(object):
|
|
|
258
389
|
|
|
259
390
|
def dump(self):
|
|
260
391
|
"""logs the current status of the store if logger defined."""
|
|
261
|
-
if
|
|
392
|
+
if not is_debug_active():
|
|
262
393
|
return
|
|
263
394
|
Ys = self.get_ys()
|
|
264
395
|
vals = []
|
|
265
396
|
for i in range(min(20, len(Ys))):
|
|
266
|
-
vals.append(round(Ys[i],
|
|
267
|
-
dt = dtime(self.t0)
|
|
268
|
-
|
|
397
|
+
vals.append(round(Ys[i],4))
|
|
398
|
+
dt = dtime(self.t0)
|
|
269
399
|
message = '{0} {1} {2} {3} {4:.6f} {5:.2f} {6:.2f} {7!s} {8!s}'.format(
|
|
270
400
|
dt, int(self.count_evals.value / dt), self.count_runs.value, self.count_evals.value, \
|
|
271
401
|
self.best_y.value, self.get_y_mean(), self.get_y_standard_dev(), vals, self.best_x[:])
|
|
272
|
-
|
|
402
|
+
logger.debug(message)
|
|
273
403
|
|
|
274
404
|
|
|
275
|
-
def _retry_loop(pid, rgs,
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
if 'win' in sys.platform and not store.logger is None:
|
|
279
|
-
store.logger = logger()
|
|
280
|
-
|
|
405
|
+
def _retry_loop(pid, rgs, store, optimize, num_retries, value_limit, stop_fitness = -np.inf):
|
|
406
|
+
store.create_xs_view()
|
|
407
|
+
fun = store.wrapper if store.statistic_num > 0 else store.fun
|
|
281
408
|
lower = store.lower
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
409
|
+
with threadpoolctl.threadpool_limits(limits=1, user_api="blas"):
|
|
410
|
+
while store.get_runs_compare_incr(num_retries) and store.best_y.value > stop_fitness:
|
|
411
|
+
try:
|
|
412
|
+
rg = rgs[pid]
|
|
413
|
+
sol, y, evals = optimize(fun, Bounds(store.lower, store.upper), None,
|
|
414
|
+
[rg.uniform(0.05, 0.1)]*len(lower), rg, store)
|
|
415
|
+
store.add_result(y, sol, evals, value_limit)
|
|
416
|
+
except Exception as ex:
|
|
417
|
+
print(str(ex))
|
|
291
418
|
|
|
292
419
|
def _convertBounds(bounds):
|
|
293
420
|
if bounds is None:
|