class documentation

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_int_indices determine integer variable indices from es or es.opts or
Method has_bounds Undocumented
Method lower_bounds 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_bounds return upper bounds of dimension dimension or a scalar.
Instance Variable center Undocumented
Instance Variable int_indices Undocumented
Instance Variable last_changes Undocumented
Instance Variable last_changes_iteration 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_mask Undocumented
Method _set_bounds return in place modified bounds
Instance Variable _has_bounds Undocumented
Instance Variable _int_mask the mask will be set from int_indices for coding convenience
Instance Variable _lower_bounds Undocumented
Instance Variable _print Undocumented
Instance Variable _record Undocumented
Instance Variable _upper_bounds Undocumented
def __call__(self, solution_list, mean):

round values of int-variables in solution_list ideally without bias to the mean

def __init__(self, int_indices, method=2, correct_bias=True, repair_into_bounds=True, **kwargs):

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).

def bound(self, i):

return lower and upper bound on variable i, not in use.

def callback(self, es):

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.

def get_int_indices(self, es_opts_indices=None):

determine integer variable indices from es or es.opts or

a variable index list or self.

def has_bounds(self, which='both'):

Undocumented

def lower_bounds(self, dimension):

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.

def method1(self, solution_list, mean):

DEPRECATED (experimental and outdated) round values of int-variables in solution_list and reduce bias to the mean

def method2(self, solution_list, 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.

def repair(self, solution_list, randomized=True):

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.

def upper_bounds(self, dimension):

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.

center =

Undocumented

int_indices =

Undocumented

last_changes: list =

Undocumented

last_changes_iteration: list =

Undocumented

mahalanobis0: list =

Undocumented

mahalanobis1: list =

Undocumented

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_mask =

Undocumented

def _set_bounds(self, which, bounds):

return in place modified bounds

_has_bounds: bool =

Undocumented

_int_mask =

the mask will be set from int_indices for coding convenience

_lower_bounds =

Undocumented

_print: bool =

Undocumented

_record: bool =

Undocumented

_upper_bounds =

Undocumented