Configurable.cxx

Go to the documentation of this file.
00001 // @(#)root/tmva $Id: Configurable.cxx 33993 2010-06-19 11:25:14Z stelzer $
00002 // Author: Andreas Hoecker, Joerg Stelzer, Helge Voss
00003 
00004 /**********************************************************************************
00005  * Project: TMVA - a Root-integrated toolkit for multivariate data analysis       *
00006  * Package: TMVA                                                                  *
00007  * Class  : Configurable                                                          *
00008  * Web    : http://tmva.sourceforge.net                                           *
00009  *                                                                                *
00010  * Description:                                                                   *
00011  *      Implementation (see header for description)                               *
00012  *                                                                                *
00013  * Authors (alphabetical):                                                        *
00014  *      Andreas Hoecker <Andreas.Hocker@cern.ch> - CERN, Switzerland              *
00015  *      Joerg Stelzer   <Joerg.Stelzer@cern.ch>  - CERN, Switzerland              *
00016  *      Helge Voss      <Helge.Voss@cern.ch>     - MPI-K Heidelberg, Germany      *
00017  *                                                                                *
00018  * Copyright (c) 2005:                                                            *
00019  *      CERN, Switzerland                                                         *
00020  *      MPI-K Heidelberg, Germany                                                 *
00021  *                                                                                *
00022  * Redistribution and use in source and binary forms, with or without             *
00023  * modification, are permitted according to the terms listed in LICENSE           *
00024  * (http://tmva.sourceforge.net/LICENSE)                                          *
00025  *                                                                                *
00026  **********************************************************************************/
00027 
00028 //________________________________________________________________________
00029 /* Begin_Html
00030 Base Class for all classes that need option parsing
00031 End_Html */
00032 //________________________________________________________________________
00033 
00034 #include <string>
00035 #include <iostream>
00036 #include <fstream>
00037 #include <cstdlib>
00038 #include <vector>
00039 
00040 #include "TROOT.h"
00041 #include "TSystem.h"
00042 #include "TString.h"
00043 #include "TObjString.h"
00044 #include "TQObject.h"
00045 #include "TSpline.h"
00046 #include "TMatrix.h"
00047 #include "TMath.h"
00048 #include "TFile.h"
00049 #include "TKey.h"
00050 
00051 #include "TMVA/Configurable.h"
00052 #include "TMVA/Config.h"
00053 #include "TMVA/Tools.h"
00054 
00055 // don't change this flag without a good reason ! The FitterBase code won't work anymore !!!
00056 // #define TMVA_Configurable_SanctionUnknownOption kTRUE
00057 
00058 ClassImp(TMVA::Configurable)
00059 
00060 #ifdef _WIN32
00061 /*Disable warning C4355: 'this' : used in base member initializer list*/
00062 #pragma warning ( disable : 4355 )
00063 #endif
00064 
00065 //_______________________________________________________________________
00066 TMVA::Configurable::Configurable( const TString& theOption)
00067    : fOptions                    ( theOption ),
00068      fLooseOptionCheckingEnabled ( kTRUE ),
00069      fLastDeclaredOption         ( 0 ),
00070      fConfigName                 ( "Configurable" ), // must be replaced by name of class that uses the configurable
00071      fConfigDescription          ( "No description" ),
00072      fReferenceFile              ( "None" ),
00073      fLogger                     ( new MsgLogger(this) )
00074 {
00075    // constructor
00076    fListOfOptions.SetOwner();
00077 
00078    // check if verbosity "V" set in option
00079    if (gTools().CheckForVerboseOption( theOption )) Log().SetMinType( kVERBOSE );
00080 }
00081 
00082 //_______________________________________________________________________
00083 TMVA::Configurable::~Configurable()
00084 {
00085    // default destructur
00086    delete fLogger;
00087 }
00088 
00089 //_______________________________________________________________________
00090 void TMVA::Configurable::SplitOptions(const TString& theOpt, TList& loo) const
00091 {
00092    // splits the option string at ':' and fills the list 'loo' with the primitive strings
00093    TString splitOpt(theOpt);
00094    loo.SetOwner();
00095    while (splitOpt.Length()>0) {
00096       if (!splitOpt.Contains(':')) {
00097          loo.Add(new TObjString(splitOpt));
00098          splitOpt = "";
00099       } 
00100       else {
00101          TString toSave = splitOpt(0,splitOpt.First(':'));
00102          loo.Add(new TObjString(toSave.Data()));
00103          splitOpt = splitOpt(splitOpt.First(':')+1,splitOpt.Length());
00104       }
00105    }
00106 }
00107 
00108 //_______________________________________________________________________
00109 void TMVA::Configurable::ResetSetFlag() 
00110 {
00111    // resets the IsSet falg for all declare options
00112    // to be called before options are read from stream
00113 
00114    TListIter decOptIt(&fListOfOptions); // declared options
00115    while (OptionBase* decOpt = (OptionBase*) decOptIt()) { // loop over declared options
00116       decOpt->fIsSet = kFALSE;
00117    }
00118 }
00119 
00120 //_______________________________________________________________________
00121 void TMVA::Configurable::ParseOptions() 
00122 {
00123    // options parser
00124    Log() << kVERBOSE << "Parsing option string: " << Endl;
00125    TString optionsWithoutTilde(fOptions);
00126    optionsWithoutTilde.ReplaceAll(TString("~"),TString(""));
00127    Log() << kVERBOSE << "... \"" << optionsWithoutTilde << "\"" << Endl;
00128    
00129    TList loo; // the List Of Options in the parsed string
00130    
00131    fOptions = fOptions.Strip(TString::kLeading, ':');
00132    
00133    // separate the options by the ':' marker
00134    SplitOptions(fOptions, loo);
00135    fOptions = "";
00136 
00137    // loop over the declared options and check for their availability
00138    std::map<TString, std::vector<std::pair<Int_t, TString> > > arrayTypeOptions;
00139 
00140    TListIter decOptIt(&fListOfOptions); // declared options
00141    TListIter setOptIt(&loo);   // parsed options
00142    while (TObjString * os = (TObjString*) setOptIt()) { // loop over parsed options
00143 
00144       TString s = os->GetString();
00145 
00146       // the tilde in the beginning is an indication that the option
00147       // has been accepted during previous parsing
00148       //
00149       // while parsing this option string eventual appearances of the
00150       // tilde will be preserved, for correctly parsed options a new
00151       // one will be added (in the end it will be checked if all
00152       // options were parsed
00153       Bool_t preserveTilde = s.BeginsWith('~');
00154       s = s.Strip(TString::kLeading, '~');
00155 
00156       Bool_t paramParsed = kFALSE;
00157       if (s.Contains('=')) { // desired way of setting an option: "...:optname=optvalue:..."
00158          TString optname = s(0,s.First('=')); optname.ToLower(); 
00159          TString optval = s(s.First('=')+1,s.Length());
00160          Int_t idx = -1;
00161 
00162          // First check if the optname exists in the list of the
00163          // objects. This does not depend on the existence of a [] in
00164          // the optname. Sometimes the [] is part of the optname and
00165          // does not describe an array
00166          OptionBase* decOpt = (OptionBase *)fListOfOptions.FindObject(optname);
00167          if (decOpt==0 && optname.Contains('[')) {
00168             // now we see if there is an [] and if the optname exists
00169             // after removing the [idx]
00170             TString st = optname(optname.First('[')+1,100);
00171             st.Remove(st.First(']'));
00172             std::stringstream str(st.Data());
00173             str >> idx;                              // save the array index
00174             optname.Remove(optname.First('['));      // and remove [idx] from the option name
00175             decOpt = (OptionBase *)fListOfOptions.FindObject(optname);
00176          }
00177 
00178          TListIter optIt(&fListOfOptions);
00179          if (decOpt!=0) {
00180             if (decOpt->IsSet())
00181                Log() << kWARNING << "Value for option " << decOpt->GetName() 
00182                        << " was previously set to " << decOpt->GetValue() << Endl;
00183 
00184             if (!decOpt->HasPreDefinedVal() || (decOpt->HasPreDefinedVal() && decOpt->IsPreDefinedVal(optval)) ) {
00185                if (decOpt->IsArrayOpt()) { // arrays
00186                   // if no index was found then we assume the value is to be set for the entire array
00187                   if (idx==-1) {
00188                      decOpt->SetValue(optval);
00189                   } 
00190                   else {
00191                      // since we don't know what else is comming we just put everthing into a map
00192                      if (!decOpt->SetValue(optval, idx))
00193                         Log() << kFATAL << "Index " << idx << " too large for option " << decOpt->TheName()
00194                                 << ", allowed range is [0," << decOpt->GetArraySize()-1 << "]" << Endl;
00195                   }
00196                } 
00197                else { // no arrays
00198                   if (idx!=-1)
00199                      Log() << kFATAL << "Option " << decOpt->TheName()
00200                              << " is not an array, but you specified an index" << Endl;
00201                   decOpt->SetValue(optval);
00202                }
00203                paramParsed = kTRUE;
00204             }
00205             else Log() << kFATAL << "Option " << decOpt->TheName() 
00206                          << " does not have predefined value: \"" << optval << "\"" << Endl;               
00207          }
00208       }
00209 
00210       // boolean variables can be specified by just their name (!name), 
00211       // which will set the to true (false):  ...:V:...:!S:..
00212       Bool_t preserveNotSign = kFALSE;
00213       if (!paramParsed) {
00214          Bool_t hasNotSign = kFALSE;
00215          if (s.BeginsWith("!")) { s.Remove(0,1); preserveNotSign = hasNotSign = kTRUE; }
00216          TString optname(s); optname.ToLower();
00217          OptionBase* decOpt = 0;
00218          Bool_t optionExists = kFALSE;
00219          TListIter optIt(&fListOfOptions);
00220          while ((decOpt = (OptionBase*)optIt()) !=0) {
00221             TString predOptName(decOpt->GetName());
00222             predOptName.ToLower();
00223             if (predOptName == optname) optionExists = kTRUE;
00224             if (dynamic_cast<Option<bool>*>(decOpt)==0) continue; // not a boolean option
00225             if (predOptName == optname) break;
00226          }
00227 
00228          
00229          if (decOpt != 0) {
00230             decOpt->SetValue( hasNotSign ? "0" : "1" );
00231             paramParsed = kTRUE;
00232          } 
00233          else {
00234             if (optionExists && hasNotSign) {
00235                Log() << kFATAL << "Negating a non-boolean variable " << optname
00236                        << ", please check the opions for method: " << GetName() << Endl;
00237             }
00238          }
00239       }
00240 
00241 
00242       if (!paramParsed && LooseOptionCheckingEnabled()) {
00243          // loose options specification, loops through the possible string 
00244          // values any parameter can have not applicable for boolean or floats
00245          decOptIt.Reset();
00246          while (OptionBase* decOpt = (OptionBase*) decOptIt()) {
00247             if (decOpt->HasPreDefinedVal() && decOpt->IsPreDefinedVal(s) ) {
00248                paramParsed = decOpt->SetValue(s);
00249                break;
00250             }
00251          }
00252       }
00253    
00254       if (fOptions!="") fOptions += ":";
00255       if (paramParsed || preserveTilde) fOptions += '~';
00256       if (preserveNotSign) fOptions += '!';
00257       fOptions += s;      
00258    }
00259 
00260    // print options summary
00261    PrintOptions();
00262    if (gConfig().WriteOptionsReference()) WriteOptionsReferenceToFile();
00263 }
00264 
00265 //______________________________________________________________________
00266 void TMVA::Configurable::CheckForUnusedOptions() const 
00267 {
00268    // checks for unused options in option string
00269    TString theOpt(fOptions);
00270    theOpt = theOpt.Strip(TString::kLeading, ':');
00271    
00272    // separate the options by the ':' marker
00273    TList loo; // the List of Options in the parsed string
00274    SplitOptions(theOpt, loo);
00275 
00276    TListIter setOptIt(&loo);   // options in a list
00277    TString unusedOptions("");
00278    while (TObjString * os = (TObjString*) setOptIt()) { // loop over parsed options
00279 
00280       TString s = os->GetString();
00281       if (!s.BeginsWith('~')) {
00282          if (unusedOptions != "") unusedOptions += ':';
00283          unusedOptions += s;
00284       }
00285    }
00286    if (unusedOptions != "") {
00287       Log() << kFATAL
00288               << "The following options were specified, but could not be interpreted: \'"
00289               << unusedOptions << "\', please check!" << Endl;
00290    }
00291 }
00292 
00293 //______________________________________________________________________
00294 void TMVA::Configurable::PrintOptions() const 
00295 {
00296    // prints out the options set in the options string and the defaults
00297 
00298    Log() << kVERBOSE << "The following options are set:" << Endl;
00299 
00300    TListIter optIt( &fListOfOptions );
00301    Log() << kVERBOSE << "- By User:" << Endl;
00302    Bool_t found = kFALSE;
00303    while (OptionBase* opt = (OptionBase *) optIt()) {
00304       if (opt->IsSet()) { Log() << kVERBOSE << "    "; opt->Print(Log()); Log() << Endl; found = kTRUE; }
00305    }
00306    if (!found) Log() << kVERBOSE << "    <none>" << Endl;
00307 
00308    optIt.Reset();
00309    Log() << kVERBOSE << "- Default:" << Endl;
00310    found = kFALSE;
00311    while (OptionBase* opt = (OptionBase *) optIt()) {
00312       if (!opt->IsSet()) { Log() << kVERBOSE << "    "; opt->Print(Log()); Log() << Endl; found = kTRUE; }
00313    }
00314    if (!found) Log() << kVERBOSE << "    <none>" << Endl;
00315 }
00316 
00317 //______________________________________________________________________
00318 void TMVA::Configurable::WriteOptionsToStream( ostream& o, const TString& prefix ) const 
00319 {
00320    // write options to output stream (e.g. in writing the MVA weight files
00321 
00322    TListIter optIt( &fListOfOptions );
00323    o << prefix << "# Set by User:" << std::endl;
00324    while (OptionBase * opt = (OptionBase *) optIt()) 
00325       if (opt->IsSet()) { o << prefix; opt->Print(o); o << std::endl; }
00326    optIt.Reset();
00327    o << prefix << "# Default:" << std::endl;
00328    while (OptionBase * opt = (OptionBase *) optIt()) 
00329       if (!opt->IsSet()) { o << prefix; opt->Print(o); o << std::endl; }
00330    o << prefix << "##" << std::endl;
00331 }
00332 
00333 //______________________________________________________________________
00334 void TMVA::Configurable::AddOptionsXMLTo( void* parent ) const 
00335 {
00336    // write options to XML file
00337    if (!parent) return;
00338    void* opts = gTools().AddChild(parent, "Options");
00339    TListIter optIt( &fListOfOptions );
00340    while (OptionBase * opt = (OptionBase *) optIt()) {
00341       void* optnode = 0;
00342       if (opt->IsArrayOpt()) {
00343          std::stringstream s("");
00344          s.precision( 16 );
00345          for(Int_t i=0; i<opt->GetArraySize(); i++) {
00346             if(i>0) s << " ";
00347             s << std::scientific << opt->GetValue(i);
00348          }
00349          optnode = gTools().AddChild(opts,"Option",s.str().c_str());
00350       }
00351       else {
00352          optnode = gTools().AddChild(opts,"Option", opt->GetValue());
00353       }
00354       gTools().AddAttr(optnode, "name", opt->TheName());
00355       if (opt->IsArrayOpt()) {
00356          gTools().AddAttr(optnode, "size", opt->GetArraySize());
00357       }
00358       gTools().AddAttr(optnode, "modified", (opt->IsSet()?"Yes":"No") );
00359    }
00360 }
00361 
00362 //______________________________________________________________________
00363 void TMVA::Configurable::ReadOptionsFromXML( void* node )
00364 {
00365    void* opt = gTools().GetChild(node);
00366    TString optName, optValue;
00367    fOptions="";
00368    while (opt != 0) {
00369       if (fOptions.Length()!=0) fOptions += ":";
00370       gTools().ReadAttr(opt, "name", optName);
00371       optValue = TString( gTools().GetContent(opt) );
00372       std::stringstream s("");
00373       s.precision( 16 );
00374       if (gTools().HasAttr(opt, "size")) {
00375          UInt_t size;
00376          gTools().ReadAttr(opt, "size", size);
00377          std::vector<TString> values = gTools().SplitString(optValue, ' ');
00378          for(UInt_t i=0; i<size; i++) {
00379             if(i!=0) s << ":";
00380             s << std::scientific << optName << "[" << i << "]=" << values[i];
00381          }
00382       }
00383       else {
00384          s << std::scientific << optName << "=" << optValue;
00385       }
00386       fOptions += s.str().c_str();
00387       opt = gTools().GetNextChild(opt);
00388    }
00389 }
00390 
00391 //______________________________________________________________________
00392 void TMVA::Configurable::WriteOptionsReferenceToFile()
00393 {
00394    // write complete options to output stream
00395 
00396    TString dir = gConfig().GetIONames().fOptionsReferenceFileDir;
00397    gSystem->MakeDirectory( dir );
00398    fReferenceFile = dir + "/" + GetConfigName() + "_optionsRef.txt";
00399    std::ofstream o( fReferenceFile );
00400    if (!o.good()) { // file could not be opened --> Error
00401       Log() << kFATAL << "<WriteOptionsToInfoFile> Unable to open output file: " << fReferenceFile << Endl;
00402    }
00403 
00404    TListIter optIt( &fListOfOptions );   
00405    o << "# List of options:" << std::endl;
00406    o << "# Configurable: " << GetConfigName() << std::endl;
00407    o << "# Description: " << GetConfigDescription() << std::endl;
00408    while (OptionBase * opt = (OptionBase *) optIt()) {
00409       opt->Print( o, 1 ); 
00410       o << std::endl << "# ------------------------------------------------" << std::endl; 
00411    }
00412 
00413    o.close();
00414    Log() << kVERBOSE << "Wrote options reference file: \"" << fReferenceFile << "\"" << Endl;
00415 }
00416 
00417 //______________________________________________________________________
00418 void TMVA::Configurable::ReadOptionsFromStream(istream& istr)
00419 {
00420    // read option back from the weight file
00421 
00422    // first set the IsSet flag of all declared options to false
00423    // that is only necessary in our factory, when we test right
00424    // after the training
00425    ResetSetFlag();
00426    fOptions = "";
00427    char buf[512];
00428    istr.getline(buf,512);
00429    TString stropt, strval;
00430    while (istr.good() && !istr.eof() && !(buf[0]=='#' && buf[1]=='#')) { // if line starts with ## return
00431       char *p = buf;
00432       while (*p==' ' || *p=='\t') p++; // 'remove' leading whitespace
00433       if (*p=='#' || *p=='\0') {
00434          istr.getline(buf,512); // reading the next line
00435          continue; // if comment or empty line, read the next line
00436       }
00437       std::stringstream sstr(buf);
00438       sstr >> stropt >> strval;
00439       stropt.ReplaceAll(':','=');
00440       strval.ReplaceAll("\"","");
00441       if (fOptions.Length()!=0) fOptions += ":";
00442       fOptions += stropt;
00443       fOptions += strval;
00444       istr.getline(buf,512); // reading the next line
00445    }
00446 }

Generated on Tue Jul 5 15:16:42 2011 for ROOT_528-00b_version by  doxygen 1.5.1