205
205
from . import constraints_handler as _constraints_handler
206
206
from cma import fitness_models as _fitness_models
207
207
from .constraints_handler import BoundNone , BoundPenalty , BoundTransform , AugmentedLagrangian
208
+ from .integer_centering import IntegerCentering
208
209
from .logger import CMADataLogger # , disp, plot
209
210
from .utilities .utils import BlancClass as _BlancClass
210
211
from .utilities .utils import rglen #, global_verbosity
@@ -231,6 +232,10 @@ def _callable_to_list(c):
231
232
return [c ]
232
233
return c
233
234
235
+ def _pass (* args , ** kwargs ):
236
+ """a callable that does nothing and return args[0] in case"""
237
+ return args [0 ] if args else None
238
+
234
239
# use_archives uses collections
235
240
use_archives = sys .version_info [0 ] >= 3 or sys .version_info [1 ] >= 6
236
241
# use_archives = False # on False some unit tests fail
@@ -913,6 +918,7 @@ def identity(x):
913
918
# self.fmean = np.nan # TODO name should change? prints nan in output files (OK with matlab&octave)
914
919
# self.fmean_noise_free = 0. # for output only
915
920
921
+ opts .amend_integer_options (N , inopts )
916
922
self .sp = options_parameters .CMAParameters (N , opts , verbose = opts ['verbose' ] > 0 )
917
923
self .sp0 = self .sp # looks useless, as it is not a copy
918
924
@@ -974,7 +980,14 @@ def eval_vector(in_, opts, N, default_value=1.0):
974
980
opts ['minstd' ] = eval_vector (opts ['minstd' ], opts , N , 0 )
975
981
opts ['maxstd' ] = eval_vector (opts ['maxstd' ], opts , N , np .inf )
976
982
977
- if 1 < 3 and len (opts ['integer_variables' ]):
983
+ # iiinteger handling currently as LB-IC, see cma.integer_centering:
984
+ if len (opts ['integer_variables' ]):
985
+ opts .set_integer_min_std (N , self .sp .weights .mueff )
986
+ self .integer_centering = IntegerCentering (self ) # read opts['integer_variables'] and use boundary handler
987
+ else :
988
+ self .integer_centering = _pass # do nothing by default
989
+
990
+ if 11 < 3 and len (opts ['integer_variables' ]):
978
991
try :
979
992
from . import integer
980
993
s = utils .format_message (
@@ -984,46 +997,6 @@ def eval_vector(in_, opts, N, default_value=1.0):
984
997
warnings .warn (s , category = DeprecationWarning ) # TODO: doesn't show up
985
998
except ImportError :
986
999
pass
987
- opts ['integer_variables' ] = list (opts ['integer_variables' ])
988
-
989
- # iiinteger handling, currently very basic:
990
- # CAVEAT: integer indices may give unexpected results if fixed_variables is used
991
- if len (opts ['integer_variables' ]) and opts ['fixed_variables' ]:
992
- # transform integer indices to genotype
993
- popped = [] # just for the record
994
- for i in reversed (range (self .N )):
995
- if i in opts ['fixed_variables' ]:
996
- opts ['integer_variables' ].remove (i )
997
- if 1 < 3 : # just for catching errors
998
- popped .append (i )
999
- if i in opts ['integer_variables' ]:
1000
- raise ValueError ("index {0} appeared more than once in `'integer_variables'` option" .format (i ))
1001
- # reduce integer variable indices > i by one
1002
- for j , idx in enumerate (opts ['integer_variables' ]):
1003
- if idx > i :
1004
- opts ['integer_variables' ][j ] -= 1
1005
- if opts ['verbose' ] >= 0 :
1006
- warnings .warn ("Handling integer variables when some variables are fixed."
1007
- "\n This code is poorly tested and fails for negative indices."
1008
- "\n Variables {0} are fixed integer variables and discarded"
1009
- " for integer handling."
1010
- .format (popped ))
1011
- # 1) prepare minstd to be a vector
1012
- if (len (opts ['integer_variables' ]) and
1013
- np .isscalar (opts ['minstd' ])):
1014
- opts ['minstd' ] = opts ['minstd' ] * np .ones (N )
1015
- # 2) set minstd to 1 / (2 Nint + 1),
1016
- # the setting 2 / (2 Nint + 1) already prevents convergence
1017
- for i in opts ['integer_variables' ]:
1018
- if - N <= i < N : # when i < 0, the index computes to N + i
1019
- if opts ['minstd' ][i ] == 0 : # negative values prevent setting minstd
1020
- # opts['minstd'][i] = 1 / (2 * len(opts['integer_variables']) + 1)
1021
- opts ['minstd' ][i ] = min ((0.2 , self .sp .weights .mueff / N ))
1022
- else :
1023
- utils .print_warning (
1024
- """dropping integer index %d as it is not in range of dimension %d""" %
1025
- (i , N ))
1026
- opts ['integer_variables' ].pop (opts ['integer_variables' ].index (i ))
1027
1000
1028
1001
# initialization of state variables
1029
1002
self .countiter = 0
@@ -2005,22 +1978,25 @@ def get_selective_mirrors(self, number=None):
2005
1978
2006
1979
def limit_integer_relative_deltas (self , dX , threshold = None ,
2007
1980
recombination_weight_condition = None ):
2008
- """limit absolute values of int-coordinates in vector list `dX`
1981
+ """versatile: limit absolute values of int-coordinates in vector list `dX`
2009
1982
2010
1983
relative to the current sample standard deviations and by default
2011
1984
only when the respective recombination weight is negative.
2012
1985
1986
+ This function is currently not in effect (called with threshold=inf)
1987
+ and not guarantied to stay as is.
1988
+
2013
1989
``dX == pop_sorted - mold`` where ``pop_sorted`` is a genotype.
2014
1990
2015
1991
``threshold=2.3`` by default.
2016
1992
2017
1993
A 2.3-sigma threshold affects 2 x 1.1% of the unmodified
2018
1994
(nonsorted) normal samples.
2019
1995
"""
2020
- if threshold is None : # TODO: how interpret negative thresholds?
2021
- threshold = 2.3
2022
1996
if not self .opts ['integer_variables' ] or not np .isfinite (threshold ):
2023
1997
return dX
1998
+ if threshold is None : # TODO: how interpret negative thresholds?
1999
+ threshold = 2.3
2024
2000
if recombination_weight_condition is None :
2025
2001
def recombination_weight_condition (w ):
2026
2002
return w < 0
@@ -2300,6 +2276,8 @@ def tell(self, solutions, function_values, check_points=None,
2300
2276
pop = np .asarray ([xp [0 ]] + list (pop ))
2301
2277
2302
2278
self .pop_sorted = pop
2279
+ self .integer_centering (pop [:sp .weights .mu ], self .mean )
2280
+
2303
2281
# compute new mean
2304
2282
self .mean = np .dot (sp .weights .positive_weights , pop [:sp .weights .mu ])
2305
2283
if sp .cmean != 1 :
@@ -2390,8 +2368,10 @@ def tell(self, solutions, function_values, check_points=None,
2390
2368
pass # without CSA we may not need the mean_shift
2391
2369
2392
2370
# covariance matrix adaptation/udpate
2393
- pop_zero = self .limit_integer_relative_deltas (
2394
- pop - mold , self .opts ['CMA_active_limit_int_std' ])
2371
+ pop_zero = self .limit_integer_relative_deltas ( # does by default nothing
2372
+ pop - mold ,
2373
+ options_parameters .integer_active_limit_std ,
2374
+ options_parameters .integer_active_limit_recombination_weight_condition )
2395
2375
if c1a + cmu > 0 :
2396
2376
# TODO: make sure cc is 1 / N**0.5 rather than 1 / N
2397
2377
# TODO: simplify code: split the c1 and cmu update and call self.sm.update twice
@@ -2429,16 +2409,22 @@ def tell(self, solutions, function_values, check_points=None,
2429
2409
sampler_weights [i + 1 ] *= self .opts ['CMA_active_injected' ]
2430
2410
if sampler_weights_dd [i + 1 ] < 0 :
2431
2411
sampler_weights_dd [i + 1 ] *= self .opts ['CMA_active_injected' ]
2432
- for s in list (self ._injected_solutions_archive ):
2433
- if self ._injected_solutions_archive [s ]['iteration' ] < self .countiter - 2 :
2434
- warnings .warn ("""orphanated injected solution %s
2435
- This could be a bug in the calling order/logics or due to
2436
- a too small popsize used in `ask()` or when only using
2437
- `ask(1)` repeatedly. Please check carefully.
2438
- In case this is desired, the warning can be surpressed with
2439
- ``warnings.simplefilter("ignore", cma.evolution_strategy.InjectionWarning)``
2440
- """ % str (self ._injected_solutions_archive .pop (s )),
2441
- InjectionWarning )
2412
+ for k , s in list (self ._injected_solutions_archive .items ()):
2413
+ if s ['iteration' ] < self .countiter - 2 :
2414
+ # warn unless TPA injections were messed up by integer centering
2415
+ if (not isinstance (self .adapt_sigma , CMAAdaptSigmaTPA )
2416
+ # self.integer_centering and
2417
+ # self.integer_centering is not _pass and
2418
+ or not isinstance (self .integer_centering , IntegerCentering )
2419
+ or s ['index' ] > 1 ):
2420
+ warnings .warn ("""orphanated injected solution %s
2421
+ This could be a bug in the calling order/logics or due to
2422
+ a too small popsize used in `ask()` or when only using
2423
+ `ask(1)` repeatedly. Please check carefully.
2424
+ In case this is desired, the warning can be surpressed with
2425
+ ``warnings.simplefilter("ignore", cma.evolution_strategy.InjectionWarning)``
2426
+ """ % str (s ), InjectionWarning )
2427
+ self ._injected_solutions_archive .pop (k )
2442
2428
assert len (sampler_weights ) == len (pop_zero ) + 1
2443
2429
if flg_diagonal :
2444
2430
self .sigma_vec .update (
0 commit comments