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/evaluator.py
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
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
7
|
""" Parallel objective function evaluator.
|
|
7
8
|
Uses pipes to avoid re-spawning new processes for each eval_parallel call.
|
|
@@ -12,31 +13,70 @@
|
|
|
12
13
|
|
|
13
14
|
from multiprocessing import Process, Pipe
|
|
14
15
|
import multiprocessing as mp
|
|
16
|
+
import ctypes as ct
|
|
15
17
|
import numpy as np
|
|
16
|
-
import sys
|
|
17
|
-
import
|
|
18
|
+
import sys, math, os
|
|
19
|
+
from loguru import logger
|
|
20
|
+
from typing import Optional, Callable, Tuple
|
|
21
|
+
from numpy.typing import ArrayLike
|
|
18
22
|
|
|
19
|
-
|
|
23
|
+
pipe_limit = 64 # higher values can cause issues
|
|
24
|
+
|
|
25
|
+
def is_log_level_active(level):
|
|
26
|
+
try: # nasty but currently there is no other way
|
|
27
|
+
for handler in logger._core.handlers.values():
|
|
28
|
+
if handler._levelno <= logger.level(level).no:
|
|
29
|
+
return True
|
|
30
|
+
except Exception as ex:
|
|
31
|
+
pass
|
|
32
|
+
return False
|
|
33
|
+
|
|
34
|
+
def is_debug_active():
|
|
35
|
+
return is_log_level_active("DEBUG")
|
|
36
|
+
|
|
37
|
+
def is_trace_active():
|
|
38
|
+
return is_log_level_active("TRACE")
|
|
39
|
+
|
|
40
|
+
def eval_parallel(xs: ArrayLike,
|
|
41
|
+
evaluator: Evaluator):
|
|
20
42
|
popsize = len(xs)
|
|
21
43
|
ys = np.empty(popsize)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
44
|
+
i0 = 0
|
|
45
|
+
i1 = min(popsize, pipe_limit)
|
|
46
|
+
while True:
|
|
47
|
+
_eval_parallel_segment(xs, ys, i0, i1, evaluator)
|
|
48
|
+
if i1 >= popsize:
|
|
49
|
+
break;
|
|
50
|
+
i0 += pipe_limit
|
|
51
|
+
i1 = min(popsize, i1 + pipe_limit)
|
|
27
52
|
return ys
|
|
28
|
-
|
|
53
|
+
|
|
54
|
+
def eval_parallel_mo(xs: ArrayLike,
|
|
55
|
+
evaluator: Evaluator,
|
|
56
|
+
nobj: int):
|
|
57
|
+
popsize = len(xs)
|
|
58
|
+
ys = np.empty((popsize,nobj))
|
|
59
|
+
i0 = 0
|
|
60
|
+
i1 = min(popsize, pipe_limit)
|
|
61
|
+
while True:
|
|
62
|
+
_eval_parallel_segment(xs, ys, i0, i1, evaluator)
|
|
63
|
+
if i1 >= popsize:
|
|
64
|
+
break;
|
|
65
|
+
i0 += pipe_limit
|
|
66
|
+
i1 = min(popsize, i1 + pipe_limit)
|
|
67
|
+
return ys
|
|
68
|
+
|
|
29
69
|
class Evaluator(object):
|
|
30
70
|
|
|
31
71
|
def __init__(self,
|
|
32
|
-
fun, # objective function
|
|
72
|
+
fun: Callable[[ArrayLike], float], # objective function
|
|
33
73
|
):
|
|
34
74
|
self.fun = fun
|
|
35
75
|
self.pipe = Pipe()
|
|
36
76
|
self.read_mutex = mp.Lock()
|
|
37
77
|
self.write_mutex = mp.Lock()
|
|
38
78
|
|
|
39
|
-
def start(self, workers=mp.cpu_count()):
|
|
79
|
+
def start(self, workers: Optional[int] = mp.cpu_count()):
|
|
40
80
|
self.workers = workers
|
|
41
81
|
self.proc=[Process(target=_evaluate, args=(self.fun,
|
|
42
82
|
self.pipe, self.read_mutex, self.write_mutex)) for _ in range(workers)]
|
|
@@ -49,6 +89,14 @@ class Evaluator(object):
|
|
|
49
89
|
for p in self.pipe:
|
|
50
90
|
p.close()
|
|
51
91
|
|
|
92
|
+
def _eval_parallel_segment(xs, ys, i0, i1, evaluator):
|
|
93
|
+
for i in range(i0, i1):
|
|
94
|
+
evaluator.pipe[0].send((i, xs[i]))
|
|
95
|
+
for _ in range(i0, i1):
|
|
96
|
+
i, y = evaluator.pipe[0].recv()
|
|
97
|
+
ys[i] = y
|
|
98
|
+
return ys
|
|
99
|
+
|
|
52
100
|
def _evaluate(fun, pipe, read_mutex, write_mutex): # worker
|
|
53
101
|
while True:
|
|
54
102
|
with read_mutex:
|
|
@@ -58,9 +106,244 @@ def _evaluate(fun, pipe, read_mutex, write_mutex): # worker
|
|
|
58
106
|
try:
|
|
59
107
|
i, x = msg
|
|
60
108
|
y = fun(x)
|
|
61
|
-
|
|
62
|
-
y = sys.float_info.max
|
|
63
|
-
except Exception:
|
|
109
|
+
except Exception as ex:
|
|
64
110
|
y = sys.float_info.max
|
|
65
111
|
with write_mutex:
|
|
66
112
|
pipe[1].send((i, y)) # Send result
|
|
113
|
+
|
|
114
|
+
def _check_bounds(bounds, guess, rg):
|
|
115
|
+
if bounds is None and guess is None:
|
|
116
|
+
raise ValueError('either guess or bounds need to be defined')
|
|
117
|
+
if bounds is None:
|
|
118
|
+
return None, None, np.asarray(guess)
|
|
119
|
+
if guess is None:
|
|
120
|
+
guess = rg.uniform(bounds.lb, bounds.ub)
|
|
121
|
+
return np.asarray(bounds.lb), np.asarray(bounds.ub), np.asarray(guess)
|
|
122
|
+
|
|
123
|
+
def _get_bounds(dim, bounds, guess, rg):
|
|
124
|
+
if bounds is None:
|
|
125
|
+
if guess is None:
|
|
126
|
+
guess = np.asarray(np.zeros(dim))
|
|
127
|
+
return None, None, guess
|
|
128
|
+
if guess is None:
|
|
129
|
+
guess = rg.uniform(bounds.lb, bounds.ub)
|
|
130
|
+
return np.asarray(bounds.lb), np.asarray(bounds.ub), np.asarray(guess)
|
|
131
|
+
|
|
132
|
+
class _fitness(object):
|
|
133
|
+
"""wrapper around the objective function, scales relative to boundaries."""
|
|
134
|
+
|
|
135
|
+
def __init__(self, fun, lower, upper, normalize = None):
|
|
136
|
+
self.fun = fun
|
|
137
|
+
self.evaluation_counter = 0
|
|
138
|
+
self.lower = lower
|
|
139
|
+
self.normalize = False
|
|
140
|
+
if not (lower is None or normalize is None):
|
|
141
|
+
self.normalize = normalize
|
|
142
|
+
if not lower is None:
|
|
143
|
+
self.upper = upper
|
|
144
|
+
self.scale = 0.5 * (upper - lower)
|
|
145
|
+
self.typx = 0.5 * (upper + lower)
|
|
146
|
+
|
|
147
|
+
def values(self, Xs): #enables parallel evaluation
|
|
148
|
+
values = self.fun(Xs)
|
|
149
|
+
self.evaluation_counter += len(Xs)
|
|
150
|
+
return np.array(values)
|
|
151
|
+
|
|
152
|
+
def closestFeasible(self, X):
|
|
153
|
+
if self.lower is None:
|
|
154
|
+
return X
|
|
155
|
+
else:
|
|
156
|
+
if self.normalize:
|
|
157
|
+
return np.clip(X, -1.0, 1.0)
|
|
158
|
+
else:
|
|
159
|
+
return np.clip(X, self.lower, self.upper)
|
|
160
|
+
|
|
161
|
+
def encode(self, X):
|
|
162
|
+
if self.normalize:
|
|
163
|
+
return (X - self.typx) / self.scale
|
|
164
|
+
else:
|
|
165
|
+
return X
|
|
166
|
+
|
|
167
|
+
def decode(self, X):
|
|
168
|
+
if self.normalize:
|
|
169
|
+
return (X * self.scale) + self.typx
|
|
170
|
+
else:
|
|
171
|
+
return X
|
|
172
|
+
|
|
173
|
+
def serial(fun):
|
|
174
|
+
"""Convert an objective function for serial execution for cmaes.minimize.
|
|
175
|
+
|
|
176
|
+
Parameters
|
|
177
|
+
----------
|
|
178
|
+
fun : objective function mapping a list of float arguments to a float value
|
|
179
|
+
|
|
180
|
+
Returns
|
|
181
|
+
-------
|
|
182
|
+
out : function
|
|
183
|
+
A function mapping a list of lists of float arguments to a list of float values
|
|
184
|
+
by applying the input function in a loop."""
|
|
185
|
+
|
|
186
|
+
return lambda xs : [_tryfun(fun, x) for x in xs]
|
|
187
|
+
|
|
188
|
+
def _func_serial(fun, num, pid, xs, ys):
|
|
189
|
+
for i in range(pid, len(xs), num):
|
|
190
|
+
ys[i] = _tryfun(fun, xs[i])
|
|
191
|
+
|
|
192
|
+
def _tryfun(fun, x):
|
|
193
|
+
try:
|
|
194
|
+
fit = fun(x)
|
|
195
|
+
return fit if math.isfinite(fit) else sys.float_info.max
|
|
196
|
+
except Exception:
|
|
197
|
+
return sys.float_info.max
|
|
198
|
+
|
|
199
|
+
class parallel(object):
|
|
200
|
+
"""Convert an objective function for parallel execution for cmaes.minimize.
|
|
201
|
+
|
|
202
|
+
Parameters
|
|
203
|
+
----------
|
|
204
|
+
fun : objective function mapping a list of float arguments to a float value.
|
|
205
|
+
|
|
206
|
+
represents a function mapping a list of lists of float arguments to a list of float values
|
|
207
|
+
by applying the input function using parallel processes. stop needs to be called to avoid
|
|
208
|
+
a resource leak"""
|
|
209
|
+
|
|
210
|
+
def __init__(self,
|
|
211
|
+
fun: Callable[[ArrayLike], float],
|
|
212
|
+
workers: Optional[int] = mp.cpu_count()):
|
|
213
|
+
self.evaluator = Evaluator(fun)
|
|
214
|
+
self.evaluator.start(workers)
|
|
215
|
+
|
|
216
|
+
def __call__(self, xs: ArrayLike) -> np.ndarray:
|
|
217
|
+
return eval_parallel(xs, self.evaluator)
|
|
218
|
+
|
|
219
|
+
def stop(self):
|
|
220
|
+
self.evaluator.stop()
|
|
221
|
+
|
|
222
|
+
class parallel_mo(object):
|
|
223
|
+
|
|
224
|
+
def __init__(self,
|
|
225
|
+
fun: Callable[[ArrayLike], ArrayLike],
|
|
226
|
+
nobj: int,
|
|
227
|
+
workers: Optional[int] = mp.cpu_count()):
|
|
228
|
+
self.nobj = nobj
|
|
229
|
+
self.evaluator = Evaluator(fun)
|
|
230
|
+
self.evaluator.start(workers)
|
|
231
|
+
|
|
232
|
+
def __call__(self, xs: ArrayLike) -> np.ndarray:
|
|
233
|
+
return eval_parallel_mo(xs, self.evaluator, self.nobj)
|
|
234
|
+
|
|
235
|
+
def stop(self):
|
|
236
|
+
self.evaluator.stop()
|
|
237
|
+
|
|
238
|
+
class callback(object):
|
|
239
|
+
|
|
240
|
+
def __init__(self, fun: Callable[[ArrayLike], float]):
|
|
241
|
+
self.fun = fun
|
|
242
|
+
|
|
243
|
+
def __call__(self, n: int, x: ArrayLike) -> float:
|
|
244
|
+
try:
|
|
245
|
+
fit = self.fun(np.fromiter((x[i] for i in range(n)), dtype=float))
|
|
246
|
+
return fit if math.isfinite(fit) else sys.float_info.max
|
|
247
|
+
except Exception as ex:
|
|
248
|
+
return sys.float_info.max
|
|
249
|
+
|
|
250
|
+
class callback_so(object):
|
|
251
|
+
|
|
252
|
+
def __init__(self,
|
|
253
|
+
fun: Callable[[ArrayLike], float],
|
|
254
|
+
dim: int,
|
|
255
|
+
is_terminate: Optional[Callable[[ArrayLike, float], bool]] = None):
|
|
256
|
+
self.fun = fun
|
|
257
|
+
self.dim = dim
|
|
258
|
+
self.nobj = 1
|
|
259
|
+
self.is_terminate = is_terminate
|
|
260
|
+
|
|
261
|
+
def __call__(self, dim, x, y):
|
|
262
|
+
try:
|
|
263
|
+
arrTypeX = ct.c_double*(self.dim)
|
|
264
|
+
xaddr = ct.addressof(x.contents)
|
|
265
|
+
xbuf = np.frombuffer(arrTypeX.from_address(xaddr))
|
|
266
|
+
arrTypeY = ct.c_double*(self.nobj)
|
|
267
|
+
yaddr = ct.addressof(y.contents)
|
|
268
|
+
ybuf = np.frombuffer(arrTypeY.from_address(yaddr))
|
|
269
|
+
fit = self.fun(xbuf)
|
|
270
|
+
ybuf[0] = fit if math.isfinite(fit) else sys.float_info.max
|
|
271
|
+
return False if self.is_terminate is None else self.is_terminate(xbuf, ybuf)
|
|
272
|
+
except Exception as ex:
|
|
273
|
+
print (ex)
|
|
274
|
+
return False
|
|
275
|
+
|
|
276
|
+
class callback_mo(object):
|
|
277
|
+
|
|
278
|
+
def __init__(self,
|
|
279
|
+
fun: Callable[[ArrayLike], ArrayLike],
|
|
280
|
+
dim: int,
|
|
281
|
+
nobj: int,
|
|
282
|
+
is_terminate: Optional[bool] = None):
|
|
283
|
+
self.fun = fun
|
|
284
|
+
self.dim = dim
|
|
285
|
+
self.nobj = nobj
|
|
286
|
+
self.is_terminate = is_terminate
|
|
287
|
+
|
|
288
|
+
def __call__(self, dim: int, x, y):
|
|
289
|
+
try:
|
|
290
|
+
arrTypeX = ct.c_double*(dim)
|
|
291
|
+
xaddr = ct.addressof(x.contents)
|
|
292
|
+
xbuf = np.frombuffer(arrTypeX.from_address(xaddr))
|
|
293
|
+
arrTypeY = ct.c_double*(self.nobj)
|
|
294
|
+
yaddr = ct.addressof(y.contents)
|
|
295
|
+
ybuf = np.frombuffer(arrTypeY.from_address(yaddr))
|
|
296
|
+
ybuf[:] = self.fun(xbuf)[:]
|
|
297
|
+
return False if self.is_terminate is None else self.is_terminate(xbuf, ybuf)
|
|
298
|
+
except Exception as ex:
|
|
299
|
+
print (ex)
|
|
300
|
+
return False
|
|
301
|
+
|
|
302
|
+
class callback_par(object):
|
|
303
|
+
|
|
304
|
+
def __init__(self,
|
|
305
|
+
fun: Callable[[ArrayLike], float],
|
|
306
|
+
parfun: Callable[[ArrayLike], ArrayLike]):
|
|
307
|
+
self.fun = fun
|
|
308
|
+
self.parfun = parfun
|
|
309
|
+
|
|
310
|
+
def __call__(self, popsize, n, xs_, ys_):
|
|
311
|
+
try:
|
|
312
|
+
arrType = ct.c_double*(popsize*n)
|
|
313
|
+
addr = ct.addressof(xs_.contents)
|
|
314
|
+
xall = np.frombuffer(arrType.from_address(addr))
|
|
315
|
+
|
|
316
|
+
if self.parfun is None:
|
|
317
|
+
for p in range(popsize):
|
|
318
|
+
ys_[p] = self.fun(xall[p*n : (p+1)*n])
|
|
319
|
+
else:
|
|
320
|
+
xs = []
|
|
321
|
+
for p in range(popsize):
|
|
322
|
+
x = xall[p*n : (p+1)*n]
|
|
323
|
+
xs.append(x)
|
|
324
|
+
ys = self.parfun(xs)
|
|
325
|
+
for p in range(popsize):
|
|
326
|
+
ys_[p] = ys[p]
|
|
327
|
+
except Exception as ex:
|
|
328
|
+
print (ex)
|
|
329
|
+
|
|
330
|
+
basepath = os.path.dirname(os.path.abspath(__file__))
|
|
331
|
+
|
|
332
|
+
try:
|
|
333
|
+
if sys.platform.startswith('linux'):
|
|
334
|
+
libcmalib = ct.cdll.LoadLibrary(basepath + '/lib/libacmalib.so')
|
|
335
|
+
elif 'mac' in sys.platform or 'darwin' in sys.platform:
|
|
336
|
+
libcmalib = ct.cdll.LoadLibrary(basepath + '/lib/libacmalib.dylib')
|
|
337
|
+
else:
|
|
338
|
+
os.environ['PATH'] = (basepath + '/lib') + os.pathsep + os.environ['PATH']
|
|
339
|
+
libcmalib = ct.cdll.LoadLibrary(basepath + '/lib/libacmalib.dll')
|
|
340
|
+
except Exception as ex:
|
|
341
|
+
libcmalib = None
|
|
342
|
+
|
|
343
|
+
mo_call_back_type = ct.CFUNCTYPE(ct.c_bool, ct.c_int, ct.POINTER(ct.c_double), ct.POINTER(ct.c_double))
|
|
344
|
+
|
|
345
|
+
call_back_type = ct.CFUNCTYPE(ct.c_double, ct.c_int, ct.POINTER(ct.c_double))
|
|
346
|
+
|
|
347
|
+
call_back_par = ct.CFUNCTYPE(None, ct.c_int, ct.c_int, \
|
|
348
|
+
ct.POINTER(ct.c_double), ct.POINTER(ct.c_double))
|
|
349
|
+
|
fcmaes/lib/libacmalib.dll
CHANGED
|
Binary file
|
|
Binary file
|
fcmaes/lib/libacmalib.so
CHANGED
|
Binary file
|
fcmaes/lib/libhbv.so
ADDED
|
Binary file
|
fcmaes/lib/liblrgv.so
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|