class IntegerCentering(object):
Constructor: IntegerCentering(int_indices, method, correct_bias, repair_into_bounds, **kwargs)
round values of int-variables that are different from the int-mean.
This callable class changes a population of solutions in place, in particular rounding some of the integer variables. The call does not guaranty to round any or all integer variables. The class assumes that the fitness function only interprets the rounded values of integer variables, that is, it assumes that int-variables change the fitness only if their rounded (genotype) value change. (This may easily become a wrong assumption if a geno-pheno transformation is applied). The class tries to correct for the bias introduced by rounding values.
This class should generally be used in combination with a lower bound
on the integer variables along the lines of min((0.2,
mueff/dimension)), as it is induced by passing a nonempty
'integer_variables' option to CMAEvolutionStrategy. Applying
lower bounds alone is generally more effective than applying integer
centering alone.
Class instances have no dynamically changing state variables!
When integer variable indices are passed to CMAEvolutionStrategy via
the 'integer_variables' CMAOptions, an IntegerCentering class
instance is created, and it is called in CMAEvolutionStrategy.tell
before the update of the state variables of CMA, passing mu (genotypic)
solutions, like int_centering(self.pop_sorted[:self.sp.weights.mu],
self.mean) . The call changes the numpy arrays of self.pop_sorted
in place. The call tries to access the (phenotypic) bounds as defined
in es.boundary_handler from the constructor argument. Hence it is
expected to fail with a combination of bounds and
fixed_variables set in CMAOptions.
By default, integer centering is applied, e.g. with fmin2 or
CMAEvolutionStrategy, when the integer variable indices are given
via the 'integer_variables' option. Since v4.3.0, candidate
solutions delivered by CMAEvolutionStrategy.ask have rounded values
in all integer variable positions which can be switched off by setting
cma.evolution_strategy.round_integer_variables to False.
A simple example code:
>>> import cma >>> >>> def int1_sphere(x): ... return int(x[0] + 0.5 - (x[0] < 0))**2 + 1000 * (sum(xi**2 for xi in x[1:]))
>>> es = cma.CMAEvolutionStrategy(2 * [2], 0.5, ... {'integer_variables': [0], 'ftarget': 1e-9, 'verbose': -9}) >>> es = es.optimize(int1_sphere) >>> # assert 'ftarget' in es.stop(), es.stop() # fails sometimes (like 1%-ish) >>> # failure is less likely with options ``'tolfun': 0, 'tolfunhist': 0, 'tolflatfitness': 60``
The following pseudocode shows a direct use case to explicitly see
how/where integer centering is applied, namely before the state
variables are updated in tell:
>>> import numpy as np
>>> # set dimension dependent lower bound on sample standard deviations >>> es = cma.CMAEvolutionStrategy(2 * [2], 0.5, ... {'minstd': [0.2, 0], 'popsize_factor': 1.5, 'ftarget': 1e-9, 'verbose': -9}) >>> # when integer_variables were passed in the above options, >>> # we can inactivate the internal integer centering like >>> es.integer_centering = lambda *args: args[0] if args else None >>> ic = cma.integer_centering.IntegerCentering([0]) >>> while not es.stop(): ... X = es.ask() ... F = [int1_sphere(x) for x in X] ... # change the mu best solutions in place ... _ = ic([X[i] for i in np.argsort(F)[:es.sp.weights.mu]], es.mean) ... es.tell(X, F, check_points=False) # don't check for changes in X ... # es.logger.add() ... # es.disp() >>> # assert 'ftarget' in es.stop(), es.stop() # fails sometimes (like 1%-ish)
Details: The default method2 was used in the below reference and, as
of version 4.0.0, is activated in CMAEvolutionStrategy when
integer_variables are given as option.
Reference: Marty et al, LB+IC-CMA-ES: Two simple modifications of CMA-ES to handle mixed-integer problems. PPSN 2024.
| Method | __call__ |
round values of int-variables in solution_list and correct for bias. |
| Method | __init__ |
int_indices can also be a CMAEvolutionStrategy or CMAOptions instance. correct_bias can be in [0, 1] indicating the fraction of the bias that should be corrected (but only up to the mean center). |
| Method | bound |
return lower and upper bound on variable i, not in use. |
| Method | callback |
change es.pop_sorted and update es.mean accordingly. |
| Method | get |
determine integer variable indices from es or es.opts or |
| Method | has |
Undocumented |
| Method | lower |
return lower bounds of dimension dimension or a scalar. |
| Method | method1 |
DEPRECATED (experimental and outdated) round values of int-variables in solution_list and reduce bias to the mean |
| Method | method2 |
center (round) values of int-variables of solutions in solution_list. |
| Method | repair |
set values of int-variables of solutions of solution_list into bounds. |
| Method | upper |
return upper bounds of dimension dimension or a scalar. |
| Instance Variable | center |
Undocumented |
| Instance Variable | centering |
Undocumented |
| Instance Variable | int |
Undocumented |
| Instance Variable | last |
Undocumented |
| Instance Variable | last |
Undocumented |
| Instance Variable | mahalanobis0 |
Undocumented |
| Instance Variable | mahalanobis1 |
Undocumented |
| Instance Variable | params |
absolute and relative epsilon offset on the bounds such that np.round should never make a solution infeasible that was set on a int+-1/2 bound |
| Property | int |
Undocumented |
| Method | _set |
return in place modified bounds |
| Instance Variable | _has |
Undocumented |
| Instance Variable | _int |
the mask will be set from int_indices for coding convenience |
| Instance Variable | _lower |
Undocumented |
| Instance Variable | _print |
Undocumented |
| Instance Variable | _record |
Undocumented |
| Instance Variable | _upper |
Undocumented |
round values of int-variables in solution_list and correct for bias.
Return solution_list, however assignment is deprecated as
solution_list is changed in place and, in particular, because we
center usually only the first half of the population.
Variables are only rounded if their rounded value is different from the mean. Bias correction is only applied if the rounded value is the same as the rounded value of the mean and only towards the rounded value of the mean, not away from it.
None of these changes change the rounded variable value.
Details: The bias correction could be applied directly to the mean after the mean update, as it probably does not have any relevant effect on the C update. This would require another call or passing the Delta mean in the return value.
int_indices can also be a CMAEvolutionStrategy or CMAOptions instance.
correct_bias can be in [0, 1] indicating the fraction of the bias
that should be corrected (but only up to the mean center).
repair_into_bounds repairs all solutions before centering is
applied. This does not guaranty solutions to be feasible after
centering in the case when np.round can make a solution
infeasible.
Details: When the bias computation and correction is applied only
to the better half of the population (as by default), the value of
correct_bias must be smaller than 1 to move the mean toward a
solution that has rank lambda/5 or worse, because w_{lambda/5}
equals roughly 1/mu (w_{lambda/3} equals roughly
1/mu/2).
change es.pop_sorted and update es.mean accordingly.
Not in use, as this must be ideally done in the middle of tell,
that is, neither before nor after tell.
return lower bounds of dimension dimension or a scalar.
dimension remains the dimension from the first call unless
the _lower_bounds attribute is reset to None.
DEPRECATED (experimental and outdated) round values of int-variables in solution_list and reduce bias to the mean
center (round) values of int-variables of solutions in solution_list.
Elements of solution_list must accept boolean indexing like np.arrays.
Values are centered iff the centered value differs from the
centered mean. If correct_bias, the introduced bias is amended by
changing the other (noncentered) coordinates towards their
int-center (which is the int-center of the mean) too, up to the
fraction correct_bias.
CAVEAT/TODO: the bias correction currently doesn't check bounds,
hence it may push feasible solutions out-of-bounds by (i) centering
single solutions and (ii) shifting coordinates towards their
centered value during bias correction. In itself and overall, this
may not be a problem, in particular when repair is applied before
or after calling method2.
set values of int-variables of solutions of solution_list into bounds.
Elements of solution_list are changed in place after passing them
through np.asarray and solution_list is changed in place too.
When randomized is True sample the value uniformly between the bound and the value center (the rounded bound) when the latter is feasible.
return upper bounds of dimension dimension or a scalar.
dimension remains the dimension from the first call unless
the _upper_bounds attribute is reset to None.
absolute and relative epsilon offset on the bounds such that np.round should never make a solution infeasible that was set on a int+-1/2 bound