class documentation

Up to a full quadratic model using the pseudo inverse to compute the model coefficients.

The full model has 1 + 2n + n(n-1)/2 = n(n+3) + 1 parameters. Model building "works" with any number of data.

Model size 1.0 doesn't work well on bbob-f10, 1.1 however works fine.

TODO: change self.types: List[str] to self.type: str with only one entry

>>> import numpy as np
>>> import cma
>>> import cma.fitness_models as fm
>>> # fm.Logger, Logger = fm.LoggerDummy, fm.Logger
>>> m = fm.LQModel()
>>> for i in range(30):
...     x = np.random.randn(3)
...     y = cma.ff.elli(x - 1.2)
...     _ = m.add_data_row(x, y)
>>> assert np.allclose(m.coefficients, [
...   1.44144144e+06,
...  -2.40000000e+00,  -2.40000000e+03,  -2.40000000e+06,
...   1.00000000e+00,   1.00000000e+03,   1.00000000e+06,
...  -4.65661287e-10,  -6.98491931e-10,   1.97906047e-09,
...   ], atol=1e-5)
>>> assert np.allclose(m.xopt, [ 1.2,  1.2,  1.2])
>>> assert np.allclose(m.xopt, [ 1.2,  1.2,  1.2])

Check the same before the full model is build:

>>> m = fm.LQModel()
>>> m.settings.min_relative_size = 3 * m.settings.truncation_ratio
>>> for i in range(30):
...     x = np.random.randn(4)
...     y = cma.ff.elli(x - 1.2)
...     _ = m.add_data_row(x, y)
>>> print(m.types)
['quadratic']
>>> assert np.allclose(m.coefficients, [
...   1.45454544e+06,
...  -2.40000000e+00,  -2.40000000e+02,  -2.40000000e+04, -2.40000000e+06,
...   1.00000000e+00,   1.00000000e+02,   1.00000000e+04,   1.00000000e+06,
...   ])
>>> assert np.allclose(m.xopt, [ 1.2,  1.2,  1.2,  1.2])
>>> assert np.allclose(m.xopt, [ 1.2,  1.2,  1.2,  1.2])

Check the Hessian in the rotated case:

>>> fitness = cma.fitness_transformations.Rotated(cma.ff.elli)
>>> m = fm.LQModel(2, 2)
>>> for i in range(30):
...     x = np.random.randn(4) - 5
...     y = fitness(x - 2.2)
...     _ = m.add_data_row(x, y)
>>> R = fitness[1].dicMatrices[4]
>>> H = np.dot(np.dot(R.T, np.diag([1, 1e2, 1e4, 1e6])), R)
>>> assert np.all(np.isclose(H, m.hessian))
>>> assert np.allclose(m.xopt, 4 * [2.2])
>>> m.set_xoffset([2.335, 1.2, 2, 4])
>>> assert np.all(np.isclose(H, m.hessian))
>>> assert np.allclose(m.xopt, 4 * [2.2])

Check a simple linear case, the optimum is not necessarily at the expected position (the Hessian matrix is chosen somewhat arbitrarily)

>>> m = fm.LQModel()
>>> m.settings.min_relative_size = 4
>>> _ = m.add_data_row([1, 1, 1], 220 + 10)
>>> _ = m.add_data_row([2, 1, 1], 220)
>>> print(m.types)
[]
>>> assert np.allclose(m.coefficients, [80, -10, 80, 80])
>>> assert np.allclose(m.xopt, [22, -159, -159])  # [ 50,  -400, -400])  # depends on Hessian
>>> # fm.Logger = Logger

For results see:

Hansen (2019). A Global Surrogate Model for CMA-ES. In Genetic and Evolutionary Computation Conference (GECCO 2019), Proceedings, ACM.

lq-CMA-ES at http://lq-cma.gforge.inria.fr/ppdata-archives/pap-gecco2019/figure5/

Method __init__ Increase model complexity if the number of data exceeds max(min_relative_size * df_biggest_model_type, self.min_absolute_size).
Method adapt_max_relative_size Undocumented
Method add_data add a sequence of x- and y-data, sorted by y-data (best last)
Method add_data_row add x to self if `force` or x not in self
Method eval return Model value of x
Method evalpop never used, return Model values of x for x in X
Method expand_x Undocumented
Method index Undocumented
Method isin return False if x is not (anymore) in the model archive
Method kendall return Kendall tau between true F-values (Y) and model values.
Method mahalanobis_norm_squared caveat: this can be negative because hessian is not guarantied to be pos def.
Method old_weighted_array return weighted Z, worst entries are clipped if possible.
Method optimize this works very poorly e.g. on Rosenbrock
Method prune prune data depending on size parameters
Method reset Undocumented
Method reset_Z set x-values Z attribute
Method set_xoffset Undocumented
Method sort sort last number entries
Method sorted_weights regression weights in decreasing order
Method type one of the model known_types, depending on self.size.
Method update_type model type/size depends on the number of observed data
Method weighted_array return weighted Z, worst entries are clipped if possible.
Method xmean Undocumented
Class Variable complexity Undocumented
Class Variable known_types Undocumented
Instance Variable count Undocumented
Instance Variable counts Undocumented
Instance Variable F Undocumented
Instance Variable hashes Undocumented
Instance Variable log_eigenvalues Undocumented
Instance Variable logger Undocumented
Instance Variable max_relative_size Undocumented
Instance Variable number_of_data_last_added Undocumented
Instance Variable settings Undocumented
Instance Variable tau Undocumented
Instance Variable type_updates Undocumented
Instance Variable types Undocumented
Instance Variable X Undocumented
Instance Variable Y Undocumented
Instance Variable Z Undocumented
Property b Undocumented
Property coefficients model coefficients that are linear in self.expand(.)
Property current_complexity degrees of freedom (nb of parameters) of the current model
Property dim Undocumented
Property eigenvalues eigenvalues of the Hessian of the model
Property hessian Undocumented
Property logging_trace some data of the current state which may be interesting to display
Property max_df Undocumented
Property max_size Undocumented
Property minY smallest f-values in data queue
Property pinv return Pseudoinverse, computed unconditionally (not lazy).
Property size number of data available to build the model
Property xopt Undocumented
Method _hash Undocumented
Method _prune deprecated
Method _sort old? sort last number entries TODO: for some reason this seems not to pass the doctest
Class Variable _complexities Undocumented
Instance Variable _coefficients_count Undocumented
Instance Variable _current_type Undocumented
Instance Variable _fieldnames Undocumented
Instance Variable _type the model can have several types, for the time being
Instance Variable _xoffset Undocumented
Instance Variable _xopt_count Undocumented
def __init__(self, max_relative_size_init=None, max_relative_size_end=None, min_relative_size=None, max_absolute_size=None, sorted_index=None):

Increase model complexity if the number of data exceeds max(min_relative_size * df_biggest_model_type, self.min_absolute_size).

Limit the number of kept data max(max_absolute_size, max_relative_size * max_df).

def adapt_max_relative_size(self, tau):

Undocumented

def add_data(self, X, Y, prune=True):

add a sequence of x- and y-data, sorted by y-data (best last)

def add_data_row(self, x, f, prune=True, force=False):

add x to self if `force` or x not in self

def eval(self, x):

return Model value of x

def evalpop(self, X):

never used, return Model values of x for x in X

def expand_x(self, x):

Undocumented

def index(self, x):

Undocumented

def isin(self, x):

return False if x is not (anymore) in the model archive

def kendall(self, number, F_model=None):

return Kendall tau between true F-values (Y) and model values.

def mahalanobis_norm_squared(self, dx):

caveat: this can be negative because hessian is not guarantied to be pos def.

def old_weighted_array(self, Z):

return weighted Z, worst entries are clipped if possible.

Z can be a vector or a matrix.

def optimize(self, fitness, x0, evals):

this works very poorly e.g. on Rosenbrock

x, m = Model().optimize(cma.ff.rosen, [0.1, -0.1], 13)

TODO (implemented, next: test): account for xopt not changing.

def prune(self):

prune data depending on size parameters

def reset(self):

Undocumented

def reset_Z(self):

set x-values Z attribute

def set_xoffset(self, offset):

Undocumented

def sort(self, number=None, argsort=np.argsort):

sort last number entries

def sorted_weights(self, number=None):

regression weights in decreasing order

def type(self):

one of the model known_types, depending on self.size.

This may replace types, but is not in use yet.

def update_type(self):

model type/size depends on the number of observed data

def weighted_array(self, Z):

return weighted Z, worst entries are clipped if possible.

Z can be a vector or a matrix.

def xmean(self):

Undocumented

complexity =

Undocumented

known_types =

Undocumented

count: int =

Undocumented

counts =

Undocumented

F =

Undocumented

hashes =

Undocumented

log_eigenvalues =

Undocumented

logger =

Undocumented

max_relative_size =

Undocumented

number_of_data_last_added =

Undocumented

settings =

Undocumented

tau =

Undocumented

type_updates =

Undocumented

types: list =

Undocumented

X =

Undocumented

Y =

Undocumented

Z =

Undocumented

@property
b =

Undocumented

@property
coefficients =

model coefficients that are linear in self.expand(.)

@property
current_complexity =

degrees of freedom (nb of parameters) of the current model

@property
dim =

Undocumented

@property
eigenvalues =

eigenvalues of the Hessian of the model

@property
hessian =

Undocumented

@property
logging_trace =

some data of the current state which may be interesting to display

@property
max_df =

Undocumented

@property
max_size =

Undocumented

@property
minY =

smallest f-values in data queue

@property
pinv =

return Pseudoinverse, computed unconditionally (not lazy).

pinv is usually not used directly but via the coefficients property.

Should this depend on something and/or become lazy?

@property
size =

number of data available to build the model

@property
xopt =

Undocumented

def _hash(self, x):

Undocumented

def _prune(self):

deprecated

def _sort(self, number=None, argsort=np.argsort):

old? sort last number entries TODO: for some reason this seems not to pass the doctest

_complexities =

Undocumented

_coefficients_count: int =

Undocumented

_current_type =

Undocumented

_fieldnames: list[str] =

Undocumented

_type: str =

the model can have several types, for the time being

_xoffset =

Undocumented

_xopt_count: int =

Undocumented