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/astro.py CHANGED
@@ -8,33 +8,27 @@ import math
8
8
  import os
9
9
  import ctypes as ct
10
10
  from scipy.optimize import Bounds
11
+ from fcmaes.decpp import libcmalib
11
12
 
12
- basepath = os.path.dirname(os.path.abspath(__file__))
13
- if sys.platform.startswith('linux'):
14
- libgtoplib = ct.cdll.LoadLibrary(basepath + '/lib/libgtoplib.so')
15
- elif 'mac' in sys.platform:
16
- libgtoplib = ct.cdll.LoadLibrary(basepath + '/lib/libgtoplib.dylib')
17
- else:
18
- os.environ['PATH'] = (basepath + '/lib') + os.pathsep + os.environ['PATH']
19
- libgtoplib = ct.cdll.LoadLibrary(basepath + '/lib/libgtoplib.dll')
20
-
21
- freemem = libgtoplib.free_mem
22
- freemem.argtypes = [ct.POINTER(ct.c_double)]
23
-
24
- # for windows compatibility. Linux can pickle c pointers, windows can not
25
- astro_map = {
26
- "messengerfullC": libgtoplib.messengerfullC,
27
- "messengerC": libgtoplib.messengerC,
28
- "gtoc1C": libgtoplib.gtoc1C,
29
- "cassini1C": libgtoplib.cassini1C,
30
- "cassini1minlpC": libgtoplib.cassini1minlpC,
31
- "cassini2C": libgtoplib.cassini2C,
32
- "rosettaC": libgtoplib.rosettaC,
33
- "sagasC": libgtoplib.sagasC,
34
- "tandemC": libgtoplib.tandemC,
35
- "tandemCu": libgtoplib.tandemCu
13
+ if not libcmalib is None:
14
+
15
+ astro_map = {
16
+ "messengerfullC": libcmalib.messengerfullC,
17
+ "messengerC": libcmalib.messengerC,
18
+ "gtoc1C": libcmalib.gtoc1C,
19
+ "cassini1C": libcmalib.cassini1C,
20
+ "cassini1minlpC": libcmalib.cassini1minlpC,
21
+ "cassini2C": libcmalib.cassini2C,
22
+ "rosettaC": libcmalib.rosettaC,
23
+ "sagasC": libcmalib.sagasC,
24
+ "tandemC": libcmalib.tandemC,
25
+ "tandemCu": libcmalib.tandemCu,
26
+ "cassini2minlpC": libcmalib.cassini2minlpC,
36
27
  }
37
28
 
29
+ freemem = libcmalib.free_mem
30
+ freemem.argtypes = [ct.POINTER(ct.c_double)]
31
+
38
32
  class Astrofun(object):
39
33
  """Provides access to ESAs GTOP optimization test functions."""
40
34
  def __init__(self, name, fun_c, lower, upper):
@@ -191,18 +185,33 @@ class Cassini1multi(object):
191
185
  class Cassini1minlp(object):
192
186
  """ see https://www.esa.int/gsp/ACT/projects/gtop/cassini1/ """
193
187
 
194
- def __init__(self, weights = [1,0,0,0]):
195
- Astrofun.__init__(self, 'Cassini1minlp', "Cassini1minlpC",
196
- [-1000.,30.,100.,30.,400.,1000., 1.0,1.0,1.0,1.0 ],
197
- [0.,400.,470.,400.,2000.,6000., 9.0,9.0,9.0,9.0 ]
188
+ def __init__(self, planets = [2,2,3,5]):
189
+ Astrofun.__init__(self, 'Cassini1', "cassini1C",
190
+ [-1000.,30.,100.,30.,400.,1000.],
191
+ [0.,400.,470.,400.,2000.,6000.]
198
192
  )
199
- self.fun = self.cassini1minlp
200
- self.weights = weights
201
- self.mfun = cassini1multi
202
-
203
- def cassini1minlp(self, x):
204
- r = cassini1multi(x)
205
- return self.weights[0]*r[0] + self.weights[1]*r[1] + self.weights[2]*r[2] + self.weights[3]*r[3]
193
+ self.fun = self.cassini1
194
+ self.planets = planets
195
+
196
+ def cassini1(self, x):
197
+ return cassini1minlp(list(x) + self.planets)
198
+
199
+ def cassini1minlp(x):
200
+ n = len(x)
201
+ array_type = ct.c_double * n
202
+ fun_c = astro_map["cassini1minlpC"]
203
+ fun_c.argtypes = [ct.c_int, ct.POINTER(ct.c_double)]
204
+ fun_c.restype = ct.POINTER(ct.c_double)
205
+ try: # function is only defined inside bounds
206
+ res = fun_c(n, array_type(*x))
207
+ dv = res[0]
208
+ freemem(res)
209
+ if not math.isfinite(dv):
210
+ dv = 1E10
211
+ except Exception as ex:
212
+ print(ex)
213
+ dv = 1E10
214
+ return dv
206
215
 
207
216
  def cassini1multi(x):
208
217
  n = len(x)
@@ -218,13 +227,28 @@ def cassini1multi(x):
218
227
  if not math.isfinite(dv):
219
228
  dv = 1E10
220
229
  except Exception as ex:
230
+ print(ex)
221
231
  dv = 1E10
222
232
  launch_dv = 1E10
223
- tof = x[1] + x[2] + x[3] + x[4]
233
+ tof = sum(x[1:6])
224
234
  launch_time = x[0]
225
- return [dv, tof, launch_time, launch_dv]
235
+ return [dv, tof, launch_time]
226
236
 
227
-
237
+ def cassini2multi(x):
238
+ n = len(x)
239
+ array_type = ct.c_double * n
240
+ fun_c = astro_map["cassini2minlpC"]
241
+ fun_c.argtypes = [ct.c_int, ct.POINTER(ct.c_double)]
242
+ fun_c.restype = ct.c_double
243
+ try: # function is only defined inside bounds
244
+ dv = fun_c(n, array_type(*x))
245
+ except Exception as ex:
246
+ print(ex)
247
+ dv = 1E99
248
+ tof = sum(x[4:9])
249
+ launch_time = x[0]
250
+ return [dv, tof, launch_time]
251
+
228
252
  class python_fun(object):
229
253
 
230
254
  def __init__(self, cfun, bounds):
@@ -242,5 +266,5 @@ class python_fun(object):
242
266
  val = 1E10
243
267
  except Exception as ex:
244
268
  val = 1E10
245
- return val
246
-
269
+ return val
270
+
fcmaes/bitecpp.py CHANGED
@@ -13,23 +13,25 @@ import os
13
13
  import math
14
14
  import ctypes as ct
15
15
  import numpy as np
16
- from numpy.random import MT19937, Generator
17
- from scipy.optimize import OptimizeResult
18
- from fcmaes.cmaes import _check_bounds
19
- from fcmaes.cmaescpp import libcmalib
20
- from fcmaes.decpp import mo_call_back_type, callback
16
+ from numpy.random import PCG64DXSM, Generator
17
+ from scipy.optimize import OptimizeResult, Bounds
18
+ from fcmaes.evaluator import _check_bounds, mo_call_back_type, callback_so, libcmalib
19
+
20
+ from typing import Optional, Callable
21
+ from numpy.typing import ArrayLike
21
22
 
22
23
  os.environ['MKL_DEBUG_CPU_TYPE'] = '5'
23
24
 
24
- def minimize(fun,
25
- bounds=None,
26
- x0=None,
27
- popsize = 0,
28
- max_evaluations = 100000,
29
- stop_fitness = None,
30
- M = 1,
31
- rg = Generator(MT19937()),
32
- runid=0):
25
+ def minimize(fun: Callable[[ArrayLike], float],
26
+ bounds: Optional[Bounds] = None,
27
+ x0: Optional[ArrayLike] = None,
28
+ max_evaluations: Optional[int] = 100000,
29
+ stop_fitness: Optional[float] = -np.inf,
30
+ M: Optional[int] = 1,
31
+ popsize: Optional[int] = 0,
32
+ stall_criterion: Optional[int] = 0,
33
+ rg: Optional[Generator] = Generator(PCG64DXSM()),
34
+ runid: Optional[int] = 0) -> OptimizeResult:
33
35
  """Minimization of a scalar function of one or more variables using a
34
36
  C++ SCMA implementation called via ctypes.
35
37
 
@@ -37,10 +39,8 @@ def minimize(fun,
37
39
  ----------
38
40
  fun : callable
39
41
  The objective function to be minimized.
40
- ``fun(x, *args) -> float``
41
- where ``x`` is an 1-D array with shape (dim,) and ``args``
42
- is a tuple of the fixed parameters needed to completely
43
- specify the function.
42
+ ``fun(x) -> float``
43
+ where ``x`` is an 1-D array with shape (dim,)
44
44
  bounds : sequence or `Bounds`, optional
45
45
  Bounds on variables. There are two ways to specify the bounds:
46
46
  1. Instance of the `scipy.Bounds` class.
@@ -49,14 +49,16 @@ def minimize(fun,
49
49
  x0 : ndarray, shape (dim,)
50
50
  Initial guess. Array of real elements of size (dim,),
51
51
  where 'dim' is the number of independent variables.
52
- popsize = int, optional
53
- CMA-ES population size.
54
52
  max_evaluations : int, optional
55
53
  Forced termination after ``max_evaluations`` function evaluations.
56
54
  stop_fitness : float, optional
57
55
  Limit for fitness value. If reached minimize terminates.
58
56
  M : int, optional
59
57
  Depth to use, 1 for plain CBiteOpt algorithm, >1 for CBiteOptDeep. Expected range is [1; 36].
58
+ popsize = int, optional
59
+ initial population size.
60
+ stall_criterion : int, optional
61
+ Terminate if stall_criterion*128*evaluations stalled, Not used if <= 0
60
62
  rg = numpy.random.Generator, optional
61
63
  Random generator for creating random guesses.
62
64
  runid : int, optional
@@ -75,19 +77,16 @@ def minimize(fun,
75
77
 
76
78
  lower, upper, guess = _check_bounds(bounds, x0, rg)
77
79
  dim = guess.size
78
- if lower is None:
79
- lower = [0]*dim
80
- upper = [0]*dim
81
- if stop_fitness is None:
82
- stop_fitness = -math.inf
83
80
  array_type = ct.c_double * dim
84
- c_callback = mo_call_back_type(callback(fun, dim))
81
+ c_callback = mo_call_back_type(callback_so(fun, dim))
85
82
  res = np.empty(dim+4)
86
83
  res_p = res.ctypes.data_as(ct.POINTER(ct.c_double))
87
84
  try:
88
85
  optimizeBite_C(runid, c_callback, dim, int(rg.uniform(0, 2**32 - 1)),
89
- array_type(*guess), array_type(*lower), array_type(*upper),
90
- max_evaluations, stop_fitness, popsize, M, res_p)
86
+ None if x0 is None else array_type(*guess),
87
+ None if lower is None else array_type(*lower),
88
+ None if upper is None else array_type(*upper),
89
+ max_evaluations, stop_fitness, M, popsize, stall_criterion, res_p)
91
90
  x = res[:dim]
92
91
  val = res[dim]
93
92
  evals = int(res[dim+1])
@@ -97,10 +96,12 @@ def minimize(fun,
97
96
  except Exception as ex:
98
97
  return OptimizeResult(x=None, fun=sys.float_info.max, nfev=0, nit=0, status=-1, success=False)
99
98
 
100
- optimizeBite_C = libcmalib.optimizeBite_C
101
- optimizeBite_C.argtypes = [ct.c_long, mo_call_back_type, ct.c_int, ct.c_int, \
102
- ct.POINTER(ct.c_double), ct.POINTER(ct.c_double), ct.POINTER(ct.c_double), \
103
- ct.c_int, ct.c_double, ct.c_int, ct.c_int, ct.POINTER(ct.c_double)]
99
+ if not libcmalib is None:
100
+
101
+ optimizeBite_C = libcmalib.optimizeBite_C
102
+ optimizeBite_C.argtypes = [ct.c_long, mo_call_back_type, ct.c_int, ct.c_int, \
103
+ ct.POINTER(ct.c_double), ct.POINTER(ct.c_double), ct.POINTER(ct.c_double), \
104
+ ct.c_int, ct.c_double, ct.c_int, ct.c_int, ct.c_int, ct.POINTER(ct.c_double)]
104
105
 
105
106
 
106
107
 
fcmaes/cmaes.py CHANGED
@@ -16,38 +16,39 @@ from time import time
16
16
  import ctypes as ct
17
17
  import multiprocessing as mp
18
18
  from scipy import linalg
19
- from scipy.optimize import OptimizeResult
20
- from numpy.random import MT19937, Generator
21
- from fcmaes.evaluator import Evaluator
19
+ from scipy.optimize import OptimizeResult, Bounds
20
+ from numpy.random import PCG64DXSM, Generator
21
+ from fcmaes.evaluator import Evaluator, serial, _check_bounds, _fitness, is_debug_active
22
+
23
+ from loguru import logger
24
+ from typing import Optional, Callable, Union
25
+ from numpy.typing import ArrayLike
22
26
 
23
27
  os.environ['MKL_DEBUG_CPU_TYPE'] = '5'
24
28
 
25
- def minimize(fun,
26
- bounds=None,
27
- x0=None,
28
- input_sigma = 0.3,
29
- popsize = 31,
30
- max_evaluations = 100000,
31
- max_iterations = 100000,
32
- workers = 1,
33
- accuracy = 1.0,
34
- stop_fitness = np.nan,
35
- is_terminate = None,
36
- rg = Generator(MT19937()),
37
- runid=0,
38
- normalize = True,
39
- update_gap = None,
40
- logger = None):
29
+ def minimize(fun: Callable[[ArrayLike], float],
30
+ bounds: Optional[Bounds] = None,
31
+ x0: Optional[ArrayLike] = None,
32
+ input_sigma: Optional[Union[float, ArrayLike, Callable]] = 0.3,
33
+ popsize: Optional[int] = 31,
34
+ max_evaluations: Optional[int] = 100000,
35
+ max_iterations: Optional[int] = 100000,
36
+ workers: Optional[int] = 1,
37
+ accuracy: Optional[float] = 1.0,
38
+ stop_fitness: Optional[float] = -np.inf,
39
+ is_terminate: Optional[Callable[[ArrayLike, float], bool]] = None,
40
+ rg: Optional[Generator] = Generator(PCG64DXSM()),
41
+ runid: Optional[int] = 0,
42
+ normalize: Optional[bool] = True,
43
+ update_gap: Optional[int] = None) -> OptimizeResult:
41
44
  """Minimization of a scalar function of one or more variables using CMA-ES.
42
45
 
43
46
  Parameters
44
47
  ----------
45
48
  fun : callable
46
49
  The objective function to be minimized.
47
- ``fun(x, *args) -> float``
48
- where ``x`` is an 1-D array with shape (n,) and ``args``
49
- is a tuple of the fixed parameters needed to completely
50
- specify the function.
50
+ ``fun(x) -> float``
51
+ where ``x`` is an 1-D array with shape (n,)
51
52
  bounds : sequence or `Bounds`, optional
52
53
  Bounds on variables. There are two ways to specify the bounds:
53
54
  1. Instance of the `scipy.Bounds` class.
@@ -82,10 +83,6 @@ def minimize(fun,
82
83
  pheno -> if true geno transformation maps arguments to interval [-1,1]
83
84
  update_gap : int, optional
84
85
  number of iterations without distribution update
85
- logger : logger, optional
86
- logger for log output for tell_one, If None, logging
87
- is switched off. Default is a logger which logs both to stdout and
88
- appends to a file ``optimizer.log``.
89
86
 
90
87
  Returns
91
88
  -------
@@ -103,7 +100,7 @@ def minimize(fun,
103
100
  max_evaluations, max_iterations,
104
101
  accuracy, stop_fitness,
105
102
  is_terminate, rg, np.random.randn, runid, normalize,
106
- update_gap, fun, logger)
103
+ update_gap, fun)
107
104
  if workers and workers > 1:
108
105
  x, val, evals, iterations, stop = cmaes.do_optimize_delayed_update(fun, workers=workers)
109
106
  else:
@@ -114,22 +111,21 @@ def minimize(fun,
114
111
  class Cmaes(object):
115
112
  """Implements the cma-es ask/tell interactive interface."""
116
113
 
117
- def __init__(self, bounds=None,
118
- x0=None,
119
- input_sigma = 0.3,
120
- popsize = 31,
121
- max_evaluations = 100000,
122
- max_iterations = 100000,
123
- accuracy = 1.0,
124
- stop_fitness = np.nan,
125
- is_terminate = None,
126
- rg = Generator(MT19937()), # used if x0 is undefined
127
- randn = np.random.randn, # used for random offspring
128
- runid=0,
129
- normalize = False,
130
- update_gap = None,
131
- fun = None,
132
- logger = None
114
+ def __init__(self, bounds: Optional[Bounds] = None,
115
+ x0: Optional[ArrayLike] = None,
116
+ input_sigma: Optional[Union[float, ArrayLike, Callable]] = 0.3,
117
+ popsize: Optional[int] = 31,
118
+ max_evaluations: Optional[int] = 100000,
119
+ max_iterations: Optional[int] = 100000,
120
+ accuracy: Optional[int] = 1.0,
121
+ stop_fitness: Optional[float] = -np.inf,
122
+ is_terminate: Optional[bool] = None,
123
+ rg: Optional[Generator] = Generator(PCG64DXSM()), # used if x0 is undefined
124
+ randn: Optional[Callable] = np.random.randn, # used for random offspring
125
+ runid: Optional[int] = 0,
126
+ normalize: Optional[bool] = True,
127
+ update_gap: Optional[int] = None,
128
+ fun: Optional[Callable[[ArrayLike], float]] = None
133
129
  ):
134
130
 
135
131
  # runid used in is_terminate callback to identify a specific run at different iteration
@@ -187,9 +183,8 @@ class Cmaes(object):
187
183
  # selection strategy parameters
188
184
  # Number of parents/points for recombination.
189
185
  self.mu = int(self.popsize/2)
190
- # logger / timing / global best value
191
- if not logger is None:
192
- self.logger = logger
186
+ # timing / global best value
187
+ if is_debug_active():
193
188
  self.best_y = mp.RawValue(ct.c_double, 1E99)
194
189
  self.n_evals = mp.RawValue(ct.c_long, 0)
195
190
  self.time_0 = time()
@@ -257,7 +252,7 @@ class Cmaes(object):
257
252
  self.arz = None
258
253
  self.fitness = None
259
254
 
260
- def ask(self):
255
+ def ask(self) -> np.array:
261
256
  """ask for popsize new argument vectors.
262
257
 
263
258
  Returns
@@ -265,9 +260,11 @@ class Cmaes(object):
265
260
  xs : popsize sized list of dim sized argument lists."""
266
261
 
267
262
  self.newArgs()
268
- return [self.fitfun.decode(x) for x in self.arx]
263
+ return np.array([self.fitfun.decode(x) for x in self.arx])
269
264
 
270
- def tell(self, ys, xs = None):
265
+ def tell(self,
266
+ ys: np.ndarray,
267
+ xs: Optional[np.ndarray] = None) -> int:
271
268
  """tell function values for the argument lists retrieved by ask().
272
269
 
273
270
  Parameters
@@ -297,8 +294,16 @@ class Cmaes(object):
297
294
  self.updateCMA()
298
295
  self.arz = None
299
296
  return self.stop
300
-
301
- def ask_one(self):
297
+
298
+ def population(self) -> np.array:
299
+ return self.fitfun.decode(self.arx)
300
+
301
+ def result(self) -> OptimizeResult:
302
+ return OptimizeResult(x=self.best_x, fun=self.best_value,
303
+ nfev=self.fitfun.evaluation_counter,
304
+ nit=self.iterations, status=self.stop, success=True)
305
+
306
+ def ask_one(self) -> np.array:
302
307
  """ask for one new argument vector.
303
308
 
304
309
  Returns
@@ -309,7 +314,9 @@ class Cmaes(object):
309
314
  arx = self.fitfun.closestFeasible(self.xmean + delta.transpose())
310
315
  return self.fitfun.decode(arx)
311
316
 
312
- def tell_one(self, y, x):
317
+ def tell_one(self,
318
+ y: float,
319
+ x: np.array) -> int:
313
320
  """tell function value for a argument list retrieved by ask_one().
314
321
 
315
322
  Parameters
@@ -341,7 +348,7 @@ class Cmaes(object):
341
348
  self.arx = []
342
349
  self.fitness = []
343
350
 
344
- if hasattr(self, 'logger'):
351
+ if is_debug_active():
345
352
  self.n_evals.value += 1
346
353
  if y < self.best_y.value or self.n_evals.value % 1000 == 999:
347
354
  if y < self.best_y.value: self.best_y.value = y
@@ -349,12 +356,10 @@ class Cmaes(object):
349
356
  c = self.n_evals.value
350
357
  message = '"c/t={0:.2f} c={1:d} t={2:.2f} y={3:.5f} yb={4:.5f} x={5!s}'.format(
351
358
  c/t, c, t, y, self.best_y.value, x)
352
- self.logger.info(message)
359
+ logger.debug(message)
353
360
  return self.stop
354
361
 
355
362
  def newArgs(self):
356
- self.xmean = self.fitfun.closestFeasible(self.xmean)
357
- self.fitness = np.full(self.popsize, math.inf)
358
363
  # generate random offspring
359
364
  self.arz = self.randn(self.popsize, self.dim)
360
365
  delta = (self.BD @ self.arz.transpose()) * self.sigma
@@ -397,10 +402,9 @@ class Cmaes(object):
397
402
  self.iterations += 1
398
403
  if self.fitfun.evaluation_counter > self.max_evaluations:
399
404
  break
400
- # Generate and evaluate popsize offspring
401
- self.newArgs()
402
- self.fitness = self.fitfun.values(self.arx)
403
- self.updateCMA()
405
+ xs = self.ask()
406
+ ys = self.fitfun.values(xs)
407
+ self.tell(ys, xs)
404
408
  if self.stop != 0:
405
409
  break
406
410
  return self.best_x, self.best_value, self.fitfun.evaluation_counter, self.iterations, self.stop
@@ -416,10 +420,9 @@ class Cmaes(object):
416
420
  if self.best_value > best_fitness:
417
421
  self.best_value = best_fitness
418
422
  self.best_x = self.fitfun.decode(self.arx[arindex[0]])
419
- if self.stop_fitness != None: # only if stop_fitness is defined
420
- if best_fitness < self.stop_fitness:
421
- self.stop = 1
422
- return
423
+ if best_fitness < self.stop_fitness:
424
+ self.stop = 1
425
+ return
423
426
 
424
427
  # Calculate new xmean, this is selection and recombination
425
428
  xold = self.xmean # for speed up of Eq. (2) and (3)
@@ -591,80 +594,4 @@ class Cmaes(object):
591
594
  self.diagD = np.sqrt(self.diagD) # diagD contains standard deviations now
592
595
 
593
596
  self.BD = self.B * self.diagD # O(n^2)
594
-
595
- def serial(fun):
596
- """Convert an objective function for serial execution for cmaes.minimize.
597
-
598
- Parameters
599
- ----------
600
- fun : objective function mapping a list of float arguments to a float value
601
-
602
- Returns
603
- -------
604
- out : function
605
- A function mapping a list of lists of float arguments to a list of float values
606
- by applying the input function in a loop."""
607
-
608
- return lambda xs : [_tryfun(fun, x) for x in xs]
609
-
610
- def _func_serial(fun, num, pid, xs, ys):
611
- for i in range(pid, len(xs), num):
612
- ys[i] = _tryfun(fun, xs[i])
613
-
614
- def _tryfun(fun, x):
615
- try:
616
- fit = fun(x)
617
- return fit if math.isfinite(fit) else sys.float_info.max
618
- except Exception:
619
- return sys.float_info.max
620
-
621
- def _check_bounds(bounds, guess, rg):
622
- if bounds is None and guess is None:
623
- raise ValueError('either guess or bounds need to be defined')
624
- if bounds is None:
625
- return None, None, np.asarray(guess)
626
- if guess is None:
627
- guess = rg.uniform(bounds.lb, bounds.ub)
628
- return np.asarray(bounds.lb), np.asarray(bounds.ub), np.asarray(guess)
629
-
630
- class _fitness(object):
631
- """wrapper around the objective function, scales relative to boundaries."""
632
-
633
- def __init__(self, fun, lower, upper, normalize = None):
634
- self.fun = fun
635
- self.evaluation_counter = 0
636
- self.lower = lower
637
- self.normalize = False
638
- if not (lower is None or normalize is None):
639
- self.normalize = normalize
640
- if not lower is None:
641
- self.upper = upper
642
- self.scale = 0.5 * (upper - lower)
643
- self.typx = 0.5 * (upper + lower)
644
-
645
- def values(self, Xs): #enables parallel evaluation
646
- values = self.fun([self.decode(X) for X in Xs])
647
- self.evaluation_counter += len(Xs)
648
- return np.array(values)
649
-
650
- def closestFeasible(self, X):
651
- if self.lower is None:
652
- return X
653
- else:
654
- if self.normalize:
655
- return np.maximum(np.minimum(X, 1.0), -1.0)
656
- else:
657
- return np.maximum(np.minimum(X, self.upper), self.lower)
658
-
659
- def encode(self, X):
660
- if self.normalize:
661
- return (X - self.typx) / self.scale
662
- else:
663
- return X
664
-
665
- def decode(self, X):
666
- if self.normalize:
667
- return (X * self.scale) + self.typx
668
- else:
669
- return X
670
-
597
+