EvolvingObjects
|
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