00001 #include "Math/GeneticMinimizer.h"
00002
00003 #include "TMVA/GeneticAlgorithm.h"
00004 #include "TMVA/IFitterTarget.h"
00005
00006 #include "Math/IFunction.h"
00007 #include "Math/GenAlgoOptions.h"
00008
00009 #include "TError.h"
00010
00011 #include <cassert>
00012
00013 namespace ROOT {
00014 namespace Math {
00015
00016
00017
00018 class MultiGenFunctionFitness : public TMVA::IFitterTarget {
00019 private:
00020 unsigned int fNCalls;
00021 const ROOT::Math::IMultiGenFunction& fFunc;
00022
00023 public:
00024 MultiGenFunctionFitness(const ROOT::Math::IMultiGenFunction& function) : fFunc(function) { fNCalls = 0; }
00025
00026 unsigned int NCalls() const { return fNCalls; }
00027 unsigned int NDims() const { return fFunc.NDim(); }
00028
00029 Double_t Evaluate(const std::vector<double> & factors ) const {
00030 return fFunc(&factors[0]);
00031 }
00032
00033 Double_t EstimatorFunction(std::vector<double> & factors ){
00034 fNCalls += 1;
00035 return fFunc(&factors[0]);
00036 }
00037 };
00038
00039 GeneticMinimizerParameters::GeneticMinimizerParameters()
00040 {
00041
00042 fNsteps = 40;
00043 fPopSize =300;
00044 fCycles = 3;
00045 fSC_steps =10;
00046 fSC_rate =5;
00047 fSC_factor=0.95;
00048 fConvCrit =10.0 * ROOT::Math::MinimizerOptions::DefaultTolerance();
00049 if (fConvCrit <=0 ) fConvCrit = 0.001;
00050
00051 }
00052
00053 GeneticMinimizer::GeneticMinimizer(int ):
00054 fFitness(0),
00055 fParameters(GeneticMinimizerParameters() )
00056 {
00057
00058
00059 ROOT::Math::IOptions * geneticOpt = ROOT::Math::MinimizerOptions::FindDefault("Genetic");
00060 if (geneticOpt) {
00061 ROOT::Math::MinimizerOptions opt;
00062 opt.SetExtraOptions(*geneticOpt);
00063 this->SetOptions(opt);
00064 }
00065 }
00066
00067 GeneticMinimizer::~GeneticMinimizer()
00068 {
00069 if ( fFitness )
00070 {
00071 delete fFitness;
00072 fFitness = 0;
00073 }
00074 }
00075
00076 void GeneticMinimizer::Clear()
00077 {
00078 fRanges.clear();
00079 fResult.clear();
00080 if ( fFitness )
00081 {
00082 delete fFitness;
00083 fFitness = 0;
00084 }
00085 }
00086
00087 void GeneticMinimizer::SetFunction(const ROOT::Math::IMultiGenFunction & func)
00088 {
00089 Clear();
00090
00091 fFitness = new MultiGenFunctionFitness(func);
00092 }
00093
00094 bool GeneticMinimizer::SetLimitedVariable(unsigned int , const std::string & , double , double , double lower , double upper )
00095 {
00096 fRanges.push_back( new TMVA::Interval(lower,upper) );
00097
00098 return true;
00099 }
00100
00101 bool GeneticMinimizer::SetVariable(unsigned int, const std::string&, double value, double step)
00102 {
00103
00104 Info("GeneticMinimizer::SetVariable", "Variables should be limited on a Genetic Minimizer - set automatic range to 50 times step size");
00105 fRanges.push_back( new TMVA::Interval(value - (50 * step), value + (50 * step)) );
00106
00107 return true;
00108 }
00109
00110 void GeneticMinimizer::SetParameters(const GeneticMinimizerParameters & params )
00111 {
00112 fParameters = params;
00113 }
00114
00115 ROOT::Math::MinimizerOptions GeneticMinimizer::Options() const {
00116 ROOT::Math::MinimizerOptions opt;
00117 GetGeneticOptions(opt);
00118 return opt;
00119 }
00120
00121 void GeneticMinimizer::GetGeneticOptions(ROOT::Math::MinimizerOptions & opt) const {
00122
00123 opt.SetTolerance(fParameters.fConvCrit/10);
00124 opt.SetPrintLevel(PrintLevel() );
00125 opt.SetMaxFunctionCalls(MaxIterations());
00126
00127 opt.SetMinimizerType("Genetic");
00128 opt.SetMaxFunctionCalls(0);
00129 opt.SetStrategy(-1);
00130 opt.SetErrorDef(0);
00131 opt.SetPrecision(0);
00132 opt.SetMinimizerAlgorithm("");
00133
00134 ROOT::Math::GenAlgoOptions geneticOpt;
00135 geneticOpt.SetValue("PopSize",fParameters.fPopSize);
00136 geneticOpt.SetValue("Steps",fParameters.fNsteps);
00137 geneticOpt.SetValue("Cycles",fParameters.fCycles);
00138 geneticOpt.SetValue("SC_steps",fParameters.fSC_steps);
00139 geneticOpt.SetValue("SC_rate",fParameters.fSC_rate);
00140 geneticOpt.SetValue("SC_factor",fParameters.fSC_factor);
00141 geneticOpt.SetValue("ConvCrit",fParameters.fConvCrit);
00142
00143 opt.SetExtraOptions(geneticOpt);
00144 }
00145
00146 void GeneticMinimizer::SetOptions(const ROOT::Math::MinimizerOptions & opt)
00147 {
00148 SetTolerance(opt.Tolerance() );
00149 SetPrintLevel(opt.PrintLevel() );
00150
00151 SetMaxIterations(opt.MaxIterations() );
00152
00153 fParameters.fConvCrit = 10.*opt.Tolerance();
00154
00155
00156 ROOT::Math::IOptions * geneticOpt = opt.ExtraOptions();
00157 if (!geneticOpt) {
00158 Warning("GeneticMinimizer::SetOptions", "No specific genetic minimizer options have been set");
00159 return;
00160 }
00161
00162
00163 geneticOpt->GetValue("PopSize",fParameters.fPopSize);
00164 geneticOpt->GetValue("Steps",fParameters.fNsteps);
00165 geneticOpt->GetValue("Cycles",fParameters.fCycles);
00166 geneticOpt->GetValue("SC_steps",fParameters.fSC_steps);
00167 geneticOpt->GetValue("SC_rate",fParameters.fSC_rate);
00168 geneticOpt->GetValue("SC_factor",fParameters.fSC_factor);
00169 geneticOpt->GetValue("ConvCrit",fParameters.fConvCrit);
00170
00171
00172 int maxiter = MaxIterations();
00173 if ( maxiter > 0 && maxiter < fParameters.fNsteps ) {
00174 Warning("GeneticMinimizer::SetOptions", "max iterations smaller than Steps - set equal to steps %d",fParameters.fNsteps);
00175 SetMaxIterations(fParameters.fNsteps);
00176 }
00177
00178
00179 }
00180
00181 bool GeneticMinimizer::Minimize()
00182 {
00183
00184 if (!fFitness) {
00185 Error("GeneticMinimizer::Minimize","Fitness function has not been set");
00186 return false;
00187 }
00188
00189 TMVA::GeneticAlgorithm mg( *fFitness, fParameters.fPopSize, fRanges );
00190
00191 if (PrintLevel() > 0) {
00192 Info("GeneticMinimizer::Minimize","Start iterating - max iterations = %d , conv criteria (tolerance) = %10e6 ",
00193 MaxIterations() , fParameters.fConvCrit );
00194 }
00195
00196 fStatus = 0;
00197 unsigned int niter = 0;
00198 do {
00199 mg.Init();
00200
00201 mg.CalculateFitness();
00202
00203
00204
00205
00206 mg.GetGeneticPopulation().TrimPopulation();
00207
00208 mg.SpreadControl( fParameters.fSC_steps, fParameters.fSC_rate, fParameters.fSC_factor );
00209
00210 if (PrintLevel() > 2) {
00211 std::cout << "New Iteration " << niter << " with parameter values :" << std::endl;
00212 TMVA::GeneticGenes* genes = mg.GetGeneticPopulation().GetGenes( 0 );
00213 if (genes) {
00214 std::vector<Double_t> gvec;
00215 gvec = genes->GetFactors();
00216 for (unsigned int i = 0; i < gvec.size(); ++i) {
00217 std::cout << gvec[i] << " ";
00218 }
00219 std::cout << std::endl;
00220 std::cout << "\tFitness function value = " << static_cast<MultiGenFunctionFitness*>(fFitness)->Evaluate(gvec) << std::endl;
00221 }
00222 }
00223 niter++;
00224 if ( niter > MaxIterations() && MaxIterations() > 0) {
00225 if (PrintLevel() > 0) {
00226 Info("GeneticMinimizer::Minimize","Max number of iterations %d reached - stop iterating",MaxIterations());
00227 }
00228 fStatus = 1;
00229 break;
00230 }
00231
00232 } while (!mg.HasConverged( fParameters.fNsteps, fParameters.fConvCrit ));
00233
00234 TMVA::GeneticGenes* genes = mg.GetGeneticPopulation().GetGenes( 0 );
00235 std::vector<Double_t> gvec;
00236 gvec = genes->GetFactors();
00237
00238 fResult = gvec;
00239
00240
00241 if (PrintLevel() > 0) {
00242 if (PrintLevel() > 2) std::cout << std::endl;
00243 std::cout << "Finished Iteration (niter = " << niter << " with fitness function value = " << MinValue() << std::endl;
00244 for (unsigned int i = 0; i < fResult.size(); ++i) {
00245 std::cout << " Parameter-" << i << "\t=\t" << fResult[i] << std::endl;
00246 }
00247 }
00248
00249 return true;
00250 }
00251
00252 double GeneticMinimizer::MinValue() const
00253 {
00254 if ( fFitness )
00255 return static_cast<MultiGenFunctionFitness*>(fFitness)->Evaluate(fResult);
00256 else
00257 return 0;
00258 }
00259
00260 const double * GeneticMinimizer::X() const { return &fResult[0]; }
00261
00262 unsigned int GeneticMinimizer::NCalls() const
00263 {
00264 if ( fFitness )
00265 return static_cast<MultiGenFunctionFitness*>(fFitness)->NCalls();
00266 else
00267 return 0;
00268 }
00269
00270 unsigned int GeneticMinimizer::NDim() const
00271 {
00272 if ( fFitness )
00273 return static_cast<MultiGenFunctionFitness*>(fFitness)->NDims();
00274 else
00275 return 0;
00276 }
00277 unsigned int GeneticMinimizer::NFree() const
00278 {
00279
00280 return NDim();
00281 }
00282
00283
00284 const double * GeneticMinimizer::MinGradient() const { return 0; }
00285 bool GeneticMinimizer::ProvidesError() const { return false; }
00286 const double * GeneticMinimizer::Errors() const { return 0; }
00287 double GeneticMinimizer::Edm() const { return 0; }
00288 double GeneticMinimizer::CovMatrix(unsigned int, unsigned int) const { return 0; }
00289
00290 }
00291 }