CODeME
boundary_transformation.h
1 /*
2  * INTERFACE: the relevant functions are
3  *
4  * * cmaes_boundary_transformation_init(this, l_bound, u_bound, len)
5  * * cmaes_boundary_transformation_exit(this)
6  * * cmaes_boundary_transformation(this, x, y, len)
7  *
8  * implements a smooth mapping double *x -> double *y that guarantees
9  * elements of y to be within specified boundaries. The mapping is piecewise
10  * either linear or quadratic and can achieve values arbitrarily close to and
11  * on the boundaries. The middle of the domain l_bound + (u_bound-l_bound) / 2.0
12  * always maps to itself. Typically, 90% of feasible values (those not close
13  * to the boundaries) are mapped to themselves, preventing any numerical subtleties.
14  * Specifically, al, au > 0 are internally chosen offsets. The mapping
15  * [l_bound - al, u_bound + au] <-> [l_bound, u_bound] is monotonous, bijective
16  * and invertible. It is the identity within [l_bound + al, u_bound - au] and
17  * quadratic for [l_bound - 3*al, l_bound + al] (with l_bound - al -> l_bound)
18  * and for [u_bound - au, u_bound + 3*au] (with u_bound + au -> u_bound).
19  *
20  * The method is robust against very small/large boundary values, say
21  * -1e99 and/or 1e99, to emulated unbounded variables. In this case values
22  * between -1e98 and 1e98 are never changed, i.e. mapped to itself.
23  *
24  */
25 
26 typedef struct {
27  double const *lower_bounds; /* array of size len_of_bounds */
28  double const *upper_bounds; /* array of size len_of_bounds */
29  unsigned long len_of_bounds; /* in case, last value is recycled */
30  double *al; /* "add"-on to lower boundary preimage, same length as bounds */
31  double *au; /* add-on to upper boundary preimage, same length as bounds */
33 
34 /* set lower and upper bounds, the values lower_bounds[len_of_bounds - 1] and
35  * upper_bounds[len_of_bounds - 1] are recycled for any element >= len_of_bounds.
36  * If len_of_bounds == 0, no bounds are assumed. If len_of_bounds == 1, the
37  * zero pointer is allowed for lower_bounds or upper_bounds and indicates no
38  * respective bounds. "no bounds" is "emulated" using the very small/large value
39  * of DBL_MAX / -1e2 and DBL_MAX / 1e2, respectively. */
40 void cmaes_boundary_transformation_init(cmaes_boundary_transformation_t *,
41  double const *lower_bounds, double const *upper_bounds, unsigned long len_of_bounds);
42 
43 /* release memory */
44 void cmaes_boundary_transformation_exit(cmaes_boundary_transformation_t *);
45 
46 /* on return, y is guaranteed to have all values within the boundaries.
47  * The caller inputs x and is responsible for having allocated y in that
48  * y[len-1] = x[len-1] is a valid operation. x==y is valid input, but
49  * will fail together with cmaes when x is an element of the population
50  * returned by cmaes_SamplePopulation (these elements are of type
51  * double const * for a reason).
52  * */
53 void cmaes_boundary_transformation(cmaes_boundary_transformation_t *,
54  double const *x, double *y, unsigned long len); /* new value into y */
55 
56 /* after
57  * cmaes_boundary_transformation(b,x,y,l) ;
58  * the two consecutive calls
59  * cmaes_boundary_transformation_inverse(b,y,x,l) ; cmaes_boundary_transformation(b,x,y,l) ;
60  * have no effect on y anymore (but they might change x!).
61  * */
62 void cmaes_boundary_transformation_inverse(cmaes_boundary_transformation_t *t,
63  double const *y, double *x, unsigned long len); /* new value into x */
64 
65 /* used by function cmaes_boundary_transformation. After applying the shift,
66  * cmaes_boundary_transformation_shift_into_feasible_preimage(b,x,x,l)
67  * the two consecutive calls
68  * cmaes_boundary_transformation(b,x,y,l) ; cmaes_boundary_transformation_inverse(b,y,x,l) ;
69  * have no effect on x anymore */
70 void cmaes_boundary_transformation_shift_into_feasible_preimage(cmaes_boundary_transformation_t *t,
71  double const *x, double *x_shifted, unsigned long len); /* new value into x_shifted */
72 
73 
Definition: boundary_transformation.h:26