Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
GeneticMinimizer.cxx
Go to the documentation of this file.
2 
4 #include "TMVA/IFitterTarget.h"
5 
6 #include "Math/IFunction.h"
7 #include "Math/GenAlgoOptions.h"
8 
9 #include "TError.h"
10 
11 #include <cassert>
12 
13 namespace ROOT {
14 namespace Math {
15 
16 
17 // wrapper class for TMVA interface to evaluate objective function
18 class MultiGenFunctionFitness : public TMVA::IFitterTarget {
19 private:
20  unsigned int fNCalls;
21  unsigned int fNFree;
22  const ROOT::Math::IMultiGenFunction& fFunc;
23  std::vector<int> fFixedParFlag;
24  mutable std::vector<double> fValues;
25 
26 public:
27  MultiGenFunctionFitness(const ROOT::Math::IMultiGenFunction& function) : fNCalls(0),
28  fFunc(function)
29  { fNFree = fFunc.NDim(); }
30 
31  unsigned int NCalls() const { return fNCalls; }
32  unsigned int NDims() const { return fNFree; }
33 
34  unsigned int NTotal() const { return fFunc.NDim(); }
35 
36  void FixParameter(unsigned int ipar, double value, bool fix = true) {
37 
38  if (fValues.size() != fFunc.NDim() ) {
39  fValues.resize(fFunc.NDim() );
40  fFixedParFlag.resize(fFunc.NDim());
41  }
42 
43  if (ipar >= fValues.size() ) return;
44 
45  // first find if it has been already fixed
46  fFixedParFlag[ipar] = fix;
47  fValues[ipar] = value;
48  // count number of fixed params
49  for (unsigned int i = 0; i < fFixedParFlag.size(); ++i)
50  if (!fFixedParFlag[i] ) fNFree++;
51 
52  }
53 
54  // transfrom from internal parameters (not fixed to external vector which include the fixed ones)
55  const std::vector<double> & Transform( const std::vector<double> & factors) const {
56  unsigned int n = fValues.size();
57  if (n == 0 || fNFree == n )
58  return factors;
59 
60  // in case of fixed parameters
61  for (unsigned int i = 0, j = 0; i < n ; ++i) {
62  if (!fFixedParFlag[i] ) {
63  assert (j < fNFree);
64  fValues[i] = factors[j];
65  j++;
66  }
67  }
68  return fValues;
69  }
70 
71  Double_t Evaluate(const std::vector<double> & factors ) const {
72  const std::vector<double> & x = Transform( factors);
73  return fFunc(&x[0]);
74  }
75 
76  Double_t EstimatorFunction(std::vector<double> & factors ){
77  fNCalls += 1;
78  return Evaluate( factors);
79  }
80 };
81 
82 GeneticMinimizerParameters::GeneticMinimizerParameters()
83 {
84  // constructor of parameters with default values (use 100 is max iterations is not defined)
85  int defmaxiter = ROOT::Math::MinimizerOptions::DefaultMaxIterations();
86  fNsteps = (defmaxiter > 0) ? defmaxiter : 100;
87  fPopSize =300;
88  fCycles = 3;
89  fSC_steps =10;
90  fSC_rate =5;
91  fSC_factor=0.95;
92  fConvCrit =10.0 * ROOT::Math::MinimizerOptions::DefaultTolerance(); // default is 0.001
93  if (fConvCrit <=0 ) fConvCrit = 0.001;
94  fSeed=0; // random seed
95 }
96 
97 // genetic minimizer class
98 
99 GeneticMinimizer::GeneticMinimizer(int ):
100  fFitness(0),
101  fMinValue(0),
102  fParameters(GeneticMinimizerParameters() )
103 {
104 
105  // check with default minimizer options
106  ROOT::Math::IOptions * geneticOpt = ROOT::Math::MinimizerOptions::FindDefault("Genetic");
107  if (geneticOpt) {
108  ROOT::Math::MinimizerOptions opt; // create using default options
109  opt.SetExtraOptions(*geneticOpt);
110  this->SetOptions(opt);
111  }
112 
113  // set the parameters
114  SetTolerance(0.1 * fParameters.fConvCrit);
115  SetMaxIterations( fParameters.fNsteps);
116  }
117 
118 GeneticMinimizer::~GeneticMinimizer()
119 {
120  if ( fFitness )
121  {
122  delete fFitness;
123  fFitness = 0;
124  }
125 }
126 
127 void GeneticMinimizer::Clear()
128 {
129  fRanges.clear();
130  fResult.clear();
131  if ( fFitness )
132  {
133  delete fFitness;
134  fFitness = 0;
135  }
136 }
137 
138 void GeneticMinimizer::SetFunction(const ROOT::Math::IMultiGenFunction & func)
139 {
140  Clear();
141 
142  fFitness = new MultiGenFunctionFitness(func);
143  fResult = std::vector<double>(func.NDim() );
144  assert(fResult.size() == NDim() );
145 }
146 
147 bool GeneticMinimizer::SetLimitedVariable(unsigned int , const std::string & , double , double , double lower , double upper )
148 {
149  fRanges.push_back( new TMVA::Interval(lower,upper) );
150 
151  return true;
152 }
153 
154 bool GeneticMinimizer::SetVariable(unsigned int, const std::string& name, double value, double step)
155 {
156  //It does nothing! As there is no variable if it has no limits!
157  double lower = value - (50 * step);
158  double upper = value + (50 * step);
159  Info("GeneticMinimizer::SetVariable", "Variables should be limited - set automatic range to 50 times step size for %s : [%f, %f]",
160  name.c_str(),lower,upper);
161  fRanges.push_back( new TMVA::Interval(lower, upper ) );
162 
163  return true;
164 }
165 
166 bool GeneticMinimizer::SetFixedVariable(unsigned int par, const std::string& name, double value) {
167  // set a fixed variable
168  if (!fFitness) {
169  Error("GeneticMinimizer::SetFixedVariable", "Function has not been set - cannot set fixed variables %s",name.c_str());
170  return false;
171  }
172 
173  static_cast<MultiGenFunctionFitness*>(fFitness)->FixParameter(par, value);
174  return true;
175 }
176 
177 
178 void GeneticMinimizer::SetParameters(const GeneticMinimizerParameters & params )
179 {
180  fParameters = params;
181  // set also the one defined in Minimizer
182  SetTolerance( 0.1 * fParameters.fConvCrit);
183  SetMaxIterations( fParameters.fNsteps );
184 }
185 
186 ROOT::Math::MinimizerOptions GeneticMinimizer::Options() const {
187  ROOT::Math::MinimizerOptions opt;
188  GetGeneticOptions(opt);
189  return opt;
190 }
191 
192 void GeneticMinimizer::GetGeneticOptions(ROOT::Math::MinimizerOptions & opt) const {
193  // get the genetic options of the class and return them in the MinimizerOptions class
194  opt.SetTolerance(fParameters.fConvCrit/10); // use a factor of 10 to have default as Minuit
195  opt.SetPrintLevel(PrintLevel() );
196  opt.SetMaxIterations(fParameters.fNsteps);
197  // use fixed or dammy value for the other options
198  opt.SetMinimizerType("Genetic");
199  opt.SetMaxFunctionCalls(0);
200  opt.SetStrategy(-1);
201  opt.SetErrorDef(0);
202  opt.SetPrecision(0);
203  opt.SetMinimizerAlgorithm("");
204 
205  ROOT::Math::GenAlgoOptions geneticOpt;
206  geneticOpt.SetValue("PopSize",fParameters.fPopSize);
207  geneticOpt.SetValue("Steps",fParameters.fNsteps);
208  geneticOpt.SetValue("Cycles",fParameters.fCycles);
209  geneticOpt.SetValue("SC_steps",fParameters.fSC_steps);
210  geneticOpt.SetValue("SC_rate",fParameters.fSC_rate);
211  geneticOpt.SetValue("SC_factor",fParameters.fSC_factor);
212  geneticOpt.SetValue("ConvCrit",fParameters.fConvCrit);
213  geneticOpt.SetValue("RandomSeed",fParameters.fSeed);
214 
215  opt.SetExtraOptions(geneticOpt);
216 }
217 
218 void GeneticMinimizer::SetOptions(const ROOT::Math::MinimizerOptions & opt)
219 {
220  SetTolerance(opt.Tolerance() );
221  SetPrintLevel(opt.PrintLevel() );
222  //SetMaxFunctionCalls(opt.MaxFunctionCalls() );
223  SetMaxIterations(opt.MaxIterations() );
224 
225  fParameters.fConvCrit = 10.*opt.Tolerance(); // use a factor of 10 to have default as Minuit
226 
227  // set genetic parameter from minimizer options
228  const ROOT::Math::IOptions * geneticOpt = opt.ExtraOptions();
229  if (!geneticOpt) {
230  Warning("GeneticMinimizer::SetOptions", "No specific genetic minimizer options have been set");
231  return;
232  }
233 
234  // if options are not existing values will not be set
235  geneticOpt->GetValue("PopSize",fParameters.fPopSize);
236  geneticOpt->GetValue("Steps",fParameters.fNsteps);
237  geneticOpt->GetValue("Cycles",fParameters.fCycles);
238  geneticOpt->GetValue("SC_steps",fParameters.fSC_steps);
239  geneticOpt->GetValue("SC_rate",fParameters.fSC_rate);
240  geneticOpt->GetValue("SC_factor",fParameters.fSC_factor);
241  geneticOpt->GetValue("ConvCrit",fParameters.fConvCrit);
242  geneticOpt->GetValue("RandomSeed",fParameters.fSeed);
243 
244  // use same of options in base class
245  int maxiter = opt.MaxIterations();
246  if (maxiter > 0 && fParameters.fNsteps > 0 && maxiter != fParameters.fNsteps ) {
247  Warning("GeneticMinimizer::SetOptions", "max iterations value given different than than Steps - set equal to Steps %d",fParameters.fNsteps);
248  }
249  if (fParameters.fNsteps > 0) SetMaxIterations(fParameters.fNsteps);
250 
251 }
252 
253 bool GeneticMinimizer::Minimize()
254 {
255 
256  if (!fFitness) {
257  Error("GeneticMinimizer::Minimize","Fitness function has not been set");
258  return false;
259  }
260 
261  // sync parameters
262  if (MaxIterations() > 0) fParameters.fNsteps = MaxIterations();
263  if (Tolerance() > 0) fParameters.fConvCrit = 10* Tolerance();
264 
265  TMVA::GeneticAlgorithm mg( *fFitness, fParameters.fPopSize, fRanges, fParameters.fSeed );
266 
267  if (PrintLevel() > 0) {
268  std::cout << "GeneticMinimizer::Minimize - Start iterating - max iterations = " << MaxIterations()
269  << " conv criteria (tolerance) = " << fParameters.fConvCrit << std::endl;
270  }
271 
272  fStatus = 0;
273  unsigned int niter = 0;
274  do {
275  mg.Init();
276 
277  mg.CalculateFitness();
278 
279  // Just for debugging options
280  //mg.GetGeneticPopulation().Print(0);
281 
282  mg.GetGeneticPopulation().TrimPopulation();
283 
284  mg.SpreadControl( fParameters.fSC_steps, fParameters.fSC_rate, fParameters.fSC_factor );
285 
286  if (PrintLevel() > 2) {
287  std::cout << "New Iteration " << niter << " with parameter values :" << std::endl;
288  TMVA::GeneticGenes* genes = mg.GetGeneticPopulation().GetGenes( 0 );
289  if (genes) {
290  std::vector<Double_t> gvec;
291  gvec = genes->GetFactors();
292  for (unsigned int i = 0; i < gvec.size(); ++i) {
293  std::cout << gvec[i] << " ";
294  }
295  std::cout << std::endl;
296  std::cout << "\tFitness function value = " << static_cast<MultiGenFunctionFitness*>(fFitness)->Evaluate(gvec) << std::endl;
297  }
298  }
299  niter++;
300  if ( niter > MaxIterations() && MaxIterations() > 0) {
301  if (PrintLevel() > 0) {
302  Info("GeneticMinimizer::Minimize","Max number of iterations %d reached - stop iterating",MaxIterations());
303  }
304  fStatus = 1;
305  break;
306  }
307 
308  } while (!mg.HasConverged( fParameters.fNsteps, fParameters.fConvCrit )); // converged if: fitness-improvement < CONVCRIT within the last CONVSTEPS loops
309 
310  TMVA::GeneticGenes* genes = mg.GetGeneticPopulation().GetGenes( 0 );
311  std::vector<Double_t> gvec;
312  gvec = genes->GetFactors();
313 
314 
315  // transform correctly gvec on fresult in case there are fixed parameters
316  const std::vector<double> & transVec = static_cast<MultiGenFunctionFitness*>(fFitness)->Transform(gvec);
317  std::copy(transVec.begin(), transVec.end(), fResult.begin() );
318  fMinValue = static_cast<MultiGenFunctionFitness*>(fFitness)->Evaluate(gvec);
319 
320 
321  if (PrintLevel() > 0) {
322  if (PrintLevel() > 2) std::cout << std::endl;
323  std::cout << "Finished Iteration (niter = " << niter << " with fitness function value = " << MinValue() << std::endl;
324  for (unsigned int i = 0; i < fResult.size(); ++i) {
325  std::cout << " Parameter-" << i << "\t=\t" << fResult[i] << std::endl;
326  }
327  }
328 
329  return true;
330 }
331 
332 double GeneticMinimizer::MinValue() const
333 {
334  return (fFitness) ? fMinValue : 0;
335 }
336 
337 const double * GeneticMinimizer::X() const {
338  return (fFitness) ? &fResult[0] : 0;
339 }
340 
341 unsigned int GeneticMinimizer::NCalls() const
342 {
343  if ( fFitness )
344  return static_cast<MultiGenFunctionFitness*>(fFitness)->NCalls();
345  else
346  return 0;
347 }
348 
349 unsigned int GeneticMinimizer::NDim() const
350 {
351  if ( fFitness )
352  return static_cast<MultiGenFunctionFitness*>(fFitness)->NTotal();
353  else
354  return 0;
355 }
356 unsigned int GeneticMinimizer::NFree() const
357 {
358  if ( fFitness )
359  return static_cast<MultiGenFunctionFitness*>(fFitness)->NDims();
360  else
361  return 0;
362 }
363 
364 // Functions we don't need...
365 const double * GeneticMinimizer::MinGradient() const { return 0; }
366 bool GeneticMinimizer::ProvidesError() const { return false; }
367 const double * GeneticMinimizer::Errors() const { return 0; }
368 double GeneticMinimizer::Edm() const { return 0; }
369 double GeneticMinimizer::CovMatrix(unsigned int, unsigned int) const { return 0; }
370 
371 }
372 }