Logo ROOT   6.12/07
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 /*! \class TMVA::
29 \ingroup TMVA
30 
31  Base Class for all classes that need option parsing
32 
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 #include "TMVA/Types.h"
56 
57 // don't change this flag without a good reason ! The FitterBase code won't work anymore !!!
58 // #define TMVA_Configurable_SanctionUnknownOption kTRUE
59 
61 
62 #ifdef _WIN32
63 /*Disable warning C4355: 'this' : used in base member initializer list*/
64 #pragma warning ( disable : 4355 )
65 #endif
66 
67 ////////////////////////////////////////////////////////////////////////////////
68 /// constructor
69 
71 : TNamed("Configurable","Configurable"),
72  fOptions ( theOption ),
73  fLooseOptionCheckingEnabled ( kTRUE ),
74  fLastDeclaredOption ( 0 ),
75  fConfigDescription ( "No description" ),
76  fReferenceFile ( "None" ),
77  fLogger ( new MsgLogger(this) )
78 {
80 
81  // check if verbosity "V" set in option
82  if (gTools().CheckForVerboseOption( theOption )) Log().SetMinType( kVERBOSE );
83 }
84 
85 ////////////////////////////////////////////////////////////////////////////////
86 /// default destructor
87 
89 {
90  delete fLogger;
91 }
92 
93 ////////////////////////////////////////////////////////////////////////////////
94 /// splits the option string at ':' and fills the list 'loo' with the primitive strings
95 
96 void TMVA::Configurable::SplitOptions(const TString& theOpt, TList& loo) const
97 {
98  TString splitOpt(theOpt);
99  loo.SetOwner();
100  while (splitOpt.Length()>0) {
101  if (!splitOpt.Contains(':')) {
102  loo.Add(new TObjString(splitOpt));
103  splitOpt = "";
104  }
105  else {
106  TString toSave = splitOpt(0,splitOpt.First(':'));
107  loo.Add(new TObjString(toSave.Data()));
108  splitOpt = splitOpt(splitOpt.First(':')+1,splitOpt.Length());
109  }
110  }
111 }
112 
113 ////////////////////////////////////////////////////////////////////////////////
114 /// resets the IsSet flag for all declare options
115 /// to be called before options are read from stream
116 
118 {
119  TListIter decOptIt(&fListOfOptions); // declared options
120  while (OptionBase* decOpt = (OptionBase*) decOptIt()) { // loop over declared options
121  decOpt->fIsSet = kFALSE;
122  }
123 }
124 
125 ////////////////////////////////////////////////////////////////////////////////
126 /// options parser
127 
129 {
130  Log() << kVERBOSE << "Parsing option string: " << Endl;
131  TString optionsWithoutTilde(fOptions);
132  optionsWithoutTilde.ReplaceAll(TString("~"),TString(""));
133  Log() << kVERBOSE << "... \"" << optionsWithoutTilde << "\"" << Endl;
134 
135  TList loo; // the List Of Options in the parsed string
136 
138 
139  // separate the options by the ':' marker
140  SplitOptions(fOptions, loo);
141  fOptions = "";
142 
143  // loop over the declared options and check for their availability
144  std::map<TString, std::vector<std::pair<Int_t, TString> > > arrayTypeOptions;
145 
146  TListIter decOptIt(&fListOfOptions); // declared options
147  TListIter setOptIt(&loo); // parsed options
148  while (TObjString * os = (TObjString*) setOptIt()) { // loop over parsed options
149 
150  TString s = os->GetString();
151 
152  // the tilde in the beginning is an indication that the option
153  // has been accepted during previous parsing
154  //
155  // while parsing this option string eventual appearances of the
156  // tilde will be preserved, for correctly parsed options a new
157  // one will be added (in the end it will be checked if all
158  // options were parsed
159  Bool_t preserveTilde = s.BeginsWith('~');
160  s = s.Strip(TString::kLeading, '~');
161 
162  Bool_t paramParsed = kFALSE;
163  if (s.Contains('=')) { // desired way of setting an option: "...:optname=optvalue:..."
164  TString optname = s(0,s.First('=')); optname.ToLower();
165  TString optval = s(s.First('=')+1,s.Length());
166  Int_t idx = -1;
167 
168  // First check if the optname exists in the list of the
169  // objects. This does not depend on the existence of a [] in
170  // the optname. Sometimes the [] is part of the optname and
171  // does not describe an array
172  OptionBase* decOpt = (OptionBase *)fListOfOptions.FindObject(optname);
173  if (decOpt==0 && optname.Contains('[')) {
174  // now we see if there is an [] and if the optname exists
175  // after removing the [idx]
176  TString st = optname(optname.First('[')+1,100);
177  st.Remove(st.First(']'));
178  std::stringstream str(st.Data());
179  str >> idx; // save the array index
180  optname.Remove(optname.First('[')); // and remove [idx] from the option name
181  decOpt = (OptionBase *)fListOfOptions.FindObject(optname);
182  }
183 
184  TListIter optIt(&fListOfOptions);
185  if (decOpt!=0) {
186  if (decOpt->IsSet())
187  Log() << kWARNING << "Value for option " << decOpt->GetName()
188  << " was previously set to " << decOpt->GetValue() << Endl;
189 
190  if (!decOpt->HasPreDefinedVal() || (decOpt->HasPreDefinedVal() && decOpt->IsPreDefinedVal(optval)) ) {
191  if (decOpt->IsArrayOpt()) { // arrays
192  // if no index was found then we assume the value is to be set for the entire array
193  if (idx==-1) {
194  decOpt->SetValue(optval);
195  }
196  else {
197  // since we don't know what else is coming we just put everthing into a map
198  if (!decOpt->SetValue(optval, idx))
199  Log() << kFATAL << "Index " << idx << " too large for option " << decOpt->TheName()
200  << ", allowed range is [0," << decOpt->GetArraySize()-1 << "]" << Endl;
201  }
202  }
203  else { // no arrays
204  if (idx!=-1)
205  Log() << kFATAL << "Option " << decOpt->TheName()
206  << " is not an array, but you specified an index" << Endl;
207  decOpt->SetValue(optval);
208  }
209  paramParsed = kTRUE;
210  }
211  else Log() << kFATAL << "Option " << decOpt->TheName()
212  << " does not have predefined value: \"" << optval << "\"" << Endl;
213  }
214  }
215 
216  // boolean variables can be specified by just their name (!name),
217  // which will set the to true (false): ...:V:...:!S:..
218  Bool_t preserveNotSign = kFALSE;
219  if (!paramParsed) {
220  Bool_t hasNotSign = kFALSE;
221  if (s.BeginsWith("!")) { s.Remove(0,1); preserveNotSign = hasNotSign = kTRUE; }
222  TString optname(s); optname.ToLower();
223  OptionBase* decOpt = 0;
224  Bool_t optionExists = kFALSE;
225  TListIter optIt(&fListOfOptions);
226  while ((decOpt = (OptionBase*)optIt()) !=0) {
227  TString predOptName(decOpt->GetName());
228  predOptName.ToLower();
229  if (predOptName == optname) optionExists = kTRUE;
230  if (dynamic_cast<Option<bool>*>(decOpt)==0) continue; // not a boolean option
231  if (predOptName == optname) break;
232  }
233 
234 
235  if (decOpt != 0) {
236  decOpt->SetValue( hasNotSign ? "0" : "1" );
237  paramParsed = kTRUE;
238  }
239  else {
240  if (optionExists && hasNotSign) {
241  Log() << kFATAL << "Negating a non-boolean variable " << optname
242  << ", please check the options for method: " << GetName() << Endl;
243  }
244  }
245  }
246 
247 
248  if (!paramParsed && LooseOptionCheckingEnabled()) {
249  // loose options specification, loops through the possible string
250  // values any parameter can have not applicable for boolean or floats
251  decOptIt.Reset();
252  while (OptionBase* decOpt = (OptionBase*) decOptIt()) {
253  if (decOpt->HasPreDefinedVal() && decOpt->IsPreDefinedVal(s) ) {
254  paramParsed = decOpt->SetValue(s);
255  break;
256  }
257  }
258  }
259 
260  if (fOptions!="") fOptions += ":";
261  if (paramParsed || preserveTilde) fOptions += '~';
262  if (preserveNotSign) fOptions += '!';
263  fOptions += s;
264  }
265 
266  // print options summary
267  PrintOptions();
268  if (gConfig().WriteOptionsReference()) WriteOptionsReferenceToFile();
269 }
270 
271 ////////////////////////////////////////////////////////////////////////////////
272 /// checks for unused options in option string
273 
275 {
276  TString theOpt(fOptions);
277  theOpt = theOpt.Strip(TString::kLeading, ':');
278 
279  // separate the options by the ':' marker
280  TList loo; // the List of Options in the parsed string
281  SplitOptions(theOpt, loo);
282 
283  TListIter setOptIt(&loo); // options in a list
284  TString unusedOptions("");
285  while (TObjString * os = (TObjString*) setOptIt()) { // loop over parsed options
286 
287  TString s = os->GetString();
288  if (!s.BeginsWith('~')) {
289  if (unusedOptions != "") unusedOptions += ':';
290  unusedOptions += s;
291  }
292  }
293  if (unusedOptions != "") {
294  Log() << kFATAL
295  << "The following options were specified, but could not be interpreted: \'"
296  << unusedOptions << "\', please check!" << Endl;
297  }
298 }
299 
300 ////////////////////////////////////////////////////////////////////////////////
301 /// prints out the options set in the options string and the defaults
302 
304 {
305  Log() << kVERBOSE << "The following options are set:" << Endl;
306 
307  TListIter optIt( &fListOfOptions );
308  Log() << kVERBOSE << "- By User:" << Endl;
309  Bool_t found = kFALSE;
310  while (OptionBase* opt = (OptionBase *) optIt()) {
311  if (opt->IsSet()) {
312  Log() << kVERBOSE << " ";
313  std::ostringstream oss;
314  opt->Print(oss);
315  Log() << oss.str();
316  Log() << Endl; found = kTRUE; }
317  }
318  if (!found) Log() << kVERBOSE << " <none>" << Endl;
319 
320  optIt.Reset();
321  Log() << kVERBOSE << "- Default:" << Endl;
322  found = kFALSE;
323  while (OptionBase* opt = (OptionBase *) optIt()) {
324  if (!opt->IsSet()) {
325  Log() << kVERBOSE << " ";
326  std::ostringstream oss;
327  opt->Print(oss);
328  Log() << oss.str();
329  Log() << Endl; found = kTRUE; }
330  }
331  if (!found) Log() << kVERBOSE << " <none>" << Endl;
332 }
333 
334 ////////////////////////////////////////////////////////////////////////////////
335 /// write options to output stream (e.g. in writing the MVA weight files
336 
337 void TMVA::Configurable::WriteOptionsToStream( std::ostream& o, const TString& prefix ) const
338 {
339  TListIter optIt( &fListOfOptions );
340  o << prefix << "# Set by User:" << std::endl;
341  while (OptionBase * opt = (OptionBase *) optIt())
342  if (opt->IsSet()) { o << prefix; opt->Print(o); o << std::endl; }
343  optIt.Reset();
344  o << prefix << "# Default:" << std::endl;
345  while (OptionBase * opt = (OptionBase *) optIt())
346  if (!opt->IsSet()) { o << prefix; opt->Print(o); o << std::endl; }
347  o << prefix << "##" << std::endl;
348 }
349 
350 ////////////////////////////////////////////////////////////////////////////////
351 /// write options to XML file
352 
353 void TMVA::Configurable::AddOptionsXMLTo( void* parent ) const
354 {
355  if (!parent) return;
356  void* opts = gTools().AddChild(parent, "Options");
357  TListIter optIt( &fListOfOptions );
358  while (OptionBase * opt = (OptionBase *) optIt()) {
359  void* optnode = 0;
360  if (opt->IsArrayOpt()) {
361  std::stringstream s("");
362  s.precision( 16 );
363  for(Int_t i=0; i<opt->GetArraySize(); i++) {
364  if(i>0) s << " ";
365  s << std::scientific << opt->GetValue(i);
366  }
367  optnode = gTools().AddChild(opts,"Option",s.str().c_str());
368  }
369  else {
370  optnode = gTools().AddChild(opts,"Option", opt->GetValue());
371  }
372  gTools().AddAttr(optnode, "name", opt->TheName());
373  if (opt->IsArrayOpt()) {
374  gTools().AddAttr(optnode, "size", opt->GetArraySize());
375  }
376  gTools().AddAttr(optnode, "modified", (opt->IsSet()?"Yes":"No") );
377  }
378 }
379 
380 ////////////////////////////////////////////////////////////////////////////////
381 
383 {
384  void* opt = gTools().GetChild(node);
385  TString optName, optValue;
386  fOptions="";
387  while (opt != 0) {
388  if (fOptions.Length()!=0) fOptions += ":";
389  gTools().ReadAttr(opt, "name", optName);
390  optValue = TString( gTools().GetContent(opt) );
391  std::stringstream s("");
392  s.precision( 16 );
393  if (gTools().HasAttr(opt, "size")) {
394  UInt_t size;
395  gTools().ReadAttr(opt, "size", size);
396  std::vector<TString> values = gTools().SplitString(optValue, ' ');
397  for(UInt_t i=0; i<size; i++) {
398  if(i!=0) s << ":";
399  s << std::scientific << optName << "[" << i << "]=" << values[i];
400  }
401  }
402  else {
403  s << std::scientific << optName << "=" << optValue;
404  }
405  fOptions += s.str().c_str();
406  opt = gTools().GetNextChild(opt);
407  }
408 }
409 
410 ////////////////////////////////////////////////////////////////////////////////
411 /// write complete options to output stream
412 
414 {
416  gSystem->MakeDirectory( dir );
417  fReferenceFile = dir + "/" + GetConfigName() + "_optionsRef.txt";
418  std::ofstream o( fReferenceFile );
419  if (!o.good()) { // file could not be opened --> Error
420  Log() << kFATAL << "<WriteOptionsToInfoFile> Unable to open output file: " << fReferenceFile << Endl;
421  }
422 
423  TListIter optIt( &fListOfOptions );
424  o << "# List of options:" << std::endl;
425  o << "# Configurable: " << GetConfigName() << std::endl;
426  o << "# Description: " << GetConfigDescription() << std::endl;
427  while (OptionBase * opt = (OptionBase *) optIt()) {
428  opt->Print( o, 1 );
429  o << std::endl << "# ------------------------------------------------" << std::endl;
430  }
431 
432  o.close();
433  Log() << kVERBOSE << "Wrote options reference file: \"" << fReferenceFile << "\"" << Endl;
434 }
435 
436 ////////////////////////////////////////////////////////////////////////////////
437 /// read option back from the weight file
438 
440 {
441  // first set the IsSet flag of all declared options to false
442  // that is only necessary in our factory, when we test right
443  // after the training
444  ResetSetFlag();
445  fOptions = "";
446  char buf[512];
447  istr.getline(buf,512);
448  TString stropt, strval;
449  while (istr.good() && !istr.eof() && !(buf[0]=='#' && buf[1]=='#')) { // if line starts with ## return
450  char *p = buf;
451  while (*p==' ' || *p=='\t') p++; // 'remove' leading whitespace
452  if (*p=='#' || *p=='\0') {
453  istr.getline(buf,512); // reading the next line
454  continue; // if comment or empty line, read the next line
455  }
456  std::stringstream sstr(buf);
457  sstr >> stropt >> strval;
458  stropt.ReplaceAll(':','=');
459  strval.ReplaceAll("\"","");
460  if (fOptions.Length()!=0) fOptions += ":";
461  fOptions += stropt;
462  fOptions += strval;
463  istr.getline(buf,512); // reading the next line
464  }
465 }
466 
TString fOptionsReferenceFileDir
Definition: Config.h:109
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
MsgLogger & Endl(MsgLogger &ml)
Definition: MsgLogger.h:158
void ReadOptionsFromXML(void *node)
Collectable string class.
Definition: TObjString.h:28
void ReadOptionsFromStream(std::istream &istr)
read option back from the weight file
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition: TString.h:638
virtual void SetOwner(Bool_t enable=kTRUE)
Set whether this collection is the owner (enable==true) of its content.
Config & gConfig()
MsgLogger & Log() const
Definition: Configurable.h:122
virtual ~Configurable()
default destructor
virtual int MakeDirectory(const char *name)
Make a directory.
Definition: TSystem.cxx:825
Basic string class.
Definition: TString.h:125
virtual Bool_t IsArrayOpt() const =0
void ToLower()
Change string to lower-case.
Definition: TString.cxx:1099
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
virtual void Print(Option_t *option="") const
This method must be overridden when a class wants to print itself.
Definition: TObject.cxx:550
virtual TString GetValue(Int_t i=-1) const =0
void AddAttr(void *node, const char *, const T &value, Int_t precision=16)
add attribute to xml
Definition: Tools.h:308
void * AddChild(void *parent, const char *childname, const char *content=0, bool isRootNode=false)
add child node
Definition: Tools.cxx:1135
MsgLogger * fLogger
Definition: Configurable.h:128
Iterator of linked list.
Definition: TList.h:197
virtual TObject * FindObject(const char *name) const
Delete a TObjLink object.
Definition: TList.cxx:574
The TNamed class is the base class for all named ROOT classes.
Definition: TNamed.h:29
void * GetChild(void *parent, const char *childname=0)
get child node
Definition: Tools.cxx:1161
IONames & GetIONames()
Definition: Config.h:85
const char * GetConfigName() const
Definition: Configurable.h:61
virtual void ParseOptions()
options parser
void SetMinType(EMsgType minType)
Definition: MsgLogger.h:72
Ssiz_t First(char c) const
Find first occurrence of a character c.
Definition: TString.cxx:477
virtual Bool_t SetValue(const TString &vs, Int_t i=-1)
set value for option
Definition: Option.cxx:59
A doubly linked list.
Definition: TList.h:44
R__EXTERN TSystem * gSystem
Definition: TSystem.h:540
void SplitOptions(const TString &theOpt, TList &loo) const
splits the option string at &#39;:&#39; and fills the list &#39;loo&#39; with the primitive strings ...
Bool_t BeginsWith(const char *s, ECaseCompare cmp=kExact) const
Definition: TString.h:561
unsigned int UInt_t
Definition: RtypesCore.h:42
Ssiz_t Length() const
Definition: TString.h:386
Class for TMVA-option handling.
Definition: Option.h:53
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:1080
void ReadAttr(void *node, const char *, T &value)
read attribute from xml
Definition: Tools.h:290
Tools & gTools()
Configurable(const TString &theOption="")
constructor
virtual Bool_t HasPreDefinedVal() const =0
virtual Int_t GetArraySize() const =0
void PrintOptions() const
prints out the options set in the options string and the defaults
const Bool_t kFALSE
Definition: RtypesCore.h:88
TString & Remove(Ssiz_t pos)
Definition: TString.h:619
#define ClassImp(name)
Definition: Rtypes.h:359
void ResetSetFlag()
resets the IsSet flag 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:1173
virtual const char * GetName() const
Returns name of object.
Definition: Option.h:62
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition: TString.h:570
static constexpr double s
virtual const char * TheName() const
Definition: Option.h:63
virtual Bool_t IsPreDefinedVal(const TString &) const =0
Bool_t LooseOptionCheckingEnabled() const
Definition: Configurable.h:95
ostringstream derivative to redirect and format output
Definition: MsgLogger.h:59
Bool_t IsSet() const
Definition: Option.h:66
const char * GetConfigDescription() const
Definition: Configurable.h:62
virtual void Add(TObject *obj)
Definition: TList.h:87
TList fListOfOptions
last declared option
Definition: Configurable.h:114
std::vector< TString > SplitString(const TString &theOpt, const char separator) const
splits the option string at &#39;separator&#39; and fills the list &#39;splitV&#39; with the primitive strings ...
Definition: Tools.cxx:1210
void AddOptionsXMLTo(void *parent) const
write options to XML file
void Reset()
Reset list iterator.
Definition: TList.cxx:1157
TString()
TString default ctor.
Definition: TString.cxx:88
const Bool_t kTRUE
Definition: RtypesCore.h:87
void CheckForUnusedOptions() const
checks for unused options in option string
void WriteOptionsToStream(std::ostream &o, const TString &prefix) const
write options to output stream (e.g. in writing the MVA weight files
const char * Data() const
Definition: TString.h:345