ROOT  6.06/09
Reference Guide
Configurable.cxx
Go to the documentation of this file.
1 // @(#)root/tmva $Id$
2 // Author: Andreas Hoecker, Joerg Stelzer, Helge Voss
3 
4 /**********************************************************************************
5  * Project: TMVA - a Root-integrated toolkit for multivariate data analysis *
6  * Package: TMVA *
7  * Class : Configurable *
8  * Web : http://tmva.sourceforge.net *
9  * *
10  * Description: *
11  * Implementation (see header for description) *
12  * *
13  * Authors (alphabetical): *
14  * Andreas Hoecker <Andreas.Hocker@cern.ch> - CERN, Switzerland *
15  * Joerg Stelzer <Joerg.Stelzer@cern.ch> - CERN, Switzerland *
16  * Helge Voss <Helge.Voss@cern.ch> - MPI-K Heidelberg, Germany *
17  * *
18  * Copyright (c) 2005: *
19  * CERN, Switzerland *
20  * MPI-K Heidelberg, Germany *
21  * *
22  * Redistribution and use in source and binary forms, with or without *
23  * modification, are permitted according to the terms listed in LICENSE *
24  * (http://tmva.sourceforge.net/LICENSE) *
25  * *
26  **********************************************************************************/
27 
28 ////////////////////////////////////////////////////////////////////////////////
29 
30 /* Begin_Html
31 Base Class for all classes that need option parsing
32 End_Html */
33 //________________________________________________________________________
34 
35 #include <string>
36 #include <iostream>
37 #include <fstream>
38 #include <cstdlib>
39 #include <vector>
40 
41 #include "TROOT.h"
42 #include "TSystem.h"
43 #include "TString.h"
44 #include "TObjString.h"
45 #include "TQObject.h"
46 #include "TSpline.h"
47 #include "TMatrix.h"
48 #include "TMath.h"
49 #include "TFile.h"
50 #include "TKey.h"
51 
52 #include "TMVA/Configurable.h"
53 #include "TMVA/Config.h"
54 #include "TMVA/Tools.h"
55 
56 // don't change this flag without a good reason ! The FitterBase code won't work anymore !!!
57 // #define TMVA_Configurable_SanctionUnknownOption kTRUE
58 
60 
61 #ifdef _WIN32
62 /*Disable warning C4355: 'this' : used in base member initializer list*/
63 #pragma warning ( disable : 4355 )
64 #endif
65 
66 ////////////////////////////////////////////////////////////////////////////////
67 /// constructor
68 
70  : fOptions ( theOption ),
71  fLooseOptionCheckingEnabled ( kTRUE ),
72  fLastDeclaredOption ( 0 ),
73  fConfigName ( "Configurable" ), // must be replaced by name of class that uses the configurable
74  fConfigDescription ( "No description" ),
75  fReferenceFile ( "None" ),
76  fLogger ( new MsgLogger(this) )
77 {
78  fListOfOptions.SetOwner();
79 
80  // check if verbosity "V" set in option
81  if (gTools().CheckForVerboseOption( theOption )) Log().SetMinType( kVERBOSE );
82 }
83 
84 ////////////////////////////////////////////////////////////////////////////////
85 /// default destructur
86 
88 {
89  delete fLogger;
90 }
91 
92 ////////////////////////////////////////////////////////////////////////////////
93 /// splits the option string at ':' and fills the list 'loo' with the primitive strings
94 
95 void TMVA::Configurable::SplitOptions(const TString& theOpt, TList& loo) const
96 {
97  TString splitOpt(theOpt);
98  loo.SetOwner();
99  while (splitOpt.Length()>0) {
100  if (!splitOpt.Contains(':')) {
101  loo.Add(new TObjString(splitOpt));
102  splitOpt = "";
103  }
104  else {
105  TString toSave = splitOpt(0,splitOpt.First(':'));
106  loo.Add(new TObjString(toSave.Data()));
107  splitOpt = splitOpt(splitOpt.First(':')+1,splitOpt.Length());
108  }
109  }
110 }
111 
112 ////////////////////////////////////////////////////////////////////////////////
113 /// resets the IsSet falg for all declare options
114 /// to be called before options are read from stream
115 
117 {
118  TListIter decOptIt(&fListOfOptions); // declared options
119  while (OptionBase* decOpt = (OptionBase*) decOptIt()) { // loop over declared options
120  decOpt->fIsSet = kFALSE;
121  }
122 }
123 
124 ////////////////////////////////////////////////////////////////////////////////
125 /// options parser
126 
128 {
129  Log() << kVERBOSE << "Parsing option string: " << Endl;
130  TString optionsWithoutTilde(fOptions);
131  optionsWithoutTilde.ReplaceAll(TString("~"),TString(""));
132  Log() << kVERBOSE << "... \"" << optionsWithoutTilde << "\"" << Endl;
133 
134  TList loo; // the List Of Options in the parsed string
135 
136  fOptions = fOptions.Strip(TString::kLeading, ':');
137 
138  // separate the options by the ':' marker
139  SplitOptions(fOptions, loo);
140  fOptions = "";
141 
142  // loop over the declared options and check for their availability
143  std::map<TString, std::vector<std::pair<Int_t, TString> > > arrayTypeOptions;
144 
145  TListIter decOptIt(&fListOfOptions); // declared options
146  TListIter setOptIt(&loo); // parsed options
147  while (TObjString * os = (TObjString*) setOptIt()) { // loop over parsed options
148 
149  TString s = os->GetString();
150 
151  // the tilde in the beginning is an indication that the option
152  // has been accepted during previous parsing
153  //
154  // while parsing this option string eventual appearances of the
155  // tilde will be preserved, for correctly parsed options a new
156  // one will be added (in the end it will be checked if all
157  // options were parsed
158  Bool_t preserveTilde = s.BeginsWith('~');
159  s = s.Strip(TString::kLeading, '~');
160 
161  Bool_t paramParsed = kFALSE;
162  if (s.Contains('=')) { // desired way of setting an option: "...:optname=optvalue:..."
163  TString optname = s(0,s.First('=')); optname.ToLower();
164  TString optval = s(s.First('=')+1,s.Length());
165  Int_t idx = -1;
166 
167  // First check if the optname exists in the list of the
168  // objects. This does not depend on the existence of a [] in
169  // the optname. Sometimes the [] is part of the optname and
170  // does not describe an array
171  OptionBase* decOpt = (OptionBase *)fListOfOptions.FindObject(optname);
172  if (decOpt==0 && optname.Contains('[')) {
173  // now we see if there is an [] and if the optname exists
174  // after removing the [idx]
175  TString st = optname(optname.First('[')+1,100);
176  st.Remove(st.First(']'));
177  std::stringstream str(st.Data());
178  str >> idx; // save the array index
179  optname.Remove(optname.First('[')); // and remove [idx] from the option name
180  decOpt = (OptionBase *)fListOfOptions.FindObject(optname);
181  }
182 
183  TListIter optIt(&fListOfOptions);
184  if (decOpt!=0) {
185  if (decOpt->IsSet())
186  Log() << kWARNING << "Value for option " << decOpt->GetName()
187  << " was previously set to " << decOpt->GetValue() << Endl;
188 
189  if (!decOpt->HasPreDefinedVal() || (decOpt->HasPreDefinedVal() && decOpt->IsPreDefinedVal(optval)) ) {
190  if (decOpt->IsArrayOpt()) { // arrays
191  // if no index was found then we assume the value is to be set for the entire array
192  if (idx==-1) {
193  decOpt->SetValue(optval);
194  }
195  else {
196  // since we don't know what else is comming we just put everthing into a map
197  if (!decOpt->SetValue(optval, idx))
198  Log() << kFATAL << "Index " << idx << " too large for option " << decOpt->TheName()
199  << ", allowed range is [0," << decOpt->GetArraySize()-1 << "]" << Endl;
200  }
201  }
202  else { // no arrays
203  if (idx!=-1)
204  Log() << kFATAL << "Option " << decOpt->TheName()
205  << " is not an array, but you specified an index" << Endl;
206  decOpt->SetValue(optval);
207  }
208  paramParsed = kTRUE;
209  }
210  else Log() << kFATAL << "Option " << decOpt->TheName()
211  << " does not have predefined value: \"" << optval << "\"" << Endl;
212  }
213  }
214 
215  // boolean variables can be specified by just their name (!name),
216  // which will set the to true (false): ...:V:...:!S:..
217  Bool_t preserveNotSign = kFALSE;
218  if (!paramParsed) {
219  Bool_t hasNotSign = kFALSE;
220  if (s.BeginsWith("!")) { s.Remove(0,1); preserveNotSign = hasNotSign = kTRUE; }
221  TString optname(s); optname.ToLower();
222  OptionBase* decOpt = 0;
223  Bool_t optionExists = kFALSE;
224  TListIter optIt(&fListOfOptions);
225  while ((decOpt = (OptionBase*)optIt()) !=0) {
226  TString predOptName(decOpt->GetName());
227  predOptName.ToLower();
228  if (predOptName == optname) optionExists = kTRUE;
229  if (dynamic_cast<Option<bool>*>(decOpt)==0) continue; // not a boolean option
230  if (predOptName == optname) break;
231  }
232 
233 
234  if (decOpt != 0) {
235  decOpt->SetValue( hasNotSign ? "0" : "1" );
236  paramParsed = kTRUE;
237  }
238  else {
239  if (optionExists && hasNotSign) {
240  Log() << kFATAL << "Negating a non-boolean variable " << optname
241  << ", please check the opions for method: " << GetName() << Endl;
242  }
243  }
244  }
245 
246 
247  if (!paramParsed && LooseOptionCheckingEnabled()) {
248  // loose options specification, loops through the possible string
249  // values any parameter can have not applicable for boolean or floats
250  decOptIt.Reset();
251  while (OptionBase* decOpt = (OptionBase*) decOptIt()) {
252  if (decOpt->HasPreDefinedVal() && decOpt->IsPreDefinedVal(s) ) {
253  paramParsed = decOpt->SetValue(s);
254  break;
255  }
256  }
257  }
258 
259  if (fOptions!="") fOptions += ":";
260  if (paramParsed || preserveTilde) fOptions += '~';
261  if (preserveNotSign) fOptions += '!';
262  fOptions += s;
263  }
264 
265  // print options summary
266  PrintOptions();
267  if (gConfig().WriteOptionsReference()) WriteOptionsReferenceToFile();
268 }
269 
270 ////////////////////////////////////////////////////////////////////////////////
271 /// checks for unused options in option string
272 
274 {
275  TString theOpt(fOptions);
276  theOpt = theOpt.Strip(TString::kLeading, ':');
277 
278  // separate the options by the ':' marker
279  TList loo; // the List of Options in the parsed string
280  SplitOptions(theOpt, loo);
281 
282  TListIter setOptIt(&loo); // options in a list
283  TString unusedOptions("");
284  while (TObjString * os = (TObjString*) setOptIt()) { // loop over parsed options
285 
286  TString s = os->GetString();
287  if (!s.BeginsWith('~')) {
288  if (unusedOptions != "") unusedOptions += ':';
289  unusedOptions += s;
290  }
291  }
292  if (unusedOptions != "") {
293  Log() << kFATAL
294  << "The following options were specified, but could not be interpreted: \'"
295  << unusedOptions << "\', please check!" << Endl;
296  }
297 }
298 
299 ////////////////////////////////////////////////////////////////////////////////
300 /// prints out the options set in the options string and the defaults
301 
303 {
304  Log() << kVERBOSE << "The following options are set:" << Endl;
305 
306  TListIter optIt( &fListOfOptions );
307  Log() << kVERBOSE << "- By User:" << Endl;
308  Bool_t found = kFALSE;
309  while (OptionBase* opt = (OptionBase *) optIt()) {
310  if (opt->IsSet()) { Log() << kVERBOSE << " "; opt->Print(Log()); Log() << Endl; found = kTRUE; }
311  }
312  if (!found) Log() << kVERBOSE << " <none>" << Endl;
313 
314  optIt.Reset();
315  Log() << kVERBOSE << "- Default:" << Endl;
316  found = kFALSE;
317  while (OptionBase* opt = (OptionBase *) optIt()) {
318  if (!opt->IsSet()) { Log() << kVERBOSE << " "; opt->Print(Log()); Log() << Endl; found = kTRUE; }
319  }
320  if (!found) Log() << kVERBOSE << " <none>" << Endl;
321 }
322 
323 ////////////////////////////////////////////////////////////////////////////////
324 /// write options to output stream (e.g. in writing the MVA weight files
325 
326 void TMVA::Configurable::WriteOptionsToStream( std::ostream& o, const TString& prefix ) const
327 {
328  TListIter optIt( &fListOfOptions );
329  o << prefix << "# Set by User:" << std::endl;
330  while (OptionBase * opt = (OptionBase *) optIt())
331  if (opt->IsSet()) { o << prefix; opt->Print(o); o << std::endl; }
332  optIt.Reset();
333  o << prefix << "# Default:" << std::endl;
334  while (OptionBase * opt = (OptionBase *) optIt())
335  if (!opt->IsSet()) { o << prefix; opt->Print(o); o << std::endl; }
336  o << prefix << "##" << std::endl;
337 }
338 
339 ////////////////////////////////////////////////////////////////////////////////
340 /// write options to XML file
341 
342 void TMVA::Configurable::AddOptionsXMLTo( void* parent ) const
343 {
344  if (!parent) return;
345  void* opts = gTools().AddChild(parent, "Options");
346  TListIter optIt( &fListOfOptions );
347  while (OptionBase * opt = (OptionBase *) optIt()) {
348  void* optnode = 0;
349  if (opt->IsArrayOpt()) {
350  std::stringstream s("");
351  s.precision( 16 );
352  for(Int_t i=0; i<opt->GetArraySize(); i++) {
353  if(i>0) s << " ";
354  s << std::scientific << opt->GetValue(i);
355  }
356  optnode = gTools().AddChild(opts,"Option",s.str().c_str());
357  }
358  else {
359  optnode = gTools().AddChild(opts,"Option", opt->GetValue());
360  }
361  gTools().AddAttr(optnode, "name", opt->TheName());
362  if (opt->IsArrayOpt()) {
363  gTools().AddAttr(optnode, "size", opt->GetArraySize());
364  }
365  gTools().AddAttr(optnode, "modified", (opt->IsSet()?"Yes":"No") );
366  }
367 }
368 
369 ////////////////////////////////////////////////////////////////////////////////
370 
372 {
373  void* opt = gTools().GetChild(node);
374  TString optName, optValue;
375  fOptions="";
376  while (opt != 0) {
377  if (fOptions.Length()!=0) fOptions += ":";
378  gTools().ReadAttr(opt, "name", optName);
379  optValue = TString( gTools().GetContent(opt) );
380  std::stringstream s("");
381  s.precision( 16 );
382  if (gTools().HasAttr(opt, "size")) {
383  UInt_t size;
384  gTools().ReadAttr(opt, "size", size);
385  std::vector<TString> values = gTools().SplitString(optValue, ' ');
386  for(UInt_t i=0; i<size; i++) {
387  if(i!=0) s << ":";
388  s << std::scientific << optName << "[" << i << "]=" << values[i];
389  }
390  }
391  else {
392  s << std::scientific << optName << "=" << optValue;
393  }
394  fOptions += s.str().c_str();
395  opt = gTools().GetNextChild(opt);
396  }
397 }
398 
399 ////////////////////////////////////////////////////////////////////////////////
400 /// write complete options to output stream
401 
403 {
405  gSystem->MakeDirectory( dir );
406  fReferenceFile = dir + "/" + GetConfigName() + "_optionsRef.txt";
407  std::ofstream o( fReferenceFile );
408  if (!o.good()) { // file could not be opened --> Error
409  Log() << kFATAL << "<WriteOptionsToInfoFile> Unable to open output file: " << fReferenceFile << Endl;
410  }
411 
412  TListIter optIt( &fListOfOptions );
413  o << "# List of options:" << std::endl;
414  o << "# Configurable: " << GetConfigName() << std::endl;
415  o << "# Description: " << GetConfigDescription() << std::endl;
416  while (OptionBase * opt = (OptionBase *) optIt()) {
417  opt->Print( o, 1 );
418  o << std::endl << "# ------------------------------------------------" << std::endl;
419  }
420 
421  o.close();
422  Log() << kVERBOSE << "Wrote options reference file: \"" << fReferenceFile << "\"" << Endl;
423 }
424 
425 ////////////////////////////////////////////////////////////////////////////////
426 /// read option back from the weight file
427 
429 {
430  // first set the IsSet flag of all declared options to false
431  // that is only necessary in our factory, when we test right
432  // after the training
433  ResetSetFlag();
434  fOptions = "";
435  char buf[512];
436  istr.getline(buf,512);
437  TString stropt, strval;
438  while (istr.good() && !istr.eof() && !(buf[0]=='#' && buf[1]=='#')) { // if line starts with ## return
439  char *p = buf;
440  while (*p==' ' || *p=='\t') p++; // 'remove' leading whitespace
441  if (*p=='#' || *p=='\0') {
442  istr.getline(buf,512); // reading the next line
443  continue; // if comment or empty line, read the next line
444  }
445  std::stringstream sstr(buf);
446  sstr >> stropt >> strval;
447  stropt.ReplaceAll(':','=');
448  strval.ReplaceAll("\"","");
449  if (fOptions.Length()!=0) fOptions += ":";
450  fOptions += stropt;
451  fOptions += strval;
452  istr.getline(buf,512); // reading the next line
453  }
454 }
455 
TString fOptionsReferenceFileDir
Definition: Config.h:102
void AddOptionsXMLTo(void *parent) const
write options to XML file
MsgLogger & Endl(MsgLogger &ml)
Definition: MsgLogger.h:162
void ReadOptionsFromXML(void *node)
Ssiz_t Length() const
Definition: TString.h:390
Collectable string class.
Definition: TObjString.h:32
void ReadOptionsFromStream(std::istream &istr)
read option back from the weight file
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition: TString.h:635
void CheckForUnusedOptions() const
checks for unused options in option string
virtual void SetOwner(Bool_t enable=kTRUE)
Set whether this collection is the owner (enable==true) of its content.
Config & gConfig()
virtual ~Configurable()
default destructur
virtual int MakeDirectory(const char *name)
Make a directory.
Definition: TSystem.cxx:821
Basic string class.
Definition: TString.h:137
virtual Bool_t IsArrayOpt() const =0
void ToLower()
Change string to lower-case.
Definition: TString.cxx:1088
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
const Bool_t kFALSE
Definition: Rtypes.h:92
void SplitOptions(const TString &theOpt, TList &loo) const
splits the option string at ':' and fills the list 'loo' with the primitive strings ...
virtual TString GetValue(Int_t i=-1) const =0
void AddAttr(void *node, const char *, const T &value, Int_t precision=16)
Definition: Tools.h:308
Bool_t BeginsWith(const char *s, ECaseCompare cmp=kExact) const
Definition: TString.h:558
void WriteOptionsToStream(std::ostream &o, const TString &prefix) const
write options to output stream (e.g. in writing the MVA weight files
void * AddChild(void *parent, const char *childname, const char *content=0, bool isRootNode=false)
add child node
Definition: Tools.cxx:1134
MsgLogger * fLogger
Definition: Configurable.h:140
Iterator of linked list.
Definition: TList.h:187
const char * Data() const
Definition: TString.h:349
Tools & gTools()
Definition: Tools.cxx:79
Bool_t IsSet() const
Definition: Option.h:74
void * GetChild(void *parent, const char *childname=0)
get child node
Definition: Tools.cxx:1158
IONames & GetIONames()
Definition: Config.h:78
virtual void ParseOptions()
options parser
virtual Bool_t SetValue(const TString &vs, Int_t i=-1)
set value for option
Definition: Option.cxx:48
A doubly linked list.
Definition: TList.h:47
void PrintOptions() const
prints out the options set in the options string and the defaults
R__EXTERN TSystem * gSystem
Definition: TSystem.h:549
virtual const char * TheName() const
Definition: Option.h:71
unsigned int UInt_t
Definition: RtypesCore.h:42
void WriteOptionsReferenceToFile()
write complete options to output stream
TSubString Strip(EStripType s=kTrailing, char c= ' ') const
Return a substring of self stripped at beginning and/or end.
Definition: TString.cxx:1069
void ReadAttr(void *node, const char *, T &value)
Definition: Tools.h:295
Configurable(const TString &theOption="")
virtual Bool_t HasPreDefinedVal() const =0
virtual Int_t GetArraySize() const =0
TString & Remove(Ssiz_t pos)
Definition: TString.h:616
void ResetSetFlag()
resets the IsSet falg for all declare options to be called before options are read from stream ...
void * GetNextChild(void *prevchild, const char *childname=0)
XML helpers.
Definition: Tools.cxx:1170
virtual Bool_t IsPreDefinedVal(const TString &) const =0
virtual void Add(TObject *obj)
Definition: TList.h:81
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition: TString.h:567
void Reset()
Reset list iterator.
Definition: TList.cxx:976
ClassImp(TMVA::Configurable) TMVA
constructor
const Bool_t kTRUE
Definition: Rtypes.h:91
virtual TObject * FindObject(const char *name) const
Must be redefined in derived classes.
Definition: TObject.cxx:379
virtual const char * GetName() const
Returns name of object.
Definition: Option.h:70
std::vector< TString > SplitString(const TString &theOpt, const char separator) const
splits the option string at 'separator' and fills the list 'splitV' with the primitive strings ...
Definition: Tools.cxx:1207
Definition: math.cpp:60
Ssiz_t First(char c) const
Find first occurrence of a character c.
Definition: TString.cxx:466