From 905cbb7a970f54ebd0ddd49e0ed09e7daad4fb32 Mon Sep 17 00:00:00 2001 From: Erik Strand <erik.strand@cba.mit.edu> Date: Thu, 16 Apr 2020 10:19:40 -0400 Subject: [PATCH] Copy in the reference CMA-ES implementation --- external/CMakeLists.txt | 5 + external/cma-es/CMakeLists.txt | 12 + external/cma-es/cmaes.cpp | 3137 +++++++++++++++++++++++++++++ external/cma-es/cmaes.h | 176 ++ external/cma-es/cmaes_interface.h | 68 + 5 files changed, 3398 insertions(+) create mode 100644 external/cma-es/CMakeLists.txt create mode 100644 external/cma-es/cmaes.cpp create mode 100644 external/cma-es/cmaes.h create mode 100644 external/cma-es/cmaes_interface.h diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index f1f7d5e..651bf92 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -7,6 +7,11 @@ target_include_directories(catch2 INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/catch2) add_library(clara INTERFACE) target_include_directories(clara INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/clara) +# CMA-ES (c-cmaes) +# From https://github.com/CMA-ES/c-cmaes. Not using it as a submodule since their repo isn't +# organized in the most extensible way and I'm compiling it as C++ anyway. +add_subdirectory(cma-es) + # nlohmann JSON add_library(json INTERFACE) target_include_directories(json INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/json) diff --git a/external/cma-es/CMakeLists.txt b/external/cma-es/CMakeLists.txt new file mode 100644 index 0000000..bd63509 --- /dev/null +++ b/external/cma-es/CMakeLists.txt @@ -0,0 +1,12 @@ +add_library(cma-es + cmaes.cpp + cmaes.h + cmaes_interface.h +) +target_include_directories(cma-es PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries(cma-es shared_settings) +# This isn't working, since shared_settings enables this and it seems to take precedence (regardless +# of the order I put things here). +target_compile_options(cma-es PRIVATE -Wno-zero-as-null-pointer-constant) +# At some point I added this, doesn't seem to do anything now but I'll leave it here for a while. +#target_compile_options(cma-es PRIVATE -Wno-stringop-overflow) diff --git a/external/cma-es/cmaes.cpp b/external/cma-es/cmaes.cpp new file mode 100644 index 0000000..a38e1d4 --- /dev/null +++ b/external/cma-es/cmaes.cpp @@ -0,0 +1,3137 @@ +/* --------------------------------------------------------- */ +/* --- File: cmaes.c -------- Author: Nikolaus Hansen --- */ +/* --------------------------------------------------------- */ +/* + CMA-ES for non-linear function minimization. + + Copyright 1996, 2003, 2007, 2013 Nikolaus Hansen + e-mail: hansen .AT. lri.fr + + SOURCE: + https://github.com/cma-es/c-cma-es + https://github.com/cma-es/c-cma-es/blob/master/src/cmaes.c + + LICENSE: this library is free/open software and may be used + either under the + + Apache License 2.0 + + or under the + + GNU Lesser General Public License 2.1 or later + + whichever suits best. + + See also the LICENSE file + https://github.com/cma-es/c-cma-es/blob/master/LICENSE +*/ + +/* --- Changes : --- + 03/03/21: argument const double *rgFunVal of + cmaes_ReestimateDistribution() was treated incorrectly. + 03/03/29: restart via cmaes_resume_distribution() implemented. + 03/03/30: Always max std dev / largest axis is printed first. + 03/08/30: Damping is adjusted for large mueff. + 03/10/30: Damping is adjusted for large mueff always. + 04/04/22: Cumulation time and damping for step size adjusted. + No iniphase but conditional update of pc. + 05/03/15: in ccov-setting mucov replaced by mueff. + 05/10/05: revise comment on resampling in example.c + 05/10/13: output of "coorstddev" changed from sigma * C[i][i] + to correct sigma * sqrt(C[i][i]). + 05/11/09: Numerical problems are not anymore handled by increasing + sigma, but lead to satisfy a stopping criterion in + cmaes_Test(). + 05/11/09: Update of eigensystem and test for numerical problems + moved right before sampling. + 06/02/24: Non-ansi array definitions replaced (thanks to Marc + Toussaint). + 06/02/25: Overflow in time measurement for runs longer than + 2100 seconds. This could lead to stalling the + covariance matrix update for long periods. + Time measurement completely rewritten. + 06/02/26: Included population size lambda as parameter to + cmaes_init (thanks to MT). + 06/02/26: Allow no initial reading/writing of parameters via + "non" and "writeonly" keywords for input parameter + filename in cmaes_init. + 06/02/27: Optimized code regarding time spent in updating the + covariance matrix in function Adapt_C2(). + 07/08/03: clean up and implementation of an exhaustive test + of the eigendecomposition (via #ifdef for now) + 07/08/04: writing of output improved + 07/08/xx: termination criteria revised and more added, + damp replaced by damps=damp*cs, documentation improved. + Interface significantly changed, evaluateSample function + and therefore the function pointer argument removed. + Renaming of functions in accordance with Java code. + Clean up of parameter names, mainly in accordance with + Matlab conventions. Most termination criteria can be + changed online now. Many more small changes, but not in + the core procedure. + 07/10/29: ReSampleSingle() got a better interface. ReSampleSingle() + is now ReSampleSingle_old only for backward + compatibility. Also fixed incorrect documentation. The new + function SampleSingleInto() has an interface similar to + the old ReSampleSingle(), but is not really necessary. + 07/11/20: bug: stopMaxIter did not translate into the correct default + value but into -1 as default. This lead to a too large + damps and the termination test became true from the first + iteration. (Thanks to Michael Calonder) + 07/11/20: new default stopTolFunHist = 1e-13; (instead of zero) + 08/09/26: initial diagonal covariance matrix in code, but not + yet in interface + 08/09/27: diagonalCovarianceMatrix option in initials.par provided + 08/10/17: uncertainty handling implemented in example3.c. + PerturbSolutionInto() provides the optional small + perturbations before reevaluation. + 10/10/16: TestForTermination changed such that diagonalCovarianceMatrix + option now yields linear time behavior + 12/05/28: random seed > 2e9 prohibited to avoid an infinite loop on 32bit systems + 12/10/21: input parameter file values "no", "none" now work as "non". + 12/10/xx: tentative implementation of cmaes_Optimize + 12/10/xx: some small changes with char * mainly to prevent warnings in C++ + 12/10/xx: added some string convenience functions isNoneStr, new_string, assign_string + 13/01/03: rename files example?, initials.par, signals.par + 14/04/29: removed bug, au = t->al[...], from the (new) boundary handling + code (thanks to Emmanuel Benazera for the hint) + 14/06/16: test of un-initialized version number removed (thanks to Paul Zimmermann) + 14/10/18: splitted cmaes_init() into cmaes_init_para() and cmaes_init_final(), + such that parameters can be set also comparatively safely within the + code, namely after calling cmaes_init_para(). The order of parameters +<<<<<<< HEAD + of readpara_init() has changed to be the same as for cmaes_init(). + 14/11/25 fix warnings from Microsoft C compiler (sherm) +======= + of readpara_init() has changed to be the same as for cmaes_init(). + 14/11/26: renamed exported symbols so they begin with a cmaes_prefix. +>>>>>>> bd5aeb2a21fbc437f1b322610022f7cb1ba6a9db + + Wish List + o make signals_filename part of cmaes_t using assign_string() + + o as writing time is measure for all files at once, the display + cannot be independently written to a file via signals.par, while + this would be desirable. + + o clean up sorting of eigenvalues and vectors which is done repeatedly. + + o either use cmaes_Get() in cmaes_WriteToFilePtr(): revise the + cmaes_write that all keywords available with get and getptr are + recognized. Also revise the keywords, keeping backward + compatibility. (not only) for this it would be useful to find a + way how cmaes_Get() signals an unrecognized keyword. For GetPtr + it can return NULL. + + o or break cmaes_Get() into single getter functions, being a nicer + interface, and compile instead of runtime error, and faster. For + file signals.par it does not help. + + o writing data depending on timing in a smarter way, e.g. using 10% + of all time. First find out whether clock() is useful for measuring + disc writing time and then cmaes_timings_t class can be utilized. + For very large dimension the default of 1 seconds waiting might + be too small. + + o allow modification of best solution depending on delivered f(xmean) + + o re-write input and output procedures +*/ + +/* Prevent Microsoft compiler from complaining that common library functions + like strncpy(), ctime(), sprintf(), fopen(), fscanf(), etc. "may be unsafe". + This must come before the first #include. +*/ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include <math.h> /* sqrt() */ +#include <stddef.h> /* size_t */ +#include <stdlib.h> /* NULL, free */ +#include <string.h> /* strlen() */ +#include <stdio.h> /* sprintf(), NULL? */ +#include "cmaes_interface.h" /* <time.h> via cmaes.h */ + +/* --------------------------------------------------------- */ +/* ------------------- Declarations ------------------------ */ +/* --------------------------------------------------------- */ + +/* ------------------- External Visibly -------------------- */ + +/* see cmaes_interface.h for those, not listed here */ + +long cmaes_random_init(cmaes_random_t *, long unsigned seed /* 0==clock */); +void cmaes_random_exit(cmaes_random_t *); +double cmaes_random_Gauss(cmaes_random_t *); /* (0,1)-normally distributed */ +double cmaes_random_Uniform(cmaes_random_t *); +long cmaes_random_Start(cmaes_random_t *, long unsigned seed /* 0==1 */); + +void cmaes_timings_init(cmaes_timings_t *timing); +void cmaes_timings_start(cmaes_timings_t *timing); /* fields totaltime and tictoctime */ +double cmaes_timings_update(cmaes_timings_t *timing); +void cmaes_timings_tic(cmaes_timings_t *timing); +double cmaes_timings_toc(cmaes_timings_t *timing); + +void cmaes_readpara_init (cmaes_readpara_t *, int dim, const double * xstart, + const double * sigma, int seed, int lambda, + const char * filename); +void cmaes_readpara_exit(cmaes_readpara_t *); +void cmaes_readpara_ReadFromFile(cmaes_readpara_t *, const char *szFileName); +void cmaes_readpara_SupplementDefaults(cmaes_readpara_t *); +void cmaes_readpara_SetWeights(cmaes_readpara_t *, const char * mode); +void cmaes_readpara_WriteToFile(cmaes_readpara_t *, const char *filenamedest); + +const double * cmaes_Optimize( cmaes_t *, double(*pFun)(double const *, int dim), + long iterations); +double const * cmaes_SetMean(cmaes_t *, const double *xmean); +double * cmaes_PerturbSolutionInto(cmaes_t *t, double *xout, + double const *xin, double eps); +void cmaes_WriteToFile(cmaes_t *, const char *key, const char *name); +void cmaes_WriteToFileAW(cmaes_t *t, const char *key, const char *name, + const char * append); +void cmaes_WriteToFilePtr(cmaes_t *, const char *key, FILE *fp); +void cmaes_ReadFromFilePtr(cmaes_t *, FILE *fp); +void cmaes_FATAL(char const *s1, char const *s2, + char const *s3, char const *s4); + + +/* ------------------- Locally visibly ----------------------- */ + +static char * getTimeStr(void); +static void TestMinStdDevs( cmaes_t *); +/* static void WriteMaxErrorInfo( cmaes_t *); */ + +static void Eigen( int N, double **C, double *diag, double **Q, + double *rgtmp); +static int Check_Eigen( int N, double **C, double *diag, double **Q); +static void QLalgo2 (int n, double *d, double *e, double **V); +static void Householder2(int n, double **V, double *d, double *e); +static void Adapt_C2(cmaes_t *t, int hsig); + +static void FATAL(char const *sz1, char const *s2, + char const *s3, char const *s4); +static void ERRORMESSAGE(char const *sz1, char const *s2, + char const *s3, char const *s4); +static int isNoneStr(const char * filename); +static void Sorted_index( const double *rgFunVal, int *index, int n); +static int SignOfDiff( const void *d1, const void * d2); +static double douSquare(double); +static double rgdouMax( const double *rgd, int len); +static double rgdouMin( const double *rgd, int len); +static double douMax( double d1, double d2); +static double douMin( double d1, double d2); +static int intMin( int i, int j); +static int MaxIdx( const double *rgd, int len); +static int MinIdx( const double *rgd, int len); +static double myhypot(double a, double b); +static double * new_double( int n); +static void * new_void( int n, size_t size); +static char * new_string( const char *); +static void assign_string( char **, const char*); + +static const char * c_cmaes_version = "3.20.00.beta"; + +/* --------------------------------------------------------- */ +/* ---------------- Functions: cmaes_t --------------------- */ +/* --------------------------------------------------------- */ + +static char * +getTimeStr(void) { + time_t tm = time(NULL); + static char s[33]; + + /* get time */ + strncpy(s, ctime(&tm), 24); /* TODO: hopefully we read something useful */ + s[24] = '\0'; /* cut the \n */ + return s; +} + +char * +cmaes_SayHello(cmaes_t *t) +{ + /* write initial message */ + sprintf(t->sOutString, + "(%d,%d)-CMA-ES(mu_eff=%.1f), Ver=\"%s\", dimension=%d, diagonalIterations=%ld, randomSeed=%d (%s)", + t->sp.mu, t->sp.lambda, t->sp.mueff, t->version, t->sp.N, (long)t->sp.diagonalCov, + t->sp.seed, getTimeStr()); + + return t->sOutString; +} + +/* --------------------------------------------------------- */ +/* --------------------------------------------------------- */ +void +cmaes_init_para(cmaes_t *t, /* "this" */ + int dimension, + double *inxstart, + double *inrgstddev, /* initial stds */ + long int inseed, + int lambda, + const char *input_parameter_filename) +{ + t->version = c_cmaes_version; + cmaes_readpara_init(&t->sp, dimension, inxstart, inrgstddev, inseed, + lambda, input_parameter_filename); +} + +double * +cmaes_init_final(cmaes_t *t /* "this" */) +/* + * */ +{ + int i, j, N; + double dtest, trace; + + if (t->version == NULL) { + ERRORMESSAGE("cmaes_init_final called (probably) without calling cmaes_init_para first", + ", which will likely lead to unexpected results",0,0); + printf("Error: cmaes_init_final called (probably) without calling cmaes_init_para first\n"); + } + if (strcmp(c_cmaes_version, t->version) != 0) { + ERRORMESSAGE("cmaes_init_final called twice, which will lead to a memory leak", + "; use cmaes_exit() first",0,0); + printf("Error: cmaes_init_final called twice, which will lead to a memory leak; use cmaes_exit first\n"); + } + /* assign_string(&t->signalsFilename, "cmaes_signals.par"); */ + + if (!t->sp.flgsupplemented) { + cmaes_readpara_SupplementDefaults(&t->sp); + if (!isNoneStr(t->sp.filename)) /* TODO: should this be done in readpara_SupplementDefaults? */ + cmaes_readpara_WriteToFile(&t->sp, "actparcmaes.par"); + } + + t->sp.seed = cmaes_random_init( &t->rand, (long unsigned int) t->sp.seed); + + N = t->sp.N; /* for convenience */ + + /* initialization */ + for (i = 0, trace = 0.; i < N; ++i) + trace += t->sp.rgInitialStds[i]*t->sp.rgInitialStds[i]; + t->sigma = sqrt(trace/N); /* t->sp.mueff/(0.2*t->sp.mueff+sqrt(N)) * sqrt(trace/N); */ + + t->chiN = sqrt((double) N) * (1. - 1./(4.*N) + 1./(21.*N*N)); + t->flgEigensysIsUptodate = 1; + t->flgCheckEigen = 0; + t->genOfEigensysUpdate = 0; + cmaes_timings_init(&t->eigenTimings); + t->flgIniphase = 0; /* do not use iniphase, hsig does the job now */ + t->flgresumedone = 0; + t->flgStop = 0; + + for (dtest = 1.; dtest && dtest < 1.1 * dtest; dtest *= 2.) + if (dtest == dtest + 1.) + break; + t->dMaxSignifKond = dtest / 1000.; /* not sure whether this is really save, 100 does not work well enough */ + + t->gen = 0; + t->countevals = 0; + t->state = 0; + t->dLastMinEWgroesserNull = 1.0; + t->printtime = t->writetime = t->firstwritetime = t->firstprinttime = 0; + + t->rgpc = new_double(N); + t->rgps = new_double(N); + t->rgdTmp = new_double(N+1); + t->rgBDz = new_double(N); + t->rgxmean = new_double(N+2); t->rgxmean[0] = N; ++t->rgxmean; + t->rgxold = new_double(N+2); t->rgxold[0] = N; ++t->rgxold; + t->rgxbestever = new_double(N+3); t->rgxbestever[0] = N; ++t->rgxbestever; + t->rgout = new_double(N+2); t->rgout[0] = N; ++t->rgout; + t->rgD = new_double(N); + t->C = (double**)new_void(N, sizeof(double*)); + t->B = (double**)new_void(N, sizeof(double*)); + t->publicFitness = new_double(t->sp.lambda); + t->rgFuncValue = new_double(t->sp.lambda+1); + t->rgFuncValue[0]=t->sp.lambda; ++t->rgFuncValue; + t->arFuncValueHist = new_double(10+(int)ceil(3.*10.*N/t->sp.lambda)+1); + t->arFuncValueHist[0] = (double)(10+(int)ceil(3.*10.*N/t->sp.lambda)); + t->arFuncValueHist++; + + for (i = 0; i < N; ++i) { + t->C[i] = new_double(i+1); + t->B[i] = new_double(N); + } + t->index = (int *) new_void(t->sp.lambda, sizeof(int)); + for (i = 0; i < t->sp.lambda; ++i) + t->index[i] = i; /* should not be necessary */ + t->rgrgx = (double **)new_void(t->sp.lambda, sizeof(double*)); + for (i = 0; i < t->sp.lambda; ++i) { + t->rgrgx[i] = new_double(N+2); + t->rgrgx[i][0] = N; + t->rgrgx[i]++; + } + + /* Initialize newed space */ + + for (i = 0; i < N; ++i) + for (j = 0; j < i; ++j) + t->C[i][j] = t->B[i][j] = t->B[j][i] = 0.; + + for (i = 0; i < N; ++i) + { + t->B[i][i] = 1.; + t->C[i][i] = t->rgD[i] = t->sp.rgInitialStds[i] * sqrt(N / trace); + t->C[i][i] *= t->C[i][i]; + t->rgpc[i] = t->rgps[i] = 0.; + } + + t->minEW = rgdouMin(t->rgD, N); t->minEW = t->minEW * t->minEW; + t->maxEW = rgdouMax(t->rgD, N); t->maxEW = t->maxEW * t->maxEW; + + t->maxdiagC=t->C[0][0]; for(i=1;i<N;++i) if(t->maxdiagC<t->C[i][i]) t->maxdiagC=t->C[i][i]; + t->mindiagC=t->C[0][0]; for(i=1;i<N;++i) if(t->mindiagC>t->C[i][i]) t->mindiagC=t->C[i][i]; + + /* set xmean */ + for (i = 0; i < N; ++i) + t->rgxmean[i] = t->rgxold[i] = t->sp.xstart[i]; + /* use in case xstart as typicalX */ + if (t->sp.typicalXcase) + for (i = 0; i < N; ++i) + t->rgxmean[i] += t->sigma * t->rgD[i] * cmaes_random_Gauss(&t->rand); + + if (strcmp(t->sp.resumefile, "_no_") != 0) + cmaes_resume_distribution(t, t->sp.resumefile); + + return (t->publicFitness); + +} /* cmaes_init_final() */ + + +/* --------------------------------------------------------- */ +/* --------------------------------------------------------- */ +double * +cmaes_init(cmaes_t *t, /* "this" */ + int dimension, + double *inxstart, + double *inrgstddev, /* initial stds */ + long int inseed, + int lambda, + const char *input_parameter_filename) +{ + cmaes_init_para(t, dimension, inxstart, inrgstddev, inseed, + lambda, input_parameter_filename); + return cmaes_init_final(t); +} + +/* --------------------------------------------------------- */ +/* --------------------------------------------------------- */ + +#ifdef __GNUC__ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wunused-result" +#endif + +void +cmaes_resume_distribution(cmaes_t *t, char *filename) +{ + int i, j, res, n; + double d; + FILE *fp = fopen( filename, "r"); + if(fp == NULL) { + ERRORMESSAGE("cmaes_resume_distribution(): could not open '", + filename, "'",0); + return; + } + /* count number of "resume" entries */ + i = 0; res = 0; + while (1) { + if ((res = fscanf(fp, " resume %lg", &d)) == EOF) + break; + else if (res==0) + fscanf(fp, " %*s"); + else if(res > 0) + i += 1; + } + + /* go to last "resume" entry */ + n = i; i = 0; res = 0; rewind(fp); + while (i<n) { + if ((res = fscanf(fp, " resume %lg", &d)) == EOF) + FATAL("cmaes_resume_distribution(): Unexpected error, bug",0,0,0); + else if (res==0) + fscanf(fp, " %*s"); + else if(res > 0) + ++i; + } + if (d != t->sp.N) + FATAL("cmaes_resume_distribution(): Dimension numbers do not match",0,0,0); + + /* find next "xmean" entry */ + while (1) { + if ((res = fscanf(fp, " xmean %lg", &d)) == EOF) + FATAL("cmaes_resume_distribution(): 'xmean' not found",0,0,0); + else if (res==0) + fscanf(fp, " %*s"); + else if(res > 0) + break; + } + + /* read xmean */ + t->rgxmean[0] = d; res = 1; + for(i = 1; i < t->sp.N; ++i) + res += fscanf(fp, " %lg", &t->rgxmean[i]); + if (res != t->sp.N) + FATAL("cmaes_resume_distribution(): xmean: dimensions differ",0,0,0); + + /* find next "path for sigma" entry */ + while (1) { + if ((res = fscanf(fp, " path for sigma %lg", &d)) == EOF) + FATAL("cmaes_resume_distribution(): 'path for sigma' not found",0,0,0); + else if (res==0) + fscanf(fp, " %*s"); + else if(res > 0) + break; + } + + /* read ps */ + t->rgps[0] = d; res = 1; + for(i = 1; i < t->sp.N; ++i) + res += fscanf(fp, " %lg", &t->rgps[i]); + if (res != t->sp.N) + FATAL("cmaes_resume_distribution(): ps: dimensions differ",0,0,0); + + /* find next "path for C" entry */ + while (1) { + if ((res = fscanf(fp, " path for C %lg", &d)) == EOF) + FATAL("cmaes_resume_distribution(): 'path for C' not found",0,0,0); + else if (res==0) + fscanf(fp, " %*s"); + else if(res > 0) + break; + } + /* read pc */ + t->rgpc[0] = d; res = 1; + for(i = 1; i < t->sp.N; ++i) + res += fscanf(fp, " %lg", &t->rgpc[i]); + if (res != t->sp.N) + FATAL("cmaes_resume_distribution(): pc: dimensions differ",0,0,0); + + /* find next "sigma" entry */ + while (1) { + if ((res = fscanf(fp, " sigma %lg", &d)) == EOF) + FATAL("cmaes_resume_distribution(): 'sigma' not found",0,0,0); + else if (res==0) + fscanf(fp, " %*s"); + else if(res > 0) + break; + } + t->sigma = d; + + /* find next entry "covariance matrix" */ + while (1) { + if ((res = fscanf(fp, " covariance matrix %lg", &d)) == EOF) + FATAL("cmaes_resume_distribution(): 'covariance matrix' not found",0,0,0); + else if (res==0) + fscanf(fp, " %*s"); + else if(res > 0) + break; + } + /* read C */ + t->C[0][0] = d; res = 1; + for (i = 1; i < t->sp.N; ++i) + for (j = 0; j <= i; ++j) + res += fscanf(fp, " %lg", &t->C[i][j]); + if (res != (t->sp.N*t->sp.N+t->sp.N)/2) + FATAL("cmaes_resume_distribution(): C: dimensions differ",0,0,0); + + fclose(fp); + + t->flgIniphase = 0; + t->flgEigensysIsUptodate = 0; + t->flgresumedone = 1; + cmaes_UpdateEigensystem(t, 1); + +} /* cmaes_resume_distribution() */ +#ifdef __GNUC__ + #pragma GCC diagnostic pop +#endif +/* --------------------------------------------------------- */ +/* --------------------------------------------------------- */ + +void +cmaes_exit(cmaes_t *t) +{ + int i, N = t->sp.N; + t->version = NULL; + /* free(t->signals_filename) */ + t->state = -1; /* not really useful at the moment */ + free( t->rgpc); + free( t->rgps); + free( t->rgdTmp); + free( t->rgBDz); + free( --t->rgxmean); + free( --t->rgxold); + free( --t->rgxbestever); + free( --t->rgout); + free( t->rgD); + for (i = 0; i < N; ++i) { + free( t->C[i]); + free( t->B[i]); + } + for (i = 0; i < t->sp.lambda; ++i) + free( --t->rgrgx[i]); + free( t->rgrgx); + free( t->C); + free( t->B); + free( t->index); + free( t->publicFitness); + free( --t->rgFuncValue); + free( --t->arFuncValueHist); + cmaes_random_exit (&t->rand); + cmaes_readpara_exit (&t->sp); +} /* cmaes_exit() */ + + +/* --------------------------------------------------------- */ +/* --------------------------------------------------------- */ +double const * +cmaes_SetMean(cmaes_t *t, const double *xmean) +/* + * Distribution mean could be changed before SamplePopulation(). + * This might lead to unexpected behaviour if done repeatedly. + */ +{ + int i, N=t->sp.N; + + if (t->state >= 1 && t->state < 3) + FATAL("cmaes_SetMean: mean cannot be set inbetween the calls of ", + "SamplePopulation and UpdateDistribution",0,0); + + if (xmean != NULL && xmean != t->rgxmean) + for(i = 0; i < N; ++i) + t->rgxmean[i] = xmean[i]; + else + xmean = t->rgxmean; + + return xmean; +} + +/* --------------------------------------------------------- */ +/* --------------------------------------------------------- */ +double * const * +cmaes_SamplePopulation(cmaes_t *t) +{ + int iNk, i, j, N=t->sp.N; + int flgdiag = ((t->sp.diagonalCov == 1) || (t->sp.diagonalCov >= t->gen)); + double sum; + double const *xmean = t->rgxmean; + + /* cmaes_SetMean(t, xmean); * xmean could be changed at this point */ + + /* calculate eigensystem */ + if (!t->flgEigensysIsUptodate) { + if (!flgdiag) + cmaes_UpdateEigensystem(t, 0); + else { + for (i = 0; i < N; ++i) + t->rgD[i] = sqrt(t->C[i][i]); + t->minEW = douSquare(rgdouMin(t->rgD, N)); + t->maxEW = douSquare(rgdouMax(t->rgD, N)); + t->flgEigensysIsUptodate = 1; + cmaes_timings_start(&t->eigenTimings); + } + } + + /* treat minimal standard deviations and numeric problems */ + TestMinStdDevs(t); + + for (iNk = 0; iNk < t->sp.lambda; ++iNk) + { /* generate scaled cmaes_random vector (D * z) */ + for (i = 0; i < N; ++i) + if (flgdiag) + t->rgrgx[iNk][i] = xmean[i] + t->sigma * t->rgD[i] * cmaes_random_Gauss(&t->rand); + else + t->rgdTmp[i] = t->rgD[i] * cmaes_random_Gauss(&t->rand); + if (!flgdiag) + /* add mutation (sigma * B * (D*z)) */ + for (i = 0; i < N; ++i) { + for (j = 0, sum = 0.; j < N; ++j) + sum += t->B[i][j] * t->rgdTmp[j]; + t->rgrgx[iNk][i] = xmean[i] + t->sigma * sum; + } + } + if(t->state == 3 || t->gen == 0) + ++t->gen; + t->state = 1; + + return(t->rgrgx); +} /* SamplePopulation() */ + +/* --------------------------------------------------------- */ +/* --------------------------------------------------------- */ +double const * +cmaes_ReSampleSingle_old( cmaes_t *t, double *rgx) +{ + int i, j, N=t->sp.N; + double sum; + + if (rgx == NULL) + FATAL("cmaes_ReSampleSingle(): Missing input double *x",0,0,0); + + for (i = 0; i < N; ++i) + t->rgdTmp[i] = t->rgD[i] * cmaes_random_Gauss(&t->rand); + /* add mutation (sigma * B * (D*z)) */ + for (i = 0; i < N; ++i) { + for (j = 0, sum = 0.; j < N; ++j) + sum += t->B[i][j] * t->rgdTmp[j]; + rgx[i] = t->rgxmean[i] + t->sigma * sum; + } + return rgx; +} + +/* --------------------------------------------------------- */ +/* --------------------------------------------------------- */ +double * const * +cmaes_ReSampleSingle( cmaes_t *t, int iindex) +{ + int i, j, N=t->sp.N; + double *rgx; + double sum; + static char s[99]; + + if (iindex < 0 || iindex >= t->sp.lambda) { + sprintf(s, "index==%d must be between 0 and %d", iindex, t->sp.lambda); + FATAL("cmaes_ReSampleSingle(): Population member ",s,0,0); + } + rgx = t->rgrgx[iindex]; + + for (i = 0; i < N; ++i) + t->rgdTmp[i] = t->rgD[i] * cmaes_random_Gauss(&t->rand); + /* add mutation (sigma * B * (D*z)) */ + for (i = 0; i < N; ++i) { + for (j = 0, sum = 0.; j < N; ++j) + sum += t->B[i][j] * t->rgdTmp[j]; + rgx[i] = t->rgxmean[i] + t->sigma * sum; + } + return(t->rgrgx); +} + +/* --------------------------------------------------------- */ +/* --------------------------------------------------------- */ +double * +cmaes_SampleSingleInto( cmaes_t *t, double *rgx) +{ + int i, j, N=t->sp.N; + double sum; + + if (rgx == NULL) + rgx = new_double(N); + + for (i = 0; i < N; ++i) + t->rgdTmp[i] = t->rgD[i] * cmaes_random_Gauss(&t->rand); + /* add mutation (sigma * B * (D*z)) */ + for (i = 0; i < N; ++i) { + for (j = 0, sum = 0.; j < N; ++j) + sum += t->B[i][j] * t->rgdTmp[j]; + rgx[i] = t->rgxmean[i] + t->sigma * sum; + } + return rgx; +} + +/* --------------------------------------------------------- */ +/* --------------------------------------------------------- */ +double * +cmaes_PerturbSolutionInto( cmaes_t *t, double *rgx, double const *xmean, double eps) +{ + int i, j, N=t->sp.N; + double sum; + + if (rgx == NULL) + rgx = new_double(N); + if (xmean == NULL) + FATAL("cmaes_PerturbSolutionInto(): xmean was not given",0,0,0); + + for (i = 0; i < N; ++i) + t->rgdTmp[i] = t->rgD[i] * cmaes_random_Gauss(&t->rand); + /* add mutation (sigma * B * (D*z)) */ + for (i = 0; i < N; ++i) { + for (j = 0, sum = 0.; j < N; ++j) + sum += t->B[i][j] * t->rgdTmp[j]; + rgx[i] = xmean[i] + eps * t->sigma * sum; + } + return rgx; +} + +/* --------------------------------------------------------- */ +/* --------------------------------------------------------- */ +const double * +cmaes_Optimize( cmaes_t *evo, double(*pFun)(double const *, int dim), long iterations) +/* TODO: make signals.par another argument or, even better, part of cmaes_t */ +{ + const char * signalsFilename = "cmaes_signals.par"; + double *const*pop; /* sampled population */ + const char *stop; + int i; + double startiter = evo->gen; + + while(!(stop=cmaes_TestForTermination(evo)) && + (evo->gen < startiter + iterations || !iterations)) + { + /* Generate population of new candidate solutions */ + pop = cmaes_SamplePopulation(evo); /* do not change content of pop */ + + /* Compute fitness value for each candidate solution */ + for (i = 0; i < cmaes_Get(evo, "popsize"); ++i) { + evo->publicFitness[i] = (*pFun)(pop[i], evo->sp.N); + } + + /* update search distribution */ + cmaes_UpdateDistribution(evo, evo->publicFitness); + + /* read control signals for output and termination */ + if (signalsFilename) + cmaes_ReadSignals(evo, signalsFilename); + fflush(stdout); + } /* while !cmaes_TestForTermination(evo) */ + + /* write some data */ + cmaes_WriteToFile(evo, "all", "allcmaes.dat"); + + return cmaes_GetPtr(evo, "xbestever"); +} + + +/* --------------------------------------------------------- */ +/* --------------------------------------------------------- */ +double * +cmaes_UpdateDistribution( cmaes_t *t, const double *rgFunVal) +{ + int i, j, iNk, hsig, N=t->sp.N; + int flgdiag = ((t->sp.diagonalCov == 1) || (t->sp.diagonalCov >= t->gen)); + double sum; + double psxps; + + if(t->state == 3) + FATAL("cmaes_UpdateDistribution(): You need to call \n", + "SamplePopulation() before update can take place.",0,0); + if(rgFunVal == NULL) + FATAL("cmaes_UpdateDistribution(): ", + "Fitness function value array input is missing.",0,0); + + if(t->state == 1) /* function values are delivered here */ + t->countevals += t->sp.lambda; + else + ERRORMESSAGE("cmaes_UpdateDistribution(): unexpected state",0,0,0); + + /* assign function values */ + for (i=0; i < t->sp.lambda; ++i) + t->rgrgx[i][N] = t->rgFuncValue[i] = rgFunVal[i]; + + + /* Generate index */ + Sorted_index(rgFunVal, t->index, t->sp.lambda); + + /* Test if function values are identical, escape flat fitness */ + if (t->rgFuncValue[t->index[0]] == + t->rgFuncValue[t->index[(int)t->sp.lambda/2]]) { + t->sigma *= exp(0.2+t->sp.cs/t->sp.damps); + ERRORMESSAGE("Warning: sigma increased due to equal function values\n", + " Reconsider the formulation of the objective function",0,0); + } + + /* update function value history */ + for(i = (int)*(t->arFuncValueHist-1)-1; i > 0; --i) /* for(i = t->arFuncValueHist[-1]-1; i > 0; --i) */ + t->arFuncValueHist[i] = t->arFuncValueHist[i-1]; + t->arFuncValueHist[0] = rgFunVal[t->index[0]]; + + /* update xbestever */ + if (t->rgxbestever[N] > t->rgrgx[t->index[0]][N] || t->gen == 1) + for (i = 0; i <= N; ++i) { + t->rgxbestever[i] = t->rgrgx[t->index[0]][i]; + t->rgxbestever[N+1] = t->countevals; + } + + /* calculate xmean and rgBDz~N(0,C) */ + for (i = 0; i < N; ++i) { + t->rgxold[i] = t->rgxmean[i]; + t->rgxmean[i] = 0.; + for (iNk = 0; iNk < t->sp.mu; ++iNk) + t->rgxmean[i] += t->sp.weights[iNk] * t->rgrgx[t->index[iNk]][i]; + t->rgBDz[i] = sqrt(t->sp.mueff)*(t->rgxmean[i] - t->rgxold[i])/t->sigma; + } + + /* calculate z := D^(-1) * B^(-1) * rgBDz into rgdTmp */ + for (i = 0; i < N; ++i) { + if (!flgdiag) + for (j = 0, sum = 0.; j < N; ++j) + sum += t->B[j][i] * t->rgBDz[j]; + else + sum = t->rgBDz[i]; + t->rgdTmp[i] = sum / t->rgD[i]; + } + + /* TODO?: check length of t->rgdTmp and set an upper limit, e.g. 6 stds */ + /* in case of manipulation of arx, + this can prevent an increase of sigma by several orders of magnitude + within one step; a five-fold increase in one step can still happen. + */ + /* + for (j = 0, sum = 0.; j < N; ++j) + sum += t->rgdTmp[j] * t->rgdTmp[j]; + if (sqrt(sum) > chiN + 6. * sqrt(0.5)) { + rgdTmp length should be set to upper bound and hsig should become zero + } + */ + + /* cumulation for sigma (ps) using B*z */ + for (i = 0; i < N; ++i) { + if (!flgdiag) + for (j = 0, sum = 0.; j < N; ++j) + sum += t->B[i][j] * t->rgdTmp[j]; + else + sum = t->rgdTmp[i]; + t->rgps[i] = (1. - t->sp.cs) * t->rgps[i] + + sqrt(t->sp.cs * (2. - t->sp.cs)) * sum; + } + + /* calculate norm(ps)^2 */ + for (i = 0, psxps = 0.; i < N; ++i) + psxps += t->rgps[i] * t->rgps[i]; + + /* cumulation for covariance matrix (pc) using B*D*z~N(0,C) */ + hsig = sqrt(psxps) / sqrt(1. - pow(1.-t->sp.cs, 2*t->gen)) / t->chiN + < 1.4 + 2./(N+1); + for (i = 0; i < N; ++i) { + t->rgpc[i] = (1. - t->sp.ccumcov) * t->rgpc[i] + + hsig * sqrt(t->sp.ccumcov * (2. - t->sp.ccumcov)) * t->rgBDz[i]; + } + + /* stop initial phase */ + if (t->flgIniphase && + t->gen > douMin(1/t->sp.cs, 1+N/t->sp.mucov)) + { + if (psxps / t->sp.damps / (1.-pow((1. - t->sp.cs), t->gen)) + < N * 1.05) + t->flgIniphase = 0; + } + +#if 0 + /* remove momentum in ps, if ps is large and fitness is getting worse */ + /* This is obsolete due to hsig and harmful in a dynamic environment */ + if(psxps/N > 1.5 + 10.*sqrt(2./N) + && t->arFuncValueHist[0] > t->arFuncValueHist[1] + && t->arFuncValueHist[0] > t->arFuncValueHist[2]) { + double tfac = sqrt((1 + douMax(0, log(psxps/N))) * N / psxps); + for (i=0; i<N; ++i) + t->rgps[i] *= tfac; + psxps *= tfac*tfac; + } +#endif + + /* update of C */ + + Adapt_C2(t, hsig); + + /* Adapt_C(t); not used anymore */ + +#if 0 + if (t->sp.ccov != 0. && t->flgIniphase == 0) { + int k; + + t->flgEigensysIsUptodate = 0; + + /* update covariance matrix */ + for (i = 0; i < N; ++i) + for (j = 0; j <=i; ++j) { + t->C[i][j] = (1 - t->sp.ccov) * t->C[i][j] + + t->sp.ccov * (1./t->sp.mucov) + * (t->rgpc[i] * t->rgpc[j] + + (1-hsig)*t->sp.ccumcov*(2.-t->sp.ccumcov) * t->C[i][j]); + for (k = 0; k < t->sp.mu; ++k) /* additional rank mu update */ + t->C[i][j] += t->sp.ccov * (1-1./t->sp.mucov) * t->sp.weights[k] + * (t->rgrgx[t->index[k]][i] - t->rgxold[i]) + * (t->rgrgx[t->index[k]][j] - t->rgxold[j]) + / t->sigma / t->sigma; + } + } +#endif + + + /* update of sigma */ + t->sigma *= exp(((sqrt(psxps)/t->chiN)-1.)*t->sp.cs/t->sp.damps); + + t->state = 3; + + return (t->rgxmean); + +} /* cmaes_UpdateDistribution() */ + + +/* --------------------------------------------------------- */ +/* --------------------------------------------------------- */ +static void +Adapt_C2(cmaes_t *t, int hsig) +{ + int i, j, k, N=t->sp.N; + int flgdiag = ((t->sp.diagonalCov == 1) || (t->sp.diagonalCov >= t->gen)); + + if (t->sp.ccov != 0. && t->flgIniphase == 0) { + + /* definitions for speeding up inner-most loop */ + double ccov1 = douMin(t->sp.ccov * (1./t->sp.mucov) * (flgdiag ? (N+1.5) / 3. : 1.), 1.); + double ccovmu = douMin(t->sp.ccov * (1-1./t->sp.mucov)* (flgdiag ? (N+1.5) / 3. : 1.), 1.-ccov1); + double sigmasquare = t->sigma * t->sigma; + + t->flgEigensysIsUptodate = 0; + + /* update covariance matrix */ + for (i = 0; i < N; ++i) + for (j = flgdiag ? i : 0; j <= i; ++j) { + t->C[i][j] = (1 - ccov1 - ccovmu) * t->C[i][j] + + ccov1 + * (t->rgpc[i] * t->rgpc[j] + + (1-hsig)*t->sp.ccumcov*(2.-t->sp.ccumcov) * t->C[i][j]); + for (k = 0; k < t->sp.mu; ++k) { /* additional rank mu update */ + t->C[i][j] += ccovmu * t->sp.weights[k] + * (t->rgrgx[t->index[k]][i] - t->rgxold[i]) + * (t->rgrgx[t->index[k]][j] - t->rgxold[j]) + / sigmasquare; + } + } + /* update maximal and minimal diagonal value */ + t->maxdiagC = t->mindiagC = t->C[0][0]; + for (i = 1; i < N; ++i) { + if (t->maxdiagC < t->C[i][i]) + t->maxdiagC = t->C[i][i]; + else if (t->mindiagC > t->C[i][i]) + t->mindiagC = t->C[i][i]; + } + } /* if ccov... */ +} + + +/* --------------------------------------------------------- */ +/* --------------------------------------------------------- */ +static void +TestMinStdDevs(cmaes_t *t) + /* increases sigma */ +{ + int i, N = t->sp.N; + if (t->sp.rgDiffMinChange == NULL) + return; + + for (i = 0; i < N; ++i) + while (t->sigma * sqrt(t->C[i][i]) < t->sp.rgDiffMinChange[i]) + t->sigma *= exp(0.05+t->sp.cs/t->sp.damps); + +} /* cmaes_TestMinStdDevs() */ + + +/* --------------------------------------------------------- */ +/* --------------------------------------------------------- */ +void cmaes_WriteToFile(cmaes_t *t, const char *key, const char *name) +{ + cmaes_WriteToFileAW(t, key, name, "a"); /* default is append */ +} + +/* --------------------------------------------------------- */ +/* --------------------------------------------------------- */ +void cmaes_WriteToFileAW(cmaes_t *t, const char *key, const char *name, + const char *appendwrite) +{ + const char *s = "tmpcmaes.dat"; + FILE *fp; + + if (name == NULL) + name = s; + + fp = fopen( name, appendwrite); + + if(fp == NULL) { + ERRORMESSAGE("cmaes_WriteToFile(): could not open '", name, + "' with flag ", appendwrite); + return; + } + + if (appendwrite[0] == 'w') { + /* write a header line, very rudimentary */ + fprintf(fp, "%% # %s (randomSeed=%d, %s)\n", key, t->sp.seed, getTimeStr()); + } else + if (t->gen > 0 || strncmp(name, "outcmaesfit", 11) != 0) + cmaes_WriteToFilePtr(t, key, fp); /* do not write fitness for gen==0 */ + + fclose(fp); + +} /* WriteToFile */ + +/* --------------------------------------------------------- */ +void cmaes_WriteToFilePtr(cmaes_t *t, const char *key, FILE *fp) + +/* this hack reads key words from input key for data to be written to + * a file, see file signals.par as input file. The length of the keys + * is mostly fixed, see key += number in the code! If the key phrase + * does not match the expectation the output might be strange. for + * cmaes_t *t == NULL it solely prints key as a header line. Input key + * must be zero terminated. + */ +{ + int i, k, N=(t ? t->sp.N : 0); + char const *keyend; /* *keystart; */ + const char *s = "few"; + if (key == NULL) + key = s; + /* keystart = key; for debugging purpose */ + keyend = key + strlen(key); + + while (key < keyend) + { + if (strncmp(key, "axisratio", 9) == 0) + { + fprintf(fp, "%.2e", sqrt(t->maxEW/t->minEW)); + while (*key != '+' && *key != '\0' && key < keyend) + ++key; + fprintf(fp, "%c", (*key=='+') ? '\t':'\n'); + } + if (strncmp(key, "idxminSD", 8) == 0) + { + int mini=0; for(i=N-1;i>0;--i) if(t->mindiagC==t->C[i][i]) mini=i; + fprintf(fp, "%d", mini+1); + while (*key != '+' && *key != '\0' && key < keyend) + ++key; + fprintf(fp, "%c", (*key=='+') ? '\t':'\n'); + } + if (strncmp(key, "idxmaxSD", 8) == 0) + { + int maxi=0; for(i=N-1;i>0;--i) if(t->maxdiagC==t->C[i][i]) maxi=i; + fprintf(fp, "%d", maxi+1); + while (*key != '+' && *key != '\0' && key < keyend) + ++key; + fprintf(fp, "%c", (*key=='+') ? '\t':'\n'); + } + /* new coordinate system == all eigenvectors */ + if (strncmp(key, "B", 1) == 0) + { + /* int j, index[N]; */ + int j, *iindex=(int*)(new_void(N,sizeof(int))); /* MT */ + Sorted_index(t->rgD, iindex, N); /* should not be necessary, see end of QLalgo2 */ + /* One eigenvector per row, sorted: largest eigenvalue first */ + for (i = 0; i < N; ++i) + for (j = 0; j < N; ++j) + fprintf(fp, "%g%c", t->B[j][iindex[N-1-i]], (j==N-1)?'\n':'\t'); + ++key; + free(iindex); /* MT */ + } + /* covariance matrix */ + if (strncmp(key, "C", 1) == 0) + { + int j; + for (i = 0; i < N; ++i) + for (j = 0; j <= i; ++j) + fprintf(fp, "%g%c", t->C[i][j], (j==i)?'\n':'\t'); + ++key; + } + /* (processor) time (used) since begin of execution */ + if (strncmp(key, "clock", 4) == 0) + { + cmaes_timings_update(&t->eigenTimings); + fprintf(fp, "%.1f %.1f", t->eigenTimings.totaltotaltime, + t->eigenTimings.tictoctime); + while (*key != '+' && *key != '\0' && key < keyend) + ++key; + fprintf(fp, "%c", (*key=='+') ? '\t':'\n'); + } + /* ratio between largest and smallest standard deviation */ + if (strncmp(key, "stddevratio", 11) == 0) /* std dev in coordinate axes */ + { + fprintf(fp, "%g", sqrt(t->maxdiagC/t->mindiagC)); + while (*key != '+' && *key != '\0' && key < keyend) + ++key; + fprintf(fp, "%c", (*key=='+') ? '\t':'\n'); + } + /* standard deviations in coordinate directions (sigma*sqrt(C[i,i])) */ + if (strncmp(key, "coorstddev", 10) == 0 + || strncmp(key, "stddev", 6) == 0) /* std dev in coordinate axes */ + { + for (i = 0; i < N; ++i) + fprintf(fp, "%s%g", (i==0) ? "":"\t", t->sigma*sqrt(t->C[i][i])); + while (*key != '+' && *key != '\0' && key < keyend) + ++key; + fprintf(fp, "%c", (*key=='+') ? '\t':'\n'); + } + /* diagonal of D == roots of eigenvalues, sorted */ + if (strncmp(key, "diag(D)", 7) == 0) + { + for (i = 0; i < N; ++i) + t->rgdTmp[i] = t->rgD[i]; + qsort(t->rgdTmp, (unsigned) N, sizeof(double), &SignOfDiff); /* superfluous */ + for (i = 0; i < N; ++i) + fprintf(fp, "%s%g", (i==0) ? "":"\t", t->rgdTmp[i]); + while (*key != '+' && *key != '\0' && key < keyend) + ++key; + fprintf(fp, "%c", (*key=='+') ? '\t':'\n'); + } + if (strncmp(key, "dim", 3) == 0) + { + fprintf(fp, "%d", N); + while (*key != '+' && *key != '\0' && key < keyend) + ++key; + fprintf(fp, "%c", (*key=='+') ? '\t':'\n'); + } + if (strncmp(key, "eval", 4) == 0) + { + fprintf(fp, "%.0f", t->countevals); + while (*key != '+' && *key != '\0' && key < keyend) + ++key; + fprintf(fp, "%c", (*key=='+') ? '\t':'\n'); + } + if (strncmp(key, "few(diag(D))", 12) == 0)/* between four and six axes */ + { + int add = (int)(0.5 + (N + 1.) / 5.); + for (i = 0; i < N; ++i) + t->rgdTmp[i] = t->rgD[i]; + qsort(t->rgdTmp, (unsigned) N, sizeof(double), &SignOfDiff); + for (i = 0; i < N-1; i+=add) /* print always largest */ + fprintf(fp, "%s%g", (i==0) ? "":"\t", t->rgdTmp[N-1-i]); + fprintf(fp, "\t%g\n", t->rgdTmp[0]); /* and smallest */ + break; /* number of printed values is not determined */ + } + if (strncmp(key, "fewinfo", 7) == 0) { + fprintf(fp," Iter Fevals Function Value Sigma "); + fprintf(fp, "MaxCoorDev MinCoorDev AxisRatio MinDii Time in eig\n"); + while (*key != '+' && *key != '\0' && key < keyend) + ++key; + } + if (strncmp(key, "few", 3) == 0) { + fprintf(fp, " %4.0f ", t->gen); + fprintf(fp, " %5.0f ", t->countevals); + fprintf(fp, "%.15e", t->rgFuncValue[t->index[0]]); + fprintf(fp, " %.2e %.2e %.2e", t->sigma, t->sigma*sqrt(t->maxdiagC), + t->sigma*sqrt(t->mindiagC)); + fprintf(fp, " %.2e %.2e", sqrt(t->maxEW/t->minEW), sqrt(t->minEW)); + while (*key != '+' && *key != '\0' && key < keyend) + ++key; + fprintf(fp, "%c", (*key=='+') ? '\t':'\n'); + } + if (strncmp(key, "funval", 6) == 0 || strncmp(key, "fitness", 6) == 0) + { + fprintf(fp, "%.15e", t->rgFuncValue[t->index[0]]); + while (*key != '+' && *key != '\0' && key < keyend) + ++key; + fprintf(fp, "%c", (*key=='+') ? '\t':'\n'); + } + if (strncmp(key, "fbestever", 9) == 0) + { + fprintf(fp, "%.15e", t->rgxbestever[N]); /* f-value */ + while (*key != '+' && *key != '\0' && key < keyend) + ++key; + fprintf(fp, "%c", (*key=='+') ? '\t':'\n'); + } + if (strncmp(key, "fmedian", 7) == 0) + { + fprintf(fp, "%.15e", t->rgFuncValue[t->index[(int)(t->sp.lambda/2)]]); + while (*key != '+' && *key != '\0' && key < keyend) + ++key; + fprintf(fp, "%c", (*key=='+') ? '\t':'\n'); + } + if (strncmp(key, "fworst", 6) == 0) + { + fprintf(fp, "%.15e", t->rgFuncValue[t->index[t->sp.lambda-1]]); + while (*key != '+' && *key != '\0' && key < keyend) + ++key; + fprintf(fp, "%c", (*key=='+') ? '\t':'\n'); + } + if (strncmp(key, "arfunval", 8) == 0 || strncmp(key, "arfitness", 8) == 0) + { + for (i = 0; i < N; ++i) + fprintf(fp, "%s%.10e", (i==0) ? "" : "\t", + t->rgFuncValue[t->index[i]]); + while (*key != '+' && *key != '\0' && key < keyend) + ++key; + fprintf(fp, "%c", (*key=='+') ? '\t':'\n'); + } + if (strncmp(key, "gen", 3) == 0) + { + fprintf(fp, "%.0f", t->gen); + while (*key != '+' && *key != '\0' && key < keyend) + ++key; + fprintf(fp, "%c", (*key=='+') ? '\t':'\n'); + } + if (strncmp(key, "iter", 4) == 0) + { + fprintf(fp, "%.0f", t->gen); + while (*key != '+' && *key != '\0' && key < keyend) + ++key; + fprintf(fp, "%c", (*key=='+') ? '\t':'\n'); + } + if (strncmp(key, "sigma", 5) == 0) + { + fprintf(fp, "%.4e", t->sigma); + while (*key != '+' && *key != '\0' && key < keyend) + ++key; + fprintf(fp, "%c", (*key=='+') ? '\t':'\n'); + } + if (strncmp(key, "minSD", 5) == 0) /* minimal standard deviation */ + { + fprintf(fp, "%.4e", sqrt(t->mindiagC)); + while (*key != '+' && *key != '\0' && key < keyend) + ++key; + fprintf(fp, "%c", (*key=='+') ? '\t':'\n'); + } + if (strncmp(key, "maxSD", 5) == 0) + { + fprintf(fp, "%.4e", sqrt(t->maxdiagC)); + while (*key != '+' && *key != '\0' && key < keyend) + ++key; + fprintf(fp, "%c", (*key=='+') ? '\t':'\n'); + } + if (strncmp(key, "mindii", 6) == 0) + { + fprintf(fp, "%.4e", sqrt(t->minEW)); + while (*key != '+' && *key != '\0' && key < keyend) + ++key; + fprintf(fp, "%c", (*key=='+') ? '\t':'\n'); + } + if (strncmp(key, "0", 1) == 0) + { + fprintf(fp, "0"); + ++key; + fprintf(fp, "%c", (*key=='+') ? '\t':'\n'); + } + if (strncmp(key, "lambda", 6) == 0 || strncmp(key, "popsi", 5) == 0 || strncmp(key, "populationsi", 12) == 0) + { + fprintf(fp, "%d", t->sp.lambda); + while (*key != '+' && *key != '\0' && key < keyend) + ++key; + fprintf(fp, "%c", (*key=='+') ? '\t':'\n'); + } + if (strncmp(key, "N", 1) == 0) + { + fprintf(fp, "%d", N); + ++key; + fprintf(fp, "%c", (*key=='+') ? '\t':'\n'); + } + if (strncmp(key, "resume", 6) == 0) + { + fprintf(fp, "\n# resume %d\n", N); + fprintf(fp, "xmean\n"); + cmaes_WriteToFilePtr(t, "xmean", fp); + fprintf(fp, "path for sigma\n"); + for(i=0; i<N; ++i) + fprintf(fp, "%g%s", t->rgps[i], (i==N-1) ? "\n":"\t"); + fprintf(fp, "path for C\n"); + for(i=0; i<N; ++i) + fprintf(fp, "%g%s", t->rgpc[i], (i==N-1) ? "\n":"\t"); + fprintf(fp, "sigma %g\n", t->sigma); + /* note than B and D might not be up-to-date */ + fprintf(fp, "covariance matrix\n"); + cmaes_WriteToFilePtr(t, "C", fp); + while (*key != '+' && *key != '\0' && key < keyend) + ++key; + } + if (strncmp(key, "xbest", 5) == 0) { /* best x in recent generation */ + for(i=0; i<N; ++i) + fprintf(fp, "%s%g", (i==0) ? "":"\t", t->rgrgx[t->index[0]][i]); + while (*key != '+' && *key != '\0' && key < keyend) + ++key; + fprintf(fp, "%c", (*key=='+') ? '\t':'\n'); + } + if (strncmp(key, "xmean", 5) == 0) { + for(i=0; i<N; ++i) + fprintf(fp, "%s%g", (i==0) ? "":"\t", t->rgxmean[i]); + while (*key != '+' && *key != '\0' && key < keyend) + ++key; + fprintf(fp, "%c", (*key=='+') ? '\t':'\n'); + } + if (strncmp(key, "all", 3) == 0) + { + time_t ti = time(NULL); + fprintf(fp, "\n# --------- %s\n", asctime(localtime(&ti))); + fprintf(fp, " N %d\n", N); + fprintf(fp, " seed %d\n", t->sp.seed); + fprintf(fp, "function evaluations %.0f\n", t->countevals); + fprintf(fp, "elapsed (CPU) time [s] %.2f\n", t->eigenTimings.totaltotaltime); + fprintf(fp, "function value f(x)=%g\n", t->rgrgx[t->index[0]][N]); + fprintf(fp, "maximal standard deviation %g\n", t->sigma*sqrt(t->maxdiagC)); + fprintf(fp, "minimal standard deviation %g\n", t->sigma*sqrt(t->mindiagC)); + fprintf(fp, "sigma %g\n", t->sigma); + fprintf(fp, "axisratio %g\n", rgdouMax(t->rgD, N)/rgdouMin(t->rgD, N)); + fprintf(fp, "xbestever found after %.0f evaluations, function value %g\n", + t->rgxbestever[N+1], t->rgxbestever[N]); + for(i=0; i<N; ++i) + fprintf(fp, " %12g%c", t->rgxbestever[i], + (i%5==4||i==N-1)?'\n':' '); + fprintf(fp, "xbest (of last generation, function value %g)\n", + t->rgrgx[t->index[0]][N]); + for(i=0; i<N; ++i) + fprintf(fp, " %12g%c", t->rgrgx[t->index[0]][i], + (i%5==4||i==N-1)?'\n':' '); + fprintf(fp, "xmean \n"); + for(i=0; i<N; ++i) + fprintf(fp, " %12g%c", t->rgxmean[i], + (i%5==4||i==N-1)?'\n':' '); + fprintf(fp, "Standard deviation of coordinate axes (sigma*sqrt(diag(C)))\n"); + for(i=0; i<N; ++i) + fprintf(fp, " %12g%c", t->sigma*sqrt(t->C[i][i]), + (i%5==4||i==N-1)?'\n':' '); + fprintf(fp, "Main axis lengths of mutation ellipsoid (sigma*diag(D))\n"); + for (i = 0; i < N; ++i) + t->rgdTmp[i] = t->rgD[i]; + qsort(t->rgdTmp, (unsigned) N, sizeof(double), &SignOfDiff); + for(i=0; i<N; ++i) + fprintf(fp, " %12g%c", t->sigma*t->rgdTmp[N-1-i], + (i%5==4||i==N-1)?'\n':' '); + fprintf(fp, "Longest axis (b_i where d_ii=max(diag(D))\n"); + k = MaxIdx(t->rgD, N); + for(i=0; i<N; ++i) + fprintf(fp, " %12g%c", t->B[i][k], (i%5==4||i==N-1)?'\n':' '); + fprintf(fp, "Shortest axis (b_i where d_ii=max(diag(D))\n"); + k = MinIdx(t->rgD, N); + for(i=0; i<N; ++i) + fprintf(fp, " %12g%c", t->B[i][k], (i%5==4||i==N-1)?'\n':' '); + while (*key != '+' && *key != '\0' && key < keyend) + ++key; + } /* "all" */ + +#if 0 /* could become generic part */ + s0 = key; + d = cmaes_Get(t, key); /* TODO find way to detect whether key was found */ + if (key == s0) /* this does not work, is always true */ + { + /* write out stuff, problem: only generic format is available */ + /* move in key until "+" or end */ + } +#endif + + if (*key == '\0') + break; + else if (*key != '+') { /* last key was not recognized */ + ERRORMESSAGE("cmaes_t:WriteToFilePtr(): unrecognized key '", key, "'", 0); + while (*key != '+' && *key != '\0' && key < keyend) + ++key; + } + while (*key == '+') + ++key; + } /* while key < keyend */ + + if (key > keyend) + FATAL("cmaes_t:WriteToFilePtr(): BUG regarding key sequence",0,0,0); + +} /* WriteToFilePtr */ + +/* --------------------------------------------------------- */ +double +cmaes_Get( cmaes_t *t, char const *s) +{ + int N=t->sp.N; + + if (strncmp(s, "axisratio", 5) == 0) { /* between lengths of longest and shortest principal axis of the distribution ellipsoid */ + return (rgdouMax(t->rgD, N)/rgdouMin(t->rgD, N)); + } + else if (strncmp(s, "eval", 4) == 0) { /* number of function evaluations */ + return (t->countevals); + } + else if (strncmp(s, "fctvalue", 6) == 0 + || strncmp(s, "funcvalue", 6) == 0 + || strncmp(s, "funvalue", 6) == 0 + || strncmp(s, "fitness", 3) == 0) { /* recent best function value */ + return(t->rgFuncValue[t->index[0]]); + } + else if (strncmp(s, "fbestever", 7) == 0) { /* ever best function value */ + return(t->rgxbestever[N]); + } + else if (strncmp(s, "generation", 3) == 0 + || strncmp(s, "iteration", 4) == 0) { + return(t->gen); + } + else if (strncmp(s, "maxeval", 4) == 0 + || strncmp(s, "MaxFunEvals", 8) == 0 + || strncmp(s, "stopMaxFunEvals", 12) == 0) { /* maximal number of function evaluations */ + return(t->sp.stopMaxFunEvals); + } + else if (strncmp(s, "maxgen", 4) == 0 + || strncmp(s, "MaxIter", 7) == 0 + || strncmp(s, "stopMaxIter", 11) == 0) { /* maximal number of generations */ + return(ceil(t->sp.stopMaxIter)); + } + else if (strncmp(s, "maxaxislength", 5) == 0) { /* sigma * max(diag(D)) */ + return(t->sigma * sqrt(t->maxEW)); + } + else if (strncmp(s, "minaxislength", 5) == 0) { /* sigma * min(diag(D)) */ + return(t->sigma * sqrt(t->minEW)); + } + else if (strncmp(s, "maxstddev", 4) == 0) { /* sigma * sqrt(max(diag(C))) */ + return(t->sigma * sqrt(t->maxdiagC)); + } + else if (strncmp(s, "minstddev", 4) == 0) { /* sigma * sqrt(min(diag(C))) */ + return(t->sigma * sqrt(t->mindiagC)); + } + else if (strncmp(s, "N", 1) == 0 || strcmp(s, "n") == 0 || + strncmp(s, "dimension", 3) == 0) { + return (N); + } + else if (strncmp(s, "lambda", 3) == 0 + || strncmp(s, "samplesize", 8) == 0 + || strncmp(s, "popsize", 7) == 0) { /* sample size, offspring population size */ + return(t->sp.lambda); + } + else if (strncmp(s, "sigma", 3) == 0) { + return(t->sigma); + } + FATAL( "cmaes_Get(cmaes_t, char const * s): No match found for s='", s, "'",0); + return(0); +} /* cmaes_Get() */ + +/* --------------------------------------------------------- */ +double * +cmaes_GetInto( cmaes_t *t, char const *s, double *res) +{ + int i, N = t->sp.N; + double const * res0 = cmaes_GetPtr(t, s); + if (res == NULL) + res = new_double(N); + for (i = 0; i < N; ++i) + res[i] = res0[i]; + return res; +} + +/* --------------------------------------------------------- */ +double * +cmaes_GetNew( cmaes_t *t, char const *s) +{ + return (cmaes_GetInto(t, s, NULL)); +} + +/* --------------------------------------------------------- */ +const double * +cmaes_GetPtr( cmaes_t *t, char const *s) +{ + int i, N=t->sp.N; + + /* diagonal of covariance matrix */ + if (strncmp(s, "diag(C)", 7) == 0) { + for (i = 0; i < N; ++i) + t->rgout[i] = t->C[i][i]; + return(t->rgout); + } + /* diagonal of axis lengths matrix */ + else if (strncmp(s, "diag(D)", 7) == 0) { + return(t->rgD); + } + /* vector of standard deviations sigma*sqrt(diag(C)) */ + else if (strncmp(s, "stddev", 3) == 0) { + for (i = 0; i < N; ++i) + t->rgout[i] = t->sigma * sqrt(t->C[i][i]); + return(t->rgout); + } + /* bestever solution seen so far */ + else if (strncmp(s, "xbestever", 7) == 0) + return(t->rgxbestever); + /* recent best solution of the recent population */ + else if (strncmp(s, "xbest", 5) == 0) + return(t->rgrgx[t->index[0]]); + /* mean of the recent distribution */ + else if (strncmp(s, "xmean", 1) == 0) + return(t->rgxmean); + + return(NULL); +} + +/* --------------------------------------------------------- */ +/* tests stopping criteria + * returns a string of satisfied stopping criterion for each line + * otherwise NULL +*/ +const char * +cmaes_TestForTermination( cmaes_t *t) +{ + double range, fac; + int iAchse, iKoo; + int flgdiag = ((t->sp.diagonalCov == 1) || (t->sp.diagonalCov >= t->gen)); + static char sTestOutString[3024]; + char * cp = sTestOutString; + int i, cTemp, N=t->sp.N; + cp[0] = '\0'; + + /* function value reached */ + if ((t->gen > 1 || t->state > 1) && t->sp.stStopFitness.flg && + t->rgFuncValue[t->index[0]] <= t->sp.stStopFitness.val) + cp += sprintf(cp, "Fitness: function value %7.2e <= stopFitness (%7.2e)\n", + t->rgFuncValue[t->index[0]], t->sp.stStopFitness.val); + + /* TolFun */ + range = douMax(rgdouMax(t->arFuncValueHist, (int)douMin(t->gen,*(t->arFuncValueHist-1))), + rgdouMax(t->rgFuncValue, t->sp.lambda)) - + douMin(rgdouMin(t->arFuncValueHist, (int)douMin(t->gen, *(t->arFuncValueHist-1))), + rgdouMin(t->rgFuncValue, t->sp.lambda)); + + if (t->gen > 0 && range <= t->sp.stopTolFun) { + cp += sprintf(cp, + "TolFun: function value differences %7.2e < stopTolFun=%7.2e\n", + range, t->sp.stopTolFun); + } + + /* TolFunHist */ + if (t->gen > *(t->arFuncValueHist-1)) { + range = rgdouMax(t->arFuncValueHist, (int)*(t->arFuncValueHist-1)) + - rgdouMin(t->arFuncValueHist, (int)*(t->arFuncValueHist-1)); + if (range <= t->sp.stopTolFunHist) + cp += sprintf(cp, + "TolFunHist: history of function value changes %7.2e stopTolFunHist=%7.2e", + range, t->sp.stopTolFunHist); + } + + /* TolX */ + for(i=0, cTemp=0; i<N; ++i) { + cTemp += (t->sigma * sqrt(t->C[i][i]) < t->sp.stopTolX) ? 1 : 0; + cTemp += (t->sigma * t->rgpc[i] < t->sp.stopTolX) ? 1 : 0; + } + if (cTemp == 2*N) { + cp += sprintf(cp, + "TolX: object variable changes below %7.2e \n", + t->sp.stopTolX); + } + + /* TolUpX */ + for(i=0; i<N; ++i) { + if (t->sigma * sqrt(t->C[i][i]) > t->sp.stopTolUpXFactor * t->sp.rgInitialStds[i]) + break; + } + if (i < N) { + cp += sprintf(cp, + "TolUpX: standard deviation increased by more than %7.2e, larger initial standard deviation recommended \n", + t->sp.stopTolUpXFactor); + } + + /* Condition of C greater than dMaxSignifKond */ + if (t->maxEW >= t->minEW * t->dMaxSignifKond) { + cp += sprintf(cp, + "ConditionNumber: maximal condition number %7.2e reached. maxEW=%7.2e,minEW=%7.2e,maxdiagC=%7.2e,mindiagC=%7.2e\n", + t->dMaxSignifKond, t->maxEW, t->minEW, t->maxdiagC, t->mindiagC); + } /* if */ + + /* Principal axis i has no effect on xmean, ie. + x == x + 0.1 * sigma * rgD[i] * B[i] */ + if (!flgdiag) { + for (iAchse = 0; iAchse < N; ++iAchse) + { + fac = 0.1 * t->sigma * t->rgD[iAchse]; + for (iKoo = 0; iKoo < N; ++iKoo){ + if (t->rgxmean[iKoo] != t->rgxmean[iKoo] + fac * t->B[iKoo][iAchse]) + break; + } + if (iKoo == N) + { + /* t->sigma *= exp(0.2+t->sp.cs/t->sp.damps); */ + cp += sprintf(cp, + "NoEffectAxis: standard deviation 0.1*%7.2e in principal axis %d without effect\n", + fac/0.1, iAchse); + break; + } /* if (iKoo == N) */ + } /* for iAchse */ + } /* if flgdiag */ + /* Component of xmean is not changed anymore */ + for (iKoo = 0; iKoo < N; ++iKoo) + { + if (t->rgxmean[iKoo] == t->rgxmean[iKoo] + + 0.2*t->sigma*sqrt(t->C[iKoo][iKoo])) + { + /* t->C[iKoo][iKoo] *= (1 + t->sp.ccov); */ + /* flg = 1; */ + cp += sprintf(cp, + "NoEffectCoordinate: standard deviation 0.2*%7.2e in coordinate %d without effect\n", + t->sigma*sqrt(t->C[iKoo][iKoo]), iKoo); + break; + } + + } /* for iKoo */ + /* if (flg) t->sigma *= exp(0.05+t->sp.cs/t->sp.damps); */ + + if(t->countevals >= t->sp.stopMaxFunEvals) + cp += sprintf(cp, "MaxFunEvals: conducted function evaluations %.0f >= %g\n", + t->countevals, t->sp.stopMaxFunEvals); + if(t->gen >= t->sp.stopMaxIter) + cp += sprintf(cp, "MaxIter: number of iterations %.0f >= %g\n", + t->gen, t->sp.stopMaxIter); + if(t->flgStop) + cp += sprintf(cp, "Manual: stop signal read\n"); + +#if 0 + else if (0) { + for(i=0, cTemp=0; i<N; ++i) { + cTemp += (sigma * sqrt(C[i][i]) < stopdx) ? 1 : 0; + cTemp += (sigma * rgpc[i] < stopdx) ? 1 : 0; + } + if (cTemp == 2*N) + flgStop = 1; + } +#endif + + if (cp - sTestOutString>320) + ERRORMESSAGE("Bug in cmaes_t:Test(): sTestOutString too short",0,0,0); + + if (cp != sTestOutString) { + return sTestOutString; + } + + return(NULL); + +} /* cmaes_Test() */ + +/* --------------------------------------------------------- */ +void cmaes_ReadSignals(cmaes_t *t, char const *filename) +{ + const char *s = "cmaes_signals.par"; + FILE *fp; + if (filename == NULL) + filename = s; +/* if (filename) assign_string(&(t->signalsFilename), filename)*/ + fp = fopen( filename, "r"); + if(fp == NULL) { + return; + } + cmaes_ReadFromFilePtr( t, fp); + fclose(fp); +} +/* --------------------------------------------------------- */ +void cmaes_ReadFromFilePtr( cmaes_t *t, FILE *fp) +/* reading commands e.g. from signals.par file +*/ +{ + const char *keys[15]; /* key strings for scanf */ + char s[199], sin1[99], sin2[129], sin3[99], sin4[99]; + int ikey, ckeys, nb; + double d; + static int flglockprint = 0; + static int flglockwrite = 0; + static long countiterlastwritten; + static long maxdiffitertowrite; /* to prevent long gaps at the beginning */ + int flgprinted = 0; + int flgwritten = 0; + double deltaprinttime = (double)(time(NULL)-t->printtime); /* using clock instead might not be a good */ + double deltawritetime = (double)(time(NULL)-t->writetime); /* idea as disc time is not CPU time? */ + double deltaprinttimefirst = (double)(t->firstprinttime ? time(NULL)-t->firstprinttime : 0); /* time is in seconds!? */ + double deltawritetimefirst = (double)(t->firstwritetime ? time(NULL)-t->firstwritetime : 0); + if (countiterlastwritten > t->gen) { /* probably restarted */ + maxdiffitertowrite = 0; + countiterlastwritten = 0; + } + + keys[0] = " stop%98s %98s"; /* s=="now" or eg "MaxIter+" %lg"-number */ + /* works with and without space */ + keys[1] = " print %98s %98s"; /* s==keyword for WriteFile */ + keys[2] = " write %98s %128s %98s"; /* s1==keyword, s2==filename */ + keys[3] = " check%98s %98s"; + keys[4] = " maxTimeFractionForEigendecompostion %98s"; + ckeys = 5; + strcpy(sin2, "tmpcmaes.dat"); + + if (cmaes_TestForTermination(t)) + { + deltaprinttime = (double)time(NULL); /* forces printing */ + deltawritetime = (double)time(NULL); + } + while(fgets(s, sizeof(s), fp) != NULL) + { + if (s[0] == '#' || s[0] == '%') /* skip comments */ + continue; + sin1[0] = sin2[0] = sin3[0] = sin4[0] = '\0'; + for (ikey=0; ikey < ckeys; ++ikey) + { + if((nb=sscanf(s, keys[ikey], sin1, sin2, sin3, sin4)) >= 1) + { + switch(ikey) { + case 0 : /* "stop", reads "stop now" or eg. stopMaxIter */ + if (strncmp(sin1, "now", 3) == 0) + t->flgStop = 1; + else if (strncmp(sin1, "MaxFunEvals", 11) == 0) { + if (sscanf(sin2, " %lg", &d) == 1) + t->sp.stopMaxFunEvals = d; + } + else if (strncmp(sin1, "MaxIter", 4) == 0) { + if (sscanf(sin2, " %lg", &d) == 1) + t->sp.stopMaxIter = d; + } + else if (strncmp(sin1, "Fitness", 7) == 0) { + if (sscanf(sin2, " %lg", &d) == 1) + { + t->sp.stStopFitness.flg = 1; + t->sp.stStopFitness.val = d; + } + } + else if (strncmp(sin1, "TolFunHist", 10) == 0) { + if (sscanf(sin2, " %lg", &d) == 1) + t->sp.stopTolFunHist = d; + } + else if (strncmp(sin1, "TolFun", 6) == 0) { + if (sscanf(sin2, " %lg", &d) == 1) + t->sp.stopTolFun = d; + } + else if (strncmp(sin1, "TolX", 4) == 0) { + if (sscanf(sin2, " %lg", &d) == 1) + t->sp.stopTolX = d; + } + else if (strncmp(sin1, "TolUpXFactor", 4) == 0) { + if (sscanf(sin2, " %lg", &d) == 1) + t->sp.stopTolUpXFactor = d; + } + break; + case 1 : /* "print" */ + d = 1; /* default */ + if (sscanf(sin2, "%lg", &d) < 1 && deltaprinttimefirst < 1) + d = 0; /* default at first time */ + if (deltaprinttime >= d && !flglockprint) { + cmaes_WriteToFilePtr(t, sin1, stdout); + flgprinted = 1; + } + if(d < 0) + flglockprint += 2; + break; + case 2 : /* "write" */ + /* write header, before first generation */ + if (t->countevals < t->sp.lambda && t->flgresumedone == 0) + cmaes_WriteToFileAW(t, sin1, sin2, "w"); /* overwrite */ + d = 0.9; /* default is one with smooth increment of gaps */ + if (sscanf(sin3, "%lg", &d) < 1 && deltawritetimefirst < 2) + d = 0; /* default is zero for the first second */ + if(d < 0) + flglockwrite += 2; + if (!flglockwrite) { + if (deltawritetime >= d) { + cmaes_WriteToFile(t, sin1, sin2); + flgwritten = 1; + } else if (d < 1 + && t->gen-countiterlastwritten > maxdiffitertowrite) { + cmaes_WriteToFile(t, sin1, sin2); + flgwritten = 1; + } + } + break; + case 3 : /* check, checkeigen 1 or check eigen 1 */ + if (strncmp(sin1, "eigen", 5) == 0) { + if (sscanf(sin2, " %lg", &d) == 1) { + if (d > 0) + t->flgCheckEigen = 1; + else + t->flgCheckEigen = 0; + } + else + t->flgCheckEigen = 0; + } + break; + case 4 : /* maxTimeFractionForEigendecompostion */ + if (sscanf(sin1, " %lg", &d) == 1) + t->sp.updateCmode.maxtime = d; + break; + default : + break; + } + break; /* for ikey */ + } /* if line contains keyword */ + } /* for each keyword */ + } /* while not EOF of signals.par */ + if (t->writetime == 0) + t->firstwritetime = time(NULL); + if (t->printtime == 0) + t->firstprinttime = time(NULL); + + if (flgprinted) + t->printtime = time(NULL); + if (flgwritten) { + t->writetime = time(NULL); + if (t->gen-countiterlastwritten > maxdiffitertowrite) + ++maxdiffitertowrite; /* smooth prolongation of writing gaps/intervals */ + countiterlastwritten = (long int) t->gen; + } + --flglockprint; + --flglockwrite; + flglockprint = (flglockprint > 0) ? 1 : 0; + flglockwrite = (flglockwrite > 0) ? 1 : 0; +} /* cmaes_ReadFromFilePtr */ + +/* ========================================================= */ +static int +Check_Eigen( int N, double **C, double *diag, double **Q) +/* + exhaustive test of the output of the eigendecomposition + needs O(n^3) operations + + writes to error file + returns number of detected inaccuracies +*/ +{ + /* compute Q diag Q^T and Q Q^T to check */ + int i, j, k, res = 0; + double cc, dd; + static char s[324]; + + for (i=0; i < N; ++i) + for (j=0; j < N; ++j) { + for (cc=0.,dd=0., k=0; k < N; ++k) { + cc += diag[k] * Q[i][k] * Q[j][k]; + dd += Q[i][k] * Q[j][k]; + } + /* check here, is the normalization the right one? */ + if (fabs(cc - C[i>j?i:j][i>j?j:i])/sqrt(C[i][i]*C[j][j]) > 1e-10 + && fabs(cc - C[i>j?i:j][i>j?j:i]) > 3e-14) { + sprintf(s, "%d %d: %.17e %.17e, %e", + i, j, cc, C[i>j?i:j][i>j?j:i], cc-C[i>j?i:j][i>j?j:i]); + ERRORMESSAGE("cmaes_t:Eigen(): imprecise result detected ", + s, 0, 0); + ++res; + } + if (fabs(dd - (i==j)) > 1e-10) { + sprintf(s, "%d %d %.17e ", i, j, dd); + ERRORMESSAGE("cmaes_t:Eigen(): imprecise result detected (Q not orthog.)", + s, 0, 0); + ++res; + } + } + return res; +} + +/* --------------------------------------------------------- */ +/* --------------------------------------------------------- */ +void +cmaes_UpdateEigensystem(cmaes_t *t, int flgforce) +{ + int i, N = t->sp.N; + + cmaes_timings_update(&t->eigenTimings); + + if(flgforce == 0) { + if (t->flgEigensysIsUptodate == 1) + return; + + /* return on modulo generation number */ + if (t->sp.updateCmode.flgalways == 0 /* not implemented, always ==0 */ + && t->gen < t->genOfEigensysUpdate + t->sp.updateCmode.modulo + ) + return; + + /* return on time percentage */ + if (t->sp.updateCmode.maxtime < 1.00 + && t->eigenTimings.tictoctime > t->sp.updateCmode.maxtime * t->eigenTimings.totaltime + && t->eigenTimings.tictoctime > 0.0002) + return; + } + cmaes_timings_tic(&t->eigenTimings); + + Eigen( N, t->C, t->rgD, t->B, t->rgdTmp); + + cmaes_timings_toc(&t->eigenTimings); + + /* find largest and smallest eigenvalue, they are supposed to be sorted anyway */ + t->minEW = rgdouMin(t->rgD, N); + t->maxEW = rgdouMax(t->rgD, N); + + if (t->flgCheckEigen) + /* needs O(n^3)! writes, in case, error message in error file */ + i = Check_Eigen( N, t->C, t->rgD, t->B); + +#if 0 + /* Limit Condition of C to dMaxSignifKond+1 */ + if (t->maxEW > t->minEW * t->dMaxSignifKond) { + ERRORMESSAGE("Warning: Condition number of covariance matrix at upper limit.", + " Consider a rescaling or redesign of the objective function. " ,"",""); + printf("\nWarning: Condition number of covariance matrix at upper limit\n"); + tmp = t->maxEW/t->dMaxSignifKond - t->minEW; + tmp = t->maxEW/t->dMaxSignifKond; + t->minEW += tmp; + for (i=0;i<N;++i) { + t->C[i][i] += tmp; + t->rgD[i] += tmp; + } + } /* if */ + t->dLastMinEWgroesserNull = minEW; +#endif + + for (i = 0; i < N; ++i) + t->rgD[i] = sqrt(t->rgD[i]); + + t->flgEigensysIsUptodate = 1; + t->genOfEigensysUpdate = t->gen; + + return; + +} /* cmaes_UpdateEigensystem() */ + + +/* ========================================================= */ +static void +Eigen( int N, double **C, double *diag, double **Q, double *rgtmp) +/* + Calculating eigenvalues and vectors. + Input: + N: dimension. + C: symmetric (1:N)xN-matrix, solely used to copy data to Q + niter: number of maximal iterations for QL-Algorithm. + rgtmp: N+1-dimensional vector for temporal use. + Output: + diag: N eigenvalues. + Q: Columns are normalized eigenvectors. + */ +{ + int i, j; + + if (rgtmp == NULL) /* was OK in former versions */ + FATAL("cmaes_t:Eigen(): input parameter double *rgtmp must be non-NULL", 0,0,0); + + /* copy C to Q */ + if (C != Q) { + for (i=0; i < N; ++i) + for (j = 0; j <= i; ++j) + Q[i][j] = Q[j][i] = C[i][j]; + } + +#if 0 + Householder( N, Q, diag, rgtmp); + QLalgo( N, diag, Q, 30*N, rgtmp+1); +#else + Householder2( N, Q, diag, rgtmp); + QLalgo2( N, diag, rgtmp, Q); +#endif + +} + + +/* ========================================================= */ +static void +QLalgo2 (int n, double *d, double *e, double **V) { + /* + -> n : Dimension. + -> d : Diagonale of tridiagonal matrix. + -> e[1..n-1] : off-diagonal, output from Householder + -> V : matrix output von Householder + <- d : eigenvalues + <- e : garbage? + <- V : basis of eigenvectors, according to d + + Symmetric tridiagonal QL algorithm, iterative + Computes the eigensystem from a tridiagonal matrix in roughtly 3N^3 operations + + code adapted from Java JAMA package, function tql2. + */ + + int i, k, l, m; + double f = 0.0; + double tst1 = 0.0; + double eps = 2.22e-16; /* Math.pow(2.0,-52.0); == 2.22e-16 */ + + /* shift input e */ + for (i = 1; i < n; i++) { + e[i-1] = e[i]; + } + e[n-1] = 0.0; /* never changed again */ + + for (l = 0; l < n; l++) { + + /* Find small subdiagonal element */ + + if (tst1 < fabs(d[l]) + fabs(e[l])) + tst1 = fabs(d[l]) + fabs(e[l]); + m = l; + while (m < n) { + if (fabs(e[m]) <= eps*tst1) { + /* if (fabs(e[m]) + fabs(d[m]+d[m+1]) == fabs(d[m]+d[m+1])) { */ + break; + } + m++; + } + + /* If m == l, d[l] is an eigenvalue, */ + /* otherwise, iterate. */ + + if (m > l) { /* TODO: check the case m == n, should be rejected here!? */ + int iter = 0; + do { /* while (fabs(e[l]) > eps*tst1); */ + double dl1, h; + double g = d[l]; + double p = (d[l+1] - g) / (2.0 * e[l]); + double r = myhypot(p, 1.); + + iter = iter + 1; /* Could check iteration count here */ + + /* Compute implicit shift */ + + if (p < 0) { + r = -r; + } + d[l] = e[l] / (p + r); + d[l+1] = e[l] * (p + r); + dl1 = d[l+1]; + h = g - d[l]; + for (i = l+2; i < n; i++) { + d[i] -= h; + } + f = f + h; + + /* Implicit QL transformation. */ + + p = d[m]; + { + double c = 1.0; + double c2 = c; + double c3 = c; + double el1 = e[l+1]; + double s = 0.0; + double s2 = 0.0; + for (i = m-1; i >= l; i--) { + c3 = c2; + c2 = c; + s2 = s; + g = c * e[i]; + h = c * p; + r = myhypot(p, e[i]); + e[i+1] = s * r; + s = e[i] / r; + c = p / r; + p = c * d[i] - s * g; + d[i+1] = h + s * (c * g + s * d[i]); + + /* Accumulate transformation. */ + + for (k = 0; k < n; k++) { + h = V[k][i+1]; + V[k][i+1] = s * V[k][i] + c * h; + V[k][i] = c * V[k][i] - s * h; + } + } + p = -s * s2 * c3 * el1 * e[l] / dl1; + e[l] = s * p; + d[l] = c * p; + } + + /* Check for convergence. */ + + } while (fabs(e[l]) > eps*tst1); + } + d[l] = d[l] + f; + e[l] = 0.0; + } + + /* Sort eigenvalues and corresponding vectors. */ +#if 1 + /* TODO: really needed here? So far not, but practical and only O(n^2) */ + { + int j; + double p; + for (i = 0; i < n-1; i++) { + k = i; + p = d[i]; + for (j = i+1; j < n; j++) { + if (d[j] < p) { + k = j; + p = d[j]; + } + } + if (k != i) { + d[k] = d[i]; + d[i] = p; + for (j = 0; j < n; j++) { + p = V[j][i]; + V[j][i] = V[j][k]; + V[j][k] = p; + } + } + } + } +#endif +} /* QLalgo2 */ + + +/* ========================================================= */ +static void +Householder2(int n, double **V, double *d, double *e) { + /* + Householder transformation of a symmetric matrix V into tridiagonal form. + -> n : dimension + -> V : symmetric nxn-matrix + <- V : orthogonal transformation matrix: + tridiag matrix == V * V_in * V^t + <- d : diagonal + <- e[0..n-1] : off diagonal (elements 1..n-1) + + code slightly adapted from the Java JAMA package, function private tred2() + + */ + + int i,j,k; + + for (j = 0; j < n; j++) { + d[j] = V[n-1][j]; + } + + /* Householder reduction to tridiagonal form */ + + for (i = n-1; i > 0; i--) { + + /* Scale to avoid under/overflow */ + + double scale = 0.0; + double h = 0.0; + for (k = 0; k < i; k++) { + scale = scale + fabs(d[k]); + } + if (scale == 0.0) { + e[i] = d[i-1]; + for (j = 0; j < i; j++) { + d[j] = V[i-1][j]; + V[i][j] = 0.0; + V[j][i] = 0.0; + } + } else { + + /* Generate Householder vector */ + + double f, g, hh; + + for (k = 0; k < i; k++) { + d[k] /= scale; + h += d[k] * d[k]; + } + f = d[i-1]; + g = sqrt(h); + if (f > 0) { + g = -g; + } + e[i] = scale * g; + h = h - f * g; + d[i-1] = f - g; + for (j = 0; j < i; j++) { + e[j] = 0.0; + } + + /* Apply similarity transformation to remaining columns */ + + for (j = 0; j < i; j++) { + f = d[j]; + V[j][i] = f; + g = e[j] + V[j][j] * f; + for (k = j+1; k <= i-1; k++) { + g += V[k][j] * d[k]; + e[k] += V[k][j] * f; + } + e[j] = g; + } + f = 0.0; + for (j = 0; j < i; j++) { + e[j] /= h; + f += e[j] * d[j]; + } + hh = f / (h + h); + for (j = 0; j < i; j++) { + e[j] -= hh * d[j]; + } + for (j = 0; j < i; j++) { + f = d[j]; + g = e[j]; + for (k = j; k <= i-1; k++) { + V[k][j] -= (f * e[k] + g * d[k]); + } + d[j] = V[i-1][j]; + V[i][j] = 0.0; + } + } + d[i] = h; + } + + /* Accumulate transformations */ + + for (i = 0; i < n-1; i++) { + double h; + V[n-1][i] = V[i][i]; + V[i][i] = 1.0; + h = d[i+1]; + if (h != 0.0) { + for (k = 0; k <= i; k++) { + d[k] = V[k][i+1] / h; + } + for (j = 0; j <= i; j++) { + double g = 0.0; + for (k = 0; k <= i; k++) { + g += V[k][i+1] * V[k][j]; + } + for (k = 0; k <= i; k++) { + V[k][j] -= g * d[k]; + } + } + } + for (k = 0; k <= i; k++) { + V[k][i+1] = 0.0; + } + } + for (j = 0; j < n; j++) { + d[j] = V[n-1][j]; + V[n-1][j] = 0.0; + } + V[n-1][n-1] = 1.0; + e[0] = 0.0; + +} /* Housholder() */ + + +#if 0 +/* ========================================================= */ +static void +WriteMaxErrorInfo(cmaes_t *t) +{ + int i,j, N=t->sp.N; + char *s = (char *)new_void(200+30*(N+2), sizeof(char)); s[0] = '\0'; + + sprintf( s+strlen(s),"\nComplete Info\n"); + sprintf( s+strlen(s)," Gen %20.12g\n", t->gen); + sprintf( s+strlen(s)," Dimension %d\n", N); + sprintf( s+strlen(s)," sigma %e\n", t->sigma); + sprintf( s+strlen(s)," lastminEW %e\n", + t->dLastMinEWgroesserNull); + sprintf( s+strlen(s)," maxKond %e\n\n", t->dMaxSignifKond); + sprintf( s+strlen(s)," x-vector rgD Basis...\n"); + ERRORMESSAGE( s,0,0,0); + s[0] = '\0'; + for (i = 0; i < N; ++i) + { + sprintf( s+strlen(s), " %20.12e", t->rgxmean[i]); + sprintf( s+strlen(s), " %10.4e", t->rgD[i]); + for (j = 0; j < N; ++j) + sprintf( s+strlen(s), " %10.2e", t->B[i][j]); + ERRORMESSAGE( s,0,0,0); + s[0] = '\0'; + } + ERRORMESSAGE( "\n",0,0,0); + free( s); +} /* WriteMaxErrorInfo() */ +#endif + +/* --------------------------------------------------------- */ +/* --------------- Functions: cmaes_timings_t -------------- */ +/* --------------------------------------------------------- */ +/* cmaes_timings_t measures overall time and times between calls + * of tic and toc. For small time spans (up to 1000 seconds) + * CPU time via clock() is used. For large time spans the + * fall-back to elapsed time from time() is used. + * cmaes_timings_update() must be called often enough to prevent + * the fallback. */ +/* --------------------------------------------------------- */ +void +cmaes_timings_init(cmaes_timings_t *t) { + t->totaltotaltime = 0; + cmaes_timings_start(t); +} +void +cmaes_timings_start(cmaes_timings_t *t) { + t->totaltime = 0; + t->tictoctime = 0; + t->lasttictoctime = 0; + t->istic = 0; + t->lastclock = clock(); + t->lasttime = time(NULL); + t->lastdiff = 0; + t->tictoczwischensumme = 0; + t->isstarted = 1; +} + +double +cmaes_timings_update(cmaes_timings_t *t) { +/* returns time between last call of cmaes_timings_*() and now, + * should better return totaltime or tictoctime? + */ + double diffc, difft; + clock_t lc = t->lastclock; /* measure CPU in 1e-6s */ + time_t lt = t->lasttime; /* measure time in s */ + + if (t->isstarted != 1) + FATAL("cmaes_timings_started() must be called before using timings... functions",0,0,0); + + t->lastclock = clock(); /* measures at most 2147 seconds, where 1s = 1e6 CLOCKS_PER_SEC */ + t->lasttime = time(NULL); + + diffc = (double)(t->lastclock - lc) / CLOCKS_PER_SEC; /* is presumably in [-21??, 21??] */ + difft = difftime(t->lasttime, lt); /* is presumably an integer */ + + t->lastdiff = difft; /* on the "save" side */ + + /* use diffc clock measurement if appropriate */ + if (diffc > 0 && difft < 1000) + t->lastdiff = diffc; + + if (t->lastdiff < 0) + FATAL("BUG in time measurement", 0, 0, 0); + + t->totaltime += t->lastdiff; + t->totaltotaltime += t->lastdiff; + if (t->istic) { + t->tictoczwischensumme += t->lastdiff; + t->tictoctime += t->lastdiff; + } + + return t->lastdiff; +} + +void +cmaes_timings_tic(cmaes_timings_t *t) { + if (t->istic) { /* message not necessary ? */ + ERRORMESSAGE("Warning: cmaes_timings_tic called twice without toc",0,0,0); + return; + } + cmaes_timings_update(t); + t->istic = 1; +} + +double +cmaes_timings_toc(cmaes_timings_t *t) { + if (!t->istic) { + ERRORMESSAGE("Warning: cmaes_timings_toc called without tic",0,0,0); + return -1; + } + cmaes_timings_update(t); + t->lasttictoctime = t->tictoczwischensumme; + t->tictoczwischensumme = 0; + t->istic = 0; + return t->lasttictoctime; +} + +/* --------------------------------------------------------- */ +/* ---------------- Functions: cmaes_random_t -------------- */ +/* --------------------------------------------------------- */ +/* --------------------------------------------------------- */ +/* X_1 exakt : 0.79788456) */ +/* chi_eins simuliert : 0.798xx (seed -3) */ +/* +-0.001 */ +/* --------------------------------------------------------- */ +/* + Gauss() liefert normalverteilte Zufallszahlen + bei vorgegebenem seed. +*/ +/* --------------------------------------------------------- */ +/* --------------------------------------------------------- */ + +long +cmaes_random_init( cmaes_random_t *t, long unsigned inseed) +{ + clock_t cloc = clock(); + + t->flgstored = 0; + t->rgrand = (long *) new_void(32, sizeof(long)); + if (inseed < 1) { + while ((long) (cloc - clock()) == 0) + ; /* TODO: remove this for time critical applications? */ + inseed = (long unsigned)labs((long)(100*time(NULL)+clock())); + } + return cmaes_random_Start(t, inseed); +} + +void +cmaes_random_exit(cmaes_random_t *t) +{ + free( t->rgrand); +} + +/* --------------------------------------------------------- */ +long cmaes_random_Start( cmaes_random_t *t, long unsigned inseed) +{ + long tmp; + int i; + + t->flgstored = 0; + t->startseed = inseed; /* purely for bookkeeping */ + while (inseed > 2e9) + inseed /= 2; /* prevent infinite loop on 32 bit system */ + if (inseed < 1) + inseed = 1; + t->aktseed = inseed; + for (i = 39; i >= 0; --i) + { + tmp = t->aktseed/127773; + t->aktseed = 16807 * (t->aktseed - tmp * 127773) + - 2836 * tmp; + if (t->aktseed < 0) t->aktseed += 2147483647; + if (i < 32) + t->rgrand[i] = t->aktseed; + } + t->aktrand = t->rgrand[0]; + return inseed; +} + +/* --------------------------------------------------------- */ +double cmaes_random_Gauss(cmaes_random_t *t) +{ + double x1, x2, rquad, fac; + + if (t->flgstored) + { + t->flgstored = 0; + return t->hold; + } + do + { + x1 = 2.0 * cmaes_random_Uniform(t) - 1.0; + x2 = 2.0 * cmaes_random_Uniform(t) - 1.0; + rquad = x1*x1 + x2*x2; + } while(rquad >= 1 || rquad <= 0); + fac = sqrt(-2.0*log(rquad)/rquad); + t->flgstored = 1; + t->hold = fac * x1; + return fac * x2; +} + +/* --------------------------------------------------------- */ +double cmaes_random_Uniform( cmaes_random_t *t) +{ + long tmp; + + tmp = t->aktseed/127773; + t->aktseed = 16807 * (t->aktseed - tmp * 127773) + - 2836 * tmp; + if (t->aktseed < 0) + t->aktseed += 2147483647; + tmp = t->aktrand / 67108865; + t->aktrand = t->rgrand[tmp]; + t->rgrand[tmp] = t->aktseed; + return (double)(t->aktrand)/(2.147483647e9); +} + +static char * +szCat(const char *sz1, const char*sz2, + const char *sz3, const char *sz4); + +/* --------------------------------------------------------- */ +/* -------------- Functions: cmaes_readpara_t -------------- */ +/* --------------------------------------------------------- */ +void +cmaes_readpara_init (cmaes_readpara_t *t, + int dim, + const double * inxstart, + const double * inrgsigma, + int inseed, + int lambda, + const char * filename) +{ + int i, N; + /* TODO: make sure cmaes_readpara_init has not been called already */ + t->filename = NULL; /* set after successful Read */ + t->rgsformat = (const char **) new_void(55, sizeof(char *)); + t->rgpadr = (void **) new_void(55, sizeof(void *)); + t->rgskeyar = (const char **) new_void(11, sizeof(char *)); + t->rgp2adr = (double ***) new_void(11, sizeof(double **)); + t->weigkey = (char *)new_void(7, sizeof(char)); + + /* All scalars: */ + i = 0; + t->rgsformat[i] = " N %d"; t->rgpadr[i++] = (void *) &t->N; + t->rgsformat[i] = " seed %d"; t->rgpadr[i++] = (void *) &t->seed; + t->rgsformat[i] = " stopMaxFunEvals %lg"; t->rgpadr[i++] = (void *) &t->stopMaxFunEvals; + t->rgsformat[i] = " stopMaxIter %lg"; t->rgpadr[i++] = (void *) &t->stopMaxIter; + t->rgsformat[i] = " stopFitness %lg"; t->rgpadr[i++]=(void *) &t->stStopFitness.val; + t->rgsformat[i] = " stopTolFun %lg"; t->rgpadr[i++]=(void *) &t->stopTolFun; + t->rgsformat[i] = " stopTolFunHist %lg"; t->rgpadr[i++]=(void *) &t->stopTolFunHist; + t->rgsformat[i] = " stopTolX %lg"; t->rgpadr[i++]=(void *) &t->stopTolX; + t->rgsformat[i] = " stopTolUpXFactor %lg"; t->rgpadr[i++]=(void *) &t->stopTolUpXFactor; + t->rgsformat[i] = " lambda %d"; t->rgpadr[i++] = (void *) &t->lambda; + t->rgsformat[i] = " mu %d"; t->rgpadr[i++] = (void *) &t->mu; + t->rgsformat[i] = " weights %5s"; t->rgpadr[i++] = (void *) t->weigkey; + t->rgsformat[i] = " fac*cs %lg";t->rgpadr[i++] = (void *) &t->cs; + t->rgsformat[i] = " fac*damps %lg"; t->rgpadr[i++] = (void *) &t->damps; + t->rgsformat[i] = " ccumcov %lg"; t->rgpadr[i++] = (void *) &t->ccumcov; + t->rgsformat[i] = " mucov %lg"; t->rgpadr[i++] = (void *) &t->mucov; + t->rgsformat[i] = " fac*ccov %lg"; t->rgpadr[i++]=(void *) &t->ccov; + t->rgsformat[i] = " diagonalCovarianceMatrix %lg"; t->rgpadr[i++]=(void *) &t->diagonalCov; + t->rgsformat[i] = " updatecov %lg"; t->rgpadr[i++]=(void *) &t->updateCmode.modulo; + t->rgsformat[i] = " maxTimeFractionForEigendecompostion %lg"; t->rgpadr[i++]=(void *) &t->updateCmode.maxtime; + t->rgsformat[i] = " resume %59s"; t->rgpadr[i++] = (void *) t->resumefile; + t->rgsformat[i] = " fac*maxFunEvals %lg"; t->rgpadr[i++] = (void *) &t->facmaxeval; + t->rgsformat[i] = " fac*updatecov %lg"; t->rgpadr[i++]=(void *) &t->facupdateCmode; + t->n1para = i; + t->n1outpara = i-2; /* disregard last parameters in WriteToFile() */ + + /* arrays */ + i = 0; + t->rgskeyar[i] = " typicalX %d"; t->rgp2adr[i++] = &t->typicalX; + t->rgskeyar[i] = " initialX %d"; t->rgp2adr[i++] = &t->xstart; + t->rgskeyar[i] = " initialStandardDeviations %d"; t->rgp2adr[i++] = &t->rgInitialStds; + t->rgskeyar[i] = " diffMinChange %d"; t->rgp2adr[i++] = &t->rgDiffMinChange; + t->n2para = i; + + t->N = dim; + t->seed = (unsigned) inseed; + t->xstart = NULL; + t->typicalX = NULL; + t->typicalXcase = 0; + t->rgInitialStds = NULL; + t->rgDiffMinChange = NULL; + t->stopMaxFunEvals = -1; + t->stopMaxIter = -1; + t->facmaxeval = 1; + t->stStopFitness.flg = -1; + t->stopTolFun = 1e-12; + t->stopTolFunHist = 1e-13; + t->stopTolX = 0; /* 1e-11*insigma would also be reasonable */ + t->stopTolUpXFactor = 1e3; + + t->lambda = lambda; + t->mu = -1; + t->mucov = -1; + t->weights = NULL; + strcpy(t->weigkey, "log"); + + t->cs = -1; + t->ccumcov = -1; + t->damps = -1; + t->ccov = -1; + + t->diagonalCov = 0; /* default is 0, but this might change in future, see below */ + + t->updateCmode.modulo = -1; + t->updateCmode.maxtime = -1; + t->updateCmode.flgalways = 0; + t->facupdateCmode = 1; + strcpy(t->resumefile, "_no_"); + + /* filename == NULL invokes default in cmaes_readpara_Read... */ + if (!isNoneStr(filename) && (!filename || strcmp(filename, "writeonly") != 0)) + cmaes_readpara_ReadFromFile(t, filename); + + if (t->N <= 0) + t->N = dim; + + N = t->N; + if (N == 0) + FATAL("cmaes_readpara_t(): problem dimension N undefined.\n", + " (no default value available).",0,0); + if (t->xstart == NULL && inxstart == NULL && t->typicalX == NULL) { + ERRORMESSAGE("Error: initialX undefined. typicalX = 0.5...0.5 used.","","",""); + printf("\nError: initialX undefined. typicalX = 0.5...0.5 used.\n"); + } + if (t->rgInitialStds == NULL && inrgsigma == NULL) { + /* FATAL("initialStandardDeviations undefined","","",""); */ + ERRORMESSAGE("Error: initialStandardDeviations undefined. 0.3...0.3 used.","","",""); + printf("\nError: initialStandardDeviations undefined. 0.3...0.3 used.\n"); + } + + if (t->xstart == NULL) { + t->xstart = new_double(N); + + /* put inxstart into xstart */ + if (inxstart != NULL) { + for (i=0; i<N; ++i) + t->xstart[i] = inxstart[i]; + } + /* otherwise use typicalX or default */ + else { + t->typicalXcase = 1; + for (i=0; i<N; ++i) + t->xstart[i] = (t->typicalX == NULL) ? 0.5 : t->typicalX[i]; + } + } /* xstart == NULL */ + + if (t->rgInitialStds == NULL) { + t->rgInitialStds = new_double(N); + for (i=0; i<N; ++i) + t->rgInitialStds[i] = (inrgsigma == NULL) ? 0.3 : inrgsigma[i]; + } + + t->flgsupplemented = 0; + +} /* cmaes_readpara_init */ + +/* --------------------------------------------------------- */ +/* --------------------------------------------------------- */ +void cmaes_readpara_exit(cmaes_readpara_t *t) +{ + if (t->filename != NULL) + free( t->filename); + if (t->xstart != NULL) /* not really necessary */ + free( t->xstart); + if (t->typicalX != NULL) + free( t->typicalX); + if (t->rgInitialStds != NULL) + free( t->rgInitialStds); + if (t->rgDiffMinChange != NULL) + free( t->rgDiffMinChange); + if (t->weights != NULL) + free( t->weights); + + free((void*)t->rgsformat); + free(t->rgpadr); + free((void*)t->rgskeyar); + free(t->rgp2adr); + free(t->weigkey); +} + +/* --------------------------------------------------------- */ +/* --------------------------------------------------------- */ +void +cmaes_readpara_ReadFromFile(cmaes_readpara_t *t, const char * filename) +{ + char s[1000]; + const char *ss = "cmaes_initials.par"; + int ipara, i; + int size; + FILE *fp; + if (filename == NULL) { + filename = ss; + } + t->filename = NULL; /* nothing read so far */ + fp = fopen( filename, "r"); + if (fp == NULL) { + ERRORMESSAGE("cmaes_ReadFromFile(): could not open '", filename, "'",0); + return; + } + for (ipara=0; ipara < t->n1para; ++ipara) + { + rewind(fp); + while(fgets(s, sizeof(s), fp) != NULL) + { /* skip comments */ + if (s[0] == '#' || s[0] == '%') + continue; + if(sscanf(s, t->rgsformat[ipara], t->rgpadr[ipara]) == 1) { + if (strncmp(t->rgsformat[ipara], " stopFitness ", 13) == 0) + t->stStopFitness.flg = 1; + break; + } + } + } /* for */ + if (t->N <= 0) + FATAL("cmaes_readpara_ReadFromFile(): No valid dimension N",0,0,0); + for (ipara=0; ipara < t->n2para; ++ipara) + { + rewind(fp); + while(fgets(s, sizeof(s), fp) != NULL) /* read one line */ + { /* skip comments */ + if (s[0] == '#' || s[0] == '%') + continue; + if(sscanf(s, t->rgskeyar[ipara], &size) == 1) { /* size==number of values to be read */ + if (size > 0) { + *t->rgp2adr[ipara] = new_double(t->N); + for (i=0;i<size&&i<t->N;++i) /* start reading next line */ + if (fscanf(fp, " %lf", &(*t->rgp2adr[ipara])[i]) != 1) + break; + if (i<size && i < t->N) { + ERRORMESSAGE("cmaes_readpara_ReadFromFile ", filename, ": ",0); + FATAL( "'", t->rgskeyar[ipara], + "' not enough values found.\n", + " Remove all comments between numbers."); + } + for (; i < t->N; ++i) /* recycle */ + (*t->rgp2adr[ipara])[i] = (*t->rgp2adr[ipara])[i%size]; + } + } + } + } /* for */ + fclose(fp); + assign_string(&(t->filename), filename); /* t->filename must be freed */ + return; +} /* cmaes_readpara_ReadFromFile() */ + +/* --------------------------------------------------------- */ +/* --------------------------------------------------------- */ +void +cmaes_readpara_WriteToFile(cmaes_readpara_t *t, const char *filenamedest) +{ + int ipara, i; + size_t len; + time_t ti = time(NULL); + FILE *fp = fopen( filenamedest, "a"); + if(fp == NULL) { + ERRORMESSAGE("cmaes_WriteToFile(): could not open '", + filenamedest, "'",0); + return; + } + fprintf(fp, "\n# Read from %s at %s\n", t->filename ? t->filename : "", + asctime(localtime(&ti))); /* == ctime() */ + for (ipara=0; ipara < 1; ++ipara) { + fprintf(fp, t->rgsformat[ipara], *(int *)t->rgpadr[ipara]); + fprintf(fp, "\n"); + } + for (ipara=0; ipara < t->n2para; ++ipara) { + if(*t->rgp2adr[ipara] == NULL) + continue; + fprintf(fp, t->rgskeyar[ipara], t->N); + fprintf(fp, "\n"); + for (i=0; i<t->N; ++i) + fprintf(fp, "%7.3g%c", (*t->rgp2adr[ipara])[i], (i%5==4)?'\n':' '); + fprintf(fp, "\n"); + } + for (ipara=1; ipara < t->n1outpara; ++ipara) { + if (strncmp(t->rgsformat[ipara], " stopFitness ", 13) == 0) + if(t->stStopFitness.flg == 0) { + fprintf(fp, " stopFitness\n"); + continue; + } + len = strlen(t->rgsformat[ipara]); + if (t->rgsformat[ipara][len-1] == 'd') /* read integer */ + fprintf(fp, t->rgsformat[ipara], *(int *)t->rgpadr[ipara]); + else if (t->rgsformat[ipara][len-1] == 's') /* read string */ + fprintf(fp, t->rgsformat[ipara], (char *)t->rgpadr[ipara]); + else { + if (strncmp(" fac*", t->rgsformat[ipara], 5) == 0) { + fprintf(fp, " "); + fprintf(fp, t->rgsformat[ipara]+5, *(double *)t->rgpadr[ipara]); + } else + fprintf(fp, t->rgsformat[ipara], *(double *)t->rgpadr[ipara]); + } + fprintf(fp, "\n"); + } /* for */ + fprintf(fp, "\n"); + fclose(fp); +} /* cmaes_readpara_WriteToFile() */ + +/* --------------------------------------------------------- */ +/* --------------------------------------------------------- */ +void +cmaes_readpara_SupplementDefaults(cmaes_readpara_t *t) +/* Called (only) once to finally set parameters. The settings + * typically depend on the current parameter values itself, + * where 0 or -1 may indicate to set them to a certain default + * value. For this reason calling `SupplementDefaults` twice + * might lead to unexpected results. +*/ +{ + double t1, t2; + int N = t->N; + clock_t cloc = clock(); + + if (t->flgsupplemented) + FATAL("cmaes_readpara_SupplementDefaults() cannot be called twice.",0,0,0); + if (t->seed < 1) { + while ((int) (cloc - clock()) == 0) + ; /* TODO: remove this for time critical applications!? */ + t->seed = (unsigned int)labs((long)(100*time(NULL)+clock())); + } + + if (t->stStopFitness.flg == -1) + t->stStopFitness.flg = 0; + + if (t->lambda < 2) + t->lambda = 4+(int)(3*log((double)N)); + if (t->mu == -1) { + t->mu = t->lambda/2; + cmaes_readpara_SetWeights(t, t->weigkey); + } + if (t->weights == NULL) + cmaes_readpara_SetWeights(t, t->weigkey); + + if (t->cs > 0) /* factor was read */ + t->cs *= (t->mueff + 2.) / (N + t->mueff + 3.); + if (t->cs <= 0 || t->cs >= 1) + t->cs = (t->mueff + 2.) / (N + t->mueff + 3.); + + if (t->ccumcov <= 0 || t->ccumcov > 1) + t->ccumcov = 4. / (N + 4); + + if (t->mucov < 1) { + t->mucov = t->mueff; + } + t1 = 2. / ((N+1.4142)*(N+1.4142)); + t2 = (2.*t->mueff-1.) / ((N+2.)*(N+2.)+t->mueff); + t2 = (t2 > 1) ? 1 : t2; + t2 = (1./t->mucov) * t1 + (1.-1./t->mucov) * t2; + if (t->ccov >= 0) /* ccov holds the read factor */ + t->ccov *= t2; + if (t->ccov < 0 || t->ccov > 1) /* set default in case */ + t->ccov = t2; + + if (t->diagonalCov == -1) + t->diagonalCov = 2 + 100. * N / sqrt((double)t->lambda); + + if (t->stopMaxFunEvals == -1) /* may depend on ccov in near future */ + t->stopMaxFunEvals = t->facmaxeval*900*(N+3)*(N+3); + else + t->stopMaxFunEvals *= t->facmaxeval; + + if (t->stopMaxIter == -1) + t->stopMaxIter = ceil((double)(t->stopMaxFunEvals / t->lambda)); + + if (t->damps < 0) + t->damps = 1; /* otherwise a factor was read */ + t->damps = t->damps + * (1 + 2*douMax(0., sqrt((t->mueff-1.)/(N+1.)) - 1)) /* basic factor */ + * douMax(0.3, 1. - /* modify for short runs */ + (double)N / (1e-6+douMin(t->stopMaxIter, t->stopMaxFunEvals/t->lambda))) + + t->cs; /* minor increment */ + + if (t->updateCmode.modulo < 0) + t->updateCmode.modulo = 1./t->ccov/(double)(N)/10.; + t->updateCmode.modulo *= t->facupdateCmode; + if (t->updateCmode.maxtime < 0) + t->updateCmode.maxtime = 0.20; /* maximal 20% of CPU-time */ + + t->flgsupplemented = 1; + +} /* cmaes_readpara_SupplementDefaults() */ + + +/* --------------------------------------------------------- */ +/* --------------------------------------------------------- */ +void +cmaes_readpara_SetWeights(cmaes_readpara_t *t, const char * mode) +{ + double s1, s2; + int i; + + if(t->weights != NULL) + free( t->weights); + t->weights = new_double(t->mu); + if (strcmp(mode, "lin") == 0) + for (i=0; i<t->mu; ++i) + t->weights[i] = t->mu - i; + else if (strncmp(mode, "equal", 3) == 0) + for (i=0; i<t->mu; ++i) + t->weights[i] = 1; + else if (strcmp(mode, "log") == 0) + for (i=0; i<t->mu; ++i) + t->weights[i] = log(t->mu+1.)-log(i+1.); + else + for (i=0; i<t->mu; ++i) + t->weights[i] = log(t->mu+1.)-log(i+1.); + + /* normalize weights vector and set mueff */ + for (i=0, s1=0, s2=0; i<t->mu; ++i) { + s1 += t->weights[i]; + s2 += t->weights[i]*t->weights[i]; + } + t->mueff = s1*s1/s2; + for (i=0; i<t->mu; ++i) + t->weights[i] /= s1; + + if(t->mu < 1 || t->mu > t->lambda || + (t->mu==t->lambda && t->weights[0]==t->weights[t->mu-1])) + FATAL("cmaes_readpara_SetWeights(): invalid setting of mu or lambda",0,0,0); + +} /* cmaes_readpara_SetWeights() */ + +/* --------------------------------------------------------- */ +/* --------------------------------------------------------- */ +static int +isNoneStr(const char * filename) +{ + if (filename && (strcmp(filename, "no") == 0 + || strcmp(filename, "non") == 0 + || strcmp(filename, "none") == 0)) + return 1; + + return 0; +} + +/* --------------------------------------------------------- */ +/* --------------------------------------------------------- */ +static double +douSquare(double d) +{ + return d*d; +} +static int +intMin( int i, int j) +{ + return i < j ? i : j; +} +static double +douMax( double i, double j) +{ + return i > j ? i : j; +} +static double +douMin( double i, double j) +{ + return i < j ? i : j; +} +static double +rgdouMax( const double *rgd, int len) +{ + int i; + double max = rgd[0]; + for (i = 1; i < len; ++i) + max = (max < rgd[i]) ? rgd[i] : max; + return max; +} + +static double +rgdouMin( const double *rgd, int len) +{ + int i; + double min = rgd[0]; + for (i = 1; i < len; ++i) + min = (min > rgd[i]) ? rgd[i] : min; + return min; +} + +static int +MaxIdx( const double *rgd, int len) +{ + int i, res; + for(i=1, res=0; i<len; ++i) + if(rgd[i] > rgd[res]) + res = i; + return res; +} +static int +MinIdx( const double *rgd, int len) +{ + int i, res; + for(i=1, res=0; i<len; ++i) + if(rgd[i] < rgd[res]) + res = i; + return res; +} + +static double +myhypot(double a, double b) +/* sqrt(a^2 + b^2) numerically stable. */ +{ + double r = 0; + if (fabs(a) > fabs(b)) { + r = b/a; + r = fabs(a)*sqrt(1+r*r); + } else if (b != 0) { + r = a/b; + r = fabs(b)*sqrt(1+r*r); + } + return r; +} + +static int SignOfDiff(const void *d1, const void * d2) +{ + return *((double *) d1) > *((double *) d2) ? 1 : -1; +} + +#if 1 +/* dirty index sort */ +static void Sorted_index(const double *rgFunVal, int *iindex, int n) +{ + int i, j; + for (i=1, iindex[0]=0; i<n; ++i) { + for (j=i; j>0; --j) { + if (rgFunVal[iindex[j-1]] < rgFunVal[i]) + break; + iindex[j] = iindex[j-1]; /* shift up */ + } + iindex[j] = i; /* insert i */ + } +} +#endif + +static void * new_void(int n, size_t size) +{ + static char s[70]; + void *p = calloc((unsigned) n, size); + if (p == NULL) { + sprintf(s, "new_void(): calloc(%ld,%ld) failed",(long)n,(long)size); + FATAL(s,0,0,0); + } + return p; +} + +double * +cmaes_NewDouble(int n) +{ + return new_double(n); +} + +static double * new_double(int n) +{ + static char s[170]; + double *p = (double *) calloc((unsigned) n, sizeof(double)); + if (p == NULL) { + sprintf(s, "new_double(): calloc(%ld,%ld) failed", + (long)n,(long)sizeof(double)); + FATAL(s,0,0,0); + } + return p; +} + +static char * new_string(const char *ins) +{ + static char s[170]; + unsigned i; + char *p; + unsigned len = (unsigned) ((ins != NULL) ? strlen(ins) : 0); + + if (len > 1000) { + FATAL("new_string(): input string length was larger then 1000 ", + "(possibly due to uninitialized char *filename)",0,0); + } + + p = (char *) calloc( len + 1, sizeof(char)); + if (p == NULL) { + sprintf(s, "new_string(): calloc(%ld,%ld) failed", + (long)len,(long)sizeof(char)); + FATAL(s,0,0,0); + } + for (i = 0; i < len; ++i) + p[i] = ins[i]; + return p; +} +static void assign_string(char ** pdests, const char *ins) +{ + if (*pdests) + free(*pdests); + if (ins == NULL) + *pdests = NULL; + else + *pdests = new_string(ins); +} + +/* --------------------------------------------------------- */ +/* --------------------------------------------------------- */ + +/* ========================================================= */ +void +cmaes_FATAL(char const *s1, char const *s2, char const *s3, + char const *s4) +{ + time_t t = time(NULL); + ERRORMESSAGE( s1, s2, s3, s4); + ERRORMESSAGE("*** Exiting cmaes_t ***",0,0,0); + printf("\n -- %s %s\n", asctime(localtime(&t)), + s2 ? szCat(s1, s2, s3, s4) : s1); + printf(" *** CMA-ES ABORTED, see errcmaes.err *** \n"); + fflush(stdout); + exit(1); +} + +/* ========================================================= */ +static void +FATAL(char const *s1, char const *s2, char const *s3, + char const *s4) +{ + cmaes_FATAL(s1, s2, s3, s4); +} + +/* ========================================================= */ +static void ERRORMESSAGE( char const *s1, char const *s2, + char const *s3, char const *s4) +{ +#if 1 + /* static char szBuf[700]; desirable but needs additional input argument + sprintf(szBuf, "%f:%f", gen, gen*lambda); + */ + time_t t = time(NULL); + FILE *fp = fopen( "errcmaes.err", "a"); + if (!fp) + { + printf("\nFATAL ERROR: %s\n", s2 ? szCat(s1, s2, s3, s4) : s1); + printf("cmaes_t could not open file 'errcmaes.err'."); + printf("\n *** CMA-ES ABORTED *** "); + fflush(stdout); + exit(1); + } + fprintf( fp, "\n -- %s %s\n", asctime(localtime(&t)), + s2 ? szCat(s1, s2, s3, s4) : s1); + fclose (fp); +#endif +} + +/* ========================================================= */ +static char *szCat(const char *sz1, const char*sz2, + const char *sz3, const char *sz4) +{ + static char szBuf[700]; + + if (!sz1) + FATAL("szCat() : Invalid Arguments",0,0,0); + + strncpy ((char *)szBuf, sz1, (unsigned)intMin( (int)strlen(sz1), 698)); + szBuf[intMin( (int)strlen(sz1), 698)] = '\0'; + if (sz2) + strncat ((char *)szBuf, sz2, + (unsigned)intMin((int)strlen(sz2)+1, 698 - (int)strlen((char const *)szBuf))); + if (sz3) + strncat((char *)szBuf, sz3, + (unsigned)intMin((int)strlen(sz3)+1, 698 - (int)strlen((char const *)szBuf))); + if (sz4) + strncat((char *)szBuf, sz4, + (unsigned)intMin((int)strlen(sz4)+1, 698 - (int)strlen((char const *)szBuf))); + return (char *) szBuf; +} + + diff --git a/external/cma-es/cmaes.h b/external/cma-es/cmaes.h new file mode 100644 index 0000000..277accb --- /dev/null +++ b/external/cma-es/cmaes.h @@ -0,0 +1,176 @@ +/* --------------------------------------------------------- */ +/* --- File: cmaes.h ----------- Author: Nikolaus Hansen --- */ +/* ---------------------- last modified: IX 2010 --- */ +/* --------------------------------- by: Nikolaus Hansen --- */ +/* --------------------------------------------------------- */ +/* + CMA-ES for non-linear function minimization. + + Copyright (C) 1996, 2003-2010 Nikolaus Hansen. + e-mail: nikolaus.hansen (you know what) inria.fr + + License: see file cmaes.c + +*/ +#ifndef NH_cmaes_h /* only include ones */ +#define NH_cmaes_h + +#include <time.h> + +typedef struct +/* cmaes_random_t + * sets up a pseudo random number generator instance + */ +{ + /* Variables for Uniform() */ + long int startseed; + long int aktseed; + long int aktrand; + long int *rgrand; + + /* Variables for Gauss() */ + short flgstored; + double hold; +} cmaes_random_t; + +typedef struct +/* cmaes_timings_t + * time measurement, used to time eigendecomposition + */ +{ + /* for outside use */ + double totaltime; /* zeroed by calling re-calling cmaes_timings_start */ + double totaltotaltime; + double tictoctime; + double lasttictoctime; + + /* local fields */ + clock_t lastclock; + time_t lasttime; + clock_t ticclock; + time_t tictime; + short istic; + short isstarted; + + double lastdiff; + double tictoczwischensumme; +} cmaes_timings_t; + +typedef struct +/* cmaes_readpara_t + * collects all parameters, in particular those that are read from + * a file before to start. This should split in future? + */ +{ + char * filename; /* keep record of the file that was taken to read parameters */ + short flgsupplemented; + + /* input parameters */ + int N; /* problem dimension, must stay constant, should be unsigned or long? */ + unsigned int seed; + double * xstart; + double * typicalX; + int typicalXcase; + double * rgInitialStds; + double * rgDiffMinChange; + + /* termination parameters */ + double stopMaxFunEvals; + double facmaxeval; + double stopMaxIter; + struct { int flg; double val; } stStopFitness; + double stopTolFun; + double stopTolFunHist; + double stopTolX; + double stopTolUpXFactor; + + /* internal evolution strategy parameters */ + int lambda; /* -> mu, <- N */ + int mu; /* -> weights, (lambda) */ + double mucov, mueff; /* <- weights */ + double *weights; /* <- mu, -> mueff, mucov, ccov */ + double damps; /* <- cs, maxeval, lambda */ + double cs; /* -> damps, <- N */ + double ccumcov; /* <- N */ + double ccov; /* <- mucov, <- N */ + double diagonalCov; /* number of initial iterations */ + struct { int flgalways; double modulo; double maxtime; } updateCmode; + double facupdateCmode; + + /* supplementary variables */ + + char *weigkey; + char resumefile[99]; + const char **rgsformat; + void **rgpadr; + const char **rgskeyar; + double ***rgp2adr; + int n1para, n1outpara; + int n2para; +} cmaes_readpara_t; + +typedef struct +/* cmaes_t + * CMA-ES "object" + */ +{ + const char *version; + /* char *signalsFilename; */ + cmaes_readpara_t sp; + cmaes_random_t rand; /* random number generator */ + + double sigma; /* step size */ + + double *rgxmean; /* mean x vector, "parent" */ + double *rgxbestever; + double **rgrgx; /* range of x-vectors, lambda offspring */ + int *index; /* sorting index of sample pop. */ + double *arFuncValueHist; + + short flgIniphase; /* not really in use anymore */ + short flgStop; + + double chiN; + double **C; /* lower triangular matrix: i>=j for C[i][j] */ + double **B; /* matrix with normalize eigenvectors in columns */ + double *rgD; /* axis lengths */ + + double *rgpc; + double *rgps; + double *rgxold; + double *rgout; + double *rgBDz; /* for B*D*z */ + double *rgdTmp; /* temporary (random) vector used in different places */ + double *rgFuncValue; + double *publicFitness; /* returned by cmaes_init() */ + + double gen; /* Generation number */ + double countevals; + double state; /* 1 == sampled, 2 == not in use anymore, 3 == updated */ + + double maxdiagC; /* repeatedly used for output */ + double mindiagC; + double maxEW; + double minEW; + + char sOutString[330]; /* 4x80 */ + + short flgEigensysIsUptodate; + short flgCheckEigen; /* control via cmaes_signals.par */ + double genOfEigensysUpdate; + cmaes_timings_t eigenTimings; + + double dMaxSignifKond; + double dLastMinEWgroesserNull; + + short flgresumedone; + + time_t printtime; + time_t writetime; /* ideally should keep track for each output file */ + time_t firstwritetime; + time_t firstprinttime; + +} cmaes_t; + + +#endif diff --git a/external/cma-es/cmaes_interface.h b/external/cma-es/cmaes_interface.h new file mode 100644 index 0000000..be7c736 --- /dev/null +++ b/external/cma-es/cmaes_interface.h @@ -0,0 +1,68 @@ +/* --------------------------------------------------------- */ +/* --- File: cmaes_interface.h - Author: Nikolaus Hansen --- */ +/* ---------------------- last modified: IV 2007 --- */ +/* --------------------------------- by: Nikolaus Hansen --- */ +/* --------------------------------------------------------- */ +/* + CMA-ES for non-linear function minimization. + + Copyright (C) 1996, 2003, 2007 Nikolaus Hansen. + e-mail: hansen AT lri.fr + + Documentation: see file docfunctions.txt + + License: see file cmaes.c +*/ +#include "cmaes.h" + +/* --------------------------------------------------------- */ +/* ------------------ Interface ---------------------------- */ +/* --------------------------------------------------------- */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* --- initialization, constructors, destructors --- */ +double * cmaes_init(cmaes_t *, int dimension , double *xstart, + double *stddev, long seed, int lambda, + const char *input_parameter_filename); +void cmaes_init_para(cmaes_t *, int dimension , double *xstart, + double *stddev, long seed, int lambda, + const char *input_parameter_filename); +double * cmaes_init_final(cmaes_t *); +void cmaes_resume_distribution(cmaes_t *evo_ptr, char *filename); +void cmaes_exit(cmaes_t *); + +/* --- core functions --- */ +double * const * cmaes_SamplePopulation(cmaes_t *); +double * cmaes_UpdateDistribution(cmaes_t *, + const double *rgFitnessValues); +const char * cmaes_TestForTermination(cmaes_t *); + +/* --- additional functions --- */ +double * const * cmaes_ReSampleSingle( cmaes_t *t, int index); +double const * cmaes_ReSampleSingle_old(cmaes_t *, double *rgx); +double * cmaes_SampleSingleInto( cmaes_t *t, double *rgx); +void cmaes_UpdateEigensystem(cmaes_t *, int flgforce); + +/* --- getter functions --- */ +double cmaes_Get(cmaes_t *, char const *keyword); +const double * cmaes_GetPtr(cmaes_t *, char const *keyword); /* e.g. "xbestever" */ +double * cmaes_GetNew( cmaes_t *t, char const *keyword); /* user is responsible to free */ +double * cmaes_GetInto( cmaes_t *t, char const *keyword, double *mem); /* allocs if mem==NULL, user is responsible to free */ + +/* --- online control and output --- */ +void cmaes_ReadSignals(cmaes_t *, char const *filename); +void cmaes_WriteToFile(cmaes_t *, const char *szKeyWord, + const char *output_filename); +char * cmaes_SayHello(cmaes_t *); +/* --- misc --- */ +double * cmaes_NewDouble(int n); /* user is responsible to free */ +void cmaes_FATAL(char const *s1, char const *s2, char const *s3, + char const *s4); + +#ifdef __cplusplus +} // end extern "C" +#endif + -- GitLab