Logo ROOT  
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
96void 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
137 fOptions = fOptions.Strip(TString::kLeading, ':');
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
337void 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
353void 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
int Int_t
Definition: RtypesCore.h:41
unsigned int UInt_t
Definition: RtypesCore.h:42
const Bool_t kFALSE
Definition: RtypesCore.h:88
bool Bool_t
Definition: RtypesCore.h:59
const Bool_t kTRUE
Definition: RtypesCore.h:87
#define ClassImp(name)
Definition: Rtypes.h:365
R__EXTERN TSystem * gSystem
Definition: TSystem.h:560
virtual void SetOwner(Bool_t enable=kTRUE)
Set whether this collection is the owner (enable==true) of its content.
Iterator of linked list.
Definition: TList.h:200
void Reset()
Reset list iterator.
Definition: TList.cxx:1158
A doubly linked list.
Definition: TList.h:44
virtual void Add(TObject *obj)
Definition: TList.h:87
TString fOptionsReferenceFileDir
Definition: Config.h:126
IONames & GetIONames()
Definition: Config.h:100
void ReadOptionsFromXML(void *node)
void ResetSetFlag()
resets the IsSet flag for all declare options to be called before options are read from stream
virtual ~Configurable()
default destructor
void WriteOptionsReferenceToFile()
write complete options to output stream
void WriteOptionsToStream(std::ostream &o, const TString &prefix) const
write options to output stream (e.g. in writing the MVA weight files
Configurable(const TString &theOption="")
constructor
TList fListOfOptions
last declared option
Definition: Configurable.h:114
virtual void ParseOptions()
options parser
MsgLogger & Log() const
Definition: Configurable.h:122
void PrintOptions() const
prints out the options set in the options string and the defaults
void CheckForUnusedOptions() const
checks for unused options in option string
void SplitOptions(const TString &theOpt, TList &loo) const
splits the option string at ':' and fills the list 'loo' with the primitive strings
void ReadOptionsFromStream(std::istream &istr)
read option back from the weight file
void AddOptionsXMLTo(void *parent) const
write options to XML file
ostringstream derivative to redirect and format output
Definition: MsgLogger.h:59
void SetMinType(EMsgType minType)
Definition: MsgLogger.h:72
Class for TMVA-option handling.
Definition: Option.h:53
virtual const char * TheName() const
Definition: Option.h:63
virtual Bool_t SetValue(const TString &vs, Int_t i=-1)
set value for option
Definition: Option.cxx:59
virtual Bool_t IsPreDefinedVal(const TString &) const =0
virtual Bool_t IsArrayOpt() const =0
Bool_t IsSet() const
Definition: Option.h:66
virtual Bool_t HasPreDefinedVal() const =0
virtual const char * GetName() const
Returns name of object.
Definition: Option.h:62
virtual Int_t GetArraySize() const =0
virtual TString GetValue(Int_t i=-1) const =0
void * GetNextChild(void *prevchild, const char *childname=0)
XML helpers.
Definition: Tools.cxx:1174
void * AddChild(void *parent, const char *childname, const char *content=0, bool isRootNode=false)
add child node
Definition: Tools.cxx:1136
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:1211
void * GetChild(void *parent, const char *childname=0)
get child node
Definition: Tools.cxx:1162
void ReadAttr(void *node, const char *, T &value)
read attribute from xml
Definition: Tools.h:337
void AddAttr(void *node, const char *, const T &value, Int_t precision=16)
add attribute to xml
Definition: Tools.h:355
The TNamed class is the base class for all named ROOT classes.
Definition: TNamed.h:29
Collectable string class.
Definition: TObjString.h:28
virtual TObject * FindObject(const char *name) const
Must be redefined in derived classes.
Definition: TObject.cxx:321
Basic string class.
Definition: TString.h:131
Ssiz_t Length() const
Definition: TString.h:405
void ToLower()
Change string to lower-case.
Definition: TString.cxx:1125
TSubString Strip(EStripType s=kTrailing, char c=' ') const
Return a substring of self stripped at beginning and/or end.
Definition: TString.cxx:1106
Ssiz_t First(char c) const
Find first occurrence of a character c.
Definition: TString.cxx:499
const char * Data() const
Definition: TString.h:364
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition: TString.h:687
@ kLeading
Definition: TString.h:262
TString & Remove(Ssiz_t pos)
Definition: TString.h:668
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition: TString.h:619
virtual int MakeDirectory(const char *name)
Make a directory.
Definition: TSystem.cxx:835
std::string GetName(const std::string &scope_name)
Definition: Cppyy.cxx:150
static constexpr double s
Config & gConfig()
Tools & gTools()
MsgLogger & Endl(MsgLogger &ml)
Definition: MsgLogger.h:158
Double_t Log(Double_t x)
Definition: TMath.h:750