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/mode.py
CHANGED
|
@@ -2,14 +2,12 @@
|
|
|
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
|
""" Numpy based implementation of multi objective
|
|
7
|
-
Differential Evolution using either DE/rand/1
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
Then it works essentially like NSGA-II but instead of the tournament selection
|
|
11
|
-
the whole population is sorted and the best individuals survive. To do this
|
|
12
|
-
efficiently the crowd distance ordering is slightly inaccurate.
|
|
8
|
+
Differential Evolution using either the DE/rand/1 strategy
|
|
9
|
+
or a NSGA-II like population update (parameter 'nsga_update=True)'.
|
|
10
|
+
Then it works similar to NSGA-II.
|
|
13
11
|
|
|
14
12
|
Supports parallel fitness function evaluation.
|
|
15
13
|
|
|
@@ -31,37 +29,56 @@
|
|
|
31
29
|
parameter to parallelize objective function evaluation. The workers parameter is limited by the
|
|
32
30
|
population size.
|
|
33
31
|
|
|
32
|
+
The ints parameter is a boolean array indicating which parameters are discrete integer values. This
|
|
33
|
+
parameter was introduced after observing non optimal DE-results for the ESP2 benchmark problem:
|
|
34
|
+
https://github.com/AlgTUDelft/ExpensiveOptimBenchmark/blob/master/expensiveoptimbenchmark/problems/DockerCFDBenchmark.py
|
|
35
|
+
If defined it causes a "special treatment" for discrete variables: They are rounded to the next integer value and
|
|
36
|
+
there is an additional mutation to avoid getting stuck at local minima. This behavior is specified by the internal
|
|
37
|
+
function _modifier which can be overwritten by providing the optional modifier argument. If modifier is defined,
|
|
38
|
+
ints is ignored.
|
|
39
|
+
|
|
34
40
|
See https://github.com/dietmarwo/fast-cma-es/blob/master/tutorials/MODE.adoc for a detailed description.
|
|
35
41
|
"""
|
|
36
42
|
|
|
37
43
|
import numpy as np
|
|
38
|
-
import os
|
|
39
|
-
import time
|
|
44
|
+
import os, sys, time
|
|
40
45
|
import ctypes as ct
|
|
41
|
-
from numpy.random import Generator,
|
|
42
|
-
from
|
|
46
|
+
from numpy.random import Generator, PCG64DXSM
|
|
47
|
+
from scipy.optimize import Bounds
|
|
48
|
+
|
|
49
|
+
from fcmaes.evaluator import Evaluator, parallel_mo
|
|
43
50
|
from fcmaes import moretry
|
|
44
51
|
import multiprocessing as mp
|
|
45
|
-
from fcmaes.optimizer import
|
|
46
|
-
from fcmaes import
|
|
52
|
+
from fcmaes.optimizer import dtime
|
|
53
|
+
from fcmaes.retry import Shared2d
|
|
54
|
+
from loguru import logger
|
|
55
|
+
from typing import Optional, Callable, Tuple
|
|
56
|
+
from numpy.typing import ArrayLike
|
|
47
57
|
|
|
48
58
|
os.environ['MKL_DEBUG_CPU_TYPE'] = '5'
|
|
49
59
|
|
|
50
|
-
def minimize(mofun,
|
|
51
|
-
nobj,
|
|
52
|
-
ncon,
|
|
53
|
-
bounds,
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
60
|
+
def minimize(mofun: Callable[[ArrayLike], ArrayLike],
|
|
61
|
+
nobj: int,
|
|
62
|
+
ncon: int,
|
|
63
|
+
bounds: Bounds,
|
|
64
|
+
guess: Optional[np.ndarray] = None,
|
|
65
|
+
popsize: Optional[int] = 64,
|
|
66
|
+
max_evaluations: Optional[int] = 100000,
|
|
67
|
+
workers: Optional[int] = 1,
|
|
68
|
+
f: Optional[float] = 0.5,
|
|
69
|
+
cr: Optional[float] = 0.9,
|
|
70
|
+
pro_c: Optional[float] = 0.5,
|
|
71
|
+
dis_c: Optional[float] = 15.0,
|
|
72
|
+
pro_m: Optional[float] = 0.9,
|
|
73
|
+
dis_m: Optional[float] = 20.0,
|
|
74
|
+
nsga_update: Optional[bool] = True,
|
|
75
|
+
pareto_update: Optional[int] = 0,
|
|
76
|
+
ints: Optional[ArrayLike] = None,
|
|
77
|
+
modifier: Callable = None,
|
|
78
|
+
min_mutate: Optional[float] = 0.1,
|
|
79
|
+
max_mutate: Optional[float] = 0.5,
|
|
80
|
+
rg: Optional[Generator] = Generator(PCG64DXSM()),
|
|
81
|
+
store: Optional[store] = None) -> Tuple[np.ndarray, np.ndarray]:
|
|
65
82
|
|
|
66
83
|
"""Minimization of a multi objjective function of one or more variables using
|
|
67
84
|
Differential Evolution.
|
|
@@ -70,10 +87,8 @@ def minimize(mofun,
|
|
|
70
87
|
----------
|
|
71
88
|
mofun : callable
|
|
72
89
|
The objective function to be minimized.
|
|
73
|
-
``mofun(x
|
|
74
|
-
where ``x`` is an 1-D array with shape (n,)
|
|
75
|
-
is a tuple of the fixed parameters needed to completely
|
|
76
|
-
specify the function.
|
|
90
|
+
``mofun(x) -> ndarray(float)``
|
|
91
|
+
where ``x`` is an 1-D array with shape (n,)
|
|
77
92
|
nobj : int
|
|
78
93
|
number of objectives
|
|
79
94
|
ncon : int
|
|
@@ -84,33 +99,40 @@ def minimize(mofun,
|
|
|
84
99
|
1. Instance of the `scipy.Bounds` class.
|
|
85
100
|
2. Sequence of ``(min, max)`` pairs for each element in `x`. None
|
|
86
101
|
is used to specify no bound.
|
|
102
|
+
guess : ndarray, shape (popsize,dim) or Tuple
|
|
103
|
+
Initial guess.
|
|
87
104
|
popsize : int, optional
|
|
88
105
|
Population size.
|
|
89
106
|
max_evaluations : int, optional
|
|
90
|
-
Forced termination after ``max_evaluations`` function evaluations.
|
|
107
|
+
Forced termination after ``max_evaluations`` function evaluations.
|
|
91
108
|
workers : int or None, optional
|
|
92
|
-
|
|
109
|
+
workers > 1, function evaluation is performed in parallel for the whole population.
|
|
93
110
|
Useful for costly objective functions
|
|
94
111
|
f = float, optional
|
|
95
112
|
The mutation constant. In the literature this is also known as differential weight,
|
|
96
113
|
being denoted by F. Should be in the range [0, 2].
|
|
97
114
|
cr = float, optional
|
|
98
115
|
The recombination constant. Should be in the range [0, 1].
|
|
99
|
-
In the literature this is also known as the crossover probability.
|
|
116
|
+
In the literature this is also known as the crossover probability.
|
|
117
|
+
pro_c, dis_c, pro_m, dis_m = float, optional
|
|
118
|
+
NSGA population update parameters, usually leave at default.
|
|
100
119
|
nsga_update = boolean, optional
|
|
101
|
-
Use of NSGA-II or DE population update. Default is
|
|
120
|
+
Use of NSGA-II/SBX or DE population update. Default is True
|
|
102
121
|
pareto_update = float, optional
|
|
103
|
-
Only applied if nsga_update = False.
|
|
104
|
-
|
|
105
|
-
|
|
122
|
+
Only applied if nsga_update = False. Favor better solutions for sample generation. Default 0 -
|
|
123
|
+
use all population members with the same probability.
|
|
124
|
+
ints = list or array, optional
|
|
125
|
+
indicating which parameters are discrete integer values. If defined these parameters will be
|
|
126
|
+
rounded to the next integer and some additional mutation of discrete parameters are performed.
|
|
127
|
+
min_mutate = float, optional
|
|
128
|
+
Determines the minimal mutation rate for discrete integer parameters.
|
|
129
|
+
max_mutate = float, optional
|
|
130
|
+
Determines the maximal mutation rate for discrete integer parameters.
|
|
131
|
+
modifier = callable, optional
|
|
132
|
+
used to overwrite the default behaviour induced by ints. If defined, the ints parameter is
|
|
133
|
+
ignored. Modifies all generated x vectors.
|
|
106
134
|
rg = numpy.random.Generator, optional
|
|
107
135
|
Random generator for creating random guesses.
|
|
108
|
-
logger : logger, optional
|
|
109
|
-
logger for log output for tell_one, If None, logging
|
|
110
|
-
is switched off. Default is a logger which logs both to stdout and
|
|
111
|
-
appends to a file ``optimizer.log``.
|
|
112
|
-
plot_name : plot_name, optional
|
|
113
|
-
if defined the pareto front is plotted during the optimization to monitor progress
|
|
114
136
|
store : result store, optional
|
|
115
137
|
if defined the optimization results are added to the result store. For multi threaded execution.
|
|
116
138
|
use workers=1 if you call minimize from multiple threads
|
|
@@ -119,17 +141,19 @@ def minimize(mofun,
|
|
|
119
141
|
-------
|
|
120
142
|
x, y: list of argument vectors and corresponding value vectors of the optimization results. """
|
|
121
143
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
144
|
+
try:
|
|
145
|
+
mode = MODE(nobj, ncon, bounds, popsize,
|
|
146
|
+
f, cr, pro_c, dis_c, pro_m, dis_m, nsga_update, pareto_update, rg, ints, min_mutate, max_mutate, modifier)
|
|
147
|
+
mode.set_guess(guess, mofun, rg)
|
|
148
|
+
if workers <= 1:
|
|
149
|
+
x, y, = mode.minimize_ser(mofun, max_evaluations)
|
|
150
|
+
else:
|
|
151
|
+
x, y = mode.minimize_par(mofun, max_evaluations, workers)
|
|
129
152
|
if not store is None:
|
|
130
153
|
store.add_results(x, y)
|
|
131
154
|
return x, y
|
|
132
155
|
except Exception as ex:
|
|
156
|
+
print(str(ex))
|
|
133
157
|
return None, None
|
|
134
158
|
|
|
135
159
|
|
|
@@ -144,7 +168,8 @@ class store():
|
|
|
144
168
|
nobj : int
|
|
145
169
|
number of objectives
|
|
146
170
|
capacity : int, optional
|
|
147
|
-
capacity of the
|
|
171
|
+
capacity of the store collecting all solutions. If full, its content is replaced by its
|
|
172
|
+
pareto front.
|
|
148
173
|
"""
|
|
149
174
|
|
|
150
175
|
def __init__(self, dim, nobj, capacity = mp.cpu_count()*512):
|
|
@@ -152,58 +177,83 @@ class store():
|
|
|
152
177
|
self.nobj = nobj
|
|
153
178
|
self.capacity = capacity
|
|
154
179
|
self.add_mutex = mp.Lock()
|
|
155
|
-
self.xs =
|
|
156
|
-
self.ys =
|
|
180
|
+
self.xs = Shared2d(np.empty((self.capacity, self.dim), dtype = np.float64))
|
|
181
|
+
self.ys = Shared2d(np.empty((self.capacity, self.nobj), dtype = np.float64))
|
|
182
|
+
self.create_views()
|
|
157
183
|
self.num_stored = mp.RawValue(ct.c_int, 0)
|
|
158
184
|
self.num_added = mp.RawValue(ct.c_int, 0)
|
|
159
185
|
|
|
186
|
+
def create_views(self): # needs to be called in the target process
|
|
187
|
+
self.xs_view = self.xs.view()
|
|
188
|
+
self.ys_view = self.ys.view()
|
|
189
|
+
|
|
190
|
+
def get_xs(self) -> np.ndarray:
|
|
191
|
+
return self.xs.view()
|
|
192
|
+
|
|
193
|
+
def get_ys(self) -> np.ndarray:
|
|
194
|
+
return self.ys.view()
|
|
195
|
+
|
|
196
|
+
def add_result(self, x, y):
|
|
197
|
+
with self.add_mutex:
|
|
198
|
+
self.num_added.value += 1
|
|
199
|
+
i = self.num_stored.value
|
|
200
|
+
if i < self.capacity:
|
|
201
|
+
self.xs_view[i] = x
|
|
202
|
+
self.ys_view[i] = y
|
|
203
|
+
self.num_stored.value = i + 1
|
|
204
|
+
|
|
160
205
|
def add_results(self, xs, ys):
|
|
161
206
|
with self.add_mutex:
|
|
162
207
|
self.num_added.value += 1
|
|
163
208
|
i = self.num_stored.value
|
|
164
209
|
for j in range(len(xs)):
|
|
165
|
-
if i < self.capacity:
|
|
166
|
-
self.
|
|
167
|
-
self.
|
|
210
|
+
if i < self.capacity:
|
|
211
|
+
self.xs_view[i] = xs[j]
|
|
212
|
+
self.ys_view[i] = ys[j][:self.nobj]
|
|
168
213
|
i += 1
|
|
169
|
-
else:
|
|
170
|
-
|
|
171
|
-
i =
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
self.set_y(i, yf[k])
|
|
175
|
-
i += 1
|
|
176
|
-
if i == self.capacity:
|
|
177
|
-
break
|
|
214
|
+
else:
|
|
215
|
+
self.get_front(update=True)
|
|
216
|
+
i = self.num_stored.value
|
|
217
|
+
if i > 0.9*self.capacity: # give up
|
|
218
|
+
return
|
|
178
219
|
self.num_stored.value = i
|
|
179
220
|
|
|
180
|
-
def get_front(self):
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
return
|
|
191
|
-
|
|
192
|
-
def set_x(self, i, x):
|
|
193
|
-
self.xs[i*self.dim:(i+1)*self.dim] = x[:]
|
|
194
|
-
|
|
195
|
-
def get_y(self, i):
|
|
196
|
-
return self.ys[i*self.nobj:(i+1)*self.nobj]
|
|
197
|
-
|
|
198
|
-
def set_y(self, i, y):
|
|
199
|
-
self.ys[i*self.nobj:(i+1)*self.nobj] = y[:]
|
|
221
|
+
def get_front(self, update=False):
|
|
222
|
+
stored = self.num_stored.value
|
|
223
|
+
xs = self.xs_view[:stored]
|
|
224
|
+
ys = self.ys_view[:stored]
|
|
225
|
+
xf, yf = moretry.pareto(xs, ys)
|
|
226
|
+
if update:
|
|
227
|
+
n = len(yf)
|
|
228
|
+
self.xs_view[:n] = xf
|
|
229
|
+
self.ys_view[:n] = yf
|
|
230
|
+
self.num_stored.value = n
|
|
231
|
+
return xf, yf
|
|
200
232
|
|
|
233
|
+
def get_content(self):
|
|
234
|
+
stored = self.num_stored.value
|
|
235
|
+
return self.xs_view[:stored], self.ys_view[:stored]
|
|
201
236
|
|
|
202
237
|
class MODE(object):
|
|
203
238
|
|
|
204
|
-
def __init__(self,
|
|
205
|
-
|
|
206
|
-
|
|
239
|
+
def __init__(self,
|
|
240
|
+
nobj: int,
|
|
241
|
+
ncon: int,
|
|
242
|
+
bounds: Bounds,
|
|
243
|
+
popsize: Optional[int] = 64,
|
|
244
|
+
F: Optional[float] = 0.5,
|
|
245
|
+
Cr: Optional[float] = 0.9,
|
|
246
|
+
pro_c: Optional[float] = 0.5,
|
|
247
|
+
dis_c: Optional[float] = 15.0,
|
|
248
|
+
pro_m: Optional[float] = 0.9,
|
|
249
|
+
dis_m: Optional[float] = 20.0,
|
|
250
|
+
nsga_update: Optional[bool] = True,
|
|
251
|
+
pareto_update: Optional[int] = 0,
|
|
252
|
+
rg: Optional[Generator] = Generator(PCG64DXSM()),
|
|
253
|
+
ints: Optional[ArrayLike] = None,
|
|
254
|
+
min_mutate: Optional[float] = 0.1,
|
|
255
|
+
max_mutate: Optional[float] = 0.5,
|
|
256
|
+
modifier: Callable = None):
|
|
207
257
|
self.nobj = nobj
|
|
208
258
|
self.ncon = ncon
|
|
209
259
|
self.dim, self.lower, self.upper = _check_bounds(bounds, None)
|
|
@@ -212,10 +262,13 @@ class MODE(object):
|
|
|
212
262
|
if popsize % 2 == 1 and nsga_update: # nsga update requires even popsize
|
|
213
263
|
popsize += 1
|
|
214
264
|
self.popsize = popsize
|
|
215
|
-
self.workers = workers
|
|
216
265
|
self.rg = rg
|
|
217
266
|
self.F0 = F
|
|
218
267
|
self.Cr0 = Cr
|
|
268
|
+
self.pro_c = pro_c
|
|
269
|
+
self.dis_c = dis_c
|
|
270
|
+
self.pro_m = pro_m
|
|
271
|
+
self.dis_m = dis_m
|
|
219
272
|
self.nsga_update = nsga_update
|
|
220
273
|
self.pareto_update = pareto_update
|
|
221
274
|
self.stop = 0
|
|
@@ -223,154 +276,103 @@ class MODE(object):
|
|
|
223
276
|
self.evals = 0
|
|
224
277
|
self.mutex = mp.Lock()
|
|
225
278
|
self.p = 0
|
|
226
|
-
|
|
279
|
+
# nsga update doesn't support mixed integer
|
|
280
|
+
self.ints = None if (ints is None or nsga_update) else np.array(ints)
|
|
281
|
+
self.min_mutate = min_mutate
|
|
282
|
+
self.max_mutate = max_mutate
|
|
283
|
+
# use default variable modifier for int variables if modifier is None
|
|
284
|
+
if modifier is None and not ints is None:
|
|
285
|
+
self.lower = self.lower.astype(float)
|
|
286
|
+
self.upper = self.upper.astype(float)
|
|
287
|
+
self.modifier = self._modifier
|
|
288
|
+
else:
|
|
289
|
+
self.modifier = modifier
|
|
227
290
|
self._init()
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
p : int population index
|
|
255
|
-
y : function value
|
|
256
|
-
x : dim sized argument list
|
|
257
|
-
|
|
258
|
-
Returns
|
|
259
|
-
-------
|
|
260
|
-
stop : int termination criteria, if != 0 loop should stop."""
|
|
261
|
-
|
|
262
|
-
with self.mutex:
|
|
263
|
-
for dp in range(len(self.done)):
|
|
264
|
-
if not self.done[dp]:
|
|
265
|
-
break
|
|
266
|
-
self.nx[dp] = x
|
|
267
|
-
self.ny[dp] = y
|
|
268
|
-
self.done[dp] = True
|
|
269
|
-
if sum(self.done) >= self.popsize:
|
|
270
|
-
done_p = np.arange(len(self.ny))
|
|
271
|
-
done_p = done_p[self.done]
|
|
272
|
-
p = self.popsize
|
|
273
|
-
for dp in done_p:
|
|
274
|
-
self.x[p] = self.nx[dp]
|
|
275
|
-
self.y[p] = self.ny[dp]
|
|
276
|
-
self.done[dp] = False
|
|
277
|
-
if p >= len(self.y):
|
|
278
|
-
break
|
|
279
|
-
p += 1
|
|
280
|
-
self.pop_update()
|
|
281
|
-
|
|
282
|
-
if hasattr(self, 'logger'):
|
|
283
|
-
self.n_evals.value += 1
|
|
284
|
-
if self.n_evals.value % 100000 == 99999:
|
|
285
|
-
t = time.perf_counter() - self.time_0
|
|
286
|
-
c = self.n_evals.value
|
|
287
|
-
message = '"c/t={0:.2f} c={1:d} t={2:.2f} y={3!s} x={4!s}'.format(
|
|
288
|
-
c/t, c, t, str(list(y)), str(list(x)))
|
|
289
|
-
self.logger.info(message)
|
|
290
|
-
if hasattr(self, "plot_name") and not self.plot_name is None:
|
|
291
|
-
name = self.plot_name + ' ' + str(self.n_evals.value)
|
|
292
|
-
np.savez_compressed(name, xs=self.x, ys=self.y)
|
|
293
|
-
moretry.plot(name, self.ncon, self.x, self.y)
|
|
294
|
-
|
|
295
|
-
return self.stop
|
|
296
|
-
|
|
291
|
+
|
|
292
|
+
def set_guess(self, guess, mofun, rg = None):
|
|
293
|
+
if not guess is None:
|
|
294
|
+
if isinstance(guess, np.ndarray):
|
|
295
|
+
ys = np.array([mofun(x) for x in guess])
|
|
296
|
+
else:
|
|
297
|
+
guess, ys = guess
|
|
298
|
+
if rg is None:
|
|
299
|
+
rg = Generator(PCG64DXSM())
|
|
300
|
+
choice = rg.choice(len(ys), self.popsize,
|
|
301
|
+
replace = (len(ys) < self.popsize))
|
|
302
|
+
self.tell(ys[choice], guess[choice])
|
|
303
|
+
|
|
304
|
+
def ask(self) -> np.ndarray:
|
|
305
|
+
for p in range(self.popsize):
|
|
306
|
+
self.x[p + self.popsize] = self._next_x(p)
|
|
307
|
+
return self.x[self.popsize:]
|
|
308
|
+
|
|
309
|
+
def tell(self, ys: np.ndarray, xs: Optional[np.ndarray] = None):
|
|
310
|
+
if not xs is None:
|
|
311
|
+
for p in range(self.popsize):
|
|
312
|
+
self.x[p + self.popsize] = xs[p]
|
|
313
|
+
for p in range(self.popsize):
|
|
314
|
+
self.y[p + self.popsize] = ys[p]
|
|
315
|
+
self.pop_update()
|
|
316
|
+
|
|
297
317
|
def _init(self):
|
|
298
318
|
self.x = np.empty((2*self.popsize, self.dim))
|
|
299
319
|
self.y = np.empty((2*self.popsize, self.nobj + self.ncon))
|
|
300
320
|
for i in range(self.popsize):
|
|
301
321
|
self.x[i] = self._sample()
|
|
302
322
|
self.y[i] = np.array([1E99]*(self.nobj + self.ncon))
|
|
303
|
-
|
|
304
|
-
next_size = 2*(max(self.workers, self.popsize))
|
|
305
|
-
self.done = np.zeros(next_size, dtype=bool)
|
|
306
|
-
self.nx = np.empty((next_size, self.dim))
|
|
307
|
-
self.ny = np.empty((next_size, self.nobj + self.ncon))
|
|
308
323
|
self.vx = self.x.copy()
|
|
309
324
|
self.vp = 0
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
self.fun = fun
|
|
313
|
-
self.max_evals = max_evals
|
|
314
|
-
self.iterations = 0
|
|
315
|
-
self.evals = 0
|
|
316
|
-
while self.evals < self.max_evals:
|
|
317
|
-
for p in range(self.popsize):
|
|
318
|
-
x = self._next_x(p)
|
|
319
|
-
self.y[self.popsize + p] = self.fun(x)
|
|
320
|
-
self.x[self.popsize + p] = x
|
|
321
|
-
self.evals += 1
|
|
322
|
-
self.pop_update()
|
|
323
|
-
x, y = filter(self.x, self.y)
|
|
324
|
-
return x, y, self.evals, self.iterations, self.stop
|
|
325
|
+
self.ycon = None
|
|
326
|
+
self.eps = 0
|
|
325
327
|
|
|
326
|
-
def
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
p, x = self.ask()
|
|
337
|
-
evaluator.pipe[0].send((self.evals, x))
|
|
338
|
-
evals_x[self.evals] = p, x # store x
|
|
339
|
-
self.evals += 1
|
|
340
|
-
|
|
341
|
-
while True: # read from pipe, tell de and create new x
|
|
342
|
-
evals, y = evaluator.pipe[0].recv()
|
|
343
|
-
p, x = evals_x[evals] # retrieve evaluated x
|
|
344
|
-
del evals_x[evals]
|
|
345
|
-
self.tell(p, y, x) # tell evaluated x
|
|
346
|
-
if self.stop != 0 or self.evals >= self.max_evals:
|
|
347
|
-
break # shutdown worker if stop criteria met
|
|
348
|
-
|
|
349
|
-
p, x = self.ask() # create new x
|
|
350
|
-
evaluator.pipe[0].send((self.evals, x))
|
|
351
|
-
evals_x[self.evals] = p, x # store x
|
|
352
|
-
self.evals += 1
|
|
353
|
-
|
|
354
|
-
evaluator.stop()
|
|
355
|
-
x, y = filter(self.x, self.y)
|
|
356
|
-
return x, y, self.evals, self.iterations, self.stop
|
|
328
|
+
def minimize_ser(self,
|
|
329
|
+
fun: Callable[[ArrayLike], ArrayLike],
|
|
330
|
+
max_evaluations: Optional[int] = 100000) -> Tuple[np.ndarray, np.ndarray]:
|
|
331
|
+
evals = 0
|
|
332
|
+
while evals < max_evaluations:
|
|
333
|
+
xs = self.ask()
|
|
334
|
+
ys = np.array([fun(x) for x in xs])
|
|
335
|
+
self.tell(ys)
|
|
336
|
+
evals += self.popsize
|
|
337
|
+
return xs, ys
|
|
357
338
|
|
|
339
|
+
|
|
340
|
+
def minimize_par(self,
|
|
341
|
+
fun: Callable[[ArrayLike], ArrayLike],
|
|
342
|
+
max_evaluations: Optional[int] = 100000,
|
|
343
|
+
workers: Optional[int] = mp.cpu_count()) -> Tuple[np.ndarray, np.ndarray]:
|
|
344
|
+
fit = parallel_mo(fun, self.nobj + self.ncon, workers)
|
|
345
|
+
evals = 0
|
|
346
|
+
while evals < max_evaluations:
|
|
347
|
+
xs = self.ask()
|
|
348
|
+
ys = fit(xs)
|
|
349
|
+
self.tell(ys)
|
|
350
|
+
evals += self.popsize
|
|
351
|
+
fit.stop()
|
|
352
|
+
return xs, ys
|
|
353
|
+
|
|
358
354
|
def pop_update(self):
|
|
359
|
-
|
|
355
|
+
y0 = self.y
|
|
356
|
+
x0 = self.x
|
|
357
|
+
if self.nobj == 1:
|
|
358
|
+
yi = np.flip(np.argsort(self.y[:,0]))
|
|
359
|
+
y0 = self.y[yi]
|
|
360
|
+
x0 = self.x[yi]
|
|
361
|
+
domination, self.ycon, self.eps = pareto_domination(y0, self.nobj, self.ncon, self.ycon, self.eps)
|
|
360
362
|
x = []
|
|
361
363
|
y = []
|
|
362
364
|
maxdom = int(max(domination))
|
|
363
365
|
for dom in range(maxdom, -1, -1):
|
|
364
366
|
domlevel = [p for p in range(len(domination)) if domination[p] == dom]
|
|
365
|
-
if
|
|
366
|
-
|
|
367
|
+
if len(domlevel) == 0:
|
|
368
|
+
continue
|
|
367
369
|
if len(x) + len(domlevel) <= self.popsize:
|
|
368
370
|
# whole level fits
|
|
369
|
-
x = [*x, *
|
|
370
|
-
y = [*y, *
|
|
371
|
+
x = [*x, *x0[domlevel]]
|
|
372
|
+
y = [*y, *y0[domlevel]]
|
|
371
373
|
else: # sort for crowding
|
|
372
|
-
nx =
|
|
373
|
-
ny =
|
|
374
|
+
nx = x0[domlevel]
|
|
375
|
+
ny = y0[domlevel]
|
|
374
376
|
si = [0]
|
|
375
377
|
if len(ny) > 1:
|
|
376
378
|
cd = crowd_dist(ny)
|
|
@@ -384,7 +386,8 @@ class MODE(object):
|
|
|
384
386
|
self.x[:self.popsize] = x[:self.popsize]
|
|
385
387
|
self.y[:self.popsize] = y[:self.popsize]
|
|
386
388
|
if self.nsga_update:
|
|
387
|
-
self.vx = variation(self.x[:self.popsize], self.lower, self.upper, self.rg
|
|
389
|
+
self.vx = variation(self.x[:self.popsize], self.lower, self.upper, self.rg,
|
|
390
|
+
pro_c = self.pro_c, dis_c = self.dis_c, pro_m = self.pro_m, dis_m = self.dis_m)
|
|
388
391
|
|
|
389
392
|
def _next_x(self, p):
|
|
390
393
|
if self.nsga_update: # use NSGA-II update strategy.
|
|
@@ -397,17 +400,15 @@ class MODE(object):
|
|
|
397
400
|
self.Cr = 0.5*self.Cr0 if self.iterations % 2 == 0 else self.Cr0
|
|
398
401
|
self.F = 0.5*self.F0 if self.iterations % 2 == 0 else self.F0
|
|
399
402
|
while True:
|
|
400
|
-
if self.
|
|
401
|
-
# sample from pareto front
|
|
402
|
-
rb = self.rg.integers(0, len(self.best_p))
|
|
403
|
-
rb = self.best_p[rb]
|
|
403
|
+
if self.pareto_update > 0: # sample elite solutions
|
|
404
404
|
r1, r2 = self.rg.integers(0, self.popsize, 2)
|
|
405
|
+
rb = int(self.popsize * (self.rg.random() ** (1.0 + self.pareto_update)))
|
|
405
406
|
else:
|
|
406
407
|
# sample from whole population
|
|
407
408
|
r1, r2, rb = self.rg.integers(0, self.popsize, 3)
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
409
|
+
if r1 != p and r1 != rb and r1 != r2 and r2 != rb \
|
|
410
|
+
and r2 != p and rb != p:
|
|
411
|
+
break
|
|
411
412
|
xp = self.x[p]
|
|
412
413
|
xb = self.x[rb]
|
|
413
414
|
x1 = self.x[r1]
|
|
@@ -416,8 +417,10 @@ class MODE(object):
|
|
|
416
417
|
r = self.rg.integers(0, self.dim)
|
|
417
418
|
tr = np.array(
|
|
418
419
|
[i != r and self.rg.random() > self.Cr for i in range(self.dim)])
|
|
419
|
-
x[tr] = xp[tr]
|
|
420
|
-
|
|
420
|
+
x[tr] = xp[tr]
|
|
421
|
+
if not self.modifier is None:
|
|
422
|
+
x = self.modifier(x)
|
|
423
|
+
return x.clip(self.lower, self.upper)
|
|
421
424
|
|
|
422
425
|
def _sample(self):
|
|
423
426
|
if self.upper is None:
|
|
@@ -429,7 +432,24 @@ class MODE(object):
|
|
|
429
432
|
if self.upper is None:
|
|
430
433
|
return x
|
|
431
434
|
else:
|
|
432
|
-
return np.
|
|
435
|
+
return np.clip(x, self.lower, self.upper)
|
|
436
|
+
|
|
437
|
+
# default modifier for integer variables
|
|
438
|
+
def _modifier(self, x):
|
|
439
|
+
x_ints = x[self.ints]
|
|
440
|
+
n_ints = len(self.ints)
|
|
441
|
+
lb = self.lower[self.ints]
|
|
442
|
+
ub = self.upper[self.ints]
|
|
443
|
+
to_mutate = self.rg.uniform(self.min_mutate, self.max_mutate)
|
|
444
|
+
# mututate some integer variables
|
|
445
|
+
x_ints = np.array([x if self.rg.random() > to_mutate/n_ints else
|
|
446
|
+
int(self.rg.uniform(lb[i], ub[i]))
|
|
447
|
+
for i, x in enumerate(x_ints)])
|
|
448
|
+
return x
|
|
449
|
+
|
|
450
|
+
def _is_dominated(self, y, p):
|
|
451
|
+
return np.all(np.fromiter((y[i] >= self.y[p, i] for i in range(len(y))), dtype=bool))
|
|
452
|
+
|
|
433
453
|
|
|
434
454
|
def _check_bounds(bounds, dim):
|
|
435
455
|
if bounds is None and dim is None:
|
|
@@ -438,8 +458,8 @@ def _check_bounds(bounds, dim):
|
|
|
438
458
|
return dim, None, None
|
|
439
459
|
else:
|
|
440
460
|
return len(bounds.ub), np.asarray(bounds.lb), np.asarray(bounds.ub)
|
|
441
|
-
|
|
442
|
-
def
|
|
461
|
+
|
|
462
|
+
def _filter(x, y):
|
|
443
463
|
ym = np.amax(y,axis=1)
|
|
444
464
|
sorted = np.argsort(ym)
|
|
445
465
|
x = x[sorted]
|
|
@@ -457,47 +477,79 @@ def objranks(objs):
|
|
|
457
477
|
rank = np.sum(rank, axis=1)
|
|
458
478
|
return rank
|
|
459
479
|
|
|
460
|
-
def ranks(cons):
|
|
461
|
-
feasible = np.less_equal(cons, 0)
|
|
480
|
+
def ranks(cons, feasible, eps):
|
|
462
481
|
ci = cons.argsort(axis=0)
|
|
463
482
|
rank = np.empty_like(ci)
|
|
464
483
|
ar = np.arange(cons.shape[0])
|
|
465
484
|
for i in range(cons.shape[1]):
|
|
466
485
|
rank[ci[:,i], i] = ar
|
|
467
486
|
rank[feasible] = 0
|
|
468
|
-
alpha = np.sum(np.greater(cons,
|
|
487
|
+
alpha = np.sum(np.greater(cons, eps), axis=1) / cons.shape[1] # violations
|
|
469
488
|
alpha = np.tile(alpha, (cons.shape[1],1)).T
|
|
470
489
|
rank = rank*alpha
|
|
471
490
|
rank = np.sum(rank, axis=1)
|
|
472
491
|
return rank
|
|
473
|
-
|
|
474
|
-
def
|
|
492
|
+
|
|
493
|
+
def get_valid(xs, ys, nobj):
|
|
494
|
+
valid = (ys.T[nobj:].T <= 0).all(axis=1)
|
|
495
|
+
return xs[valid], ys[valid]
|
|
496
|
+
|
|
497
|
+
def pareto_sort(x0, y0, nobj, ncon):
|
|
498
|
+
domination, _, _ = pareto_domination(y0, nobj, ncon)
|
|
499
|
+
x = []
|
|
500
|
+
y = []
|
|
501
|
+
maxdom = int(max(domination))
|
|
502
|
+
for dom in range(maxdom, -1, -1):
|
|
503
|
+
domlevel = [p for p in range(len(domination)) if domination[p] == dom]
|
|
504
|
+
if len(domlevel) == 0:
|
|
505
|
+
continue
|
|
506
|
+
nx = x0[domlevel]
|
|
507
|
+
ny = y0[domlevel]
|
|
508
|
+
si = [0]
|
|
509
|
+
if len(ny) > 1:
|
|
510
|
+
cd = crowd_dist(ny)
|
|
511
|
+
si = np.flip(np.argsort(cd))
|
|
512
|
+
for p in si:
|
|
513
|
+
x.append(nx[p])
|
|
514
|
+
y.append(ny[p])
|
|
515
|
+
return np.array(x), np.array(y)
|
|
516
|
+
|
|
517
|
+
def pareto_domination(ys, nobj, ncon, last_ycon = None, last_eps = 0):
|
|
475
518
|
if ncon == 0:
|
|
476
|
-
return pareto_levels(ys)
|
|
519
|
+
return pareto_levels(ys), None, 0
|
|
477
520
|
else:
|
|
521
|
+
eps = 0 # adjust tolerance to small constraint violations
|
|
522
|
+
if not last_ycon is None and np.amax(last_ycon) < 1E90:
|
|
523
|
+
eps = 0.5*(last_eps + 0.5*np.mean(last_ycon, axis=0))
|
|
524
|
+
if np.amax(eps) < 1E-8: # ignore small eps
|
|
525
|
+
eps = 0
|
|
526
|
+
|
|
478
527
|
yobj = np.array([y[:nobj] for y in ys])
|
|
479
|
-
ycon = np.array([np.maximum(y[-ncon:], 0) for y in ys])
|
|
480
|
-
|
|
481
|
-
feasible = np.less_equal(
|
|
528
|
+
ycon = np.array([np.maximum(y[-ncon:], 0) for y in ys])
|
|
529
|
+
popn = len(ys)
|
|
530
|
+
feasible = np.less_equal(ycon, eps).all(axis=1)
|
|
531
|
+
|
|
532
|
+
csum = ranks(ycon, feasible, eps)
|
|
482
533
|
if sum(feasible) > 0:
|
|
483
534
|
csum += objranks(yobj)
|
|
535
|
+
|
|
484
536
|
ci = np.argsort(csum)
|
|
485
|
-
popn = len(ys)
|
|
486
537
|
domination = np.zeros(popn)
|
|
487
538
|
# first pareto front of feasible solutions
|
|
488
|
-
cy = np.
|
|
539
|
+
cy = np.fromiter((i for i in ci if feasible[i]), dtype=int)
|
|
489
540
|
if len(cy) > 0:
|
|
490
541
|
ypar = pareto_levels(yobj[cy])
|
|
491
|
-
domination[cy]
|
|
542
|
+
domination[cy] = ypar
|
|
543
|
+
|
|
492
544
|
# then constraint violations
|
|
493
|
-
ci = np.
|
|
545
|
+
ci = np.fromiter((i for i in ci if not feasible[i]), dtype=int)
|
|
494
546
|
if len(ci) > 0:
|
|
495
|
-
|
|
496
|
-
cdom = np.arange(maxcdom, 0, -1)
|
|
547
|
+
cdom = np.arange(len(ci), 0, -1)
|
|
497
548
|
domination[ci] += cdom
|
|
498
549
|
if len(cy) > 0: # priorize feasible solutions
|
|
499
|
-
domination[cy] +=
|
|
500
|
-
|
|
550
|
+
domination[cy] += len(ci) + 1
|
|
551
|
+
|
|
552
|
+
return domination, ycon, eps
|
|
501
553
|
|
|
502
554
|
def pareto_levels(ys):
|
|
503
555
|
popn = len(ys)
|
|
@@ -515,7 +567,7 @@ def pareto_levels(ys):
|
|
|
515
567
|
|
|
516
568
|
def crowd_dist(y): # crowd distance for 1st objective
|
|
517
569
|
n = len(y)
|
|
518
|
-
y0 = np.
|
|
570
|
+
y0 = np.fromiter((yi[0] for yi in y), dtype=float)
|
|
519
571
|
si = np.argsort(y0) # sort 1st objective
|
|
520
572
|
y0_s = y0[si] # sorted
|
|
521
573
|
d = y0_s[1:n] - y0_s[0:n-1] # neighbor distance
|
|
@@ -533,6 +585,8 @@ def crowd_dist(y): # crowd distance for 1st objective
|
|
|
533
585
|
# derived from https://github.com/ChengHust/NSGA-II/blob/master/GLOBAL.py
|
|
534
586
|
def variation(pop, lower, upper, rg, pro_c = 1, dis_c = 20, pro_m = 1, dis_m = 20):
|
|
535
587
|
"""Generate offspring individuals"""
|
|
588
|
+
dis_c *= 0.5 + 0.5*rg.random() # vary spread factors randomly
|
|
589
|
+
dis_m *= 0.5 + 0.5*rg.random()
|
|
536
590
|
pop = pop[:(len(pop) // 2) * 2][:]
|
|
537
591
|
(n, d) = np.shape(pop)
|
|
538
592
|
parent_1 = pop[:n // 2, :]
|
|
@@ -545,8 +599,9 @@ def variation(pop, lower, upper, rg, pro_c = 1, dis_c = 20, pro_m = 1, dis_m = 2
|
|
|
545
599
|
beta[rg.random((n // 2, d)) < 0.5] = 1
|
|
546
600
|
if pro_c < 1.0:
|
|
547
601
|
beta[np.tile(rg.random((n // 2, 1)) > pro_c, (1, d))] = 1
|
|
548
|
-
|
|
549
|
-
|
|
602
|
+
parent_mean = (parent_1 + parent_2) * 0.5
|
|
603
|
+
parent_diff = (parent_1 - parent_2) * 0.5
|
|
604
|
+
offspring = np.vstack((parent_mean + beta * parent_diff, parent_mean - beta * parent_diff))
|
|
550
605
|
site = rg.random((n, d)) < pro_m / d
|
|
551
606
|
mu = rg.random((n, d))
|
|
552
607
|
temp = site & (mu <= 0.5)
|
|
@@ -561,16 +616,104 @@ def variation(pop, lower, upper, rg, pro_c = 1, dis_c = 20, pro_m = 1, dis_m = 2
|
|
|
561
616
|
(1. - np.power(
|
|
562
617
|
2. * (1. - mu[temp]) + 2. * (mu[temp] - 0.5) * np.power(1. - norm, dis_m + 1.),
|
|
563
618
|
1. / (dis_m + 1.)))
|
|
564
|
-
offspring = np.
|
|
619
|
+
offspring = np.clip(offspring, lower, upper)
|
|
565
620
|
return offspring
|
|
566
621
|
|
|
567
|
-
def
|
|
568
|
-
|
|
622
|
+
def feasible(xs, ys, ncon, eps = 1E-2):
|
|
623
|
+
if ncon > 0: # select feasible
|
|
624
|
+
ycon = np.array([np.maximum(y[-ncon:], 0) for y in ys])
|
|
625
|
+
con = np.sum(ycon, axis=1)
|
|
626
|
+
nobj = len(ys[0]) - ncon
|
|
627
|
+
feasible = np.fromiter((i for i in range(len(ys)) if con[i] < eps), dtype=int)
|
|
628
|
+
if len(feasible) > 0:
|
|
629
|
+
xs, ys = xs[feasible], np.array([y[:nobj] for y in ys[feasible]])
|
|
630
|
+
else:
|
|
631
|
+
print("no feasible")
|
|
632
|
+
return xs, ys
|
|
633
|
+
|
|
634
|
+
def is_feasible(y, nobj, eps = 1E-2):
|
|
635
|
+
ncon = len(y) - nobj
|
|
636
|
+
if ncon == 0:
|
|
637
|
+
return True
|
|
638
|
+
else:
|
|
639
|
+
c = np.sum(np.maximum(y[-ncon:], 0))
|
|
640
|
+
return c < eps
|
|
641
|
+
|
|
642
|
+
class wrapper(object):
|
|
643
|
+
"""thread safe wrapper for objective function monitoring evaluation count and optimization result."""
|
|
644
|
+
|
|
645
|
+
def __init__(self,
|
|
646
|
+
fun: Callable[[ArrayLike], ArrayLike],
|
|
647
|
+
nobj: int,
|
|
648
|
+
store: Optional[store] = None,
|
|
649
|
+
interval: Optional[int] = 100000,
|
|
650
|
+
plot: Optional[bool] = False,
|
|
651
|
+
name: Optional[str] = None):
|
|
652
|
+
self.fun = fun
|
|
653
|
+
self.nobj = nobj
|
|
654
|
+
self.n_evals = mp.RawValue(ct.c_long, 0)
|
|
655
|
+
self.time_0 = time.perf_counter()
|
|
656
|
+
self.best_y = mp.RawArray(ct.c_double, nobj)
|
|
657
|
+
for i in range(nobj):
|
|
658
|
+
self.best_y[i] = sys.float_info.max
|
|
659
|
+
self.store = store
|
|
660
|
+
self.interval = interval
|
|
661
|
+
self.plot = plot
|
|
662
|
+
self.name = name
|
|
663
|
+
self.lock = mp.Lock()
|
|
664
|
+
|
|
665
|
+
def __call__(self, x: ArrayLike) -> np.ndarray:
|
|
666
|
+
try:
|
|
667
|
+
y = self.fun(x)
|
|
668
|
+
with self.lock:
|
|
669
|
+
self.n_evals.value += 1
|
|
670
|
+
if not self.store is None and is_feasible(y, self.nobj):
|
|
671
|
+
self.store.create_views()
|
|
672
|
+
self.store.add_result(x, y[:self.nobj])
|
|
673
|
+
improve = False
|
|
674
|
+
for i in range(self.nobj):
|
|
675
|
+
if y[i] < self.best_y[i]:
|
|
676
|
+
improve = True
|
|
677
|
+
self.best_y[i] = y[i]
|
|
678
|
+
improve = improve# and self.n_evals.value > 10000
|
|
679
|
+
if self.n_evals.value % self.interval == 0 or improve:
|
|
680
|
+
constr = np.maximum(y[self.nobj:], 0)
|
|
681
|
+
logger.info(
|
|
682
|
+
str(dtime(self.time_0)) + ' ' +
|
|
683
|
+
str(self.n_evals.value) + ' ' +
|
|
684
|
+
str(round(self.n_evals.value/(1E-9 + dtime(self.time_0)),0)) + ' ' +
|
|
685
|
+
str(self.best_y[:]) + ' ' + str(list(constr)) + ' ' + str(list(x)))
|
|
686
|
+
if (not self.store is None) and (not self.name is None):
|
|
687
|
+
try:
|
|
688
|
+
xs, ys = self.store.get_front()
|
|
689
|
+
num = self.store.num_stored.value
|
|
690
|
+
name = self.name + '_' + str(num)
|
|
691
|
+
np.savez_compressed(name, xs=xs, ys=ys)
|
|
692
|
+
if self.plot:
|
|
693
|
+
moretry.plot(name, 0, xs, ys, all=False)
|
|
694
|
+
except Exception as ex:
|
|
695
|
+
print(str(ex))
|
|
696
|
+
return y
|
|
697
|
+
except Exception as ex:
|
|
698
|
+
print(str(ex))
|
|
699
|
+
return None
|
|
700
|
+
|
|
701
|
+
def minimize_plot(name: str,
|
|
702
|
+
fun: Callable[[ArrayLike], ArrayLike],
|
|
703
|
+
nobj: int,
|
|
704
|
+
ncon: int,
|
|
705
|
+
bounds: Bounds,
|
|
706
|
+
popsize: Optional[int] = 64,
|
|
707
|
+
max_evaluations: Optional[int] = 100000,
|
|
708
|
+
nsga_update: Optional[bool] = True,
|
|
709
|
+
pareto_update: Optional[int] = 0,
|
|
710
|
+
ints: Optional[ArrayLike] = None,
|
|
711
|
+
workers: Optional[int] = mp.cpu_count()) -> Tuple[np.ndarray, np.ndarray]:
|
|
569
712
|
name += '_mode_' + str(popsize) + '_' + \
|
|
570
713
|
('nsga_update' if nsga_update else ('de_update_' + str(pareto_update)))
|
|
571
714
|
logger.info('optimize ' + name)
|
|
572
715
|
xs, ys = minimize(fun, nobj, ncon, bounds, popsize = popsize, max_evaluations = max_evaluations,
|
|
573
|
-
nsga_update = nsga_update, pareto_update = pareto_update, workers=workers,
|
|
574
|
-
logger=logger, plot_name = plot_name)
|
|
716
|
+
nsga_update = nsga_update, pareto_update = pareto_update, workers=workers, ints=ints)
|
|
575
717
|
np.savez_compressed(name, xs=xs, ys=ys)
|
|
576
718
|
moretry.plot(name, ncon, xs, ys)
|
|
719
|
+
return xs, ys
|