Module cma :: Class BoxConstraintsLinQuadTransformation
[hide private]
[frames] | no frames]

Class BoxConstraintsLinQuadTransformation

source code

                      object --+    
                               |    
BoxConstraintsTransformationBase --+
                                   |
                                  BoxConstraintsLinQuadTransformation

implements a bijective, monotonous transformation between [lb - al, ub + au] and [lb, ub] which is the identity (and therefore linear) in [lb + al, ub - au] (typically about 90% of the interval) and quadratic in [lb - 3*al, lb + al] and in [ub - au, ub + 3*au]. The transformation is periodically expanded beyond the limits (somewhat resembling the shape sin(x-pi/2)) with a period of 2 * (ub - lb + al + au).

Details

Partly due to numerical considerations depend the values al and au on abs(lb) and abs(ub) which makes the transformation non-translation invariant. In contrast to sin(.), the transformation is robust to "arbitrary" values for boundaries, e.g. a lower bound of -1e99 or np.Inf or None.

Examples

Example to use with cma:

>>> import cma
>>> # only the first variable has an upper bound
>>> tf = cma.BoxConstraintsLinQuadTransformation([[1,2], [1,None]]) # second==last pair is re-cycled
>>> cma.fmin(cma.felli, 9 * [2], 1, {'transformation': [tf.transform, tf.inverse], 'verb_disp': 0})
>>> # ...or...
>>> es = cma.CMAEvolutionStrategy(9 * [2], 1)
>>> while not es.stop():
...     X = es.ask()
...     f = [cma.felli(tf(x)) for x in X]  # tf(x) == tf.transform(x)
...     es.tell(X, f)

Example of the internal workings:

>>> import cma
>>> tf = cma.BoxConstraintsLinQuadTransformation([[1,2], [1,11], [1,11]])
>>> tf.bounds
[[1, 2], [1, 11], [1, 11]]
>>> tf([1.5, 1.5, 1.5])
[1.5, 1.5, 1.5]
>>> tf([1.52, -2.2, -0.2, 2, 4, 10.4])
[1.52, 4.0, 2.0, 2.0, 4.0, 10.4]
>>> res = np.round(tf._au, 2)
>>> assert list(res[:4]) == [ 0.15, 0.6, 0.6, 0.6]
>>> res = [round(x, 2) for x in tf.shift_or_mirror_into_invertible_domain([1.52, -12.2, -0.2, 2, 4, 10.4])]
>>> assert res == [1.52, 9.2, 2.0, 2.0, 4.0, 10.4]
>>> tmp = tf([1])  # call with lower dimension
Instance Methods [hide private]
 
__init__(self, bounds)
x is defined in [lb - 3*al, ub + au + r - 2*al] with r = ub - lb + al + au, and x == transformation(x) in [lb + al, ub - au]. beta*x - alphal = beta*x - alphau is then defined in [lb, ub],
source code
 
initialize(self, length=None)
see __init__
source code
 
__call__(self, solution_genotype, copy_if_changed=True, copy_always=False) source code
 
transform(self, solution_genotype, copy_if_changed=True, copy_always=False) source code
 
idx_infeasible(self, solution_genotype)
return indices of "infeasible" variables, that is, variables that do not directly map into the feasible domain such that tf.inverse(tf(x)) == x.
source code
 
is_feasible_i(self, x, i)
return True if value x is in the invertible domain of variable i
source code
 
is_loosely_feasible_i(self, x, i)
never used
source code
 
shift_or_mirror_into_invertible_domain(self, solution_genotype, copy=False)
return the reference solution that has the same box_constraints_transformation(solution) value, i.e. tf.shift_or_mirror_into_invertible_domain(x) = tf.inverse(tf.transform(x)). This is an idempotent mapping (leading to the same result independent how often it is repeatedly applied).
source code
 
_shift_or_mirror_into_invertible_i(self, x, i)
shift into the invertible domain [lb - ab, ub + au], mirror close to boundaries in order to get a smooth transformation everywhere
source code
 
_transform_i(self, x, i)
return transform of x in component i
source code
 
_inverse_i(self, y, i)
return inverse of y in component i
source code

Inherited from BoxConstraintsTransformationBase: bounds_i, inverse

Inherited from object: __delattr__, __format__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __repr__, __setattr__, __sizeof__, __str__, __subclasshook__

Properties [hide private]

Inherited from object: __class__

Method Details [hide private]

__init__(self, bounds)
(Constructor)

source code 

x is defined in [lb - 3*al, ub + au + r - 2*al] with r = ub - lb + al + au, and x == transformation(x) in [lb + al, ub - au]. beta*x - alphal = beta*x - alphau is then defined in [lb, ub],

alphal and alphau represent the same value, but respectively numerically better suited for values close to lb and ub.

Overrides: object.__init__

initialize(self, length=None)

source code 
see __init__
Overrides: BoxConstraintsTransformationBase.initialize

__call__(self, solution_genotype, copy_if_changed=True, copy_always=False)
(Call operator)

source code 
Overrides: BoxConstraintsTransformationBase.__call__

transform(self, solution_genotype, copy_if_changed=True, copy_always=False)

source code 
Overrides: BoxConstraintsTransformationBase.__call__

shift_or_mirror_into_invertible_domain(self, solution_genotype, copy=False)

source code 

return the reference solution that has the same box_constraints_transformation(solution) value, i.e. tf.shift_or_mirror_into_invertible_domain(x) = tf.inverse(tf.transform(x)). This is an idempotent mapping (leading to the same result independent how often it is repeatedly applied).

Details: input solution_genotype is changed. The domain is [lb - al, ub + au] and in [lb - 2*al - (ub - lb) / 2, lb - al] mirroring is applied.

Overrides: BoxConstraintsTransformationBase.shift_or_mirror_into_invertible_domain

_transform_i(self, x, i)

source code 
return transform of x in component i
Overrides: BoxConstraintsTransformationBase._transform_i

_inverse_i(self, y, i)

source code 
return inverse of y in component i
Overrides: BoxConstraintsTransformationBase._inverse_i