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.
The callable class instance changes a population of solutions in place. This assumes that int-variables change the fitness only if their rounded (genotype) value change (which may be wrong if a geno-pheno transformation is applied). The class corrects for the bias introduced by the rounding.
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
.
This class has no dynamically changing state variables!
When integer variable indices are given with the
'integer_variables' option, an IntegerCentering
class instance is
called in cma.CMAEvolutionStrategy.tell
with (genotypic) solutions
like int_centering(self.pop_sorted[:self.sp.weights.mu], self.mean)
before the CMA update of the state variables. 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 cma.CMAOptions
.
Pseudocode usage hints:
>> es = cma.CMA(...) >> ic = cma.integer_centering.IntegerCentering(es) >> [...] >> ic(es.pop_sorted[0:es.sp.weights.mu], es.mean) # before the mean update, use es.mean_old after >> es.mean = np.dot(es.sp.weights.positive_weights, # (re-)assign mean .. es.pop_sorted[0:es.sp.weights.mu])
Pseudocode example via ask-and-tell:
>> es = cma.CMA(...) # set integer_variables option here >> ic = cma.integer_centering.IntegerCentering(es) # read integer_variables >> while not es.stop(): >> X = es.ask() >> F = [fun(x) for x in X] >> ic([X[i] for i in np.argsort(F)[:es.sp.weights.mu]], es.mean) >> es.tell(X, F) >> es.logger.add() >> es.disp()
Working code example:
>>> 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.CMA([2, 0.1], 0.22, {'integer_variables': [0], ... 'tolfun': 0, 'tolfunhist': 0, 'tolflatfitness': 60, 'verbose': -9}) >>> _ = es.optimize(int1_sphere) >>> assert int1_sphere(es.mean) < 1e-6, es.stop()
Details: The default method2
was used in the below reference and, as
of version 4.0.0, is activated in cma.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 ideally without bias to the mean |
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 | 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 |
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