// @(#)root/tmva $Id$
// Author: Andreas Hoecker, Joerg Stelzer, Helge Voss, Eckhard von Toerne

/**********************************************************************************
 * Project: TMVA - a Root-integrated toolkit for multivariate data analysis       *
 * Package: TMVA                                                                  *
 * Class  : MethodCompositeBase                                                   *
 * Web    : http://tmva.sourceforge.net                                           *
 *                                                                                *
 * Description:                                                                   *
 *      Virtual base class for all MVA method                                     *
 *                                                                                *
 * Authors (alphabetical):                                                        *
 *      Andreas Hoecker   <Andreas.Hocker@cern.ch>   - CERN, Switzerland          *
 *      Nadim Sah         <Nadim.Sah@cern.ch>        - Berlin, Germany            *
 *      Peter Speckmayer  <Peter.Speckmazer@cern.ch> - CERN, Switzerland          *
 *      Joerg Stelzer     <Joerg.Stelzer@cern.ch>    - MSU East Lansing, USA      *
 *      Helge Voss        <Helge.Voss@cern.ch>       - MPI-K Heidelberg, Germany  *
 *      Jan Therhaag      <Jan.Therhaag@cern.ch>     - U of Bonn, Germany         *
 *      Eckhard v. Toerne <evt@uni-bonn.de>          - U of Bonn, Germany         *
 *                                                                                *
 * Copyright (c) 2005-2011:                                                       *
 *      CERN, Switzerland                                                         *
 *      MSU East Lansing, USA                                                     *
 *      MPI-K Heidelberg, Germany                                                 *
 *      U. of Bonn, Germany                                                       *
 *                                                                                *
 * Redistribution and use in source and binary forms, with or without             *
 * modification, are permitted according to the terms listed in LICENSE           *
 * (http://tmva.sourceforge.net/LICENSE)                                          *
 **********************************************************************************/

//__________________________________________________________________________
//
// This class is meant to allow categorisation of the data. For different //
// categories, different classifiers may be booked and different variab-  //
// les may be considered. The aim is to account for the difference that   //
// is due to different locations/angles.                                  //
//__________________________________________________________________________
#include <algorithm>
#include <iomanip>
#include <vector>
#include <iostream>

#include "Riostream.h"
#include "TRandom3.h"
#include "TMath.h"
#include "TObjString.h"
#include "TH1F.h"
#include "TGraph.h"
#include "TSpline.h"
#include "TDirectory.h"
#include "TTreeFormula.h"

#include "TMVA/MethodCategory.h"
#include "TMVA/Tools.h"
#include "TMVA/ClassifierFactory.h"
#include "TMVA/Timer.h"
#include "TMVA/Types.h"
#include "TMVA/PDF.h"
#include "TMVA/Config.h"
#include "TMVA/Ranking.h"
#include "TMVA/VariableInfo.h"
#include "TMVA/DataSetManager.h"
#include "TMVA/VariableRearrangeTransform.h"

REGISTER_METHOD(Category)

ClassImp(TMVA::MethodCategory)

//_______________________________________________________________________
   TMVA::MethodCategory::MethodCategory( const TString& jobName,
                                         const TString& methodTitle,
                                         DataSetInfo& theData,
                                         const TString& theOption,
                                         TDirectory* theTargetDir )
   : TMVA::MethodCompositeBase( jobName, Types::kCategory, methodTitle, theData, theOption, theTargetDir ),
   fCatTree(0),
   fDataSetManager(NULL)
{
   // standard constructor
}

//_______________________________________________________________________
TMVA::MethodCategory::MethodCategory( DataSetInfo& dsi,
                                      const TString& theWeightFile,
                                      TDirectory* theTargetDir )
   : TMVA::MethodCompositeBase( Types::kCategory, dsi, theWeightFile, theTargetDir ),
     fCatTree(0),
     fDataSetManager(NULL)
{
   // constructor from weight file
}

//_______________________________________________________________________
TMVA::MethodCategory::~MethodCategory( void )
{
   // destructor
   std::vector<TTreeFormula*>::iterator formIt = fCatFormulas.begin();
   std::vector<TTreeFormula*>::iterator lastF = fCatFormulas.end();
   for(;formIt!=lastF; ++formIt) delete *formIt;
   delete fCatTree;
}

//_______________________________________________________________________
Bool_t TMVA::MethodCategory::HasAnalysisType( Types::EAnalysisType type, UInt_t numberClasses, UInt_t numberTargets )
{
   // check whether method category has analysis type
   // the method type has to be the same for all sub-methods

   std::vector<IMethod*>::iterator itrMethod = fMethods.begin();

   // iterate over methods and check whether they have the analysis type
   for(; itrMethod != fMethods.end(); ++itrMethod ) {
      if ( !(*itrMethod)->HasAnalysisType(type, numberClasses, numberTargets) )
         return kFALSE;
   }
   return kTRUE;
}

//_______________________________________________________________________
void TMVA::MethodCategory::DeclareOptions()
{
   // options for this method
}

//_______________________________________________________________________
TMVA::IMethod* TMVA::MethodCategory::AddMethod( const TCut& theCut,
                                                const TString& theVariables,
                                                Types::EMVA theMethod ,
                                                const TString& theTitle,
                                                const TString& theOptions )
{
   // adds sub-classifier for a category

   std::string addedMethodName = std::string(Types::Instance().GetMethodName(theMethod));

   Log() << kINFO << "Adding sub-classifier: " << addedMethodName << "::" << theTitle << Endl;

   DataSetInfo& dsi = CreateCategoryDSI(theCut, theVariables, theTitle);

   IMethod* addedMethod = ClassifierFactory::Instance().Create(addedMethodName,GetJobName(),theTitle,dsi,theOptions);

   MethodBase *method = (dynamic_cast<MethodBase*>(addedMethod));
   if(method==0) return 0;

   method->SetAnalysisType( fAnalysisType );
   method->SetupMethod();
   method->ParseOptions();
   method->ProcessSetup();

   // set or create correct method base dir for added method
   const TString dirName(Form("Method_%s",method->GetMethodTypeName().Data()));
   TDirectory * dir = BaseDir()->GetDirectory(dirName);
   if (dir != 0) method->SetMethodBaseDir( dir );
   else method->SetMethodBaseDir( BaseDir()->mkdir(dirName,Form("Directory for all %s methods", method->GetMethodTypeName().Data())) );

   // method->SetBaseDir(eigenes base dir, gucken ob Fisher dir existiert, sonst erzeugen )

   // check-for-unused-options is performed; may be overridden by derived
   // classes
   method->CheckSetup();

   // disable writing of XML files and standalone classes for sub methods
   method->DisableWriting( kTRUE );

   // store method, cut and variable names and create cut formula
   fMethods.push_back(method);
   fCategoryCuts.push_back(theCut);
   fVars.push_back(theVariables);

   DataSetInfo& primaryDSI = DataInfo();

   UInt_t newSpectatorIndex = primaryDSI.GetSpectatorInfos().size();
   fCategorySpecIdx.push_back(newSpectatorIndex);

   primaryDSI.AddSpectator( Form("%s_cat%i:=%s", GetName(),(int)fMethods.size(),theCut.GetTitle()),
                            Form("%s:%s",GetName(),method->GetName()),
                            "pass", 0, 0, 'C' );

   return method;
}

//_______________________________________________________________________
TMVA::DataSetInfo& TMVA::MethodCategory::CreateCategoryDSI(const TCut& theCut,
                                                           const TString& theVariables,
                                                           const TString& theTitle)
{
   // create a DataSetInfo object for a sub-classifier

   // create a new dsi with name: theTitle+"_dsi"
   TString dsiName=theTitle+"_dsi";
   DataSetInfo& oldDSI = DataInfo();
   DataSetInfo* dsi = new DataSetInfo(dsiName);

   // register the new dsi
   //   DataSetManager::Instance().AddDataSetInfo(*dsi); // DSMTEST replaced by following line
   fDataSetManager->AddDataSetInfo(*dsi);

   // copy the targets and spectators from the old dsi to the new dsi
   std::vector<VariableInfo>::iterator itrVarInfo;

   for (itrVarInfo = oldDSI.GetTargetInfos().begin(); itrVarInfo != oldDSI.GetTargetInfos().end(); itrVarInfo++)
      dsi->AddTarget(*itrVarInfo);

   for (itrVarInfo = oldDSI.GetSpectatorInfos().begin(); itrVarInfo != oldDSI.GetSpectatorInfos().end(); itrVarInfo++)
      dsi->AddSpectator(*itrVarInfo);

   // split string that contains the variables into tiny little pieces
   std::vector<TString> variables = gTools().SplitString(theVariables,':' );

   // prepare to create varMap
   std::vector<UInt_t> varMap;
   Int_t counter=0;

   // add the variables that were specified in theVariables
   std::vector<TString>::iterator itrVariables;
   Bool_t found = kFALSE;

   // iterate over all variables in 'variables' and add them
   for (itrVariables = variables.begin(); itrVariables != variables.end(); itrVariables++) {
      counter=0;

      // check the variables of the old dsi for the variable that we want to add
      for (itrVarInfo = oldDSI.GetVariableInfos().begin(); itrVarInfo != oldDSI.GetVariableInfos().end(); itrVarInfo++) {
         if((*itrVariables==itrVarInfo->GetLabel()) ) { // || (*itrVariables==itrVarInfo->GetExpression())) { 
            // don't compare the expression, since the user might take two times the same expression, but with different labels
            // and apply different transformations to the variables.
            dsi->AddVariable(*itrVarInfo);
            varMap.push_back(counter);
            found = kTRUE;
         }
         counter++;
      }
      
      // check the spectators of the old dsi for the variable that we want to add
      for (itrVarInfo = oldDSI.GetSpectatorInfos().begin(); itrVarInfo != oldDSI.GetSpectatorInfos().end(); itrVarInfo++) {
         if((*itrVariables==itrVarInfo->GetLabel()) ) { // || (*itrVariables==itrVarInfo->GetExpression())) {
            // don't compare the expression, since the user might take two times the same expression, but with different labels
            // and apply different transformations to the variables.
            dsi->AddVariable(*itrVarInfo);
            varMap.push_back(counter);
            found = kTRUE;
         }
         counter++;
      }

      // if the variable is neither in the variables nor in the spectators, we abort
      if (!found) {
         Log() << kFATAL <<"The variable " << itrVariables->Data() << " was not found and could not be added " << Endl;
      }
      found = kFALSE;
   }

   // in the case that no variables are specified, add the default-variables from the original dsi
   if (theVariables=="") {
      for (UInt_t i=0; i<oldDSI.GetVariableInfos().size(); i++) {
         dsi->AddVariable(oldDSI.GetVariableInfos()[i]);
         varMap.push_back(i);
      }
   }

   // add the variable map 'varMap' to the vector of varMaps
   fVarMaps.push_back(varMap);

   // set classes and cuts
   UInt_t nClasses=oldDSI.GetNClasses();
   TString className;
  
   for (UInt_t i=0; i<nClasses; i++) {
      className = oldDSI.GetClassInfo(i)->GetName();
      dsi->AddClass(className);
      dsi->SetCut(oldDSI.GetCut(i),className);
      dsi->AddCut(theCut,className);
      dsi->SetWeightExpression(oldDSI.GetWeightExpression(i),className);
   }

   // set split options, root dir and normalization for the new dsi
   dsi->SetSplitOptions(oldDSI.GetSplitOptions());
   dsi->SetRootDir(oldDSI.GetRootDir());
   TString norm(oldDSI.GetNormalization().Data());
   dsi->SetNormalization(norm);

   DataSetInfo& dsiReference= (*dsi);

   return dsiReference;  
}

//_______________________________________________________________________
void TMVA::MethodCategory::Init()
{
   // initialize the method
}

//_______________________________________________________________________
void TMVA::MethodCategory::InitCircularTree(const DataSetInfo& dsi)
{
   // initialize the circular tree

   delete fCatTree;

   std::vector<VariableInfo>::const_iterator viIt;
   const std::vector<VariableInfo>& vars  = dsi.GetVariableInfos();
   const std::vector<VariableInfo>& specs = dsi.GetSpectatorInfos();

   Bool_t hasAllExternalLinks = kTRUE;
   for (viIt = vars.begin(); viIt != vars.end(); ++viIt)
      if( viIt->GetExternalLink() == 0 ) {
         hasAllExternalLinks = kFALSE;
         break;
      }
   for (viIt = specs.begin(); viIt != specs.end(); ++viIt)
      if( viIt->GetExternalLink() == 0 ) {
         hasAllExternalLinks = kFALSE;
         break;
      }

   if(!hasAllExternalLinks) return;

   {
      // Rather than having TTree::TTree add to the current directory and then remove it, let
      // make sure to not add it in the first place.
      // The add-then-remove can lead to  a problem if gDirectory points to the same directory (for example
      // gROOT) in the current thread and another one (and both try to add to the directory at the same time).
      TDirectory::TContext ctxt(nullptr);
      fCatTree = new TTree(Form("Circ%s",GetMethodName().Data()),"Circlar Tree for categorization");
      fCatTree->SetCircular(1);
   }

   for (viIt = vars.begin(); viIt != vars.end(); ++viIt) {
      const VariableInfo& vi = *viIt;
      fCatTree->Branch(vi.GetExpression(),(Float_t*)vi.GetExternalLink(), TString(vi.GetExpression())+TString("/F"));
   }
   for (viIt = specs.begin(); viIt != specs.end(); ++viIt) {
      const VariableInfo& vi = *viIt;
      if(vi.GetVarType()=='C') continue;
      fCatTree->Branch(vi.GetExpression(),(Float_t*)vi.GetExternalLink(), TString(vi.GetExpression())+TString("/F"));
   }

   for(UInt_t cat=0; cat!=fCategoryCuts.size(); ++cat) {
      fCatFormulas.push_back(new TTreeFormula(Form("Category_%i",cat), fCategoryCuts[cat].GetTitle(), fCatTree));
   }
}

//_______________________________________________________________________
void TMVA::MethodCategory::Train()
{
   // train all sub-classifiers

   // specify the minimum # of training events and set 'classification'
   const Int_t  MinNoTrainingEvents = 10;

   Types::EAnalysisType analysisType = GetAnalysisType();

   // start the training
   Log() << kINFO << "Train all sub-classifiers for "
         << (analysisType == Types::kRegression ? "Regression" : "Classification") << " ..." << Endl;

   // don't do anything if no sub-classifier booked
   if (fMethods.empty()) {
      Log() << kINFO << "...nothing found to train" << Endl;
      return;
   }

   std::vector<IMethod*>::iterator itrMethod;

   // iterate over all booked sub-classifiers  and train them
   for (itrMethod = fMethods.begin(); itrMethod != fMethods.end(); ++itrMethod ) {

      MethodBase* mva = dynamic_cast<MethodBase*>(*itrMethod);
      if(!mva) continue;
      mva->SetAnalysisType( analysisType );
      if (!mva->HasAnalysisType( analysisType,
                                 mva->DataInfo().GetNClasses(),
                                 mva->DataInfo().GetNTargets() ) ) {
         Log() << kWARNING << "Method " << mva->GetMethodTypeName() << " is not capable of handling " ;
         if (analysisType == Types::kRegression)
            Log() << "regression with " << mva->DataInfo().GetNTargets() << " targets." << Endl;
         else
            Log() << "classification with " << mva->DataInfo().GetNClasses() << " classes." << Endl;
         itrMethod = fMethods.erase( itrMethod );
         continue;
      }
      if (mva->Data()->GetNTrainingEvents() >= MinNoTrainingEvents) {

         Log() << kINFO << "Train method: " << mva->GetMethodName() << " for "
               << (analysisType == Types::kRegression ? "Regression" : "Classification") << Endl;
         mva->TrainMethod();
         Log() << kINFO << "Training finished" << Endl;

      } else {

         Log() << kWARNING << "Method " << mva->GetMethodName()
               << " not trained (training tree has less entries ["
               << mva->Data()->GetNTrainingEvents()
               << "] than required [" << MinNoTrainingEvents << "]" << Endl;

         Log() << kERROR << " w/o training/test events for that category, I better stop here and let you fix " << Endl;
         Log() << kFATAL << "that one first, otherwise things get too messy later ... " << Endl;

      }
   }

   if (analysisType != Types::kRegression) {

      // variable ranking
      Log() << kINFO << "Begin ranking of input variables..." << Endl;
      for (itrMethod = fMethods.begin(); itrMethod != fMethods.end(); itrMethod++) {
         MethodBase* mva = dynamic_cast<MethodBase*>(*itrMethod);
         if (mva && mva->Data()->GetNTrainingEvents() >= MinNoTrainingEvents) {
            const Ranking* ranking = (*itrMethod)->CreateRanking();
            if (ranking != 0)
               ranking->Print();
            else
               Log() << kINFO << "No variable ranking supplied by classifier: "
                     << dynamic_cast<MethodBase*>(*itrMethod)->GetMethodName() << Endl;
         }
      }
   }
}

//_______________________________________________________________________
void TMVA::MethodCategory::AddWeightsXMLTo( void* parent ) const
{
   // create XML description of Category classifier
   void* wght = gTools().AddChild(parent, "Weights");
   gTools().AddAttr( wght, "NSubMethods", fMethods.size() );
   void* submethod(0);

   std::vector<IMethod*>::iterator itrMethod;

   // iterate over methods and write them to XML file
   for (UInt_t i=0; i<fMethods.size(); i++) {
      MethodBase* method = dynamic_cast<MethodBase*>(fMethods[i]);
      submethod = gTools().AddChild(wght, "SubMethod");
      gTools().AddAttr(submethod, "Index", i);
      gTools().AddAttr(submethod, "Method", method->GetMethodTypeName() + "::" + method->GetMethodName());
      gTools().AddAttr(submethod, "Cut", fCategoryCuts[i]);
      gTools().AddAttr(submethod, "Variables", fVars[i]);
      method->WriteStateToXML( submethod );
   }
}

//_______________________________________________________________________
void TMVA::MethodCategory::ReadWeightsFromXML( void* wghtnode )
{
   // read weights of sub-classifiers of MethodCategory from xml weight file
   UInt_t nSubMethods;
   TString fullMethodName;
   TString methodType;
   TString methodTitle;
   TString theCutString;
   TString theVariables;
   Int_t titleLength;
   gTools().ReadAttr( wghtnode, "NSubMethods",  nSubMethods );
   void* subMethodNode = gTools().GetChild(wghtnode);

   Log() << kINFO << "Recreating sub-classifiers from XML-file " << Endl;

   // recreate all sub-methods from weight file
   for (UInt_t i=0; i<nSubMethods; i++) {
      gTools().ReadAttr( subMethodNode, "Method",    fullMethodName );
      gTools().ReadAttr( subMethodNode, "Cut",       theCutString   );
      gTools().ReadAttr( subMethodNode, "Variables", theVariables   );

      // determine sub-method type
      methodType = fullMethodName(0,fullMethodName.Index("::"));
      if (methodType.Contains(" ")) methodType = methodType(methodType.Last(' ')+1,methodType.Length());

      // determine sub-method title
      titleLength = fullMethodName.Length()-fullMethodName.Index("::")-2;
      methodTitle = fullMethodName(fullMethodName.Index("::")+2,titleLength);

      // reconstruct dsi for sub-method
      DataSetInfo& dsi = CreateCategoryDSI(TCut(theCutString), theVariables, methodTitle);

      // recreate sub-method from weights and add to fMethods
      MethodBase* method = dynamic_cast<MethodBase*>( ClassifierFactory::Instance().Create( methodType.Data(),
                                                                                            dsi, "none" ) );
      if(method==0)
         Log() << kFATAL << "Could not create sub-method " << method << " from XML." << Endl;

      method->SetupMethod();
      method->ReadStateFromXML(subMethodNode);

      fMethods.push_back(method);
      fCategoryCuts.push_back(TCut(theCutString));
      fVars.push_back(theVariables);

      DataSetInfo& primaryDSI = DataInfo();

      UInt_t spectatorIdx = 10000;
      UInt_t counter=0;

      // find the spectator index
      std::vector<VariableInfo>& spectators=primaryDSI.GetSpectatorInfos();
      std::vector<VariableInfo>::iterator itrVarInfo;
      TString specName= Form("%s_cat%i", GetName(),(int)fCategorySpecIdx.size()+1);

      for (itrVarInfo = spectators.begin(); itrVarInfo != spectators.end(); ++itrVarInfo, ++counter) {
         if((specName==itrVarInfo->GetLabel()) || (specName==itrVarInfo->GetExpression())) {
            spectatorIdx=counter;
            fCategorySpecIdx.push_back(spectatorIdx);
            break;
         }
      }

      subMethodNode = gTools().GetNextChild(subMethodNode);
   }

   InitCircularTree(DataInfo());

}

//_______________________________________________________________________
void TMVA::MethodCategory::ProcessOptions() 
{
   // process user options
}

//_______________________________________________________________________
void TMVA::MethodCategory::GetHelpMessage() const
{
   // Get help message text
   //
   // typical length of text line:
   //         "|--------------------------------------------------------------|"
   Log() << Endl;
   Log() << gTools().Color("bold") << "--- Short description:" << gTools().Color("reset") << Endl;
   Log() << Endl;
   Log() << "This method allows to define different categories of events. The" <<Endl;  
   Log() << "categories are defined via cuts on the variables. For each" << Endl; 
   Log() << "category, a different classifier and set of variables can be" <<Endl;
   Log() << "specified. The categories which are defined for this method must" << Endl;
   Log() << "be disjoint." << Endl;
}

//_______________________________________________________________________
const TMVA::Ranking* TMVA::MethodCategory::CreateRanking()
{ 
   // no ranking 
   return 0;
}

//_______________________________________________________________________
Bool_t TMVA::MethodCategory::PassesCut( const Event* ev, UInt_t methodIdx )
{

   // if it's not a simple 'spectator' variable (0 or 1) that the categories are defined by
   // (but rather some 'formula' (i.e. eta>0), then this formulas are stored in fCatTree and that
   // one will be evaluated.. (the formulae return 'true' or 'false' 
   if (fCatTree) {
      if (methodIdx>=fCatFormulas.size()) {
         Log() << kFATAL << "Large method index " << methodIdx << ", number of category formulas = "
               << fCatFormulas.size() << Endl;
      }
      TTreeFormula* f = fCatFormulas[methodIdx];
      return f->EvalInstance(0) > 0.5;
   } 
   // otherwise, it simply looks if "variable == true"  ("greater 0.5 to be "sure" )
   else {

      // checks whether an event lies within a cut
      if (methodIdx>=fCategorySpecIdx.size()) {
         Log() << kFATAL << "Unknown method index " << methodIdx << " maximum allowed index="
               << fCategorySpecIdx.size() << Endl;
      }
      UInt_t spectatorIdx = fCategorySpecIdx[methodIdx];
      Float_t specVal = ev->GetSpectator(spectatorIdx);
      Bool_t pass = (specVal>0.5);
      return pass;
   }
}

//_______________________________________________________________________
Double_t TMVA::MethodCategory::GetMvaValue( Double_t* err, Double_t* errUpper )
{
   // returns the mva value of the right sub-classifier

   if (fMethods.empty()) return 0;

   UInt_t methodToUse = 0;
   const Event* ev = GetEvent();

   // determine which sub-classifier to use for this event
   Int_t suitableCutsN = 0;

   for (UInt_t i=0; i<fMethods.size(); ++i) {
      if (PassesCut(ev, i)) {
         ++suitableCutsN;
         methodToUse=i;
      }
   }

   if (suitableCutsN == 0) {
      Log() << kWARNING << "Event does not lie within the cut of any sub-classifier." << Endl;
      return 0;
   }

   if (suitableCutsN > 1) {
      Log() << kFATAL << "The defined categories are not disjoint." << Endl;
      return 0;
   }

   // get mva value from the suitable sub-classifier
   ev->SetVariableArrangement(&fVarMaps[methodToUse]);
   Double_t mvaValue = dynamic_cast<MethodBase*>(fMethods[methodToUse])->GetMvaValue(ev,err,errUpper);
   ev->SetVariableArrangement(0);

   return mvaValue;
}



//_______________________________________________________________________
const std::vector<Float_t> &TMVA::MethodCategory::GetRegressionValues() 
{
   // returns the mva value of the right sub-classifier

   if (fMethods.empty()) return MethodBase::GetRegressionValues();

   UInt_t methodToUse = 0;
   const Event* ev = GetEvent();

   // determine which sub-classifier to use for this event
   Int_t suitableCutsN = 0;

   for (UInt_t i=0; i<fMethods.size(); ++i) {
      if (PassesCut(ev, i)) {
         ++suitableCutsN;
         methodToUse=i;
      }
   }

   if (suitableCutsN == 0) {
      Log() << kWARNING << "Event does not lie within the cut of any sub-classifier." << Endl;
      return MethodBase::GetRegressionValues();
   }

   if (suitableCutsN > 1) {
      Log() << kFATAL << "The defined categories are not disjoint." << Endl;
      return MethodBase::GetRegressionValues();
   }
   MethodBase* meth = dynamic_cast<MethodBase*>(fMethods[methodToUse]);
   if (!meth){
      Log() << kFATAL << "method not found in Category Regression method" << Endl;
      return MethodBase::GetRegressionValues();
   }
   // get mva value from the suitable sub-classifier
   return meth->GetRegressionValues(ev);
}

 MethodCategory.cxx:1
 MethodCategory.cxx:2
 MethodCategory.cxx:3
 MethodCategory.cxx:4
 MethodCategory.cxx:5
 MethodCategory.cxx:6
 MethodCategory.cxx:7
 MethodCategory.cxx:8
 MethodCategory.cxx:9
 MethodCategory.cxx:10
 MethodCategory.cxx:11
 MethodCategory.cxx:12
 MethodCategory.cxx:13
 MethodCategory.cxx:14
 MethodCategory.cxx:15
 MethodCategory.cxx:16
 MethodCategory.cxx:17
 MethodCategory.cxx:18
 MethodCategory.cxx:19
 MethodCategory.cxx:20
 MethodCategory.cxx:21
 MethodCategory.cxx:22
 MethodCategory.cxx:23
 MethodCategory.cxx:24
 MethodCategory.cxx:25
 MethodCategory.cxx:26
 MethodCategory.cxx:27
 MethodCategory.cxx:28
 MethodCategory.cxx:29
 MethodCategory.cxx:30
 MethodCategory.cxx:31
 MethodCategory.cxx:32
 MethodCategory.cxx:33
 MethodCategory.cxx:34
 MethodCategory.cxx:35
 MethodCategory.cxx:36
 MethodCategory.cxx:37
 MethodCategory.cxx:38
 MethodCategory.cxx:39
 MethodCategory.cxx:40
 MethodCategory.cxx:41
 MethodCategory.cxx:42
 MethodCategory.cxx:43
 MethodCategory.cxx:44
 MethodCategory.cxx:45
 MethodCategory.cxx:46
 MethodCategory.cxx:47
 MethodCategory.cxx:48
 MethodCategory.cxx:49
 MethodCategory.cxx:50
 MethodCategory.cxx:51
 MethodCategory.cxx:52
 MethodCategory.cxx:53
 MethodCategory.cxx:54
 MethodCategory.cxx:55
 MethodCategory.cxx:56
 MethodCategory.cxx:57
 MethodCategory.cxx:58
 MethodCategory.cxx:59
 MethodCategory.cxx:60
 MethodCategory.cxx:61
 MethodCategory.cxx:62
 MethodCategory.cxx:63
 MethodCategory.cxx:64
 MethodCategory.cxx:65
 MethodCategory.cxx:66
 MethodCategory.cxx:67
 MethodCategory.cxx:68
 MethodCategory.cxx:69
 MethodCategory.cxx:70
 MethodCategory.cxx:71
 MethodCategory.cxx:72
 MethodCategory.cxx:73
 MethodCategory.cxx:74
 MethodCategory.cxx:75
 MethodCategory.cxx:76
 MethodCategory.cxx:77
 MethodCategory.cxx:78
 MethodCategory.cxx:79
 MethodCategory.cxx:80
 MethodCategory.cxx:81
 MethodCategory.cxx:82
 MethodCategory.cxx:83
 MethodCategory.cxx:84
 MethodCategory.cxx:85
 MethodCategory.cxx:86
 MethodCategory.cxx:87
 MethodCategory.cxx:88
 MethodCategory.cxx:89
 MethodCategory.cxx:90
 MethodCategory.cxx:91
 MethodCategory.cxx:92
 MethodCategory.cxx:93
 MethodCategory.cxx:94
 MethodCategory.cxx:95
 MethodCategory.cxx:96
 MethodCategory.cxx:97
 MethodCategory.cxx:98
 MethodCategory.cxx:99
 MethodCategory.cxx:100
 MethodCategory.cxx:101
 MethodCategory.cxx:102
 MethodCategory.cxx:103
 MethodCategory.cxx:104
 MethodCategory.cxx:105
 MethodCategory.cxx:106
 MethodCategory.cxx:107
 MethodCategory.cxx:108
 MethodCategory.cxx:109
 MethodCategory.cxx:110
 MethodCategory.cxx:111
 MethodCategory.cxx:112
 MethodCategory.cxx:113
 MethodCategory.cxx:114
 MethodCategory.cxx:115
 MethodCategory.cxx:116
 MethodCategory.cxx:117
 MethodCategory.cxx:118
 MethodCategory.cxx:119
 MethodCategory.cxx:120
 MethodCategory.cxx:121
 MethodCategory.cxx:122
 MethodCategory.cxx:123
 MethodCategory.cxx:124
 MethodCategory.cxx:125
 MethodCategory.cxx:126
 MethodCategory.cxx:127
 MethodCategory.cxx:128
 MethodCategory.cxx:129
 MethodCategory.cxx:130
 MethodCategory.cxx:131
 MethodCategory.cxx:132
 MethodCategory.cxx:133
 MethodCategory.cxx:134
 MethodCategory.cxx:135
 MethodCategory.cxx:136
 MethodCategory.cxx:137
 MethodCategory.cxx:138
 MethodCategory.cxx:139
 MethodCategory.cxx:140
 MethodCategory.cxx:141
 MethodCategory.cxx:142
 MethodCategory.cxx:143
 MethodCategory.cxx:144
 MethodCategory.cxx:145
 MethodCategory.cxx:146
 MethodCategory.cxx:147
 MethodCategory.cxx:148
 MethodCategory.cxx:149
 MethodCategory.cxx:150
 MethodCategory.cxx:151
 MethodCategory.cxx:152
 MethodCategory.cxx:153
 MethodCategory.cxx:154
 MethodCategory.cxx:155
 MethodCategory.cxx:156
 MethodCategory.cxx:157
 MethodCategory.cxx:158
 MethodCategory.cxx:159
 MethodCategory.cxx:160
 MethodCategory.cxx:161
 MethodCategory.cxx:162
 MethodCategory.cxx:163
 MethodCategory.cxx:164
 MethodCategory.cxx:165
 MethodCategory.cxx:166
 MethodCategory.cxx:167
 MethodCategory.cxx:168
 MethodCategory.cxx:169
 MethodCategory.cxx:170
 MethodCategory.cxx:171
 MethodCategory.cxx:172
 MethodCategory.cxx:173
 MethodCategory.cxx:174
 MethodCategory.cxx:175
 MethodCategory.cxx:176
 MethodCategory.cxx:177
 MethodCategory.cxx:178
 MethodCategory.cxx:179
 MethodCategory.cxx:180
 MethodCategory.cxx:181
 MethodCategory.cxx:182
 MethodCategory.cxx:183
 MethodCategory.cxx:184
 MethodCategory.cxx:185
 MethodCategory.cxx:186
 MethodCategory.cxx:187
 MethodCategory.cxx:188
 MethodCategory.cxx:189
 MethodCategory.cxx:190
 MethodCategory.cxx:191
 MethodCategory.cxx:192
 MethodCategory.cxx:193
 MethodCategory.cxx:194
 MethodCategory.cxx:195
 MethodCategory.cxx:196
 MethodCategory.cxx:197
 MethodCategory.cxx:198
 MethodCategory.cxx:199
 MethodCategory.cxx:200
 MethodCategory.cxx:201
 MethodCategory.cxx:202
 MethodCategory.cxx:203
 MethodCategory.cxx:204
 MethodCategory.cxx:205
 MethodCategory.cxx:206
 MethodCategory.cxx:207
 MethodCategory.cxx:208
 MethodCategory.cxx:209
 MethodCategory.cxx:210
 MethodCategory.cxx:211
 MethodCategory.cxx:212
 MethodCategory.cxx:213
 MethodCategory.cxx:214
 MethodCategory.cxx:215
 MethodCategory.cxx:216
 MethodCategory.cxx:217
 MethodCategory.cxx:218
 MethodCategory.cxx:219
 MethodCategory.cxx:220
 MethodCategory.cxx:221
 MethodCategory.cxx:222
 MethodCategory.cxx:223
 MethodCategory.cxx:224
 MethodCategory.cxx:225
 MethodCategory.cxx:226
 MethodCategory.cxx:227
 MethodCategory.cxx:228
 MethodCategory.cxx:229
 MethodCategory.cxx:230
 MethodCategory.cxx:231
 MethodCategory.cxx:232
 MethodCategory.cxx:233
 MethodCategory.cxx:234
 MethodCategory.cxx:235
 MethodCategory.cxx:236
 MethodCategory.cxx:237
 MethodCategory.cxx:238
 MethodCategory.cxx:239
 MethodCategory.cxx:240
 MethodCategory.cxx:241
 MethodCategory.cxx:242
 MethodCategory.cxx:243
 MethodCategory.cxx:244
 MethodCategory.cxx:245
 MethodCategory.cxx:246
 MethodCategory.cxx:247
 MethodCategory.cxx:248
 MethodCategory.cxx:249
 MethodCategory.cxx:250
 MethodCategory.cxx:251
 MethodCategory.cxx:252
 MethodCategory.cxx:253
 MethodCategory.cxx:254
 MethodCategory.cxx:255
 MethodCategory.cxx:256
 MethodCategory.cxx:257
 MethodCategory.cxx:258
 MethodCategory.cxx:259
 MethodCategory.cxx:260
 MethodCategory.cxx:261
 MethodCategory.cxx:262
 MethodCategory.cxx:263
 MethodCategory.cxx:264
 MethodCategory.cxx:265
 MethodCategory.cxx:266
 MethodCategory.cxx:267
 MethodCategory.cxx:268
 MethodCategory.cxx:269
 MethodCategory.cxx:270
 MethodCategory.cxx:271
 MethodCategory.cxx:272
 MethodCategory.cxx:273
 MethodCategory.cxx:274
 MethodCategory.cxx:275
 MethodCategory.cxx:276
 MethodCategory.cxx:277
 MethodCategory.cxx:278
 MethodCategory.cxx:279
 MethodCategory.cxx:280
 MethodCategory.cxx:281
 MethodCategory.cxx:282
 MethodCategory.cxx:283
 MethodCategory.cxx:284
 MethodCategory.cxx:285
 MethodCategory.cxx:286
 MethodCategory.cxx:287
 MethodCategory.cxx:288
 MethodCategory.cxx:289
 MethodCategory.cxx:290
 MethodCategory.cxx:291
 MethodCategory.cxx:292
 MethodCategory.cxx:293
 MethodCategory.cxx:294
 MethodCategory.cxx:295
 MethodCategory.cxx:296
 MethodCategory.cxx:297
 MethodCategory.cxx:298
 MethodCategory.cxx:299
 MethodCategory.cxx:300
 MethodCategory.cxx:301
 MethodCategory.cxx:302
 MethodCategory.cxx:303
 MethodCategory.cxx:304
 MethodCategory.cxx:305
 MethodCategory.cxx:306
 MethodCategory.cxx:307
 MethodCategory.cxx:308
 MethodCategory.cxx:309
 MethodCategory.cxx:310
 MethodCategory.cxx:311
 MethodCategory.cxx:312
 MethodCategory.cxx:313
 MethodCategory.cxx:314
 MethodCategory.cxx:315
 MethodCategory.cxx:316
 MethodCategory.cxx:317
 MethodCategory.cxx:318
 MethodCategory.cxx:319
 MethodCategory.cxx:320
 MethodCategory.cxx:321
 MethodCategory.cxx:322
 MethodCategory.cxx:323
 MethodCategory.cxx:324
 MethodCategory.cxx:325
 MethodCategory.cxx:326
 MethodCategory.cxx:327
 MethodCategory.cxx:328
 MethodCategory.cxx:329
 MethodCategory.cxx:330
 MethodCategory.cxx:331
 MethodCategory.cxx:332
 MethodCategory.cxx:333
 MethodCategory.cxx:334
 MethodCategory.cxx:335
 MethodCategory.cxx:336
 MethodCategory.cxx:337
 MethodCategory.cxx:338
 MethodCategory.cxx:339
 MethodCategory.cxx:340
 MethodCategory.cxx:341
 MethodCategory.cxx:342
 MethodCategory.cxx:343
 MethodCategory.cxx:344
 MethodCategory.cxx:345
 MethodCategory.cxx:346
 MethodCategory.cxx:347
 MethodCategory.cxx:348
 MethodCategory.cxx:349
 MethodCategory.cxx:350
 MethodCategory.cxx:351
 MethodCategory.cxx:352
 MethodCategory.cxx:353
 MethodCategory.cxx:354
 MethodCategory.cxx:355
 MethodCategory.cxx:356
 MethodCategory.cxx:357
 MethodCategory.cxx:358
 MethodCategory.cxx:359
 MethodCategory.cxx:360
 MethodCategory.cxx:361
 MethodCategory.cxx:362
 MethodCategory.cxx:363
 MethodCategory.cxx:364
 MethodCategory.cxx:365
 MethodCategory.cxx:366
 MethodCategory.cxx:367
 MethodCategory.cxx:368
 MethodCategory.cxx:369
 MethodCategory.cxx:370
 MethodCategory.cxx:371
 MethodCategory.cxx:372
 MethodCategory.cxx:373
 MethodCategory.cxx:374
 MethodCategory.cxx:375
 MethodCategory.cxx:376
 MethodCategory.cxx:377
 MethodCategory.cxx:378
 MethodCategory.cxx:379
 MethodCategory.cxx:380
 MethodCategory.cxx:381
 MethodCategory.cxx:382
 MethodCategory.cxx:383
 MethodCategory.cxx:384
 MethodCategory.cxx:385
 MethodCategory.cxx:386
 MethodCategory.cxx:387
 MethodCategory.cxx:388
 MethodCategory.cxx:389
 MethodCategory.cxx:390
 MethodCategory.cxx:391
 MethodCategory.cxx:392
 MethodCategory.cxx:393
 MethodCategory.cxx:394
 MethodCategory.cxx:395
 MethodCategory.cxx:396
 MethodCategory.cxx:397
 MethodCategory.cxx:398
 MethodCategory.cxx:399
 MethodCategory.cxx:400
 MethodCategory.cxx:401
 MethodCategory.cxx:402
 MethodCategory.cxx:403
 MethodCategory.cxx:404
 MethodCategory.cxx:405
 MethodCategory.cxx:406
 MethodCategory.cxx:407
 MethodCategory.cxx:408
 MethodCategory.cxx:409
 MethodCategory.cxx:410
 MethodCategory.cxx:411
 MethodCategory.cxx:412
 MethodCategory.cxx:413
 MethodCategory.cxx:414
 MethodCategory.cxx:415
 MethodCategory.cxx:416
 MethodCategory.cxx:417
 MethodCategory.cxx:418
 MethodCategory.cxx:419
 MethodCategory.cxx:420
 MethodCategory.cxx:421
 MethodCategory.cxx:422
 MethodCategory.cxx:423
 MethodCategory.cxx:424
 MethodCategory.cxx:425
 MethodCategory.cxx:426
 MethodCategory.cxx:427
 MethodCategory.cxx:428
 MethodCategory.cxx:429
 MethodCategory.cxx:430
 MethodCategory.cxx:431
 MethodCategory.cxx:432
 MethodCategory.cxx:433
 MethodCategory.cxx:434
 MethodCategory.cxx:435
 MethodCategory.cxx:436
 MethodCategory.cxx:437
 MethodCategory.cxx:438
 MethodCategory.cxx:439
 MethodCategory.cxx:440
 MethodCategory.cxx:441
 MethodCategory.cxx:442
 MethodCategory.cxx:443
 MethodCategory.cxx:444
 MethodCategory.cxx:445
 MethodCategory.cxx:446
 MethodCategory.cxx:447
 MethodCategory.cxx:448
 MethodCategory.cxx:449
 MethodCategory.cxx:450
 MethodCategory.cxx:451
 MethodCategory.cxx:452
 MethodCategory.cxx:453
 MethodCategory.cxx:454
 MethodCategory.cxx:455
 MethodCategory.cxx:456
 MethodCategory.cxx:457
 MethodCategory.cxx:458
 MethodCategory.cxx:459
 MethodCategory.cxx:460
 MethodCategory.cxx:461
 MethodCategory.cxx:462
 MethodCategory.cxx:463
 MethodCategory.cxx:464
 MethodCategory.cxx:465
 MethodCategory.cxx:466
 MethodCategory.cxx:467
 MethodCategory.cxx:468
 MethodCategory.cxx:469
 MethodCategory.cxx:470
 MethodCategory.cxx:471
 MethodCategory.cxx:472
 MethodCategory.cxx:473
 MethodCategory.cxx:474
 MethodCategory.cxx:475
 MethodCategory.cxx:476
 MethodCategory.cxx:477
 MethodCategory.cxx:478
 MethodCategory.cxx:479
 MethodCategory.cxx:480
 MethodCategory.cxx:481
 MethodCategory.cxx:482
 MethodCategory.cxx:483
 MethodCategory.cxx:484
 MethodCategory.cxx:485
 MethodCategory.cxx:486
 MethodCategory.cxx:487
 MethodCategory.cxx:488
 MethodCategory.cxx:489
 MethodCategory.cxx:490
 MethodCategory.cxx:491
 MethodCategory.cxx:492
 MethodCategory.cxx:493
 MethodCategory.cxx:494
 MethodCategory.cxx:495
 MethodCategory.cxx:496
 MethodCategory.cxx:497
 MethodCategory.cxx:498
 MethodCategory.cxx:499
 MethodCategory.cxx:500
 MethodCategory.cxx:501
 MethodCategory.cxx:502
 MethodCategory.cxx:503
 MethodCategory.cxx:504
 MethodCategory.cxx:505
 MethodCategory.cxx:506
 MethodCategory.cxx:507
 MethodCategory.cxx:508
 MethodCategory.cxx:509
 MethodCategory.cxx:510
 MethodCategory.cxx:511
 MethodCategory.cxx:512
 MethodCategory.cxx:513
 MethodCategory.cxx:514
 MethodCategory.cxx:515
 MethodCategory.cxx:516
 MethodCategory.cxx:517
 MethodCategory.cxx:518
 MethodCategory.cxx:519
 MethodCategory.cxx:520
 MethodCategory.cxx:521
 MethodCategory.cxx:522
 MethodCategory.cxx:523
 MethodCategory.cxx:524
 MethodCategory.cxx:525
 MethodCategory.cxx:526
 MethodCategory.cxx:527
 MethodCategory.cxx:528
 MethodCategory.cxx:529
 MethodCategory.cxx:530
 MethodCategory.cxx:531
 MethodCategory.cxx:532
 MethodCategory.cxx:533
 MethodCategory.cxx:534
 MethodCategory.cxx:535
 MethodCategory.cxx:536
 MethodCategory.cxx:537
 MethodCategory.cxx:538
 MethodCategory.cxx:539
 MethodCategory.cxx:540
 MethodCategory.cxx:541
 MethodCategory.cxx:542
 MethodCategory.cxx:543
 MethodCategory.cxx:544
 MethodCategory.cxx:545
 MethodCategory.cxx:546
 MethodCategory.cxx:547
 MethodCategory.cxx:548
 MethodCategory.cxx:549
 MethodCategory.cxx:550
 MethodCategory.cxx:551
 MethodCategory.cxx:552
 MethodCategory.cxx:553
 MethodCategory.cxx:554
 MethodCategory.cxx:555
 MethodCategory.cxx:556
 MethodCategory.cxx:557
 MethodCategory.cxx:558
 MethodCategory.cxx:559
 MethodCategory.cxx:560
 MethodCategory.cxx:561
 MethodCategory.cxx:562
 MethodCategory.cxx:563
 MethodCategory.cxx:564
 MethodCategory.cxx:565
 MethodCategory.cxx:566
 MethodCategory.cxx:567
 MethodCategory.cxx:568
 MethodCategory.cxx:569
 MethodCategory.cxx:570
 MethodCategory.cxx:571
 MethodCategory.cxx:572
 MethodCategory.cxx:573
 MethodCategory.cxx:574
 MethodCategory.cxx:575
 MethodCategory.cxx:576
 MethodCategory.cxx:577
 MethodCategory.cxx:578
 MethodCategory.cxx:579
 MethodCategory.cxx:580
 MethodCategory.cxx:581
 MethodCategory.cxx:582
 MethodCategory.cxx:583
 MethodCategory.cxx:584
 MethodCategory.cxx:585
 MethodCategory.cxx:586
 MethodCategory.cxx:587
 MethodCategory.cxx:588
 MethodCategory.cxx:589
 MethodCategory.cxx:590
 MethodCategory.cxx:591
 MethodCategory.cxx:592
 MethodCategory.cxx:593
 MethodCategory.cxx:594
 MethodCategory.cxx:595
 MethodCategory.cxx:596
 MethodCategory.cxx:597
 MethodCategory.cxx:598
 MethodCategory.cxx:599
 MethodCategory.cxx:600
 MethodCategory.cxx:601
 MethodCategory.cxx:602
 MethodCategory.cxx:603
 MethodCategory.cxx:604
 MethodCategory.cxx:605
 MethodCategory.cxx:606
 MethodCategory.cxx:607
 MethodCategory.cxx:608
 MethodCategory.cxx:609
 MethodCategory.cxx:610
 MethodCategory.cxx:611
 MethodCategory.cxx:612
 MethodCategory.cxx:613
 MethodCategory.cxx:614
 MethodCategory.cxx:615
 MethodCategory.cxx:616
 MethodCategory.cxx:617
 MethodCategory.cxx:618
 MethodCategory.cxx:619
 MethodCategory.cxx:620
 MethodCategory.cxx:621
 MethodCategory.cxx:622
 MethodCategory.cxx:623
 MethodCategory.cxx:624
 MethodCategory.cxx:625
 MethodCategory.cxx:626
 MethodCategory.cxx:627
 MethodCategory.cxx:628
 MethodCategory.cxx:629
 MethodCategory.cxx:630
 MethodCategory.cxx:631
 MethodCategory.cxx:632
 MethodCategory.cxx:633
 MethodCategory.cxx:634
 MethodCategory.cxx:635
 MethodCategory.cxx:636
 MethodCategory.cxx:637
 MethodCategory.cxx:638
 MethodCategory.cxx:639
 MethodCategory.cxx:640
 MethodCategory.cxx:641
 MethodCategory.cxx:642
 MethodCategory.cxx:643
 MethodCategory.cxx:644
 MethodCategory.cxx:645
 MethodCategory.cxx:646
 MethodCategory.cxx:647
 MethodCategory.cxx:648
 MethodCategory.cxx:649
 MethodCategory.cxx:650
 MethodCategory.cxx:651
 MethodCategory.cxx:652