|
| 1 | +/** |
| 2 | + * CMA-ES, Covariance Matrix Adaptation Evolution Strategy |
| 3 | + * Copyright (c) 2014 Inria |
| 4 | + * Author: Emmanuel Benazera <[email protected]> |
| 5 | + * |
| 6 | + * This file is part of libcmaes. |
| 7 | + * |
| 8 | + * libcmaes is free software: you can redistribute it and/or modify |
| 9 | + * it under the terms of the GNU Lesser General Public License as published by |
| 10 | + * the Free Software Foundation, either version 3 of the License, or |
| 11 | + * (at your option) any later version. |
| 12 | + * |
| 13 | + * libcmaes is distributed in the hope that it will be useful, |
| 14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | + * GNU Lesser General Public License for more details. |
| 17 | + * |
| 18 | + * You should have received a copy of the GNU Lesser General Public License |
| 19 | + * along with libcmaes. If not, see <http://www.gnu.org/licenses/>. |
| 20 | + */ |
| 21 | + |
| 22 | +#include "cmaes.h" |
| 23 | +#include <gflags/gflags.h> |
| 24 | + |
| 25 | +using namespace libcmaes; |
| 26 | + |
| 27 | +DEFINE_string(fname,"fsphere","name of the function to optimize"); |
| 28 | +DEFINE_string(dims,"10","comma-separated list of problem dimension"); |
| 29 | +//DEFINE_bool(tpa,false,"whether to use two-point adapation for step-size update"); |
| 30 | +DEFINE_string(alg,"cmaes","algorithm, among cmaes, ipop, bipop, acmaes, aipop, abipop, sepcmaes, sepipop, sepbipop, sepacmaes, sepaipop, sepabipop"); |
| 31 | +DEFINE_int32(runs,10,"number of runs for each configuration"); |
| 32 | +//DEFINE_bool(with_gradient,false,"whether to use the function gradient when available in closed form"); |
| 33 | + |
| 34 | +FitFunc fsphere = [](const double *x, const int N) |
| 35 | +{ |
| 36 | + double val = 0.0; |
| 37 | + for (int i=0;i<N;i++) |
| 38 | + val += x[i]*x[i]; |
| 39 | + return val; |
| 40 | +}; |
| 41 | + |
| 42 | +GradFunc grad_fsphere = [](const double *x, const int N) |
| 43 | +{ |
| 44 | + dVec grad(N); |
| 45 | + for (int i=0;i<N;i++) |
| 46 | + grad(i) = 2.0*x[i]; |
| 47 | + return grad; |
| 48 | +}; |
| 49 | + |
| 50 | +FitFunc rosenbrock = [](const double *x, const int N) |
| 51 | +{ |
| 52 | + double val = 0.0; |
| 53 | + for (int i=0;i<N-1;i++) |
| 54 | + { |
| 55 | + val += 100.0*pow((x[i+1]-x[i]*x[i]),2) + pow((x[i]-1.0),2); |
| 56 | + } |
| 57 | + return val; |
| 58 | +}; |
| 59 | + |
| 60 | +GradFunc grad_rosenbrock = [](const double *x, const int N) |
| 61 | +{ |
| 62 | + dVec grad = dVec::Zero(N); |
| 63 | + for (int i=0;i<N-1;i++) |
| 64 | + { |
| 65 | + grad(i) = -400.0*x[i]*(x[i+1]-x[i]*x[i])-2.0*(1.0-x[i]); |
| 66 | + grad(i+1) += 200.0*(x[i+1]-x[i]*x[i]); |
| 67 | + } |
| 68 | + return grad; |
| 69 | +}; |
| 70 | + |
| 71 | +FitFunc elli = [](const double *x, const int N) |
| 72 | +{ |
| 73 | + if (N == 1) |
| 74 | + return x[0] * x[0]; |
| 75 | + double val = 0.0; |
| 76 | + for (int i=0;i<N;i++) |
| 77 | + val += exp(log(1e3)*2.0*static_cast<double>(i)/static_cast<double>((N-1))) * x[i]*x[i]; |
| 78 | + return val; |
| 79 | +}; |
| 80 | + |
| 81 | +GradFunc grad_elli = [](const double *x, const int N) |
| 82 | +{ |
| 83 | + dVec grad(N); |
| 84 | + if (N == 1) |
| 85 | + { |
| 86 | + grad(0) = 2.0*x[0]; |
| 87 | + return grad; |
| 88 | + } |
| 89 | + for (int i=0;i<N;i++) |
| 90 | + grad(i) = exp(log(1e3)*2.0*static_cast<double>(i)/static_cast<double>((N-1)))*2.0*x[i]; |
| 91 | + return grad; |
| 92 | +}; |
| 93 | + |
| 94 | +std::map<std::string,FitFunc> mfuncs; |
| 95 | +std::map<std::string,GradFunc> mgfuncs; |
| 96 | + |
| 97 | +void tokenize(const std::string &str, |
| 98 | + std::vector<std::string> &tokens, |
| 99 | + const std::string &delim) |
| 100 | +{ |
| 101 | + |
| 102 | + // Skip delimiters at beginning. |
| 103 | + std::string::size_type lastPos = str.find_first_not_of(delim, 0); |
| 104 | + // Find first "non-delimiter". |
| 105 | + std::string::size_type pos = str.find_first_of(delim, lastPos); |
| 106 | + while (std::string::npos != pos || std::string::npos != lastPos) |
| 107 | + { |
| 108 | + // Found a token, add it to the vector. |
| 109 | + tokens.push_back(str.substr(lastPos, pos - lastPos)); |
| 110 | + // Skip delimiters. Note the "not_of" |
| 111 | + lastPos = str.find_first_not_of(delim, pos); |
| 112 | + // Find next "non-delimiter" |
| 113 | + pos = str.find_first_of(delim, lastPos); |
| 114 | + } |
| 115 | +} |
| 116 | + |
| 117 | +void run(const int &dim, const bool &gi, const bool &tpa, const std::string &alg, |
| 118 | + double &fevals_avg, double &succ_runs) |
| 119 | +{ |
| 120 | + fevals_avg = 0.0; |
| 121 | + succ_runs = 0.0; |
| 122 | + for (int r=0;r<FLAGS_runs;r++) |
| 123 | + { |
| 124 | + std::vector<double> x0(dim,-std::numeric_limits<double>::max()); |
| 125 | + CMAParameters<> cmaparams(x0,-1); |
| 126 | + cmaparams.set_tpa(tpa); |
| 127 | + cmaparams.set_gradient(gi); |
| 128 | + cmaparams.set_str_algo(alg); |
| 129 | + cmaparams.set_ftarget(1e-8); |
| 130 | + cmaparams.set_stopping_criteria(STAGNATION,false); |
| 131 | + //cmaparams.set_quiet(false); |
| 132 | + GradFunc gfunc = nullptr; |
| 133 | + if (gi) |
| 134 | + gfunc = mgfuncs[FLAGS_fname]; |
| 135 | + CMASolutions cmasols = cmaes<>(mfuncs[FLAGS_fname],cmaparams,CMAStrategy<CovarianceUpdate>::_defaultPFunc,gfunc); |
| 136 | + if (cmasols.best_candidate().get_fvalue() <= 1e-8) |
| 137 | + succ_runs++; |
| 138 | + fevals_avg += cmasols.fevals(); |
| 139 | + } |
| 140 | + fevals_avg /= succ_runs; |
| 141 | +} |
| 142 | + |
| 143 | +int main(int argc, char *argv[]) |
| 144 | +{ |
| 145 | + mfuncs["fsphere"]=fsphere; |
| 146 | + mgfuncs["fsphere"]=grad_fsphere; |
| 147 | + mfuncs["rosenbrock"]=rosenbrock; |
| 148 | + mgfuncs["rosenbrock"]=grad_rosenbrock; |
| 149 | + mfuncs["elli"]=elli; |
| 150 | + mgfuncs["elli"]=grad_elli; |
| 151 | + |
| 152 | + google::ParseCommandLineFlags(&argc, &argv, true); |
| 153 | + |
| 154 | + // dims |
| 155 | + std::vector<std::string> vdims_str; |
| 156 | + tokenize(FLAGS_dims,vdims_str,","); |
| 157 | + std::vector<int> vdims; |
| 158 | + for (size_t i=0;i<vdims_str.size();i++) |
| 159 | + vdims.push_back(atoi(vdims_str.at(i).c_str())); |
| 160 | + |
| 161 | + // dsigma |
| 162 | + /*std::vector<std::string> vds_str; |
| 163 | + tokenize(FLAGS_tpa_dsigmas,vds_str,","); |
| 164 | + std::vector<double> vds; |
| 165 | + for (size_t i=0;i<vds_str.size();i++) |
| 166 | + vds.push_back(strtod(vds_str.at(i).c_str(),NULL));*/ |
| 167 | + |
| 168 | + // runs |
| 169 | + std::cout << "D\tfevals_avg\t\tfevals_avg_tpa\t\tfevals_avg_gi\t\tfevals_avg_gi_tpa\n"; |
| 170 | + for (size_t d=0;d<vdims.size();d++) |
| 171 | + { |
| 172 | + int dim = vdims.at(d); |
| 173 | + double fevals_avg,fevals_avg_tpa,fevals_avg_gi,fevals_avg_gi_tpa; |
| 174 | + double succ_runs,succ_runs_tpa,succ_runs_gi,succ_runs_gi_tpa; |
| 175 | + run(dim,false,false,FLAGS_alg,fevals_avg,succ_runs); |
| 176 | + run(dim,false,true,FLAGS_alg,fevals_avg_tpa,succ_runs_tpa); |
| 177 | + run(dim,true,false,FLAGS_alg,fevals_avg_gi,succ_runs_gi); |
| 178 | + run(dim,true,true,FLAGS_alg,fevals_avg_gi_tpa,succ_runs_gi_tpa); |
| 179 | + std::cout << dim << "\t" << fevals_avg << " (" << succ_runs << ")\t\t" |
| 180 | + << fevals_avg_tpa << " (" << succ_runs_tpa << ")\t\t" |
| 181 | + << fevals_avg_gi << " (" << succ_runs_gi << ")\t\t" |
| 182 | + << fevals_avg_gi_tpa << "(" << succ_runs_gi_tpa << ")\n"; |
| 183 | + } |
| 184 | +} |
0 commit comments