00001
00020 #include "cmaes.h"
00021 #include "cmaesb.h"
00022 #include <realea/common/distance.h>
00023 #include <algorithm>
00024 #include <cassert>
00025
00026 using namespace realea;
00027 using namespace realea::internal;
00028
00029 class ProblemEvalReal : public IEvalReal {
00030 public:
00031 ProblemEvalReal(IEval* eval) : m_eval(eval) {
00032 }
00033
00034 double eval(Real *sol, unsigned n) {
00035 tChromosomeReal solv(n);
00036
00037 for (unsigned i = 0; i < n; i++) {
00038 solv[i] = sol[i];
00039 }
00040 return m_eval->eval(solv);
00041 }
00042
00043 private:
00044 IEval *m_eval;
00045 };
00046
00047 void copySol(const Real *ini, const Real *fin, tChromosomeReal &sol) {
00048 const Real *p;
00049 unsigned i;
00050
00051 for (i = 0, p = ini; p != fin; ++p, ++i) {
00052 sol[i] = *p;
00053 }
00054
00055 }
00056
00057 typedef vector<tGen> DistVector;
00058
00059 class CMAESParams : public ILSParameters {
00060 public:
00061 MyMatrix B;
00062 MyMatrix BD;
00063
00064 MyMatrix C;
00065 DiagonalMatrix D;
00066 int m_N;
00067
00068
00069 ColumnVector pc;
00070
00071 ColumnVector ps;
00072
00073 ColumnVector sigma;
00074
00075 CMAESParams(int N, ColumnVector &psigma) : B(N,N), BD(N,N), C(N,N), D(N), pc(N), ps(N), sigma(N) {
00076 m_N = N;
00077 reset(psigma);
00078 }
00079
00080 void reset(ColumnVector &sigma) {
00081 B = eye(m_N);
00082 D << eye(m_N);
00083 BD = (B*D);
00084 C = (BD* BD.t());
00085 pc = 0;
00086 ps = 0;
00087 this->sigma = sigma;
00088 }
00089
00090 };
00091
00092 MyReturnMatrix randn(Random *m_random, int fil,int col) {
00093 int total = fil*col;
00094 double data[total];
00095 MyMatrix R(fil,col);
00096 int i;
00097
00098 for (i = 0; i < total; i++) {
00099 data[i] = m_random->normal(1);
00100 }
00101
00102 R <<data;
00103 R.Release();
00104 return R;
00105 }
00106
00107
00108
00109 CMAES::CMAES(void) : m_debug(false) {
00110 m_pop = NULL;
00111 m_rfactor = 0;
00112 m_nfactor = 0;
00113 }
00114
00122 void getRange(DomainRealPtr domain, vector<tGen> *range) {
00123 tReal min, max;
00124 unsigned ndim = domain->getDimension();
00125
00126 for (unsigned i = 0; i < ndim; i++) {
00127 domain->getValues(0, &min, &max);
00128 (*range)[i] = max-min;
00129 }
00130 }
00131
00132
00133 double getMean(DomainRealPtr domain) {
00134 double sum;
00135 tReal min, max;
00136 unsigned ndim = domain->getDimension();
00137
00138 for (unsigned i = 0; i < ndim; i++) {
00139 domain->getValues(0, &min, &max);
00140 sum += (max-min);
00141 }
00142
00143 return sum/ndim;
00144 }
00145
00146 void CMAES::searchRange(double factor) {
00147 assert(factor > 0 && factor <= 1);
00148 m_rfactor = factor;
00149 }
00150
00151 void CMAES::searchNeighborhood(double factor) {
00152 assert(factor > 0 && factor <= 1);
00153 m_rfactor = factor;
00154 }
00155
00156
00157 ILSParameters *CMAES::getInitOptions(tChromosomeReal &sol) {
00158 unsigned N = sol.size();
00159 DistVector dist(N);
00160 ColumnVector sigma(N);
00161
00162 if (m_nfactor) {
00163 if (m_pop == NULL) {
00164 throw ConfigException("CMAES::Population");
00165 }
00166
00167 min_vector_distance(sol, m_pop, dist);
00168 copyToColumn(dist, &sigma);
00169 sigma *= m_nfactor;
00170 }
00171 else if (m_rfactor) {
00172 DomainRealPtr domain = m_problem->getDomain();
00173 vector<tGen> range(N);
00174 getRange(domain, &range);
00175 copyToColumn(range, &sigma);
00176 sigma *= m_rfactor;
00177 }
00178 return new CMAESParams(m_problem->getDimension(), sigma);
00179 }
00180
00181 unsigned CMAES::apply(ILSParameters *opt, tChromosomeReal &sol, double &fitness, unsigned itera) {
00182 ColumnVector better;
00183 CMAESParams *params = (CMAESParams *) opt;
00184 double fit_better, fit_actual;
00185
00186 int N = m_problem->getDimension();
00187 unsigned maxeval = itera;
00188 DomainRealPtr domain = m_problem->getDomain();
00189
00190
00191 IEvalReal *eval = new ProblemEvalReal(m_eval);
00192
00194 CMAESBound bound(eval, domain);
00195
00196
00197 ColumnVector xmean(N);
00198
00199 copyToColumn(sol, &xmean);
00200
00201 better = xmean;
00202 fit_better = fitness;
00203
00204 int stopeval = maxeval;
00205
00206
00207 int lambda=4+(int)floor(3*log(N));
00208 int mu = (int) floor(lambda/2.0);
00209
00210
00211 int arindex[lambda];
00212 int arindex_raw[lambda];
00213
00214
00215 ColumnVector weights(mu);
00216 int i;
00217
00218 for (i = 1; i <= mu; i++) {
00219 weights[i-1] = log(mu+1) - log(i);
00220 }
00221
00222 double mueff=pow2(weights.Sum())/pow2(weights).Sum();
00223
00224 if (m_debug) {
00225 cout <<"xmean: \n" <<xmean <<endl;
00226 cout <<"C: \n" <<params->C <<endl;
00227 cout <<"B: \n" <<params->B <<endl;
00228 cout <<"sigma: " <<params->sigma <<endl;
00229 cout <<"Lambda: " <<lambda <<endl;
00230 cout <<"Mu: " <<mu <<endl;
00231 cout <<"Weights: \n" <<weights <<endl;
00232 cout <<"mueff " <<mueff <<endl;
00233 }
00234
00235
00236 double cc = 4.0/(N+4.0);
00237 double cs = (mueff+2)/(N+mueff+3);
00238 double mucov = mueff;
00239 double ccov = (1/mucov) * 2/pow2(N+1.4) + (1-1/mucov)
00240 *((2*mueff-1)/(pow2(N+2)+2*mueff));
00241
00242 double damps = 1 + 2*max(0.0, sqrt((mueff-1)/(N+1))-1) + cs;
00243
00244 if (m_debug) {
00245 cout <<"cc: " <<cc <<endl;
00246 cout <<"cs: " <<cs <<endl;
00247 cout <<"ccov: " <<ccov <<endl;
00248 cout <<"damps: " <<damps <<endl;
00249 }
00250
00251 DiagonalMatrix DiagZeros(N);
00252 DiagZeros = 0;
00253
00254 double chiN=sqrt(N)*(1-1/(4.0*N)+1/(21.0*pow2(N)));
00255
00256
00257
00258 weights = weights/weights.Sum();
00259
00260 if (m_debug) {
00261 cout <<" C : \n" <<params->C <<endl;
00262 cout <<"chiN : " <<chiN <<endl;
00263 cout <<"weights : \n" <<weights <<endl;
00264 }
00265
00266
00267
00268 int counteval = 0;
00269 RowVector arfitness(lambda);
00270 RowVector arfitness_sel(lambda);
00271 RowVector arfitness_raw(lambda);
00272 MyMatrix arx(N,lambda);
00273 MyMatrix arxvalid(N,lambda);
00274 Matrix arx_bests(N,mu);
00275 Matrix arz_bests(N,mu);
00276
00277
00278 bool last = false;
00279 int countiter = 0;
00280
00281 while (counteval+lambda < stopeval && !m_running->isFinish() && !last
00282
00283 ) {
00284 countiter += 1;
00285
00286 MyMatrix arz = randn(m_random,N,lambda);
00287
00288 if (m_debug) {
00289 cout <<"randn:\n" <<arz <<endl;
00290 cout <<"xmean:\n" <<xmean <<endl;
00291 cout <<"sigma:\n" <<params->sigma <<endl;
00292 cout <<"BD:\n" <<params->BD <<endl;
00293 }
00294
00295 int k;
00296
00297
00298 bound.setParam(lambda, mueff, params->sigma, params->C);
00299
00300 for (k = 1; k <= lambda && counteval < stopeval; k++) {
00301 ColumnVector arx_k = xmean+DotVectors(params->sigma, (params->BD*arz.Column(k)));
00302 arx.Column(k) <<arx_k;
00303 counteval += 1;
00304 }
00305
00306
00307 if (k < lambda) {
00308 lambda = min(k,lambda);
00309 last = true;
00310 }
00311
00312
00313
00314
00315 bound.evalSols(xmean, arx, arxvalid, arfitness_raw, arfitness_sel);
00316
00317 arfitness = arfitness_sel;
00318
00319 if (counteval == stopeval) {
00320 last = true;
00321 }
00322
00323 if (m_debug) {
00324 cout <<"arz :\n" <<arz <<endl;
00325 cout <<"arx :\n" <<arx <<endl;
00326 cout <<"arxvalid :\n" <<arxvalid <<endl;
00327 cout <<" arfitness :\n" <<arfitness <<endl;
00328 }
00329
00330 range(1, lambda, arindex);
00331 set_sort_matrix(&arfitness);
00332 partial_sort(arindex, arindex+mu, arindex+lambda, sort_index_matrix);
00333
00334 range(1, lambda, arindex_raw);
00335 set_sort_matrix(&arfitness_raw);
00336 partial_sort(arindex_raw, arindex_raw+1, arindex_raw+lambda, sort_index_matrix);
00337
00338
00339
00340 int newbest = arindex_raw[0];
00341
00342 if (m_debug) {
00343 cout <<"arfitness[newbest]" <<arfitness_raw[newbest-1] <<endl;
00344 }
00345
00346 fit_actual = arfitness_raw[newbest-1];
00347
00348 if (m_running->isBetter(fit_actual, fit_better)) {
00349 fit_better = fit_actual;
00350 better = arxvalid.Column(newbest);
00351 }
00352
00353 if (last) {
00354 copySol(better.Store(), better.Store()+N, sol);
00355 fitness = fit_better;
00356 return counteval;
00357 }
00358
00359
00360 int posconv = (int) ceil(1.0+lambda/4.0);
00361
00362 if (arfitness[arindex[0]-1] == arfitness[arindex[posconv]-1]) {
00363
00364
00365 params->sigma *= exp(0.2+cs/damps);
00366 }
00367
00368
00369
00370
00371 getColumns(arxvalid, arindex, mu, arx_bests);
00372 getColumns(arz, arindex, mu, arz_bests);
00373
00374 xmean = arx_bests*weights;
00375 MyMatrix zmean = arz_bests*weights;
00376
00377 params->ps = (1-cs)*params->ps + sqrt(cs*(2-cs)*mueff) * (params->B * zmean);
00378
00379 double hsig = norm(params->ps)/pow(sqrt(1-(1-cs)), ((2.0*counteval)/lambda))/chiN < 1.5 + 1/(N+1);
00380
00381 params->pc = (1-cc)*params->pc + hsig * sqrt(cc*(2-cc)*mueff) * (params->B * params->D * zmean);
00382
00383 if (m_debug) {
00384 cout <<"arx_bests\n" <<arx_bests <<endl;
00385 cout <<"arz_bests\n" <<arz_bests <<endl;
00386 cout <<"new xmean:\n" <<xmean <<endl;
00387 cout <<"zmean:\n" <<zmean <<endl;
00388 cout <<"ps:\n" <<params->ps <<endl;
00389 cout <<"hsig:\n" <<hsig <<endl;
00390 cout <<"pc:\n" <<params->pc <<endl;
00391 }
00392
00393
00394 params->C = (1-ccov) * params->C
00395 + ccov * (1/mucov) * (params->pc*params->pc.t()
00396 + (1-hsig) * cc*(2-cc) * params->C)
00397 + ccov * (1-1/mucov)
00398 * (params->B*params->D*arz_bests)
00399 * weights.AsDiagonal() * (params->BD*arz_bests).t();
00400
00401 if (m_debug) {
00402 cout <<"C:\n" <<params->C <<endl;
00403 }
00404
00405
00406 params->sigma = params->sigma * exp((cs/damps)*(norm(params->ps)/chiN - 1));
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419 UpperTriangularMatrix triu,triu1;
00420
00421 triu << params->C; triu1 <<params->C;
00422 triu1.Inject(DiagZeros);
00423
00424 if (m_debug) {
00425 cout <<"triu:\n" <<triu <<endl;
00426 cout <<"triu1:\n" <<triu1 <<endl;
00427 }
00428
00429 params->C = triu+triu1.t();
00430
00431 SymmetricMatrix S(N);
00432 S <<params->C;
00433
00434 if (m_debug) {
00435 cout <<"C:\n" <<params->C <<endl;
00436 cout <<"S:\n" <<S <<endl;
00437 }
00438
00439 EigenValues(S,params->D,params->B);
00440
00441 if (m_debug) {
00442 cout <<"sigma:\n" <<params->sigma <<endl;
00443 cout <<"C:\n" <<params->C <<endl;
00444 cout <<"B: \n" <<params->B <<endl;
00445 cout <<"D: \n" <<params->D <<endl;
00446 }
00447
00448
00449 checkDiag(params->C, params->D);
00450
00451 params->D << sqrt(params->D);
00452
00453 if (m_debug) {
00454 cout <<"Sqrt D: \n" <<params->D <<endl;
00455 cout <<counteval <<": " <<arfitness[newbest-1] <<endl;
00456 }
00457
00458 params->BD = (params->B*params->D);
00459
00460
00461 checkAxis(xmean, ccov, cs, damps, countiter, params->sigma, params->C, params->BD);
00462 }
00463
00464 if (m_debug) {
00465 cout <<"xmean: \n" <<xmean <<endl;
00466 cout <<"better: \n" <<better <<endl;
00467 cout <<"C: \n" <<params->C <<endl;
00468 cout <<"B: \n" <<params->B <<endl;
00469 cout <<"sigma: " <<params->sigma <<endl;
00470 }
00471
00472 copySol(better.Store(), better.Store()+N, sol);
00473 fitness = fit_better;
00474
00475 if (eval)
00476 delete eval;
00477
00478 return counteval;
00479 }
00480