Newer
Older
//************************************************************************//
// //
// Copyright 2013 Bertram Kopf (bertram@ep1.rub.de) //
// Julian Pychy (julian@ep1.rub.de) //
// - Ruhr-Universität Bochum //
// //
// This file is part of Pawian. //
// //
// Pawian is free software: you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation, either version 3 of the License, or //
// (at your option) any later version. //
// //
// Pawian is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with Pawian. If not, see <http://www.gnu.org/licenses/>. //
// //
//************************************************************************//
#define mysign(x) (( x > 0 ) - ( x < 0 ))
#include <iostream>
#include <fstream>
#include "ErrLogger/ErrLogger.hh"
#include "PwaUtils/EvoMinimizer.hh"
#include "PwaUtils/FitParamsBase.hh"
const double EvoMinimizer::DECREASESIGMAFACTOR = 0.9;
const double EvoMinimizer::INCREASESIGMAFACTOR = 1.1;
const double EvoMinimizer::DECREASELOWTHRESH = 0.2;
const double EvoMinimizer::INCREASEHIGHTHRESH = 0.2;
const double EvoMinimizer::LHSPREADEXIT = 0.01;
// Constructor takes AbsFcn to minimze, start parameters upar, population and iteration
// sizes and the output file name suffix
EvoMinimizer::EvoMinimizer(AbsFcn& theAbsFcn, MnUserParameters upar, int population, int iterations, std::string suffix) :
_population(population)
, _iterations(iterations)
, _theAbsFcn(&theAbsFcn)
, _fitParamBase(theAbsFcn.fitParamBase())
, _currentBestParams(theAbsFcn.defaultFitValParms())
, _defaultFitErrParms(theAbsFcn.defaultFitErrParms())
, _currentResultFileName("currentEvoResult"+suffix+".dat")
std::vector<double> EvoMinimizer::Minimize(){
double startlh = (*_theAbsFcn)(_bestParamsGlobal.Params());
double minlh = startlh;
int numnoimprovement = 0;
Info << "Start LH = " << startlh << endmsg;
for(int i = 0; i<_iterations; i++){
double itlh = minlh;
_iterationParamBackup = _bestParamsGlobal;
_bestParamsIteration = _bestParamsGlobal;
for(int j = 0; j<_population; j++){
// Get iteration start parameters and shuffle them
_tmpParams = _bestParamsGlobal;
ShuffleParams();
// Calc likelihood
double currentlh = (*_theAbsFcn)(_tmpParams.Params());
// Get information for break condition
if(fabs(currentlh - minlh) > maxitlhspread){
maxitlhspread = fabs(currentlh - minlh);
}
// Test for new best lh in iteration;
if(currentlh < itlh){
itlh = currentlh;
_bestParamsIteration = _tmpParams;
}
// Count number of lh improvements in the iteration
if(currentlh < minlh){
numbetterlh++;
}
}
// If a new minimum has been found, store information
// and print parameters
if(numbetterlh > 0){
_bestParamsGlobal = _bestParamsIteration;
minlh = itlh;
numnoimprovement=0;
_fitParamBase->getFitParamVal(_bestParamsGlobal.Params(), _currentBestParams);
std::ofstream theStream(_currentResultFileName.c_str());
_fitParamBase->dumpParams(theStream, _currentBestParams, _defaultFitErrParms);
}
else{
numnoimprovement++;
// Emergency sigma decrease
if(numnoimprovement > 5){
AdjustSigma(DECREASESIGMAFACTOR*DECREASESIGMAFACTOR, 0);
// Adjust errors depending on ratio of improved likelihoods to population size
std::string logmessage;
if(((double)numbetterlh / (double)_population) <= DECREASELOWTHRESH){
AdjustSigma(DECREASESIGMAFACTOR, numbetterlh);
logmessage = "Decreasing errors.";
else if(((double)numbetterlh / (double)_population) > INCREASEHIGHTHRESH){
AdjustSigma(INCREASESIGMAFACTOR, numbetterlh);
logmessage = "Increasing errors.";
Info << "===============================================" << endmsg;
Info << "Iteration " << i+1 << " / " << _iterations << " done. Best LH " << minlh << endmsg;
Info << "Likelihood improvements " << numbetterlh << " / " << _population << endmsg;
Info << "Likelihood spread " << maxitlhspread << endmsg;
Info << logmessage << endmsg;
Info << "===============================================" << endmsg;
} // Iterations
return _bestParamsGlobal.Params();
}
// Shuffles parameters using gauss distributions
void EvoMinimizer::ShuffleParams(){
typedef boost::normal_distribution<double> NormalDistribution;
typedef boost::mt19937 RandomGenerator;
typedef boost::variate_generator<RandomGenerator&, NormalDistribution> GaussianGenerator;
static RandomGenerator rng(static_cast<unsigned> (time(0)));
for(unsigned int i=0; i<_tmpParams.Params().size(); i++){
// Don't touch fixed parameters
if(_tmpParams.Parameter(i).IsFixed()){
continue;
}
// Decide whether parameter is increased or decreased
boost::random::uniform_int_distribution<> coin(0,1);
bool c = coin(rng);
// Initialize gaussian width as parameter error
double sigma = _tmpParams.Parameter(i).Error();
// If gaussian collides with parameter limit, reduce width
if(_tmpParams.Parameter(i).HasLimits()){
if(c && (2*sigma > (_tmpParams.Parameter(i).UpperLimit() - _tmpParams.Value(i)))){
sigma = (_tmpParams.Parameter(i).UpperLimit() - _tmpParams.Value(i)) / 2.0;
}
else if(!c && (2*sigma > (_tmpParams.Value(i) - _tmpParams.Parameter(i).LowerLimit()))){
sigma = (_tmpParams.Value(i) - _tmpParams.Parameter(i).LowerLimit()) / 2.0;
}
}
// Get random number and set new parameter
NormalDistribution gaussian_dist(0, sigma);
GaussianGenerator generator(rng, gaussian_dist);
double val = fabs(generator());
if(c) _tmpParams.SetValue(i, _tmpParams.Value(i) + val);
else _tmpParams.SetValue(i, _tmpParams.Value(i) - val);
if(_tmpParams.Parameter(i).HasLimits()){
if(_tmpParams.Value(i) < _tmpParams.Parameter(i).LowerLimit())
_tmpParams.SetValue(i, _tmpParams.Parameter(i).LowerLimit());
if(_tmpParams.Value(i) > _tmpParams.Parameter(i).UpperLimit())
_tmpParams.SetValue(i, _tmpParams.Parameter(i).UpperLimit());
}
// Increase or decrease parameter errors by a factor
void EvoMinimizer::AdjustSigma(double factor, int numimprovements){
for(unsigned int i=0; i<_bestParamsGlobal.Params().size(); i++){
// Don't touch fixed parameters
if(_bestParamsGlobal.Parameter(i).IsFixed()){
continue;
}
// When a lh improvement was achieved, don't decrease errors of parameters
// that changed rapidly, also add a bonus to increasements.
double afactor=factor;
double pardiffsigmas = fabs(_bestParamsGlobal.Value(i) - _iterationParamBackup.Value(i)) / _bestParamsGlobal.Error(i);
if(numimprovements > 0 && pardiffsigmas > 1.5){
if(factor < 1) afactor = 1.0;
else if(factor > 1 ) afactor *= afactor;
// Set new error
_bestParamsGlobal.SetError(i, _bestParamsGlobal.Error(i) * afactor);
const char* EvoMinimizer::evologo = R"(
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
....$$$$ZZZ$$Z7ZZ:..... .
.~$ZZ.............O$ZZ+.
.. ... ...=...............ZZZ.. .... .. ..ZOO: ...
......$OZZ$7$ZZ$ZZZZZZZZZZ$ZZ.....ZO$.... .. .ZO. .
..:8OO...................:ZZ.......Z$. .. .. ..OO...
...OOO. .... .. .... ....$Z...
.8OO..... . . .. . +$Z...
. .OO... .......$Z...
.OO. ... ....Z:Z$... .
OO...... . ........ .. ...$$:ZZ.ZZOZ.. .
OOO88O8OOI........... .. ....... .....ZZZZZ...$ZZO...
8O.....,$ZZOZZOOOO8OOOZ$........ ..$OZ$..........7$7..
88.. . . ....~ZZOOZOOZZZ$.... .Z....ZZZ$... .$$$:....
.8O..... ................ZZ.. .... ....ZZ.. ..$ZZ....
..8OO... . ....... ........ ....... .OO$. ..$:Z...
...888~.... ..... ....ZOZ.. ...ZZ$..
......88OO. .. ..... .,OZZ.. ....ZZ$.
.888OO............. . ..OOZ.. . ....ZZOO. ..$$Z....
...7888OO$........ . ...ZOOZZZZDZZZO.... ...ZZ$...
.......ZO8O8OOZZ.. . ...ZOOO8Z$..... . ... ZZZ..
....,ZOOOOZ.. . ........=ZOOZZO$...... .ZZ$....
.........=O8.... ..O88OZZ...$ZZZZ?.. ...ZZ....
. ..88O... .. ...OO?ZOZZ... ..ZZZZ.......ZZ...
... .O8O?.... .O8,.ZOZZ$. ....ZZZZ......ZO..
.....ODOI.. .O8.....ZO.. .... .ZZZZ. ..OO.
..OOO8OI.. .. ..O8. ZZZ... . ...Z$$$?.Z$....
.O8..ZOOOOZ..... ZZ.. .ZO.... .. ...ZZZ$$$$.. .
....O8,...ZOOO88O...... .Z.. ..ZZ.... .ZZ$$Z...
...OO8.....ZOO.O8OZ. .....:. .. .ZO... ....$$Z$.
.. .Z8...... .OO$.ZOOO.Z.,O8. . ..$O.. .. ..$$$
....OO........,OOOOOOOO$Z.OO..... ..$O~....... .ZZZ:
....IZO.......8888O8OO..Z$ZZOO.... ..,Z8....... ...ZO$O
.......=O8888O.. .O88O....OO+OOOOZO88O........~,ZZZ$Z....... . ....ZZ..
.Z888OOO7....O88O............ZOZOOZOOOOZOOOO$.............. ....7ZOO...
..O888OOOO8OOOO8OZZ=IZZOZO8OOO8OOOZZOZ..ZZZ~$ZZ$?.7?I?::?$OOOZZZZZZ$Z.OOZ.
. .O88888888OOOOOOOO8OOOOOOZZOOOZ~..,ZZ=.~=7......ZZZZ$$ZZZZ$Z$ZZZZZZZOZ...
.. .......... ....... .Z$?ZZZOZ$IIZ$=7Z:=7ZZ~.....................$ZZO..
. ... .... ....... .... ..$+I7Z$$ZZZZZZZ$ZZZZZZZZZZZZZ$Z$$..
. ........ ...............+?=...
//**********************************************************************************//
// //
// ApeFrog evolutionary minimizer //
// //
//**********************************************************************************//
)";