fcmaes 1.3.17__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 +5 -4
- fcmaes/advretry.py +135 -141
- fcmaes/astro.py +64 -40
- fcmaes/bitecpp.py +33 -32
- fcmaes/cmaes.py +69 -142
- fcmaes/cmaescpp.py +231 -39
- fcmaes/crfmnes.py +339 -0
- fcmaes/crfmnescpp.py +273 -0
- fcmaes/dacpp.py +26 -27
- fcmaes/de.py +163 -56
- fcmaes/decpp.py +188 -179
- fcmaes/diversifier.py +357 -0
- fcmaes/evaluator.py +279 -6
- 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/mapelites.py +737 -0
- fcmaes/mode.py +399 -256
- fcmaes/modecpp.py +326 -149
- fcmaes/moretry.py +107 -77
- fcmaes/multiretry.py +37 -30
- fcmaes/optimizer.py +695 -271
- fcmaes/pgpecpp.py +340 -0
- fcmaes/pygmoretry.py +8 -17
- fcmaes/retry.py +161 -139
- fcmaes/test_cma.py +45 -25
- fcmaes-1.6.9.dist-info/METADATA +47 -0
- fcmaes-1.6.9.dist-info/RECORD +36 -0
- {fcmaes-1.3.17.dist-info → fcmaes-1.6.9.dist-info}/WHEEL +1 -1
- fcmaes/csmacpp.py +0 -108
- fcmaes/gcldecpp.py +0 -148
- fcmaes/lcldecpp.py +0 -138
- fcmaes/ldecpp.py +0 -172
- fcmaes/lib/libgcc_s_seh-1.dll +0 -0
- fcmaes/lib/libgtoplib.dll +0 -0
- fcmaes/lib/libgtoplib.so +0 -0
- fcmaes/lib/libstdc++-6.dll +0 -0
- fcmaes/lib/libwinpthread-1.dll +0 -0
- fcmaes-1.3.17.dist-info/METADATA +0 -55
- fcmaes-1.3.17.dist-info/RECORD +0 -37
- {fcmaes-1.3.17.dist-info → fcmaes-1.6.9.dist-info}/LICENSE +0 -0
- {fcmaes-1.3.17.dist-info → fcmaes-1.6.9.dist-info}/top_level.txt +0 -0
fcmaes/__init__.py
CHANGED
|
@@ -3,21 +3,22 @@
|
|
|
3
3
|
# This source code is licensed under the MIT license found in the
|
|
4
4
|
# LICENSE file in the root directory.
|
|
5
5
|
|
|
6
|
-
__version__ = '1.
|
|
6
|
+
__version__ = '1.6.9'
|
|
7
7
|
|
|
8
8
|
__all__ = [
|
|
9
9
|
'cmaes',
|
|
10
10
|
'cmaescpp',
|
|
11
|
+
'crmfnes',
|
|
12
|
+
'crfmnescpp',
|
|
11
13
|
'de',
|
|
12
14
|
'dacpp',
|
|
13
15
|
'decpp',
|
|
14
|
-
'
|
|
15
|
-
'ldecpp',
|
|
16
|
-
'lgcldecpp',
|
|
16
|
+
'diversifier',
|
|
17
17
|
'bitecpp',
|
|
18
18
|
'csmacpp',
|
|
19
19
|
'retry',
|
|
20
20
|
'advretry',
|
|
21
|
+
'mapelites',
|
|
21
22
|
'multiretry',
|
|
22
23
|
'mode',
|
|
23
24
|
'modecpp',
|
fcmaes/advretry.py
CHANGED
|
@@ -3,44 +3,49 @@
|
|
|
3
3
|
# This source code is licensed under the MIT license found in the
|
|
4
4
|
# LICENSE file in the root directory.
|
|
5
5
|
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
6
9
|
import time
|
|
7
10
|
import os
|
|
8
|
-
import sys
|
|
9
11
|
import math
|
|
12
|
+
import threadpoolctl
|
|
10
13
|
import _pickle as cPickle
|
|
11
14
|
import bz2
|
|
12
15
|
import ctypes as ct
|
|
13
16
|
import numpy as np
|
|
14
17
|
from numpy.linalg import norm
|
|
15
|
-
|
|
18
|
+
import random
|
|
16
19
|
import multiprocessing as mp
|
|
17
20
|
from multiprocessing import Process
|
|
18
|
-
from numpy.random import Generator,
|
|
21
|
+
from numpy.random import Generator, PCG64DXSM, SeedSequence
|
|
19
22
|
from scipy.optimize import OptimizeResult, Bounds
|
|
23
|
+
from loguru import logger
|
|
24
|
+
from fcmaes.retry import _convertBounds, plot, Shared2d
|
|
25
|
+
from fcmaes.optimizer import Optimizer, dtime, fitting, de_cma
|
|
20
26
|
|
|
21
|
-
from
|
|
22
|
-
from
|
|
27
|
+
from typing import Optional, Callable, List, Tuple
|
|
28
|
+
from numpy.typing import ArrayLike
|
|
23
29
|
|
|
24
30
|
os.environ['MKL_DEBUG_CPU_TYPE'] = '5'
|
|
25
31
|
os.environ['MKL_NUM_THREADS'] = '1'
|
|
26
32
|
os.environ['OPENBLAS_NUM_THREADS'] = '1'
|
|
27
33
|
|
|
28
|
-
def minimize(fun,
|
|
29
|
-
bounds,
|
|
30
|
-
value_limit =
|
|
31
|
-
num_retries = 5000,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
):
|
|
34
|
+
def minimize(fun: Callable[[ArrayLike], float],
|
|
35
|
+
bounds: Bounds,
|
|
36
|
+
value_limit: Optional[float] = np.inf,
|
|
37
|
+
num_retries: Optional[int] = 5000,
|
|
38
|
+
workers: Optional[int] = mp.cpu_count(),
|
|
39
|
+
popsize: Optional[int] = 31,
|
|
40
|
+
min_evaluations: Optional[int] = 1500,
|
|
41
|
+
max_eval_fac: Optional[int] = None,
|
|
42
|
+
check_interval: Optional[int] = 100,
|
|
43
|
+
capacity: Optional[int] = 500,
|
|
44
|
+
stop_fitness: Optional[float] = -np.inf,
|
|
45
|
+
optimizer: Optional[Optimizer] = None,
|
|
46
|
+
statistic_num: Optional[int] = 0,
|
|
47
|
+
datafile: Optional[str] = None
|
|
48
|
+
) -> OptimizeResult:
|
|
44
49
|
"""Minimization of a scalar function of one or more variables using
|
|
45
50
|
smart parallel optimization retry.
|
|
46
51
|
|
|
@@ -48,10 +53,8 @@ def minimize(fun,
|
|
|
48
53
|
----------
|
|
49
54
|
fun : callable
|
|
50
55
|
The objective function to be minimized.
|
|
51
|
-
``fun(x
|
|
52
|
-
where ``x`` is an 1-D array with shape (n,)
|
|
53
|
-
is a tuple of the fixed parameters needed to completely
|
|
54
|
-
specify the function.
|
|
56
|
+
``fun(x) -> float``
|
|
57
|
+
where ``x`` is an 1-D array with shape (n,)
|
|
55
58
|
bounds : sequence or `Bounds`, optional
|
|
56
59
|
Bounds on variables. There are two ways to specify the bounds:
|
|
57
60
|
1. Instance of the `scipy.Bounds` class.
|
|
@@ -65,10 +68,6 @@ def minimize(fun,
|
|
|
65
68
|
cause the algorithm to get stuck at local minima.
|
|
66
69
|
num_retries : int, optional
|
|
67
70
|
Number of optimization retries.
|
|
68
|
-
logger : logger, optional
|
|
69
|
-
logger for log output of the retry mechanism. If None, logging
|
|
70
|
-
is switched off. Default is a logger which logs both to stdout and
|
|
71
|
-
appends to a file ``optimizer.log``.
|
|
72
71
|
workers : int, optional
|
|
73
72
|
number of parallel processes used. Default is mp.cpu_count()
|
|
74
73
|
popsize = int, optional
|
|
@@ -106,7 +105,7 @@ def minimize(fun,
|
|
|
106
105
|
optimizer = de_cma(min_evaluations, popsize, stop_fitness)
|
|
107
106
|
if max_eval_fac is None:
|
|
108
107
|
max_eval_fac = int(min(50, 1 + num_retries // check_interval))
|
|
109
|
-
store = Store(fun, bounds, max_eval_fac, check_interval, capacity,
|
|
108
|
+
store = Store(fun, bounds, max_eval_fac, check_interval, capacity, num_retries,
|
|
110
109
|
statistic_num, datafile)
|
|
111
110
|
if not datafile is None:
|
|
112
111
|
try:
|
|
@@ -115,10 +114,14 @@ def minimize(fun,
|
|
|
115
114
|
pass
|
|
116
115
|
return retry(store, optimizer.minimize, value_limit, workers, stop_fitness)
|
|
117
116
|
|
|
118
|
-
def retry(store
|
|
119
|
-
|
|
117
|
+
def retry(store: Store,
|
|
118
|
+
optimize: Callable,
|
|
119
|
+
value_limit:Optional[float] = np.inf,
|
|
120
|
+
workers=mp.cpu_count(),
|
|
121
|
+
stop_fitness = -np.inf) -> OptimizeResult:
|
|
122
|
+
|
|
120
123
|
sg = SeedSequence()
|
|
121
|
-
rgs = [Generator(
|
|
124
|
+
rgs = [Generator(PCG64DXSM(s)) for s in sg.spawn(workers)]
|
|
122
125
|
proc=[Process(target=_retry_loop,
|
|
123
126
|
args=(pid, rgs, store, optimize, value_limit, stop_fitness)) for pid in range(workers)]
|
|
124
127
|
[p.start() for p in proc]
|
|
@@ -128,14 +131,22 @@ def retry(store, optimize, value_limit = math.inf,
|
|
|
128
131
|
return OptimizeResult(x=store.get_x_best(), fun=store.get_y_best(),
|
|
129
132
|
nfev=store.get_count_evals(), success=True)
|
|
130
133
|
|
|
131
|
-
def minimize_plot(name
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
134
|
+
def minimize_plot(name: str,
|
|
135
|
+
optimizer: Optimizer,
|
|
136
|
+
fun: Callable[[ArrayLike], float],
|
|
137
|
+
bounds: Bounds,
|
|
138
|
+
value_limit: Optional[float] = np.inf,
|
|
139
|
+
plot_limit: Optional[float] = np.inf,
|
|
140
|
+
num_retries: Optional[int] = 1024,
|
|
141
|
+
workers: Optional[int] = mp.cpu_count(),
|
|
142
|
+
stop_fitness: Optional[float] = -np.inf,
|
|
143
|
+
statistic_num: Optional[int] = 5000) -> OptimizeResult:
|
|
144
|
+
|
|
135
145
|
time0 = time.perf_counter() # optimization start time
|
|
136
146
|
name += '_' + optimizer.name
|
|
137
147
|
logger.info('optimize ' + name)
|
|
138
|
-
store = Store(fun, bounds, capacity = 500,
|
|
148
|
+
store = Store(fun, bounds, capacity = 500, statistic_num = statistic_num,
|
|
149
|
+
num_retries=num_retries)
|
|
139
150
|
ret = retry(store, optimizer.minimize, value_limit, workers, stop_fitness)
|
|
140
151
|
impr = store.get_improvements()
|
|
141
152
|
np.savez_compressed(name, ys=impr)
|
|
@@ -151,20 +162,18 @@ class Store(object):
|
|
|
151
162
|
delivers boundary and initial step size vectors for advanced retry crossover operation."""
|
|
152
163
|
|
|
153
164
|
def __init__(self,
|
|
154
|
-
fun, # fitness function
|
|
155
|
-
bounds, # bounds of the objective function arguments
|
|
156
|
-
max_eval_fac = None, # maximal number of evaluations factor
|
|
157
|
-
check_interval = 100, # sort evaluation store after check_interval iterations
|
|
158
|
-
capacity = 500, # capacity of the evaluation store
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
datafile = None
|
|
165
|
+
fun: Callable[[ArrayLike], float], # fitness function
|
|
166
|
+
bounds: Bounds, # bounds of the objective function arguments
|
|
167
|
+
max_eval_fac: Optional[int] = None, # maximal number of evaluations factor
|
|
168
|
+
check_interval: Optional[int] = 100, # sort evaluation store after check_interval iterations
|
|
169
|
+
capacity: Optional[int] = 500, # capacity of the evaluation store
|
|
170
|
+
num_retries: Optional[int] = None,
|
|
171
|
+
statistic_num: Optional[int] = 0,
|
|
172
|
+
datafile: Optional[str] = None
|
|
163
173
|
):
|
|
164
174
|
self.fun = fun
|
|
165
175
|
self.lower, self.upper = _convertBounds(bounds)
|
|
166
|
-
self.delta = self.upper - self.lower
|
|
167
|
-
self.logger = logger
|
|
176
|
+
self.delta = self.upper - self.lower
|
|
168
177
|
self.capacity = capacity
|
|
169
178
|
if max_eval_fac is None:
|
|
170
179
|
if num_retries is None:
|
|
@@ -179,8 +188,12 @@ class Store(object):
|
|
|
179
188
|
self.max_eval_fac = max_eval_fac
|
|
180
189
|
self.check_interval = check_interval
|
|
181
190
|
self.dim = len(self.lower)
|
|
182
|
-
self.random = Random()
|
|
183
191
|
self.t0 = time.perf_counter()
|
|
192
|
+
self.statistic_num = statistic_num
|
|
193
|
+
self.datafile = datafile
|
|
194
|
+
self.rg = random.Random()
|
|
195
|
+
#self.rg = Generator(PCG64DXSM()))
|
|
196
|
+
#self.rg = Generator(PCG64DXSM(random.randint(0, 2**63 - 1)))
|
|
184
197
|
|
|
185
198
|
#shared between processes
|
|
186
199
|
self.add_mutex = mp.Lock()
|
|
@@ -190,13 +203,10 @@ class Store(object):
|
|
|
190
203
|
self.eval_fac = mp.RawValue(ct.c_double, 1)
|
|
191
204
|
self.count_evals = mp.RawValue(ct.c_long, 0)
|
|
192
205
|
self.count_runs = mp.RawValue(ct.c_int, 0)
|
|
193
|
-
self.num_stored = mp.RawValue(ct.c_int, 0)
|
|
194
|
-
self.
|
|
195
|
-
self.
|
|
196
|
-
self.worst_y = mp.RawValue(ct.c_double, math.inf)
|
|
206
|
+
self.num_stored = mp.RawValue(ct.c_int, 0)
|
|
207
|
+
self.best_y = mp.RawValue(ct.c_double, np.inf)
|
|
208
|
+
self.worst_y = mp.RawValue(ct.c_double, np.inf)
|
|
197
209
|
self.best_x = mp.RawArray(ct.c_double, self.dim)
|
|
198
|
-
self.statistic_num = statistic_num
|
|
199
|
-
self.datafile = datafile
|
|
200
210
|
|
|
201
211
|
if statistic_num > 0: # enable statistics
|
|
202
212
|
self.statistic_num = statistic_num
|
|
@@ -204,10 +214,10 @@ class Store(object):
|
|
|
204
214
|
self.val = mp.RawArray(ct.c_double, self.statistic_num)
|
|
205
215
|
self.si = mp.RawValue(ct.c_int, 0)
|
|
206
216
|
self.sevals = mp.RawValue(ct.c_long, 0)
|
|
207
|
-
self.bval = mp.RawValue(ct.c_double,
|
|
217
|
+
self.bval = mp.RawValue(ct.c_double, np.inf)
|
|
208
218
|
|
|
209
219
|
# register improvement - time and value
|
|
210
|
-
def wrapper(self, x):
|
|
220
|
+
def wrapper(self, x: ArrayLike) -> float:
|
|
211
221
|
y = self.fun(x)
|
|
212
222
|
self.sevals.value += 1
|
|
213
223
|
if y < self.bval.value:
|
|
@@ -217,23 +227,22 @@ class Store(object):
|
|
|
217
227
|
self.si.value = si + 1
|
|
218
228
|
self.time[si] = dtime(self.t0)
|
|
219
229
|
self.val[si] = y
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
str(list(x)))
|
|
230
|
+
logger.info(str(self.time[si]) + ' ' +
|
|
231
|
+
str(self.sevals.value) + ' ' +
|
|
232
|
+
str(y) + ' ' +
|
|
233
|
+
str(list(x)))
|
|
225
234
|
return y
|
|
226
235
|
|
|
227
236
|
# persist store
|
|
228
|
-
def save(self, name):
|
|
237
|
+
def save(self, name: str):
|
|
229
238
|
with bz2.BZ2File(name + '.pbz2', 'w') as f:
|
|
230
239
|
cPickle.dump(self.get_data(), f)
|
|
231
240
|
|
|
232
|
-
def load(self, name):
|
|
241
|
+
def load(self, name: str):
|
|
233
242
|
data = cPickle.load(bz2.BZ2File(name + '.pbz2', 'rb'))
|
|
234
243
|
self.set_data(data)
|
|
235
244
|
|
|
236
|
-
def get_data(self):
|
|
245
|
+
def get_data(self) -> List:
|
|
237
246
|
data = []
|
|
238
247
|
data.append(self.get_xs())
|
|
239
248
|
data.append(self.get_ys())
|
|
@@ -242,7 +251,7 @@ class Store(object):
|
|
|
242
251
|
data.append(self.num_stored.value)
|
|
243
252
|
return data
|
|
244
253
|
|
|
245
|
-
def set_data(self, data):
|
|
254
|
+
def set_data(self, data: ArrayLike):
|
|
246
255
|
xs = data[0]
|
|
247
256
|
ys = data[1]
|
|
248
257
|
for i in range(len(ys)):
|
|
@@ -252,11 +261,11 @@ class Store(object):
|
|
|
252
261
|
self.num_stored.value = data[4]
|
|
253
262
|
self.sort()
|
|
254
263
|
|
|
255
|
-
def get_improvements(self):
|
|
264
|
+
def get_improvements(self) -> np.ndarray:
|
|
256
265
|
return np.array(list(zip(self.time[:self.si.value], self.val[:self.si.value])))
|
|
257
266
|
|
|
258
267
|
# get num best values at evenly distributed times
|
|
259
|
-
def get_statistics(self, num):
|
|
268
|
+
def get_statistics(self, num: int) -> List:
|
|
260
269
|
ts = self.time[:self.si.value]
|
|
261
270
|
vs = self.val[:self.si.value]
|
|
262
271
|
mt = ts[-1]
|
|
@@ -271,56 +280,56 @@ class Store(object):
|
|
|
271
280
|
stats.append(val)
|
|
272
281
|
return stats
|
|
273
282
|
|
|
274
|
-
def eval_num(self, max_evals):
|
|
283
|
+
def eval_num(self, max_evals: int) -> int:
|
|
275
284
|
return int(self.eval_fac.value * max_evals)
|
|
276
285
|
|
|
277
|
-
def limits(self):
|
|
286
|
+
def limits(self) -> Tuple[float, np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
|
|
278
287
|
"""guess, boundaries and initial step size for crossover operation."""
|
|
279
|
-
diff_fac = self.
|
|
280
|
-
lim_fac = self.
|
|
288
|
+
diff_fac = self.rg.uniform(0.5, 1.0)
|
|
289
|
+
lim_fac = self.rg.uniform(2.0, 4.0) * diff_fac
|
|
281
290
|
with self.add_mutex:
|
|
282
291
|
i, j = self.crossover()
|
|
283
292
|
if i < 0:
|
|
284
293
|
return math.inf, None, None, None, None
|
|
285
294
|
x0 = np.asarray(self.get_x(i))
|
|
286
295
|
x1 = np.asarray(self.get_x(j))
|
|
287
|
-
y0 =
|
|
296
|
+
y0 = self.get_y(i)
|
|
288
297
|
|
|
289
298
|
deltax = np.abs(x1 - x0)
|
|
290
299
|
delta_bound = np.maximum(0.0001, lim_fac * deltax)
|
|
291
300
|
lower = np.maximum(self.lower, x0 - delta_bound)
|
|
292
301
|
upper = np.minimum(self.upper, x0 + delta_bound)
|
|
293
|
-
sdev = np.
|
|
302
|
+
sdev = np.clip(diff_fac * deltax / self.delta, 0.001, 0.5)
|
|
294
303
|
return y0, x1, lower, upper, sdev
|
|
295
304
|
|
|
296
|
-
def distance(self, xprev, x):
|
|
305
|
+
def distance(self, xprev: np.ndarray, x: np.ndarray) -> float:
|
|
297
306
|
"""distance between entries in store."""
|
|
298
307
|
return norm((x - xprev) / self.delta) / math.sqrt(self.dim)
|
|
299
308
|
|
|
300
|
-
def replace(self, i, y,
|
|
309
|
+
def replace(self, i: int, y: float, x: np.ndarray):
|
|
301
310
|
"""replace entry in store."""
|
|
302
311
|
self.set_y(i, y)
|
|
303
|
-
self.set_x(i,
|
|
304
|
-
|
|
305
|
-
def crossover(self): # Choose two good entries for recombination
|
|
312
|
+
self.set_x(i, x)
|
|
313
|
+
|
|
314
|
+
def crossover(self) -> Tuple[int,int]: # Choose two good entries for recombination
|
|
306
315
|
"""indices of store entries to be used for crossover operation."""
|
|
307
|
-
n = self.
|
|
316
|
+
n = self.num_stored.value
|
|
308
317
|
if n < 2:
|
|
309
318
|
return -1, -1
|
|
310
|
-
lim = self.
|
|
319
|
+
lim = self.rg.uniform(min(0.1*n, 1), 0.2*n)/n
|
|
311
320
|
for _ in range(100):
|
|
312
321
|
i1 = -1
|
|
313
322
|
i2 = -1
|
|
314
323
|
for j in range(n):
|
|
315
|
-
if self.
|
|
324
|
+
if self.rg.random() < lim:
|
|
316
325
|
if i1 < 0:
|
|
317
326
|
i1 = j
|
|
318
327
|
else:
|
|
319
328
|
i2 = j
|
|
320
329
|
return i1, i2
|
|
321
330
|
return -1, -1
|
|
322
|
-
|
|
323
|
-
def sort(self):
|
|
331
|
+
|
|
332
|
+
def sort(self) -> int:
|
|
324
333
|
"""sorts all store entries, keep only the 90% best to make room for new ones;
|
|
325
334
|
skip entries having similar x values than their neighbors to preserve diversity"""
|
|
326
335
|
ns = self.num_stored.value
|
|
@@ -329,34 +338,31 @@ class Store(object):
|
|
|
329
338
|
|
|
330
339
|
ys = np.asarray(self.ys[:ns])
|
|
331
340
|
yi = ys.argsort()
|
|
332
|
-
sortRuns = []
|
|
333
341
|
|
|
334
|
-
|
|
342
|
+
ys2 = []
|
|
343
|
+
xs2 = []
|
|
335
344
|
for i in range(ns):
|
|
336
345
|
y = ys[yi[i]]
|
|
337
|
-
x = np.asarray(self.get_x(yi[i]))
|
|
338
|
-
if (
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
xprev2 = xprev
|
|
342
|
-
xprev = x
|
|
346
|
+
x = np.asarray(self.get_x(yi[i])) # preserve diversity
|
|
347
|
+
if np.all([self.distance(xp, x) > 0.15 for xp in xs2[-2:]]):
|
|
348
|
+
ys2.append(y)
|
|
349
|
+
xs2.append(x)
|
|
343
350
|
|
|
344
|
-
|
|
345
|
-
for i in range(
|
|
346
|
-
self.replace(i,
|
|
347
|
-
self.
|
|
348
|
-
self.
|
|
349
|
-
|
|
350
|
-
return numStored
|
|
351
|
+
ns = min(len(ys2),int(0.9*self.capacity)) # keep 90% best
|
|
352
|
+
for i in range(ns):
|
|
353
|
+
self.replace(i, ys2[i], xs2[i])
|
|
354
|
+
self.num_stored.value = ns
|
|
355
|
+
self.worst_y.value = self.get_y(ns-1)
|
|
356
|
+
return ns
|
|
351
357
|
|
|
352
|
-
def add_result(self, y
|
|
358
|
+
def add_result(self, y: float, x: np.ndarray, evals: int, limit: Optional[float] = np.inf):
|
|
353
359
|
"""registers an optimization result at the store."""
|
|
354
360
|
with self.add_mutex:
|
|
355
|
-
self.
|
|
361
|
+
self.count_evals.value += evals
|
|
356
362
|
if y < limit:
|
|
357
363
|
if y < self.best_y.value:
|
|
358
364
|
self.best_y.value = y
|
|
359
|
-
self.best_x[:] =
|
|
365
|
+
self.best_x[:] = x[:]
|
|
360
366
|
self.dump()
|
|
361
367
|
if not self.datafile is None:
|
|
362
368
|
self.save(self.datafile)
|
|
@@ -364,91 +370,79 @@ class Store(object):
|
|
|
364
370
|
if self.num_stored.value >= self.capacity - 1:
|
|
365
371
|
self.sort()
|
|
366
372
|
ns = self.num_stored.value
|
|
373
|
+
self.replace(ns, y, x)
|
|
367
374
|
self.num_stored.value = ns + 1
|
|
368
|
-
self.replace(ns, y, xs)
|
|
369
375
|
|
|
370
|
-
def
|
|
376
|
+
def get_x_best(self) -> np.ndarray:
|
|
377
|
+
return np.array(self.best_x[:])
|
|
378
|
+
|
|
379
|
+
def get_x(self, pid) -> np.ndarray:
|
|
371
380
|
return self.xs[pid*self.dim:(pid+1)*self.dim]
|
|
372
381
|
|
|
373
|
-
def get_xs(self):
|
|
382
|
+
def get_xs(self)-> np.ndarray:
|
|
374
383
|
return np.array([self.get_x(i) for i in range(self.num_stored.value)])
|
|
375
384
|
|
|
376
|
-
def
|
|
377
|
-
return np.array(self.best_x[:])
|
|
378
|
-
|
|
379
|
-
def get_y(self, pid):
|
|
385
|
+
def get_y(self, pid: int) -> float:
|
|
380
386
|
return self.ys[pid]
|
|
381
387
|
|
|
382
|
-
def get_ys(self):
|
|
388
|
+
def get_ys(self) -> np.ndarray:
|
|
383
389
|
return np.array(self.ys[:self.num_stored.value])
|
|
384
390
|
|
|
385
|
-
def get_y_best(self):
|
|
391
|
+
def get_y_best(self) -> float:
|
|
386
392
|
return self.best_y.value
|
|
387
393
|
|
|
388
|
-
def get_count_evals(self):
|
|
394
|
+
def get_count_evals(self) -> int:
|
|
389
395
|
return self.count_evals.value
|
|
390
396
|
|
|
391
|
-
def get_count_runs(self):
|
|
397
|
+
def get_count_runs(self) -> int:
|
|
392
398
|
return self.count_runs.value
|
|
393
399
|
|
|
394
400
|
def set_x(self, pid, xs):
|
|
395
401
|
self.xs[pid*self.dim:(pid+1)*self.dim] = xs[:]
|
|
396
402
|
|
|
397
403
|
def set_y(self, pid, y):
|
|
398
|
-
self.ys[pid] = y
|
|
404
|
+
self.ys[pid] = y
|
|
399
405
|
|
|
400
|
-
def get_runs_compare_incr(self, limit):
|
|
406
|
+
def get_runs_compare_incr(self, limit: float) -> bool:
|
|
407
|
+
"""trigger sorting after check_interval calls. """
|
|
401
408
|
with self.add_mutex:
|
|
402
409
|
if self.count_runs.value < limit:
|
|
403
410
|
self.count_runs.value += 1
|
|
411
|
+
if self.count_runs.value % self.check_interval == self.check_interval-1:
|
|
412
|
+
if self.eval_fac.value < self.max_eval_fac:
|
|
413
|
+
self.eval_fac.value += self.eval_fac_incr
|
|
414
|
+
self.sort()
|
|
404
415
|
return True
|
|
405
416
|
else:
|
|
406
417
|
return False
|
|
407
418
|
|
|
408
|
-
def incr_count_evals(self, evals):
|
|
409
|
-
"""registers the number of evaluations of an optimization run;
|
|
410
|
-
trigger sorting after check_interval calls. """
|
|
411
|
-
if self.count_runs.value % self.check_interval == self.check_interval-1:
|
|
412
|
-
if self.eval_fac.value < self.max_eval_fac:
|
|
413
|
-
self.eval_fac.value += self.eval_fac_incr
|
|
414
|
-
#print(self.eval_fac.value)
|
|
415
|
-
self.sort()
|
|
416
|
-
self.count_evals.value += evals
|
|
417
|
-
|
|
418
419
|
def dump(self):
|
|
419
420
|
"""logs the current status of the store if logger defined."""
|
|
420
|
-
if self.logger is None:
|
|
421
|
-
return
|
|
422
421
|
Ys = self.get_ys()
|
|
423
422
|
vals = []
|
|
424
423
|
for i in range(min(20, len(Ys))):
|
|
425
424
|
vals.append(round(Ys[i],2))
|
|
426
|
-
dt = dtime(self.t0)
|
|
425
|
+
dt = dtime(self.t0)+.000001
|
|
427
426
|
message = '{0} {1} {2} {3} {4:.6f} {5:.2f} {6} {7} {8!s} {9!s}'.format(
|
|
428
427
|
dt, int(self.count_evals.value / dt), self.count_runs.value, self.count_evals.value,
|
|
429
428
|
self.best_y.value, self.worst_y.value, self.num_stored.value, int(self.eval_fac.value),
|
|
430
429
|
vals, self.best_x[:])
|
|
431
|
-
|
|
430
|
+
logger.info(message)
|
|
432
431
|
|
|
433
|
-
def _retry_loop(pid, rgs, store, optimize, value_limit, stop_fitness = -
|
|
432
|
+
def _retry_loop(pid, rgs, store, optimize, value_limit, stop_fitness = -np.inf):
|
|
434
433
|
fun = store.wrapper if store.statistic_num > 0 else store.fun
|
|
435
|
-
#
|
|
436
|
-
|
|
437
|
-
store.logger = logger()
|
|
438
|
-
|
|
439
|
-
while store.get_runs_compare_incr(store.num_retries) and store.best_y.value > stop_fitness:
|
|
434
|
+
#with threadpoolctl.threadpool_limits(limits=1, user_api="blas"):
|
|
435
|
+
while store.get_runs_compare_incr(store.num_retries) and store.best_y.value > stop_fitness:
|
|
440
436
|
if _crossover(fun, store, optimize, rgs[pid]):
|
|
441
437
|
continue
|
|
442
438
|
try:
|
|
443
439
|
rg = rgs[pid]
|
|
444
440
|
dim = len(store.lower)
|
|
445
|
-
sol, y, evals = optimize(fun, Bounds(store.lower, store.upper), None,
|
|
441
|
+
sol, y, evals = optimize(fun, Bounds(store.lower, store.upper), None,
|
|
446
442
|
[rg.uniform(0.05, 0.1)]*dim, rg, store)
|
|
447
|
-
store.add_result(y, sol,
|
|
443
|
+
store.add_result(y, sol, evals, value_limit)
|
|
448
444
|
except Exception as ex:
|
|
449
445
|
continue
|
|
450
|
-
# if pid == 0:
|
|
451
|
-
# store.dump()
|
|
452
446
|
|
|
453
447
|
def _crossover(fun, store, optimize, rg):
|
|
454
448
|
if rg.uniform(0,1) < 0.5:
|
|
@@ -459,7 +453,7 @@ def _crossover(fun, store, optimize, rg):
|
|
|
459
453
|
guess = fitting(guess, lower, upper) # take X from lower
|
|
460
454
|
try:
|
|
461
455
|
sol, y, evals = optimize(fun, Bounds(lower, upper), guess, sdev, rg, store)
|
|
462
|
-
store.add_result(y, sol,
|
|
456
|
+
store.add_result(y, sol, evals, y0) # limit to y0
|
|
463
457
|
except:
|
|
464
458
|
return False
|
|
465
459
|
return True
|