class documentation

Multi-variate normal distribution with zero mean.

Provides methods to sample from and update a multi-variate normal distribution with zero mean and full covariance matrix.

>>> import cma, numpy as np
>>> g = cma.sampler.GaussFullSampler(np.ones(4))
>>> z = g.sample(1)[0]
>>> assert g.norm([1,0,0,0]) == 1
>>> g.update([[1., 0., 0., 0]], [.9])
>>> g.update_now()
>>> assert g.norm([1,0,0,0]) == 1
>>> g.update([[4., 0., 0.,0]], [.5])
>>> g.update_now()
>>> g *= 2
>>> assert cma.utilities.math.Mh.equals_approximately(g.variances[0], 17)
>>> assert cma.utilities.math.Mh.equals_approximately(g.D[-1]**2, 17)

TODO

o Clean up CMAEvolutionStrategy attributes related to sampling (like usage of B, C, D, dC, sigma_vec, these are pretty substantial changes). In particular this should become compatible with any StatisticalModelSampler. Plan: keep B, C, D, dC for the time being as output-info attributes, DONE: keep sigma_vec (55 appearances) as a class.

o combination of sigma_vec and C:
  • update sigma_vec with y (this is wrong: use "z")
  • rescale y according to the inverse update of sigma_vec (as if y is expressed in the new sigma_vec while C in the old)
  • update C with the "new" y.
Parameters
dimension(required) define the dimensionality (attribute dimension) of the normal distribution. If dimension is a vector, it sets the diagonal of the initial covariance matrix.
lazy_update_gap=0is the number of iterations to wait between the O(n^3) updates of the sampler. All values <=1 behave identically.
constant_trace='''arithmetic'/'aeigen' or 'geometric' or 'geigen' (geometric mean of eigenvalues) are available to be constant.
randn=np.random.randnis used to generate N(0,1) numbers.
eigenmethod=np.linalg.eighfunction returning eigenvalues and -vectors of symmetric matrix
Method __imul__ sm *= factor is a shortcut for sm = sm.__imul__(factor).
Method __init__ declarative init, doesn't need to be executed
Method correlation return correlation between variables i and j.
Method inverse_hessian_scalar_correction return scalar correction alpha such that X and f fit to f(x) = (x-mean) (alpha * C)**-1 (x-mean)
Method limit_condition bound condition number to limit by adding eps to the trace.
Method multiply_C multiply self.C with factor updating internal states.
Method norm compute the Mahalanobis norm that is induced by the statistical model / sample distribution, specifically by covariance matrix C. The expected Mahalanobis norm is about sqrt(dimension).
Method reset reset distribution while keeping all other parameters.
Method sample return list of i.i.d. samples.
Method to_correlation_matrix "re-scale" C to a correlation matrix and return the scaling factors as standard deviations.
Method to_linear_transformation return associated linear transformation.
Method to_linear_transformation_inverse return inverse of associated linear transformation.
Method transform apply linear transformation C**0.5 to x.
Method transform_inverse apply inverse linear transformation C**-0.5 to x.
Method update update/learn by natural gradient ascent.
Method update_now update internal variables for sampling the distribution with the current covariance matrix C.
Instance Variable B axis lengths, roots of eigenvalues, sorted
Instance Variable C covariance matrix
Instance Variable condition_limit Undocumented
Instance Variable constant_trace Undocumented
Instance Variable count_eigen Undocumented
Instance Variable count_tell Undocumented
Instance Variable D Undocumented
Instance Variable dimension Undocumented
Instance Variable eigenmethod Undocumented
Instance Variable inverse_root_C Undocumented
Instance Variable last_update Undocumented
Instance Variable lazy_update_gap Undocumented
Instance Variable randn Undocumented
Property beta_diagonal_acceleration beta from Algorithm 1 line 16 in https://direct.mit.edu/evco/article/28/3/405/94999/Diagonal-Acceleration-for-Covariance-Matrix
Property condition_number Undocumented
Property corr_condition condition number of the correlation matrix
Property correlation_matrix return correlation matrix of the distribution.
Property covariance_matrix Undocumented
Property variances vector of coordinate-wise (marginal) variances
Method _decompose_C eigen-decompose self.C thereby updating self.B and self.D.
Method _sortBD sort columns of B and D according to the values in D
Method _updateC Undocumented
Instance Variable _beta_diagonal_acceleration Undocumented
Instance Variable _corr_condition Undocumented
Instance Variable _corr_condition_count_eigen Undocumented
Instance Variable _inverse_root_C Undocumented

Inherited from GaussSampler:

Method set_H set Hessian w.r.t. which to compute the eigen spectrum.
Method set_H_by_f set Hessian from f at x0.
Property chin approximation of the expected length when isotropic with variance 1.
Property eigenspectrum return eigen spectrum w.r.t. H like sqrt(H) C sqrt(H)
Instance Variable _left Undocumented
Instance Variable _right Undocumented

Inherited from StatisticalModelSamplerWithZeroMeanBaseClass (via GaussSampler):

Method parameters return dict with (default) parameters, e.g., c1 and cmu.
Instance Variable _lam Undocumented
Instance Variable _mueff Undocumented
Instance Variable _parameters Undocumented
def __imul__(self, factor):

sm *= factor is a shortcut for sm = sm.__imul__(factor).

Multiplies the covariance matrix with factor.

def __init__(self, dimension, lazy_update_gap=0, constant_trace='', condition_limit=None, randn=np.random.randn, eigenmethod=np.linalg.eigh):

declarative init, doesn't need to be executed

def correlation(self, i, j):

return correlation between variables i and j.

def inverse_hessian_scalar_correction(self, mean, sigma, f):

return scalar correction alpha such that X and f fit to f(x) = (x-mean) (alpha * C)**-1 (x-mean)

def limit_condition(self, limit=None):

bound condition number to limit by adding eps to the trace.

This method only changes the sampling distribution, but not the underlying covariance matrix.

We add eps = (a - limit * b) / (limit - 1) to the diagonal variances, derived from limit = (a + eps) / (b + eps) with a, b = lambda_max, lambda_min.

>>> import cma
>>> es = cma.CMAEvolutionStrategy(3 * [1], 1, {'CMA_diagonal_decoding':False, 'verbose':-9})
>>> _ = es.optimize(cma.ff.elli)
>>> assert es.sm.condition_number > 1e4
>>> es.sm.limit_condition(1e4 - 1)
>>> assert es.sm.condition_number < 1e4
def multiply_C(self, factor):

multiply self.C with factor updating internal states.

factor can be a scalar, a vector or a matrix. The vector is used as outer product and multiplied element-wise, i.e., multiply_C(diag(C)**-0.5) generates a correlation matrix.

Details:

def norm(self, x):

compute the Mahalanobis norm that is induced by the statistical model / sample distribution, specifically by covariance matrix C. The expected Mahalanobis norm is about sqrt(dimension).

Example

>>> import cma, numpy as np
>>> sm = cma.sampler.GaussFullSampler(np.ones(10))
>>> x = np.random.randn(10)
>>> d = sm.norm(x)

d is the norm "in" the true sample distribution, sampled points have a typical distance of sqrt(2*sm.dim), where sm.dim is the dimension, and an expected distance of close to dim**0.5 to the sample mean zero. In the example, d is the Euclidean distance, because C = I.

def reset(self, standard_deviations=None):

reset distribution while keeping all other parameters.

If standard_deviations is not given, np.ones is used, which might not be the original initial setting.

def sample(self, number, lazy_update_gap=None, same_length=False):

return list of i.i.d. samples.

Parameters
numberis the number of samples.
lazy_update_gapUndocumented
same_lengthUndocumented
updatecontrols a possibly lazy update of the sampler.
def to_correlation_matrix(self):

"re-scale" C to a correlation matrix and return the scaling factors as standard deviations.

See also: to_linear_transformation.

def to_linear_transformation(self, reset=False):

return associated linear transformation.

If B = sm.to_linear_transformation() and z ~ N(0, I), then np.dot(B, z) ~ Normal(0, sm.C) and sm.C and B have the same eigenvectors. With reset=True, np.dot(B, sm.sample(1)[0]) obeys the same distribution after the call.

See also: to_unit_matrix

def to_linear_transformation_inverse(self, reset=False):

return inverse of associated linear transformation.

If B = sm.to_linear_transformation_inverse() and z ~ Normal(0, sm.C), then np.dot(B, z) ~ Normal(0, I) and sm.C and B have the same eigenvectors. With reset=True, also sm.sample(1)[0] ~ Normal(0, I) after the call.

See also: to_unit_matrix

def transform(self, x):

apply linear transformation C**0.5 to x.

def transform_inverse(self, x):

apply inverse linear transformation C**-0.5 to x.

def update(self, vectors, weights, c1_times_delta_hsigma=0):

update/learn by natural gradient ascent.

The natural gradient used for the update is:

np.dot(weights * vectors.T, vectors)

and equivalently:

sum([outer(weights[i] * vec, vec)
     for i, vec in enumerate(vectors)], axis=0)

Details:

  • The weights include the learning rate and -1 <= sum( weights[idx]) <= 1 must be True for idx = weights > 0 and for idx = weights < 0.
  • The content (length) of vectors with negative weights is changed!
def update_now(self, lazy_update_gap=None):

update internal variables for sampling the distribution with the current covariance matrix C.

This method is O(dim^3) by calling _decompose_C.

If lazy_update_gap is None the lazy_update_gap from init is taken. If lazy_update_gap < 0 the (possibly expensive) update is done even when the model seems to be up to date.

B =

axis lengths, roots of eigenvalues, sorted

C =

covariance matrix

condition_limit =

Undocumented

constant_trace =

Undocumented

count_eigen: int =

Undocumented

count_tell: int =

Undocumented

D =

Undocumented

dimension =

Undocumented

eigenmethod =

Undocumented

inverse_root_C =

Undocumented

last_update =

Undocumented

lazy_update_gap =

Undocumented

randn =

Undocumented

@property
beta_diagonal_acceleration =
@property
corr_condition =

condition number of the correlation matrix

@property
correlation_matrix =

return correlation matrix of the distribution.

@property
variances =

vector of coordinate-wise (marginal) variances

def _decompose_C(self):

eigen-decompose self.C thereby updating self.B and self.D.

self.C is made symmetric.

Know bugs: if update is not called before decompose, the state variables can get into an inconsistent state.

def _sortBD(self):

sort columns of B and D according to the values in D

def _updateC(self):

Undocumented

_beta_diagonal_acceleration: int =

Undocumented

_corr_condition: int =

Undocumented

_corr_condition_count_eigen: int =

Undocumented

_inverse_root_C =

Undocumented