# CMAParams.cpp

    00001
    00002 /*
    00003  * C++ification of Nikolaus Hansen's original C-source code for the
    00004  * CMA-ES
    00005  *
    00006  * C++-ificiation performed by Maarten Keijzer (C) 2005. Licensed under
    00007  * the LGPL. Original copyright of Nikolaus Hansen can be found below
    00008  *
    00009  *
    00010  *
    00011  */
    00012
    00013 /* --------------------------------------------------------- */
    00014 /* --------------------------------------------------------- */
    00015 /* --- File: cmaes.c  -------- Author: Nikolaus Hansen   --- */
    00016 /* --------------------------------------------------------- */
    00017 /*
    00018  *      CMA-ES for non-linear function minimization.
    00019  *
    00020  *           Copyright (C) 1996, 2003  Nikolaus Hansen.
    00021  *           e-mail: hansen@bionik.tu-berlin.de
    00022  *
    00023  *           This library is free software; you can redistribute it and/or
    00024  *           modify it under the terms of the GNU Lesser General Public
    00025  *           License as published by the Free Software Foundation; either
    00026  *           version 2.1 of the License, or (at your option) any later
    00027  *           version (see http://www.gnu.org/copyleft/lesser.html).
    00028  *
    00029  *           This library is distributed in the hope that it will be useful,
    00030  *           but WITHOUT ANY WARRANTY; without even the implied warranty of
    00031  *           MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00032  *           Lesser General Public License for more details.
    00033  *
    00034  *                                                             */
    00035 /* --- Changes : ---
    00036  *   03/03/21: argument const double *rgFunVal of
    00037  *   cmaes_ReestimateDistribution() was treated incorrectly.
    00038  *   03/03/29: restart via cmaes_resume_distribution() implemented.
    00039  *   03/03/30: Always max std dev / largest axis is printed first.
    00040  *   03/08/30: Damping is adjusted for large mueff.
    00041  *   03/10/30: Damping is adjusted for large mueff always.
    00042  *   04/04/22: Cumulation time and damping for step size adjusted.
    00043  *   No iniphase but conditional update of pc.
    00044  *   Version 2.23.
    00045  *                               */
    00046
    00047 #include <es/CMAParams.h>
    00048 #include <utils/eoParser.h>
    00049
    00050 #include <string>
    00051
    00052 using namespace std;
    00053
    00054 namespace eo {
    00055
    00056 CMAParams::CMAParams(eoParser& parser, unsigned dimensionality) {
    00057
    00058     string section = "CMA parameters";
    00059
    00060     n = parser.createParam(dimensionality, "dimensionality", "Dimensionality (N) of the problem", 'N', section, dimensionality == 0).value();
    00061
    00062     maxgen = parser.createParam(
    00063             1000,
    00064             "max-gen",
    00065             "Maximum number of generations that the system will run (needed for damping)",
    00066             'M',
    00067             section).value();
    00068
    00069
    00070     if (n == 0) {
    00071         return;
    00072     }
    00073
    00074     defaults(n, maxgen);
    00075
    00076     /* handle lambda */
    00077     lambda = parser.createParam(
    00078             lambda,
    00079             "lambda",
    00080             "Number of offspring",
    00081             'l',
    00082             section).value();
    00083
    00084     if (lambda < 2) {
    00085         lambda = 4+(int)(3*log((double) n));
    00086         cerr << "Too small lambda specified, setting it to " << lambda << endl;
    00087     }
    00088
    00089     /* handle mu */
    00090     mu = parser.createParam(
    00091             mu,
    00092             "mu",
    00093             "Population size",
    00094             'm',
    00095             section).value();
    00096
    00097     if (mu >= lambda) {
    00098         mu = lambda/2;
    00099         cerr << "Mu set larger/equal to lambda, setting it to " << mu << endl;
    00100     }
    00101
    00102     /* handle selection weights */
    00103
    00104     int weight_type = parser.createParam(
    00105             0,
    00106             "weighting",
    00107             "Weighting scheme (for 'selection'): 0 = logarithmic, 1 = equal, 2 = linear",
    00108             'w',
    00109             section).value();
    00110
    00111     switch (weight_type) {
    00112         case 1:
    00113             {
    00114                 for (unsigned i = 0; i < weights.size(); ++i) {
    00115                     weights[i] = mu - i;
    00116                 }
    00117             }
    00118         case 2:
    00119             {
    00120                 weights = 1.;
    00121             }
    00122         default :
    00123             {
    00124                 for (unsigned i = 0; i < weights.size(); ++i) {
    00125                     weights[i] = log(mu+1.)-log(i+1.);
    00126                 }
    00127             }
    00128
    00129     }
    00130
    00131     /* Normalize weights and set mu_eff */
    00132     double sumw = weights.sum();
    00133     mueff =  sumw * sumw / (weights * weights).sum();
    00134     weights /= sumw;
    00135
    00136
    00137     /* most of the rest depends on mu_eff, so needs to be set again */
    00138
    00139     /* set the others using Nikolaus logic. If you want to tweak, you can parameterize over these defaults */
    00140     mucov = mueff;
    00141     ccumsig = (mueff + 2.) / (n + mueff + 3.);
    00142     ccumcov = 4. / (n + 4);
    00143
    00144     double t1 = 2. / ((n+1.4142)*(n+1.4142));
    00145     double t2 = (2.*mucov-1.) / ((n+2.)*(n+2.)+mucov);
    00146     t2 = (t2 > 1) ? 1 : t2;
    00147     t2 = (1./mucov) * t1 + (1.-1./mucov) * t2;
    00148
    00149     ccov = t2;
    00150
    00151     damp = 1 + std::max(0.3,(1.-(double)n/(double)maxgen))
    00152               * (1+2*std::max(0.,sqrt((mueff-1.)/(n+1.))-1)) /* limit sigma increase */
    00153                     / ccumsig;
    00154
    00155     vector<double> mins(1,0.0);
    00156     mins = parser.createParam(
    00157             mins,
    00158             "min-stdev",
    00159             "Array of minimum stdevs, last one will apply for all remaining axes",
    00160             0,
    00161             section).value();
    00162
    00163     if (mins.size() > n) mins.resize(n);
    00164
    00165     if (mins.size()) {
    00166         minStdevs = mins.back();
    00167         for (unsigned i = 0; i < mins.size(); ++i) {
    00168             minStdevs[i] = mins[i];
    00169         }
    00170     }
    00171
    00172     vector<double> inits(1,0.3);
    00173     inits = parser.createParam(
    00174             inits,
    00175             "init-stdev",
    00176             "Array of initial stdevs, last one will apply for all remaining axes",
    00177             0,
    00178             section).value();
    00179
    00180     if (inits.size() > n) inits.resize(n);
    00181
    00182     if (inits.size()) {
    00183         initialStdevs = inits.back();
    00184         for (unsigned i = 0; i < inits.size(); ++i) {
    00185             initialStdevs[i] = inits[i];
    00186         }
    00187     }
    00188
    00189 }
    00190
    00191 void CMAParams::defaults(unsigned n_, unsigned maxgen_) {
    00192     n = n_;
    00193     maxgen = maxgen_;
    00194
    00195     lambda = 4+(int)(3*log((double) n));
    00196     mu = lambda / 2;
    00197
    00198     weights.resize(mu);
    00199
    00200     for (unsigned i = 0; i < weights.size(); ++i) {
    00201         weights[i] = log(mu+1.)-log(i+1.);
    00202     }
    00203
    00204     /* Normalize weights and set mu_eff */
    00205     double sumw = weights.sum();
    00206     mueff =  sumw * sumw / (weights * weights).sum();
    00207     weights /= sumw;
    00208
    00209     mucov = mueff;
    00210     ccumsig *= (mueff + 2.) / (n + mueff + 3.);
    00211     ccumcov = 4. / (n + 4);
    00212
    00213     double t1 = 2. / ((n+1.4142)*(n+1.4142));
    00214     double t2 = (2.*mucov-1.) / ((n+2.)*(n+2.)+mucov);
    00215     t2 = (t2 > 1) ? 1 : t2;
    00216     t2 = (1./mucov) * t1 + (1.-1./mucov) * t2;
    00217
    00218     ccov = t2;
    00219
    00220     damp = 1 + std::max(0.3,(1.-(double)n/maxgen))
    00221               * (1+2*std::max(0.,sqrt((mueff-1.)/(n+1.))-1)) /* limit sigma increase */
    00222                     / ccumsig;
    00223
    00224     minStdevs.resize(n);
    00225     minStdevs = 0.0;
    00226
    00227     initialStdevs.resize(n);
    00228     initialStdevs = 0.3;
    00229
    00230
    00231 }
    00232
    00233
    00234 }// namespace eo