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