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 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.3.17'
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
- 'gcldecpp',
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
- from random import Random
18
+ import random
16
19
  import multiprocessing as mp
17
20
  from multiprocessing import Process
18
- from numpy.random import Generator, MT19937, SeedSequence
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 fcmaes.retry import _convertBounds, plot
22
- from fcmaes.optimizer import dtime, fitting, de_cma, logger
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 = math.inf,
31
- num_retries = 5000,
32
- logger = None,
33
- workers = mp.cpu_count(),
34
- popsize = 31,
35
- min_evaluations = 1500,
36
- max_eval_fac = None,
37
- check_interval = 100,
38
- capacity = 500,
39
- stop_fitness = -math.inf,
40
- optimizer = None,
41
- statistic_num = 0,
42
- datafile = None
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, *args) -> float``
52
- where ``x`` is an 1-D array with shape (n,) and ``args``
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, logger, num_retries,
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, optimize, value_limit = math.inf,
119
- workers=mp.cpu_count(), stop_fitness = -math.inf):
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(MT19937(s)) for s in sg.spawn(workers)]
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, optimizer, fun, bounds, value_limit = math.inf,
132
- plot_limit = math.inf, num_retries = 1024,
133
- workers = mp.cpu_count(), logger=logger(),
134
- stop_fitness = -math.inf, statistic_num = 5000):
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, logger = logger, statistic_num = statistic_num)
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
- logger = None, # if None logging is switched off
160
- num_retries = None,
161
- statistic_num = 0,
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.num_sorted = mp.RawValue(ct.c_int, 0)
195
- self.best_y = mp.RawValue(ct.c_double, math.inf)
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, math.inf)
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
- if not self.logger is None:
221
- self.logger.info(str(self.time[si]) + ' ' +
222
- str(self.sevals.value) + ' ' +
223
- str(y) + ' ' +
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.random.uniform(0.5, 1.0)
280
- lim_fac = self.random.uniform(2.0, 4.0) * diff_fac
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 = np.asarray(self.get_y(i))
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.maximum(0.001, np.minimum(0.5, diff_fac * deltax / self.delta))
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, xs):
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, xs)
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.num_sorted.value
316
+ n = self.num_stored.value
308
317
  if n < 2:
309
318
  return -1, -1
310
- lim = self.random.uniform(min(0.1*n, 1), 0.2*n)/n
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.random.random() < lim:
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
- xprev = xprev2 = None
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 (xprev is None or self.distance(xprev, x) > 0.15) and \
339
- (xprev2 is None or self.distance(xprev2, x) > 0.15):
340
- sortRuns.append( (y, x) )
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
- numStored = min(len(sortRuns),int(0.9*self.capacity)) # keep 90% best
345
- for i in range(numStored):
346
- self.replace(i, sortRuns[i][0], sortRuns[i][1])
347
- self.num_sorted.value = numStored
348
- self.num_stored.value = numStored
349
- self.worst_y.value = self.get_y(numStored-1)
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, xs, lower, upper, evals, limit=math.inf):
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.incr_count_evals(evals)
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[:] = xs[:]
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 get_x(self, pid):
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 get_x_best(self):
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
- self.logger.info(message)
430
+ logger.info(message)
432
431
 
433
- def _retry_loop(pid, rgs, store, optimize, value_limit, stop_fitness = -math.inf):
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
- #reinitialize logging config for windows - multi threading fix
436
- if 'win' in sys.platform and not store.logger is None:
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, store.lower, store.upper, evals, value_limit)
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, lower, upper, evals, y0) # limit to y0
456
+ store.add_result(y, sol, evals, y0) # limit to y0
463
457
  except:
464
458
  return False
465
459
  return True