![]() |
|
|||
File indexing completed on 2025-04-19 09:06:52
0001 #ifndef RIVET_MendelMin_H 0002 #define RIVET_MendelMin_H 0003 0004 #include "Rivet/Tools/Random.hh" 0005 #include <valarray> 0006 #include <random> 0007 #include <functional> 0008 #include <map> 0009 #include <vector> 0010 #include <cmath> 0011 #include <iostream> 0012 #include <iomanip> 0013 0014 namespace Rivet { 0015 0016 using std::valarray; 0017 0018 0019 /// @brief A genetic algorithm functional minimizer 0020 /// 0021 /// MendelMin implements a home brewed genetic algorithm for finding 0022 /// the minimum of a function defined on a unit hypercube returning a 0023 /// non-negative real number (eg. a Chi-squared value). 0024 class MendelMin { 0025 public: 0026 0027 /// Typedef for a valaray of parameters to the function to be minimised. 0028 using Params = std::valarray<double>; 0029 /// Typedef for the function to be minimised 0030 using FuncT = std::function<double(const Params&, const Params&)>; 0031 /// Typedef for the function to be minimised 0032 using FuncNoFixedT = std::function<double(const Params&)>; 0033 // /// Typedef for the [0,1] random number generator 0034 // using RndT = std::function<double()>; 0035 0036 0037 /// Constructor with fixed parameters 0038 /// 0039 /// Mandatory arguments: the function, @a fin, to be minimised; 0040 /// the dimension, @a ndim, of the unit hypercube for which @a fin is 0041 /// defined; a set of fixed parameters not to be optimised. 0042 /// 0043 /// Optional arguments are: the number, @a npop, of individuals in the 0044 /// population; and @a margin which determines how much randomness is 0045 /// involved when an individual is evolved twowards the fittest individual. 0046 MendelMin(const FuncT& fin, unsigned int ndim, 0047 const Params& fixpar, //const RndT & rndin, 0048 unsigned int npop=20, //unsigned int ngen=20, //< unused 0049 double margin=0.1) 0050 : _f(fin), _q(fixpar), //_rnd(rndin), 0051 _NDim(ndim), _margin(margin), 0052 _pop(npop), _fit(npop, -1.0), showTrace(false) {} 0053 0054 0055 /// Constructor without fixed parameters 0056 /// 0057 /// Mandatory arguments: the function, @a fin, to be minimised; the 0058 /// dimension, @a ndim, of the unit hypercube for which @a fin is defined. 0059 /// 0060 /// Optional arguments are: the number, @a npop, of individuals in the 0061 /// population; and @a margin which determines how much randomness is 0062 /// involved when an individual is evolved twowards the fittest individual. 0063 MendelMin(const FuncNoFixedT& fin, unsigned int ndim, 0064 //const RndT & rndin, 0065 unsigned int npop=20, unsigned int ngen=20, 0066 double margin=0.1) 0067 : MendelMin([&](const Params& ps, const Params&) -> double { return fin(ps); }, 0068 ndim, {}, npop, /* ngen, */ margin) 0069 { } 0070 0071 0072 /// Supply a best guess for the fittest parameter point to help 0073 /// things along. 0074 void guess(const Params & p) { 0075 _pop.push_back(p); 0076 limit01(_pop.back()); 0077 _fit.push_back(f(_pop.back())); 0078 } 0079 0080 0081 /// Evolve the population a given number of generations and return 0082 /// the best fit value. 0083 double evolve(unsigned int nGen) { 0084 for ( unsigned n = 0; n < nGen; ++n ) { 0085 // Calculate the fitness. 0086 auto mm = minmax(); 0087 // Always kill the fittest individual. 0088 if ( showTrace ) _debug(); 0089 for ( unsigned int i = 1; i < _pop.size(); ++i ) { 0090 if ( _fit[i] > rnd()*(mm.second - mm.first) ) 0091 // Kill all individuals that have low fitness or are just unlucky. 0092 _fit[i] = -1.0; 0093 else 0094 // Improve This individual to be more like the fittest. 0095 move(_pop[i],_pop[0]); 0096 } 0097 } 0098 return _fit[0]; 0099 } 0100 0101 /// Return the fittest parameter point found. 0102 Params fittest() const { 0103 return _pop[0]; 0104 } 0105 0106 /// Return the fittest value found. 0107 double fit() const { 0108 return _fit[0]; 0109 } 0110 0111 /// Simple wrapper around the random number generator. 0112 double rnd() const { 0113 return rand01(); //_rnd(); 0114 } 0115 0116 /// Return a random parameter point in the unit hypercube. 0117 Params rndParams() const { 0118 Params ret(_NDim); 0119 for ( unsigned int i = 0; i < _NDim; ++i ) ret[i] = rnd(); 0120 return ret; 0121 } 0122 0123 /// Limit a parameter point to inside the unit hypercube. 0124 void limit01(Params & p) const { 0125 for ( unsigned int i = 0; i < _NDim; ++i ) 0126 p[i] = std::max(0.0, std::min(p[i], 1.0)); 0127 } 0128 0129 /// Move a @a bad parameter point towards a @a better one. The new 0130 /// point is picked randomly within the generalized hypercube where 0131 /// @a bad and @a better are at diagonally opposite corners, enlarged by 0132 /// a fraction _margin. 0133 void move(Params & bad, const Params & better) const { 0134 bad += (better - bad)*(rndParams()*(1.0 + 2.0*_margin) - _margin); 0135 limit01(bad); 0136 } 0137 0138 /// Simple wrapper around the function to be minimised. 0139 double f(const Params & p) const { 0140 return _f(p, _q); 0141 } 0142 0143 0144 /// Calculate the fitness values of all individuals and put the 0145 /// fittest one first. @return the best and worst fitness values. 0146 std::pair<double, double> minmax() { 0147 std::pair<double,double> mm(std::numeric_limits<double>::max(), 0.0); 0148 unsigned int iwin = 0; 0149 for ( unsigned int i = 0; i < _pop.size(); ++i ) { 0150 double & v = _fit[i]; 0151 // negative fitness value means the individual is dead, so we 0152 // welocme a new immigrant. 0153 if ( v < 0.0 ) _pop[i] = rndParams(); 0154 0155 // The calculated fitness value cannot be negative. 0156 v = std::max(0.0, f(_pop[i])); 0157 0158 // Compare to the best and worst fitness so far. 0159 if ( v < mm.first ) iwin = i; 0160 mm.first = std::min(v, mm.first); 0161 mm.second = std::max(mm.second, v); 0162 } 0163 0164 // Move the winner to the top. 0165 if ( iwin != 0 ) { 0166 std::swap(_pop[0], _pop[iwin]); 0167 std::swap(_fit[0], _fit[iwin]); 0168 } 0169 return mm; 0170 } 0171 0172 /// Inspect a population and the fitness of its individuals. 0173 void _debug() { 0174 std::cout << "GenAlgMax population status:" << std::endl; 0175 for ( unsigned int i = 0; i < _pop.size(); ++i ) { 0176 std::cout << std::setw(10) << _fit[i] << " (" << _pop[i][0]; 0177 for ( unsigned int ip = 1; ip < _NDim; ++ip ) 0178 std::cout << "," << _pop[i][ip]; 0179 std::cout << ")" << std::endl; 0180 } 0181 } 0182 0183 0184 private: 0185 0186 /// The function to be minimised. 0187 const FuncT _f; 0188 0189 /// The fixed parameter points. 0190 Params _q; 0191 0192 /// The fixed parameters of the function. 0193 // const double _q; 0194 0195 /// The random number generator. 0196 //const RndT _rnd; 0197 0198 /// The dimension of the unit hypercube of allowed parameter points. 0199 unsigned int _NDim; 0200 0201 /// WHen evolving less fit parameter point towards the fittest one 0202 /// we choose randomly in a generalised hypercube where these two 0203 /// parameter points are in diagonally opposite corners, expanded in 0204 /// each direction with This fraction. 0205 double _margin; 0206 0207 /// The population of parameter points. 0208 std::vector<Params> _pop; 0209 0210 0211 /// The fitness value of each individual in the population. 0212 std::vector<double> _fit; 0213 0214 public: 0215 0216 /// Set true to get a verbose record of the evolution. 0217 bool showTrace; 0218 0219 }; 0220 0221 0222 /// Construct a MendelMin object taking as arguments: the function, @a 0223 /// fin, to be minimised; a random number generator, @rndin, returning 0224 /// double random numbers between 0 and 1; the dimension, @a ndim, of 0225 /// the unit hypercube for which @a fin is defined; the number, @a 0226 /// npop, of individuals in the population; and a @a margin which 0227 /// determines how much ramndomness is involved when an individual is 0228 /// evolved twowards the fittest individual. 0229 // template <typename FuncT, typename RndT> 0230 // MendelMin <FuncT, RndT> 0231 // makeMendelMin(const FuncT & f, const RndT & rnd, unsigned int ndim, 0232 // unsigned int npop = 20, double margin = 0.1) { 0233 // return MendelMin<FuncT, RndT>(f, rnd, ndim, npop, margin); 0234 // } 0235 0236 } 0237 0238 #endif // RIVET_MendelMin_H
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
![]() ![]() |