//
// this stress test for TMVA is a shorter version of the extended TMVA testsuite
// generated by script tmvaValidation/testsuite/RootTest/buildRootTest.sh
//
// Eckhard von Toerne, Dec 2010
//
/* if working, it creates output like this:

******************************************************************
* TMVA - S T R E S S and U N I T test suite (FAST)
******************************************************************
Event [107/107]..................................................OK
VariableInfo [31/31].............................................OK
DataSetInfo [20/20]..............................................OK
DataSet [15/15]..................................................OK
Factory [11/11]..................................................OK
Reader [2/2].....................................................OK
CutsGA [3/3].....................................................OK
LikelihoodD [4/4]................................................OK
PDERS [4/4]......................................................OK
PDEFoam [4/4]....................................................OK
KNN [4/4]........................................................OK
Fisher [4/4].....................................................OK
BoostedFisher [4/4]..............................................OK
LD [4/4].........................................................OK
MLP [4/4]........................................................OK
MLPBFGS [4/4]....................................................OK
SVM [4/4]........................................................OK
BDTG [4/4].......................................................OK
BDT [4/4]........................................................OK
Regression_LD [4/4]..............................................OK
Regression_MLPBFGSN [4/4]........................................OK
Regression_BDTG2 [4/4]...........................................OK
Event [107/107]..................................................OK
VariableInfo [31/31].............................................OK
DataSetInfo [20/20]..............................................OK
DataSet [15/15]..................................................OK
Factory [11/11]..................................................OK
Reader [2/2].....................................................OK
CutsGA [3/3].....................................................OK
LikelihoodD [4/4]................................................OK
PDERS [4/4]......................................................OK
PDEFoam [4/4]....................................................OK
KNN [4/4]........................................................OK
Fisher [4/4].....................................................OK
BoostedFisher [4/4]..............................................OK
LD [4/4].........................................................OK
MLP [4/4]........................................................OK
MLPBFGS [4/4]....................................................OK
SVM [4/4]........................................................OK
BDTG [4/4].......................................................OK
BDT [4/4]........................................................OK
Regression_LD [4/4]..............................................OK
Regression_MLPBFGSN [4/4]........................................OK
Regression_BDTG2 [4/4]...........................................OK
******************************************************************
*  SYS: Linux linux-7p93 2.6.27.7-9-default #1 SMP 2008-12-04 18:10:
*  SYS: "openSUSE 11.1 (x86_64)"
******************************************************************
*  CPUTIME   =  90.2   *  Root5.27/07   20100929/1318
******************************************************************
*/
// including file tmvaut/UnitTest.h
#ifndef UNITTEST_H
#define UNITTEST_H

// Author: Christoph Rosemann   Dec. 2009
// TMVA unit tests

#include "TMVA/IMethod.h"
#include "TMVA/Types.h"

#include <string>
#include <iostream>
#include <cassert>
#include <atomic>

// The following have underscores because
// they are macros. For consistency,
// succeed_() also has an underscore.

#define test_(cond) \
  do_test(cond, #cond, __FILE__, __LINE__)
#define fail_(str) \
  do_fail(str, __FILE__, __LINE__)

namespace UnitTesting
{

   class UnitTest
   {
   public:
      UnitTest(const std::string & xname="", const std::string & filename="", std::ostream* osptr = &std::cout);
      virtual ~UnitTest(){}
      virtual void run() = 0;
      long getNumPassed() const;
      long getNumFailed() const;
      const std::ostream* getStream() const;
      void setStream(std::ostream* osptr);
      void succeed_();
      long report() const;
      virtual void reset();
      void intro() const;
      const std::string & name() const;
   protected:
      void do_test(bool cond, const std::string& lbl, const char* fname, long lineno);
      void do_fail(const std::string& lbl, const char* fname, long lineno);
      bool floatCompare(float x1, float x2);
   private:
      std::ostream* osptr;
      std::atomic<long> nPass;
      std::atomic<long> nFail;
      mutable std::string fName;
      std::string fFileName;
      // Disallowed:
      UnitTest(const UnitTest&);
      UnitTest& operator=(const UnitTest&);
   };

   inline UnitTest::UnitTest(const std::string & xname,
                             const std::string & filename,
                             std::ostream* sptr) :
      fName(xname),
      fFileName(filename)
   {
      this->osptr = sptr;
      nPass = nFail = 0;
   }

   inline long UnitTest::getNumPassed() const
   {
      return nPass;
   }

   inline long UnitTest::getNumFailed() const
   {
      return nFail;
   }

   inline const std::ostream* UnitTest::getStream() const
   {
      return osptr;
   }

   inline void UnitTest::setStream(std::ostream* sptr)
   {
      this->osptr = sptr;
   }

   inline void UnitTest::succeed_()
   {
      ++nPass;
   }

   inline void UnitTest::reset()
   {
      nPass = nFail = 0;
   }

} // namespace UnitTesting
#endif // UNITTEST_H
// including file tmvaut/UnitTest.cxx


#include <iostream>
#include <iomanip>
#include "TString.h"
#include "TMath.h"
#include <typeinfo>

#ifdef WIN32
#pragma warning(disable: 4290)
#endif

using namespace std;
using namespace UnitTesting;

void UnitTest::do_test(bool cond, const std::string& lbl, const char* fname, long lineno)
{
   if (!cond)
      do_fail(lbl, fname, lineno);
   else
      succeed_();
}

void UnitTest::do_fail(const std::string& lbl, const char* /* fname */ , long lineno)
{
   ++nFail;
   if (osptr)
      {
         *osptr << "failure: " << setw(76) << std::left << lbl << std::right << " [line " << setw(3) << lineno << "]\n";
      }
}

bool UnitTest::floatCompare(float x1, float x2)
{
   bool ret = (TMath::Abs(x1-x2)<1.e-9); // fix me, empirical number
   if (!ret) cout << "warning floatCompare: x1="<<x1<<" x2="<<x2<<", diff="<<x1-x2<<endl;
   return ret;
}

const std::string & UnitTest::name() const
{
   if(fName=="")
      fName=std::string(typeid(*this).name());
   return fName;
}


long UnitTest::report() const
{
   if (osptr)
      {
         std::string counts(Form(" [%li/%li]", nPass.load(), nPass+nFail));

         *osptr << name() << counts;

         UInt_t ndots = 82-19-name().size() - counts.size();

         for (UInt_t i=0; i<ndots; ++i) *osptr << '.';

         *osptr << (nFail==0?"..OK":"FAIL") << endl;
      }
   return nFail;
}

void UnitTest::intro() const
{
#ifdef COUTDEBUG
   if (osptr) {
      *osptr << "************************************************************************************************" << endl;
      *osptr << "* Starting U N I T test : " << name() << " (file " << fFileName << ")" << endl;
      *osptr << "************************************************************************************************" << endl;
   }
#endif
}
// including file tmvaut/UnitTestSuite.h
#ifndef UNITTESTSUITE_H
#define UNITTESTSUITE_H

// Author: Christoph Rosemann   Dec. 2009
// TMVA unit tests


#include <vector>
#include <stdexcept>

namespace UnitTesting
{

   class UnitTestSuiteError : public std::logic_error
   {
   public:
      UnitTestSuiteError(const std::string& s = "") : logic_error(s) {}
   };

   class UnitTestSuite
   {
   public:
      UnitTestSuite(const std::string& title, std::ostream* sptr = &std::cout);
      std::string getName() const;
      long getNumPassed() const;
      long getNumFailed() const;
      const std::ostream* getStream() const;
      void setStream(std::ostream* osptr);
      void addTest(UnitTest* t);
      void addSuite(const UnitTestSuite&);
      void run();  // Calls Test::run() repeatedly
      void intro() const;
      long report() const;
      void free();  // Deletes tests
   private:
      std::string name;
      std::ostream* osptr;
      std::vector<UnitTest*> tests;
      void reset();
      // Disallowed ops:
      UnitTestSuite(const UnitTestSuite&);
      UnitTestSuite& operator=(const UnitTestSuite&);
   };

   inline UnitTestSuite::UnitTestSuite(const std::string& title, std::ostream* sptr) : name(title)
   {
      this->osptr = sptr;
   }

   inline std::string UnitTestSuite::getName() const
   {
      return name;
   }

   inline const std::ostream* UnitTestSuite::getStream() const
   {
      return osptr;
   }

   inline void UnitTestSuite::setStream(std::ostream* sptr)
   {
      this->osptr = sptr;
   }

} // namespace UnitTesting
#endif // UNITTESTSUITE_H
// including file tmvaut/UnitTestSuite.cxx

#include <iostream>
#include <iomanip>
#include <cassert>
using namespace std;
using namespace UnitTesting;

void UnitTestSuite::addTest(UnitTest* t)
{
   // Verify test is valid and has a stream:
   if (t == 0)
      throw UnitTestSuiteError("Null test in UnitTestSuite::addTest");
   else if (osptr && !t->getStream())
      t->setStream(osptr);
   tests.push_back(t);
   t->reset();
}

void UnitTestSuite::addSuite(const UnitTestSuite& s)
{
   for (size_t i = 0; i < s.tests.size(); ++i)
      {
         assert(tests[i]);
         addTest(s.tests[i]);
      }
}

void UnitTestSuite::free()
{
   for (size_t i = 0; i < tests.size(); ++i)
      {
         delete tests[i];
         tests[i] = 0;
      }
}

void UnitTestSuite::run()
{
   reset();
   for (size_t i = 0; i < tests.size(); ++i)
      {
         assert(tests[i]);
         tests[i]->intro();
         tests[i]->run();
#ifndef FULL
         tests[i]->report();
#endif
      }
}

void UnitTestSuite::intro() const
{
   if (osptr) {
      *osptr << "******************************************************************" << endl;
      *osptr << "* TMVA - S T R E S S and U N I T test suite ";
#ifdef FULL
      *osptr << "(FULL)"<< endl;
#else
      *osptr << "(FAST)"<< endl;
#endif
      //*osptr << "                                             *" << endl;
      *osptr << "******************************************************************" << endl;

   }
}

long UnitTestSuite::report() const
{
   if (osptr) {
      long totFail = 0;
#ifdef FULL
      *osptr << "************************************************************************************************" << endl;
      *osptr << "* TMVA - U N I T test : Summary                                                                *" << endl;
      *osptr << "************************************************************************************************" << endl;
#endif
      size_t i;
      for (i = 0; i < tests.size(); ++i)
         {
            assert(tests[i]);
#ifdef FULL
            *osptr << "Test " << setw(2) << i << " : ";
#endif
            totFail += tests[i]->report();
         }
      return totFail;
   }
   else
      return getNumFailed();
}

long UnitTestSuite::getNumPassed() const
{
   long totPass = 0;
   for (size_t i = 0; i < tests.size(); ++i)
      {
         assert(tests[i]);
         totPass += tests[i]->getNumPassed();
      }
   return totPass;
}

long UnitTestSuite::getNumFailed() const
{
   long totFail = 0;
   for (size_t i = 0; i < tests.size(); ++i)
      {
         assert(tests[i]);
         totFail += tests[i]->getNumFailed();
      }
   return totFail;
}

void UnitTestSuite::reset()
{
   for (size_t i = 0; i < tests.size(); ++i)
      {
         assert(tests[i]);
         tests[i]->reset();
      }
}
// including file tmvaut/utDataSetInfo.h
#ifndef UTDATASETINFO_H
#define UTDATASETINFO_H

// Author: Christoph Rosemann   Dec. 2009
// TMVA unit tests



#include <vector>

#include "TString.h"
#include "TCut.h"
#include "TMatrixDfwd.h"

#include "TMVA/VariableInfo.h"

namespace TMVA {
   class DataSetInfo;
   class ClassInfo;
   class Event;
}

class utDataSetInfo : public UnitTesting::UnitTest
{
public:
   utDataSetInfo();
   void run();

private:
   void testConstructor();
   void testMethods();

   TMVA::DataSetInfo* datasetinfo;

   // the members needed for the creation and comparison of instances
   TString     name;
   TString     expression;
   TString     title;
   TString     unit;
   Double_t    min;
   Double_t    max;
   Int_t       varcounter;
   char        vartype;
   Bool_t      normalized;
   void*       external;
   TString     norm;
   TString     classname;
   TCut        cut1;
   TCut        cut2;
   TString     splitoption;
   TMatrixD*   matrix;
   TString     histname;
   TString     histtitle;
   TString     weightexpr;

   TMVA::Event*                    event;
   //   TMVA::ClassInfo*                classinfo;
   TMVA::VariableInfo              varinfo;
   std::vector<TMVA::VariableInfo> vecvarinfo;
};
#endif // UTDATASETINFO_H
// including file tmvaut/utDataSetInfo.cxx



#include "TMatrixD.h"

#include "TMVA/DataSetInfo.h"
#include "TMVA/ClassInfo.h"
#include "TMVA/Event.h"

using namespace std;
using namespace UnitTesting;
using namespace TMVA;

utDataSetInfo::utDataSetInfo() :
   UnitTest("DataSetInfo", __FILE__)
{
   name = "name";
   expression = "expression";
   title  = "title";
   unit = "unit";
   min = 2.781828;
   max = 3.1416;
   vartype = 'D';
   varcounter = 123;
   normalized = kFALSE;
   external = &max;
   norm = "norm";
   classname = "classname";
   cut1 = "x<1.";
   cut2 = "y>2.";
   splitoption = "splitoption";
   matrix = new TMatrixD();
   histname = "histname";
   histtitle = "histtitle";
   weightexpr = "weightexpr";
   event = new TMVA::Event();

   varinfo = VariableInfo( expression, title,  unit, varcounter, vartype, external, min, max, normalized);

   vecvarinfo.push_back(varinfo);
   vecvarinfo.push_back(varinfo);
}



void utDataSetInfo::run()
{
   testConstructor();
   testMethods();
}


void utDataSetInfo::testConstructor()
{
   datasetinfo  = new DataSetInfo(name);
   datasetinfo->SetMsgType(TMVA::kWARNING);
   test_(datasetinfo->GetName() == name);
}


void utDataSetInfo::testMethods()
{
   // FIXME:this doesn't work straightforward
   // test_(datasetinfo->GetDataSet() == 0);

   // note: the "constructor"-like call is different from the /standard/ VariableInfo constructor
   datasetinfo->AddVariable(expression, title,  unit, min, max, vartype, normalized, external);
   datasetinfo->AddVariable(varinfo);
   // note: the method has a different argument list than the other two
   datasetinfo->AddTarget(expression, title,  unit, min, max, normalized, external);
   datasetinfo->AddTarget(varinfo);
   datasetinfo->AddSpectator(expression, title,  unit, min, max, vartype, normalized, external);
   datasetinfo->AddSpectator(varinfo);
   datasetinfo->AddClass(classname);

   test_((datasetinfo->GetVariableInfos()).size()  == vecvarinfo.size());
   test_((datasetinfo->GetTargetInfos()).size()    == vecvarinfo.size());
   test_((datasetinfo->GetSpectatorInfos()).size() == vecvarinfo.size());

   test_(datasetinfo->GetNVariables()  == vecvarinfo.size());
   test_(datasetinfo->GetNTargets()    == vecvarinfo.size());
   test_(datasetinfo->GetNSpectators() == vecvarinfo.size());

   datasetinfo->SetNormalization(norm);
   test_(datasetinfo->GetNormalization() == norm);

   // there is no comparison operator for VariableInfo, this will be broken if the implementation changes
   /*
     for(vector<VariableInfo>::const_iterator varinf = vecvarinfo.begin(); varinf < vecvarinfo.end(); ++varinf)
     {
     unsigned int index = vecvarinfo.begin() - varinf;
     test_(datasetinfo->GetVariableInfo(index) == varinfo); // doesn't work!
     }
   */

   test_(datasetinfo->GetClassNameMaxLength() == classname.Length() );
   test_(datasetinfo->GetNClasses()           == 1);
   test_(datasetinfo->IsSignal(event)         == kTRUE);

   /*
   // classification information
   ClassInfo*         GetClassInfo( Int_t clNum ) const;
   ClassInfo*         GetClassInfo( const TString& name ) const;
   */


   test_(datasetinfo->HasCuts() == kFALSE); // why does this fail?

   datasetinfo->SetCut(cut1, classname);
   test_(datasetinfo->HasCuts() == kTRUE);

   test_(datasetinfo->GetCut(0) == cut1);
   //  test_(datasetinfo->GetCut(1) == cut2); // there is no guard against using the wrong index
   test_(datasetinfo->GetCut(classname) == cut1);
   datasetinfo->AddCut(cut2, classname);
   cut1 += cut2;
   test_(TString(datasetinfo->GetCut(classname)) == TString(cut1));

   datasetinfo->SetSplitOptions(splitoption);
   test_(datasetinfo->GetSplitOptions() == splitoption);

   test_(datasetinfo->GetWeightExpression(0) == "");
   datasetinfo->SetWeightExpression(weightexpr);
   test_(datasetinfo->GetWeightExpression(0) == weightexpr);

   datasetinfo->SetCorrelationMatrix(classname,matrix);
   //  datasetinfo->PrintCorrelationMatrix(classname);// this is insecure!

   test_(datasetinfo->FindVarIndex(expression) == 0);

   vector<TString> vars = datasetinfo->GetListOfVariables();


   /*
     void               ClearDataSet() const;
     Int_t              FindVarIndex( const TString& )      const;
     std::vector<TString> GetListOfVariables() const;
     const TMatrixD*    CorrelationMatrix     ( const TString& className ) const;
     void               SetCorrelationMatrix  ( const TString& className, TMatrixD* matrix );
     TH2*               CreateCorrelationMatrixHist( const TMatrixD* m, const TString& hName, const TString& hTitle ) const;
   */


   /*
     unclear to me, what to test:
     void               SetRootDir(TDirectory* d) { fOwnRootDir = d; }
     TDirectory*        GetRootDir() const { return fOwnRootDir; }
   */

}

// including file tmvaut/utDataSet.h
#ifndef UTDATASET_H
#define UTDATASET_H

// Author: Christoph Rosemann   Dec. 2009
// TMVA unit tests



#include <vector>

namespace TMVA {
   class DataSet;
   class DataSetInfo;
   class Event;
}

class utDataSet : public UnitTesting::UnitTest
{
public:
   utDataSet();
   void run();

private:
   void testMethods();

   TMVA::DataSet*            dataset;
   TMVA::DataSetInfo*        datasetinfo;
   TMVA::Event*              event0;
   TMVA::Event*              event1;
   TMVA::Event*              event2;
   TMVA::Event*              event3;
   TMVA::Event*              event4;
   //  std::vector<TMVA::Event>* vecevent;
   //  TMVA::Results*            result;
};
#endif // UTDATASET_H
// including file tmvaut/utDataSet.cxx



#include "TMVA/VariableInfo.h"
#include "TMVA/Types.h"
#include "TMVA/Event.h"
#include "TMVA/DataSet.h"
#include "TMVA/DataSetInfo.h"

#include "TString.h"

using namespace std;
using namespace TMVA;

utDataSet::utDataSet() :
   UnitTest("DataSet", __FILE__)
{
   //   event;
   //   vecevent;
   //  results;

   TString xname       = "name";
   TString expression1 = "expression1";
   TString expression2 = "expression2";
   TString expression3 = "expression3";
   TString title      = "title";
   TString unit       = "unit";
   char    vartype    = 'D';
   Float_t min        = 2.781828;
   Float_t max        = 3.1416;
   Bool_t  normalized = kFALSE;
   TString classname  = "classname";
   void* external = &max;
   UInt_t   _testClassVal    = 2;

   // the test values for initialisation
   vector<Float_t> _testValueVec, _testTargetVec, _testSpectatorVec;
   _testValueVec.push_back(1.);
   _testValueVec.push_back(2.);
   _testValueVec.push_back(3.);
   _testTargetVec.push_back(11.);
   _testTargetVec.push_back(12.);
   _testTargetVec.push_back(13.);
   _testSpectatorVec.push_back(25.);
   Float_t  _testWeight      = 3.1415;
   Float_t _testBoostWeight = 0.1234;
   event0 = new TMVA::Event( _testValueVec, _testTargetVec, _testSpectatorVec, _testClassVal, _testWeight, _testBoostWeight);
   event1 = new TMVA::Event( _testValueVec, _testTargetVec, _testSpectatorVec, _testClassVal, _testWeight, _testBoostWeight);
   event2 = new TMVA::Event( _testValueVec, _testTargetVec, _testSpectatorVec, _testClassVal, _testWeight, _testBoostWeight);
   event3 = new TMVA::Event( _testValueVec, _testTargetVec, _testSpectatorVec, _testClassVal, _testWeight, _testBoostWeight);
   event4 = new TMVA::Event( _testValueVec, _testTargetVec, _testSpectatorVec, _testClassVal, _testWeight, _testBoostWeight);

   UInt_t  varcounter = 0;

   VariableInfo* varinfo1     = new VariableInfo( expression1, title,  unit, varcounter++, vartype, external, min, max, normalized);
   VariableInfo* varinfo2     = new VariableInfo( expression2, title,  unit, varcounter++, vartype, external, min, max, normalized);
   VariableInfo* varinfo3     = new VariableInfo( expression3, title,  unit, varcounter++, vartype, external, min, max, normalized);
   datasetinfo               = new DataSetInfo(xname);
   datasetinfo->AddVariable(*varinfo1);
   datasetinfo->AddVariable(*varinfo2);
   datasetinfo->AddVariable(*varinfo3);
   datasetinfo->AddTarget(*varinfo1);
   datasetinfo->AddTarget(*varinfo2);
   datasetinfo->AddTarget(*varinfo3);
   datasetinfo->AddSpectator(*varinfo1);

   dataset = new DataSet(*datasetinfo);
}



void utDataSet::run()
{
  testMethods();
}



void utDataSet::testMethods()
{
   test_(dataset->GetNEvents() == 0);
   dataset->AddEvent(event0, Types::kTraining);
   dataset->AddEvent(event1, Types::kTraining);
   dataset->AddEvent(event2, Types::kTesting);
   dataset->AddEvent(event3, Types::kMaxTreeType);
   dataset->AddEvent(event4, Types::kValidation);

   test_(dataset->GetNEvents(Types::kTraining) == 2);
   test_(dataset->GetNEvents(Types::kTesting) == 1);
   //test_(dataset->GetNEvents(Types::kMaxTreeType) == 1); //ToDo check this isuue
   test_(dataset->GetNEvents(Types::kValidation) == 1);
   //test_(dataset->GetNEvents(Types::kTrainingOriginal) == 0);//ToDo check this issue

   test_(dataset->GetNTrainingEvents() == 2);
   test_(dataset->GetNTestEvents() == 1);

   test_(dataset->GetNVariables()  == 3);
   test_(dataset->GetNTargets()    == 3);
   test_(dataset->GetNSpectators() == 1);

   // this is only a temporary solution for the testing
   // FIXME:: Extend to a real test!

   test_(dataset->GetEvent());
   test_(dataset->GetEvent(0));
   test_(dataset->GetTrainingEvent(0));
   test_(dataset->GetTestEvent(0));
   test_(dataset->GetEvent(1, Types::kTraining));

   // calls to these function will cause the program to crash
   //  test_(dataset->GetNEvtSigTest() == 1);
   //  test_(dataset->GetNEvtBkgdTest() == 1);
   //  test_(dataset->GetNEvtSigTrain() == 1);
   //   test_(dataset->GetNEvtBkgdTrain() == 1);

   test_(dataset->HasNegativeEventWeights() == kFALSE);

   /* function still to develop tests for:
      void      SetCurrentEvent( Long64_t ievt         ) const { fCurrentEventIdx = ievt; }
      void      SetCurrentType ( Types::ETreeType type ) const { fCurrentTreeIdx = TreeIndex(type); }

      void                       SetEventCollection( std::vector<Event*>*, Types::ETreeType );
      const std::vector<Event*>& GetEventCollection( Types::ETreeType type = Types::kMaxTreeType ) const;
      const TTree*               GetEventCollectionAsTree();

      Results*  GetResults   ( const TString &,Types::ETreeType type, Types::EAnalysisType analysistype );
      void      DivideTrainingSet( UInt_t blockNum );
      void      MoveTrainingBlock( Int_t blockInd,Types::ETreeType dest, Bool_t applyChanges = kTRUE );
      void      IncrementNClassEvents( Int_t type, UInt_t classNumber );
      Long64_t  GetNClassEvents      ( Int_t type, UInt_t classNumber );
      void      ClearNClassEvents    ( Int_t type );
      TTree*    GetTree( Types::ETreeType type );
      void      InitSampling( Float_t fraction, Float_t weight, UInt_t seed = 0 );
      void      EventResult( Bool_t successful, Long64_t evtNumber = -1 );
      void      CreateSampling() const;
      UInt_t    TreeIndex(Types::ETreeType type) const;
   */
}


// including file tmvaut/utEvent.h
#ifndef UTEVENT_H
#define UTEVENT_H

// Author: Christoph Rosemann   Dec. 2009
// TMVA unit tests

#include <vector>

#include "Rtypes.h"



namespace TMVA {
   class Event;
}

class utEvent : public UnitTesting::UnitTest
{
public:
   utEvent();
   void run();

private:
   // the test calls in different blocks
   // the distinctions are arbitrary:
   void _testConstructor1();
   void _testConstructor2();
   void _testConstructor3();
   void _testConstructor4();
   void _testConstructor5();
   void _testConstructor6();
   void _testMutators();

   // there are six different constructors:
   TMVA::Event* _eventC1;
   TMVA::Event* _eventC2;
   TMVA::Event* _eventC3;
   TMVA::Event* _eventC4;
   TMVA::Event* _eventC5;
   TMVA::Event* _eventC6;

   // the values needed to create all "Event" objects in all ways
   std::vector<Float_t>  _testValueVec;
   std::vector<Float_t*> _testPointerVec;
   std::vector<Float_t>  _testTargetVec;
   std::vector<Float_t>  _testSpectatorVec;

   std::vector<Float_t>  _compareValueVec;
   std::vector<Float_t>  _compareTargetVec;
   std::vector<Float_t>  _compareSpectatorVec;

   Float_t               _t, _u, _v;
   Float_t               _testScale;
   UInt_t                _testClassVal;
   Float_t               _testWeight;
   Float_t               _testBoostWeight;
   UInt_t                _testNVar;
};
#endif // UTEVENT_H
// including file tmvaut/utEvent.cxx



#include "TMath.h"

#include "TMVA/Event.h"

using namespace std;
using namespace TMVA;

utEvent::utEvent() :
   UnitTest("Event", __FILE__)
{
   // the test values for initialisation
   _testValueVec.push_back(1.);
   _testValueVec.push_back(2.);
   _testValueVec.push_back(3.);
   _t = 1.;
   _u = 2.;
   _v = 3.;
   _testPointerVec.push_back(&_t);
   _testPointerVec.push_back(&_u);
   _testPointerVec.push_back(&_v);
   _testTargetVec.push_back(11.);
   _testTargetVec.push_back(12.);
   _testTargetVec.push_back(13.);
   _testSpectatorVec.push_back(25.);
   _testScale       = 2.7818;
   _testClassVal    = 2;
   _testWeight      = 3.1415;
   _testBoostWeight = 0.1234;
   _testNVar        = 3;
}



void utEvent::run()
{
   _testConstructor1();
   _testConstructor3();
   _testConstructor2(); // constructor 3 must be called before...
   _testConstructor4();
   _testConstructor5();
   _testConstructor6();
}



void utEvent::_testConstructor1()
{
   _eventC1 = new TMVA::Event();

   test_(_eventC1->IsDynamic()         == false);

   test_(floatCompare(_eventC1->GetWeight(), 1.));
   test_(floatCompare(_eventC1->GetOriginalWeight(), 1.));
   test_(floatCompare(_eventC1->GetBoostWeight(),1.));

   test_(_eventC1->GetWeight()         == 1.);
   test_(_eventC1->GetOriginalWeight() == 1.);
   test_(_eventC1->GetBoostWeight()    == 1.);
   test_(_eventC1->GetClass()          == 0);
   test_(_eventC1->GetNVariables()     == 0);
   test_(_eventC1->GetNTargets()       == 0);
   test_(_eventC1->GetNSpectators()    == 0);

   _testMutators();
}



void utEvent::_testConstructor2()
{
   _eventC2 = new TMVA::Event(*_eventC3);

   test_(_eventC2->IsDynamic()         == false);

   test_(floatCompare(_eventC2->GetWeight(), _testWeight*_testBoostWeight));
   test_(floatCompare(_eventC2->GetOriginalWeight(), _testWeight));
   test_(floatCompare(_eventC2->GetBoostWeight(), _testBoostWeight));

   test_(_eventC2->GetClass()          == _testClassVal);
   test_(_eventC2->GetNVariables()     == (UInt_t)_testValueVec.size());
   test_(_eventC2->GetNTargets()       == (UInt_t)_testTargetVec.size());
   test_(_eventC2->GetNSpectators()    == (UInt_t)_testSpectatorVec.size());
   // ? const std::vector<UInt_t>* GetVariableArrangement() const { return fVariableArrangement; }

   _compareValueVec = _eventC2->GetValues();
   for(vector<Float_t>::const_iterator it = _testValueVec.begin(); it < _testValueVec.end(); ++it)
      {
         unsigned int index = it - _testValueVec.begin();
         test_(_eventC2->GetValue(index)  == *it);
         test_(_compareValueVec.at(index) == *it);
      }
   _compareTargetVec = _eventC2->GetTargets();
   for(vector<Float_t>::const_iterator it = _testTargetVec.begin(); it < _testTargetVec.end(); ++it)
      {
         unsigned int index = it - _testTargetVec.begin();
         test_(_eventC2->GetTarget(index)  == *it);
         test_(_compareTargetVec.at(index) == *it);
      }
   _compareSpectatorVec = _eventC2->GetSpectators();
   for(vector<Float_t>::const_iterator it = _testSpectatorVec.begin(); it < _testSpectatorVec.end(); ++it)
      {
         unsigned int index = it - _testSpectatorVec.begin();
         test_(_eventC2->GetSpectator(index)  == *it);
         test_(_compareSpectatorVec.at(index) == *it);
      }

}



void utEvent::_testConstructor3()
{
   _eventC3 = new TMVA::Event( _testValueVec, _testTargetVec, _testSpectatorVec, _testClassVal, _testWeight, _testBoostWeight);

   test_(_eventC3->IsDynamic()         == false);

   test_(floatCompare(_eventC3->GetWeight(), _testWeight*_testBoostWeight));
   test_(floatCompare(_eventC3->GetOriginalWeight(), _testWeight));
   test_(floatCompare(_eventC3->GetBoostWeight(), _testBoostWeight));

   test_(_eventC3->GetClass()          == _testClassVal);
   test_(_eventC3->GetNVariables()     == (UInt_t)_testValueVec.size());
   test_(_eventC3->GetNTargets()       == (UInt_t)_testTargetVec.size());
   test_(_eventC3->GetNSpectators()    == (UInt_t)_testSpectatorVec.size());
   // ? const std::vector<UInt_t>* GetVariableArrangement() const { return fVariableArrangement; }

   _compareValueVec = _eventC3->GetValues();
   for(vector<Float_t>::const_iterator it = _testValueVec.begin(); it < _testValueVec.end(); ++it)
      {
         unsigned int index = it - _testValueVec.begin();
         test_(_eventC3->GetValue(index)  == *it);
         test_(_compareValueVec.at(index) == *it);
      }
   _compareTargetVec = _eventC3->GetTargets();
   for(vector<Float_t>::const_iterator it = _testTargetVec.begin(); it < _testTargetVec.end(); ++it)
      {
         unsigned int index = it - _testTargetVec.begin();
         test_(_eventC3->GetTarget(index)  == *it);
         test_(_compareTargetVec.at(index) == *it);
      }
   _compareSpectatorVec = _eventC3->GetSpectators();
   for(vector<Float_t>::const_iterator it = _testSpectatorVec.begin(); it < _testSpectatorVec.end(); ++it)
      {
         unsigned int index = it - _testSpectatorVec.begin();
         test_(_eventC3->GetSpectator(index)  == *it);
         test_(_compareSpectatorVec.at(index) == *it);
      }
}



void utEvent::_testConstructor4()
{
   _eventC4 = new TMVA::Event( _testValueVec, _testTargetVec, _testClassVal, _testWeight, _testBoostWeight);

   test_(_eventC4->IsDynamic()         == false);

   test_(floatCompare(_eventC4->GetWeight(), _testWeight*_testBoostWeight));
   test_(floatCompare(_eventC4->GetOriginalWeight(), _testWeight));
   test_(floatCompare(_eventC4->GetBoostWeight(), _testBoostWeight));

   test_(_eventC4->GetClass()          == _testClassVal);
   test_(_eventC4->GetNVariables()     == (UInt_t)_testValueVec.size());
   test_(_eventC4->GetNTargets()       == (UInt_t)_testTargetVec.size());

   _compareValueVec = _eventC4->GetValues();
   for(vector<Float_t>::const_iterator it = _testValueVec.begin(); it < _testValueVec.end(); ++it)
      {
         unsigned int index = it - _testValueVec.begin();
         test_(_eventC4->GetValue(index)  == *it);
         test_(_compareValueVec.at(index) == *it);
      }
   _compareTargetVec = _eventC4->GetTargets();
   for(vector<Float_t>::const_iterator it = _testTargetVec.begin(); it < _testTargetVec.end(); ++it)
      {
         unsigned int index = it - _testTargetVec.begin();
         test_(_eventC4->GetTarget(index)  == *it);
         test_(_compareTargetVec.at(index) == *it);
      }
}



void utEvent::_testConstructor5()
{
   _eventC5 = new TMVA::Event( _testValueVec, _testClassVal, _testWeight, _testBoostWeight);

   test_(_eventC5->IsDynamic()         == false);

   test_(floatCompare(_eventC5->GetWeight(), _testWeight*_testBoostWeight));
   test_(floatCompare(_eventC5->GetOriginalWeight(), _testWeight));
   test_(floatCompare(_eventC5->GetBoostWeight(), _testBoostWeight));

   test_(_eventC5->GetClass()          == _testClassVal);
   test_(_eventC5->GetNVariables()     == (UInt_t)_testValueVec.size());

   _compareValueVec = _eventC5->GetValues();
   for(vector<Float_t>::const_iterator it = _testValueVec.begin(); it < _testValueVec.end(); ++it)
      {
         unsigned int index = it - _testValueVec.begin();
         test_(_eventC5->GetValue(index)  == *it);
         test_(_compareValueVec.at(index) == *it);
      }
}



void utEvent::_testConstructor6()
{
   const vector<Float_t*>* _constPointerToPointerVec = &_testPointerVec;
   _eventC6 = new TMVA::Event( _constPointerToPointerVec, _testNVar);

   // TODO I don't understand what the constructor is for
   // or in what cases it should be used

   test_(_eventC6->IsDynamic()         == true);

   //   test_(_eventC6->GetWeight()         == 1.);
   //   test_(_eventC6->GetOriginalWeight() == 1.);
   //   test_(_eventC6->GetBoostWeight()    == 1.);
   //   test_(_eventC6->GetClass()          == _testClassVal);
   //   test_(_eventC6->GetNVariables()     == (UInt_t)_testValueVec.size());

   // ? const std::vector<UInt_t>* GetVariableArrangement() const { return fVariableArrangement; }

   //   _compareValueVec = _eventC6->GetValues();
   //   for(vector<Float_t>::const_iterator it = _testValueVec.begin(); it < _testValueVec.end(); ++it)
   //     {
   //       unsigned int index = it - _testValueVec.begin();
   //       test_(_eventC6->GetValue(index)  == *it);
   //       test_(_compareValueVec.at(index) == *it);
   //     }
}



void utEvent::_testMutators()
{
   // the empty/default constructor is taken for these tests

   _eventC1->SetWeight(_testWeight);
   test_(_eventC1->GetWeight() == _testWeight);

   //_eventC1->ScaleWeight(_testScale);
   //test_(floatCompare((float) _eventC1->GetWeight(), _testWeight*_testScale));
   test_(true);

   _eventC1->SetBoostWeight(_testBoostWeight);
   test_(floatCompare( _eventC1->GetBoostWeight() , _testBoostWeight));
   _eventC1->ScaleBoostWeight(_testScale);
   test_(floatCompare( _eventC1->GetBoostWeight(), _testBoostWeight*_testScale));


   _eventC1->SetClass(_testClassVal);
   test_(_eventC1->GetClass() == (UInt_t)_testClassVal);

   // check variables
   for(vector<Float_t>::const_iterator it = _testValueVec.begin(); it < _testValueVec.end(); ++it)
      {
         unsigned int index = it - _testValueVec.begin();
         _eventC1->SetVal(index, *it);
      }
   _compareValueVec = _eventC1->GetValues();
   for(vector<Float_t>::const_iterator it = _testValueVec.begin(); it < _testValueVec.end(); ++it)
      {
         unsigned int index = it - _testValueVec.begin();
         test_(_eventC1->GetValue(index)  == *it);
         test_(_compareValueVec.at(index) == *it);
      }
   // check targets
   for(vector<Float_t>::const_iterator it = _testTargetVec.begin(); it < _testTargetVec.end(); ++it)
      {
         unsigned int index = it - _testTargetVec.begin();
         _eventC1->SetTarget(index, *it);
      }
   _compareTargetVec = _eventC1->GetTargets();
   for(vector<Float_t>::const_iterator it = _testTargetVec.begin(); it < _testTargetVec.end(); ++it)
      {
         unsigned int index = it - _testTargetVec.begin();
         test_(_eventC1->GetTarget(index)  == *it);
         test_(_compareTargetVec.at(index) == *it);
      }
   // check spectators
   for(vector<Float_t>::const_iterator it = _testSpectatorVec.begin(); it < _testSpectatorVec.end(); ++it)
      {
         unsigned int index = it - _testSpectatorVec.begin();
         _eventC1->SetSpectator(index, *it);
      }
   _compareSpectatorVec = _eventC1->GetSpectators();
   for(vector<Float_t>::const_iterator it = _testSpectatorVec.begin(); it < _testSpectatorVec.end(); ++it)
      {
         unsigned int index = it - _testSpectatorVec.begin();
         test_(_eventC1->GetSpectator(index)  == *it);
         test_(_compareSpectatorVec.at(index) == *it);
      }

   _eventC1->SetClass(_testClassVal);
   test_(_eventC1->GetClass() == (UInt_t)_testClassVal);

   // ??    _eventC1->SetVariableArrangement( std::vector<UInt_t>* const m ) const;
}

// including file tmvaut/utReader.h
#ifndef UTREADER_H
#define UTREADER_H

// Author: E. v. Toerne,  Nov 2011, implementing unit tests by C. Rosemann
// TMVA unit tests
//
// this class acts as interface to several reader applications

#include <string>
#include <iostream>
#include <cassert>
#include <vector>

#include "TTree.h"
#include "TString.h"

#include "TMVA/Reader.h"
#include "TMVA/Types.h"



namespace UnitTesting
{
  class utReader : public UnitTest
  {
  public:
    utReader(const char* theOption="");
    virtual ~utReader();

    virtual void run();

  protected:

  private:
     // disallow copy constructor and assignment
     utReader(const utReader&);
     utReader& operator=(const utReader&);
  };
} // namespace UnitTesting
#endif //
// including file tmvaut/utReader.cxx


#include <string>
#include <iostream>
#include <cassert>
#include <vector>

#include "TTree.h"
#include "TString.h"

#include "TMVA/Reader.h"
#include "TMVA/Types.h"



using namespace std;
using namespace UnitTesting;
using namespace TMVA;

utReader::utReader(const char* /*theOption*/)
   : UnitTest(string("Reader"))
{

}
utReader::~utReader(){ }

void utReader::run()
{
   float xtest,xtest2;
   Reader* reader2 = new Reader();
   Reader* reader3 = new Reader();
   reader2->AddVariable("test", &xtest);
   reader2->AddVariable("test2", &xtest2);
   reader3->AddVariable("test", &xtest);

   delete reader2;
   delete reader3;
   test_(1>0);
   const int nTest=3;
   int ievt;
   vector<float> testvar(10);
   std::vector< TMVA::Reader* > reader(nTest);
   for (int iTest=0;iTest<nTest;iTest++){
      reader[iTest] = new TMVA::Reader( "!Color:Silent" );
      if (iTest==0){
         reader[iTest]->AddVariable( "var0" ,&testvar[0]);
         reader[iTest]->AddVariable( "var1" ,&testvar[1]);
         reader[iTest]->AddSpectator( "ievt" ,&ievt);
         reader[iTest]->BookMVA( "LD method", "dataset/weights/TMVATest_LD.weights.xml") ;
      }
      if (iTest==1){
         reader[iTest]->AddVariable( "var0" ,&testvar[0]);
         reader[iTest]->AddVariable( "var1" ,&testvar[1]);
         reader[iTest]->AddVariable( "var2" ,&testvar[2]);
         reader[iTest]->AddSpectator( "ievt" ,&ievt);
         reader[iTest]->BookMVA( "LD method", "dataset/weights/TMVATest3Var_LD.weights.xml") ;
      }
      if (iTest==2){
         reader[iTest]->AddVariable( "var0" ,&testvar[0]);
         reader[iTest]->AddVariable( "var1" ,&testvar[1]);
         reader[iTest]->AddVariable( "var2" ,&testvar[2]);
         reader[iTest]->AddVariable( "ivar0" ,&testvar[3]);
         reader[iTest]->AddVariable( "ivar1" ,&testvar[4]);
         reader[iTest]->AddSpectator( "ievt" ,&ievt);
         reader[iTest]->BookMVA( "LD method", "dataset/weights/TMVATest3VarF2VarI_LD.weights.xml") ;
      }
   }
   reader[0]->EvaluateMVA( "LD method");
   reader[1]->EvaluateMVA( "LD method");
   reader[2]->EvaluateMVA( "LD method");
   test_(1>0);
}
#ifndef UTREADERMT_H
#define UTREADERMT_H

// Author: D. Piparo, 2015
// TMVA unit tests
//
// this class acts as interface to several reader applications in MT mode

#include <string>
#include <iostream>
#include <cassert>
#include <vector>
#include <thread>

#include "TTree.h"
#include "TString.h"

#include "TMVA/Reader.h"
#include "TMVA/Types.h"



namespace UnitTesting
{
  class utReaderMT : public UnitTest
  {
  public:
    utReaderMT(const char* theOption="");
    virtual ~utReaderMT();

    virtual void run();

  protected:

  private:
     // disallow copy constructor and assignment
     utReaderMT(const utReaderMT&);
     utReaderMT& operator=(const utReaderMT&);
  };
} // namespace UnitTesting
#endif //


#include <string>
#include <iostream>
#include <cassert>
#include <vector>

#include "TTree.h"
#include "TString.h"

#include "TMVA/Reader.h"
#include "TMVA/Types.h"



using namespace std;
using namespace UnitTesting;
using namespace TMVA;

utReaderMT::utReaderMT(const char* /*theOption*/)
   : UnitTest(string("ReaderMT"))
{

}
utReaderMT::~utReaderMT(){ }

void utReaderMT::run()
{
   auto runSingleReader = [&] () {
      float xtest,xtest2;
      Reader* reader2 = new Reader();
      Reader* reader3 = new Reader();
      reader2->AddVariable("test", &xtest);
      reader2->AddVariable("test2", &xtest2);
      reader3->AddVariable("test", &xtest);

      delete reader2;
      delete reader3;
      test_(1>0);
      const int nTest=3;
      int ievt;
      vector<float> testvar(10);
      std::vector< TMVA::Reader* > reader(nTest);
      for (int iTest=0;iTest<nTest;iTest++){
         reader[iTest] = new TMVA::Reader( "!Color:Silent" );
         if (iTest==0){
            reader[iTest]->AddVariable( "var0" ,&testvar[0]);
            reader[iTest]->AddVariable( "var1" ,&testvar[1]);
            reader[iTest]->AddSpectator( "ievt" ,&ievt);
            reader[iTest]->BookMVA( "LD method", "dataset/weights/TMVATest_LD.weights.xml") ;
         }
         if (iTest==1){
            reader[iTest]->AddVariable( "var0" ,&testvar[0]);
            reader[iTest]->AddVariable( "var1" ,&testvar[1]);
            reader[iTest]->AddVariable( "var2" ,&testvar[2]);
            reader[iTest]->AddSpectator( "ievt" ,&ievt);
            reader[iTest]->BookMVA( "LD method", "dataset/weights/TMVATest3Var_LD.weights.xml") ;
         }
         if (iTest==2){
            reader[iTest]->AddVariable( "var0" ,&testvar[0]);
            reader[iTest]->AddVariable( "var1" ,&testvar[1]);
            reader[iTest]->AddVariable( "var2" ,&testvar[2]);
            reader[iTest]->AddVariable( "ivar0" ,&testvar[3]);
            reader[iTest]->AddVariable( "ivar1" ,&testvar[4]);
            reader[iTest]->AddSpectator( "ievt" ,&ievt);
            reader[iTest]->BookMVA( "LD method", "dataset/weights/TMVATest3VarF2VarI_LD.weights.xml") ;
         }
      }
      reader[0]->EvaluateMVA( "LD method");
      reader[1]->EvaluateMVA( "LD method");
      reader[2]->EvaluateMVA( "LD method");
      test_(1>0);
   };
   for (int j=0;j<5;++j){ // challenge non reproducibility repeating the loop
      vector<thread> threads;
      for (int i=0;i<10;++i) threads.emplace_back(runSingleReader);
      for (auto&& t : threads) t.join();
   }

}

// including file tmvaut/utFactory.h
#ifndef UTFACTORY_H
#define UTFACTORY_H

// Author: E. v. Toerne,  Nov 2011, implementing unit tests by C. Rosemann
// TMVA unit tests
//
// this class acts as interface to several factory applications

#include <string>
#include <iostream>
#include <cassert>
#include <vector>

#include "TTree.h"
#include "TString.h"

#include "TMVA/Factory.h"
#include "TMVA/DataLoader.h"
#include "TMVA/Types.h"



namespace UnitTesting
{
   class utFactory : public UnitTest
   {
   public:
      utFactory(const char* theOption="");
      virtual ~utFactory();
      virtual void run();

   protected:
      virtual TTree* create_Tree(const char* opt="");
      virtual bool operateSingleFactory(const char* factoryname, const char* opt="");
      virtual bool addEventsToFactoryByHand(const char* factoryname, const char* opt="");

   private:
      // disallow copy constructor and assignment
      utFactory(const utFactory&);
      utFactory& operator=(const utFactory&);
   };
} // namespace UnitTesting
#endif //
// including file tmvaut/utFactory.cxx


#include <string>
#include <iostream>
#include <cassert>
#include <vector>
#include <exception>

#include "TMath.h"
#include "TTree.h"
#include "TFile.h"
#include "TSystem.h"
#include "TString.h"

#include "TMVA/Factory.h"
#include "TMVA/MethodBase.h"
#include "TMVA/Types.h"



using namespace std;
using namespace UnitTesting;
using namespace TMVA;

utFactory::utFactory(const char* /*theOption*/)
   : UnitTest(string("Factory"))
{

}
utFactory::~utFactory(){ }
TTree* utFactory::create_Tree(const char* opt)
{
   TString option = opt;
   const int nmax=100;
   const int nvar=3, nfval=2, nivar=2, nclass=3;
   float weight=1.;
   vector<float> var(nvar), fval(nfval); // fix me hardcoded nvar
   vector<int> ivar(nivar), nevt(nclass);
   Int_t iclass, ievt=0,i=0;

   TTree* tree = new TTree( "Tree", "Tree");
   for (i=0; i<nvar ; i++) tree->Branch(Form( "var%i", i), &var[i],
                                        Form( "var%i/F", i ));
   for (i=0; i<nfval; i++) tree->Branch(Form( "fval%i", i), &fval[i],
                                        Form( "fval%i/F", i ));
   for (i=0; i<nivar; i++) tree->Branch(Form( "ivar%i", i), &ivar[i],
                                        Form( "ivar%i/I", i ));
   tree->Branch("iclass",&iclass,"iclass/I");
   tree->Branch("ievt",&ievt,"ievt/I");
   tree->Branch("weight",&weight,"weight/F");
   TRandom3 R( 99 );

   do {
      for (i=0; i<nvar; i++)  var[i]  = 2.*R.Rndm()-1.;
      for (i=0; i<nivar; i++) ivar[i] = (int) (20.*(R.Rndm()-0.5));
      for (i=0; i<nfval; i++)  fval[i]  = 5.*(R.Rndm()-0.5);
      Float_t xout = var[0]+var[1]+var[2]*var[1]-var[0]*var[1]*var[1]+2.*(R.Rndm()-1.);
      if (xout < -2.) iclass=2;
      else if (xout > 0) iclass=0; // signal
      else iclass=1;               // background
      nevt[iclass]++;
      //std::cout << xout<< " " <<nevt[0]<< " " << nevt[1]<< " " << nevt[2]<< std::endl;
      ievt++;
      tree->Fill();
   } while ( TMath::Min(nevt[0],TMath::Min(nevt[1],nevt[2])) < nmax);
   //tree->Print();
   return tree;
}

bool utFactory::addEventsToFactoryByHand(const char* factoryname, const char* opt)
{
#ifdef COUTDEBUG
   std::cout <<"addEventsToFactoryByHand option="<<opt<<std::endl;
#endif
   TString option=opt;
   bool useWeights = option.Contains("useWeights");
   bool useNegWeights = option.Contains("useNegWeights");
   TString _methodTitle,_methodOption="!H:!V"; // fix me
   if (option.Contains("useBDT")) _methodTitle="BDT";
   else if (option.Contains("useMLP")) _methodTitle="MLP";
   else _methodTitle="LD";

   TString prepareString="";
   string factoryOptions( "!V:Silent:Transformations=I:AnalysisType=Classification:!Color:!DrawProgressBar" );
   TString outfileName( "weights/ByHand.root" );
   TFile* outputFile = TFile::Open( outfileName, "RECREATE" );
   Factory* factory = new Factory(factoryname,outputFile,factoryOptions);
   DataLoader * dataloader = new DataLoader("dataset"); 
   dataloader->AddVariable( "var0",  "Variable 0", 'F' );
   dataloader->AddVariable( "var1",  "Variable 1", 'F' );

   vector <double> vars(2);
   TRandom3 r(99);
   double weight = 1.;
   for (int i=0;i<100;i++){
      if (useWeights){
         vars[0]= 4. * (r.Rndm()-0.5);
         vars[1]= 4. * (r.Rndm()-0.5);
         weight = TMath::Gaus(vars[0],1.,1.)*TMath::Gaus(vars[1],0.,1.);
         if (useNegWeights && i>90) weight = -weight;
      }
      else {
         vars[0]=r.Gaus(1.,1.);
         vars[1]=r.Gaus(0.,1.);
      }
      dataloader->AddSignalTrainingEvent( vars, weight );
      dataloader->AddSignalTestEvent( vars, weight );
   }
   for (int i=0;i<100;i++){
      vars[0]= 4. * (r.Rndm()-0.5);
      vars[1]= 4. * (r.Rndm()-0.5);
      weight = 1.;
      dataloader->AddBackgroundTrainingEvent( vars, weight);
      dataloader->AddBackgroundTestEvent( vars, weight);
   }
   if (prepareString=="") prepareString = "nTrain_Signal=0:nTrain_Background=0:SplitMode=Random:NormMode=NumEvents:!V" ;
   dataloader->PrepareTrainingAndTestTree( "", "", prepareString);

   factory->BookMethod(dataloader, _methodTitle,_methodTitle, "!H:!V");
   factory->TrainAllMethods();
   factory->TestAllMethods();
   factory->EvaluateAllMethods();
   double ROCValue(0.);
   if (auto theMethod = dynamic_cast<TMVA::MethodBase *>(factory->GetMethod(dataloader->GetName(), _methodTitle))) {
      ROCValue = theMethod->GetROCIntegral();
   }
   //cout << "ROC="<<ROCValue<<endl;
   delete dataloader; 
   delete factory;
   outputFile->Close();
   if (outputFile) delete outputFile;
   return (ROCValue>0.6);
}

bool utFactory::operateSingleFactory(const char* factoryname, const char* opt)
{
   if (TString(factoryname)=="") factoryname = "TMVATest";
#ifdef COUTDEBUG
   std::cout <<"operateSingleFactory option="<<opt<<std::endl;
#endif
   TString option=opt;
   TTree* tree(0);
   TFile* inFile(0);
   if (!(option.Contains("MemoryResidentTree"))){
      inFile = TFile::Open( "weights/input.root", "RECREATE" );
      tree = create_Tree();
      inFile->Write();
      inFile->Close();
      if (inFile) delete inFile;
      inFile = TFile::Open( "weights/input.root");
      tree = (TTree*) inFile->Get("Tree");
   }
   else if (! (option.Contains("LateTreeBooking"))) tree = create_Tree();

   TString _methodTitle="LD",_methodOption="!H:!V"; // fix me
   TString prepareString="";
   string factoryOptions( "!V:Silent:Transformations=I,D:AnalysisType=Classification:!Color:!DrawProgressBar" );
   TString outfileName( "weights/TMVA.root" );
   TFile* outputFile = TFile::Open( outfileName, "RECREATE" );
   if (option.Contains("LateTreeBooking") && option.Contains("MemoryResidentTree")) tree = create_Tree();

   Factory* factory = new Factory(factoryname,outputFile,factoryOptions);
   DataLoader * dataloader = new DataLoader("dataset");
   dataloader->AddVariable( "var0",  "Variable 0", 'F' );
   dataloader->AddVariable( "var1",  "Variable 1", 'F' );
   if (option.Contains("var2"))  dataloader->AddVariable( "var2",  "Var 2", 'F' );
   if (option.Contains("ivar0")) dataloader->AddVariable( "ivar0",  "Var i0", 'I' );
   if (option.Contains("ivar1")) dataloader->AddVariable( "ivar1",  "Var i1", 'I' );

   dataloader->AddSpectator( "ievt", 'I' );
   dataloader->AddSignalTree(tree);
   dataloader->AddBackgroundTree(tree);
   if (prepareString=="") prepareString = "nTrain_Signal=0:nTrain_Background=0:SplitMode=Random:NormMode=NumEvents:!V" ;
   // this crashes "nTrain_Signal=0:nTrain_Background=0:SplitMode=Random:NormMode=NumEvents:!V" ;
   dataloader->PrepareTrainingAndTestTree( "iclass==0", "iclass==1", prepareString);

   if (option.Contains("StringMethodBooking")) factory->BookMethod(dataloader,"LD","LD","!H:!V");
   else factory->BookMethod(dataloader,TMVA::Types::kLD,"LD","!H:!V");

   //factory->BookMethod(_methodType, _methodTitle, _methodOption);

   factory->TrainAllMethods();
   factory->TestAllMethods();
   factory->EvaluateAllMethods();
   double ROCValue(0.);
   if (auto theMethod = dynamic_cast<TMVA::MethodBase *>(factory->GetMethod(dataloader->GetName(), _methodTitle))) {
      ROCValue = theMethod->GetROCIntegral();
   }
   delete tree;
   delete dataloader; 
   delete factory;
   outputFile->Close();
   if (option.Contains("InputFile")){
      inFile->Close();
   }
   if (outputFile) delete outputFile;
   if (inFile) delete inFile;

   Bool_t ret = (ROCValue>0.6);
   if (!ret) {
      std::cout <<"FAILURE with operateSingleFactory option="<<opt<< ",  bad value ROC="<<ROCValue<<std::endl;
   }
   return ret;
}

void utFactory::run()
{
   // create directory weights if necessary
   FileStat_t stat;
   if(gSystem->GetPathInfo("./weights",stat)) {// FIXME:: give the filename of the sample somewhere else?
      gSystem->MakeDirectory("weights");
#ifdef COUTDEBUG
      std::cout << "creating directory weights"<<std::endl;
#endif
   }
   // create three factories with two methods each
   test_(addEventsToFactoryByHand("ByHand","")); // uses Factory::AddSignalTrainingEvent
   test_(addEventsToFactoryByHand("ByHand2","useWeights"));

   test_(addEventsToFactoryByHand("ByHand","useMLP")); // uses Factory::AddSignalTrainingEvent
   test_(addEventsToFactoryByHand("ByHand2","useWeights:useMLP"));


   test_(addEventsToFactoryByHand("ByHand","useBDT")); // uses Factory::AddSignalTrainingEvent
   test_(addEventsToFactoryByHand("ByHand2","useWeights:useNegWeights:useBDT"));
   test_(addEventsToFactoryByHand("ByHand2","useWeights:useBDT"));



   test_(operateSingleFactory("TMVATest","StringMethodBooking"));
   test_(operateSingleFactory("TMVATest",""));
   test_(operateSingleFactory("TMVATest3Var","var2"));
   test_(operateSingleFactory("TMVATest3VarF2VarI","var2:ivar0:ivar1"));


// uses Factory::AddSignalTrainingEvent

   //creates crash test_(operateSingleFactory("TMVATest","MemoryResidentTree:StringMethodBooking"));
   //creates crash test_(operateSingleFactory("TMVATest","MemoryResidentTree"));
   //creates crash test_(operateSingleFactory("TMVATest","MemoryResidentTree:LateTreeBooking"));
   //creates crash test_(operateSingleFactory("TMVATest","MemoryResidentTree:LateTreeBooking:StringMethodBooking"));



}

// including file tmvaut/utVariableInfo.h
#ifndef UTVARIABLEINFO_H
#define UTVARIABLEINFO_H

// Author: Christoph Rosemann   Dec. 2009
// TMVA unit tests

#include <vector>

#include "TString.h"



namespace TMVA {
   class VariableInfo;
}


class utVariableInfo : public UnitTesting::UnitTest
{
 public:
  utVariableInfo();
  void run();

 private:
  // the test calls in different blocks
  // the distinctions are arbitrary:
  void _testConstructor1();
  void _testConstructor2();
  void _testConstructor3();

  void _testMethods();

  // there are six different constructors:
  TMVA::VariableInfo* _varinfoC1;
  TMVA::VariableInfo* _varinfoC2;
  TMVA::VariableInfo* _varinfoC3;

  // the values needed to create all "VariableInfo" objects in all ways
  TString  expression;
  TString  title;
  TString  unit;
  Int_t    varCounter;
  char     varType;
  Double_t min;
  Double_t max;
  Bool_t   normalized;
  void*    external;
  Float_t  mean;
  Float_t  rms;
};
#endif // UTVARIABLEINFO_H
// including file tmvaut/utVariableInfo.cxx

#include "TMath.h"

#include "TMVA/VariableInfo.h"

using namespace std;
using namespace UnitTesting;
using namespace TMVA;

utVariableInfo::utVariableInfo() :
   UnitTest("VariableInfo", __FILE__)
{
   expression = "expression";
   title      = "title";
   unit       = "unit";

   varCounter = 123;
   varType    = 'D';
   min        = 2.781828;
   max        = 3.1416;
   normalized = kTRUE;
   external   = &max;

   mean       = 42.;
   rms        = 47.11;
   _varinfoC1 = nullptr;
   _varinfoC2 = nullptr;
   _varinfoC3 = nullptr;
}



void utVariableInfo::run()
{
   _testConstructor1();
   _testConstructor2();
   _testConstructor3();
   _testMethods();
}



void utVariableInfo::_testConstructor1()
{
   _varinfoC1 = new VariableInfo( expression, title,  unit, varCounter, varType, external, min, max, normalized);

   test_(_varinfoC1->GetExpression()  == expression);
   //  test_(_varinfoC1->GetInternalName() == );
   //  test_(_varinfoC1->GetLabel()
   test_(_varinfoC1->GetTitle()   == title);
   test_(_varinfoC1->GetUnit()    == unit);
   test_(_varinfoC1->GetVarType() == varType);

   test_(_varinfoC1->GetMin()  == min);
   test_(_varinfoC1->GetMax()  == max);
   //   test_(_varinfoC1->GetMean() == 0.);
   //   test_(_varinfoC1->GetRMS()  == 0.);
   test_(_varinfoC1->GetExternalLink() == external);

}



void utVariableInfo::_testConstructor2()
{
   _varinfoC2 = new VariableInfo();
   test_(_varinfoC2->GetExpression()  == "");
   //  test_(_varinfoC2->GetInternalName() == );
   //  test_(_varinfoC2->GetLabel()
   test_(_varinfoC2->GetTitle()   == TString(""));
   test_(_varinfoC2->GetUnit()    == "");
   test_(_varinfoC2->GetVarType() == '\0');

   test_(_varinfoC2->GetMin()  == 1e30);
   test_(_varinfoC2->GetMax()  == -1e30);
   //   test_(_varinfoC2->GetMean() == 0.);
   //   test_(_varinfoC2->GetRMS()  == 0.);
   //  test_(_varinfoC2->GetExternalLink() == external);
}



void utVariableInfo::_testConstructor3()
{
   _varinfoC3 = new VariableInfo(*_varinfoC1);

   test_(_varinfoC3->GetExpression()  == expression);
   //  test_(_varinfoC3->GetInternalName() == );
   //  test_(_varinfoC3->GetLabel()
   test_(_varinfoC3->GetTitle()   == title);
   test_(_varinfoC3->GetUnit()    == unit);
   test_(_varinfoC3->GetVarType() == varType);

   test_(_varinfoC3->GetMin()  == min);
   test_(_varinfoC3->GetMax()  == max);
   //   test_(_varinfoC3->GetMean() == 0.);
   //   test_(_varinfoC3->GetRMS()  == 0.);
   test_(_varinfoC3->GetExternalLink() == external);
}



void utVariableInfo::_testMethods()
{
   _varinfoC2->SetMin(min);
   _varinfoC2->SetMax(max);
   _varinfoC2->SetMean(mean);
   _varinfoC2->SetRMS(rms);
   _varinfoC2->SetExternalLink(external);

   test_(_varinfoC2->GetMin()  == min);
   test_(_varinfoC2->GetMax()  == max);
   test_(_varinfoC2->GetMean() == mean);
   test_(_varinfoC2->GetRMS()  == rms);

   _varinfoC2->ResetMinMax();
   test_(_varinfoC2->GetMin()  == 1e30);
   test_(_varinfoC2->GetMax()  == -1e30);

   // test assignment
   *_varinfoC2 = *_varinfoC1;

   test_(_varinfoC2->GetExpression()  == expression);
   //  test_(_varinfoC2->GetTitle()   == title); // title is not copied
   //  test_(_varinfoC2->GetUnit()    == unit);  // unit is not copied
   test_(_varinfoC2->GetVarType() == varType);

   test_(_varinfoC2->GetMin()  == min);
   test_(_varinfoC2->GetMax()  == max);
   test_(_varinfoC2->GetExternalLink() == external);
}




// including file tmvaut/MethodUnitTestWithROCLimits.h
#ifndef METHODUNITTESTWITHROCLIMITS_H
#define METHODUNITTESTWITHROCLIMITS_H

// Author: Christoph Rosemann  Jul 2010
// TMVA unit tests
//
// this class acts as interface to create, train and evaluate the method
// specified in the constructor
// as additional argument the limits of the ROC integral can be given
// to determine the performance

#include <string>
#include <iostream>
#include <cassert>
#include <vector>

#include "TTree.h"
#include "TString.h"

#include "TMVA/Factory.h"
#include "TMVA/MethodBase.h"
#include "TMVA/Types.h"



namespace UnitTesting
{
  class MethodUnitTestWithROCLimits : public UnitTest
  {
  public:
    MethodUnitTestWithROCLimits(const TMVA::Types::EMVA& theMethod, const TString& methodTitle, const TString& theOption,
                                double lowLimit = 0., double upLimit = 1.,
                                const std::string & name="", const std::string & filename="", std::ostream* osptr = &std::cout);
    virtual ~MethodUnitTestWithROCLimits();

    virtual void run();

  protected:
    TTree*          theTree;

  private:
     TMVA::Factory* _factory;
     TMVA::MethodBase* _theMethod;
     TMVA::Types::EMVA _methodType;
     TString _methodTitle;
     TString _methodOption;

     double _upROCLimit;
     double _lowROCLimit;
     double _ROCValue;

     //TString _OutputROOTFile;
     std::vector<TString>* _VariableNames;
     std::vector<TString>* _TreeVariableNames;
     bool ROCIntegralWithinInterval();

     // disallow copy constructor and assignment
     MethodUnitTestWithROCLimits(const MethodUnitTestWithROCLimits&);
     MethodUnitTestWithROCLimits& operator=(const MethodUnitTestWithROCLimits&);
  };
} // namespace UnitTesting
#endif // METHODUNITTESTWITHROCLIMITS_H
// including file tmvaut/MethodUnitTestWithROCLimits.cxx

#include "TFile.h"
#include "TROOT.h"
#include "TSystem.h"
#include "TMath.h"
#include "TMVA/MethodBase.h"
#include "TMVA/Reader.h"
#include <iostream>
#include <fstream>
#include <sstream>

using namespace std;
using namespace UnitTesting;
using namespace TMVA;

MethodUnitTestWithROCLimits::MethodUnitTestWithROCLimits(const Types::EMVA &theMethod, const TString &methodTitle,
                                                         const TString &theOption, double lowLimit, double upLimit,
                                                         const std::string & /* xname */,
                                                         const std::string & /* filename */, std::ostream * /* sptr */)
   : UnitTest(string(methodTitle.Data()), __FILE__), _methodType(theMethod), _methodTitle(methodTitle),
     _methodOption(theOption), _upROCLimit(upLimit), _lowROCLimit(lowLimit), _VariableNames(0), _TreeVariableNames(0)
{
   _VariableNames  = new std::vector<TString>(0);
   _TreeVariableNames = new std::vector<TString>(0);
   _VariableNames->push_back("var1+var2");
   _VariableNames->push_back("var1-var2");
   _VariableNames->push_back("var3");
   _VariableNames->push_back("var4");
   _TreeVariableNames->push_back("myvar1");
   _TreeVariableNames->push_back("myvar2");
   _TreeVariableNames->push_back("var3");
   _TreeVariableNames->push_back("var4");
}


MethodUnitTestWithROCLimits::~MethodUnitTestWithROCLimits()
{
}

bool MethodUnitTestWithROCLimits::ROCIntegralWithinInterval()
{
   return (_ROCValue <= _upROCLimit) && (_ROCValue >= _lowROCLimit);
}

void MethodUnitTestWithROCLimits::run()
{
   TString outfileName( "weights/TMVA.root" );
   TFile* outputFile = TFile::Open( outfileName, "RECREATE" );

// FIXME:: if file can't be created do something more?
  if(!outputFile)
    return;

// FIXME:: make the factory option mutable?
// absolute silence options:
  string factoryOptions( "!V:Silent:AnalysisType=Classification:!Color:!DrawProgressBar" );

  if (_methodOption.Contains("VarTransform")) factoryOptions+=":Transformations=I;D;P;G";
  Factory* factory = new Factory( "TMVAUnitTesting", outputFile, factoryOptions );
  DataLoader * dataloader = new DataLoader("dataset");
  // factory->AddVariable( "myvar1 := var1+var2", 'F' );
  // factory->AddVariable( "myvar2 := var1-var2", "Expression 2", "", 'F' );
  dataloader->AddVariable( Form("%s  := %s",_TreeVariableNames->at(0).Data(), _VariableNames->at(0).Data()), 'F' );
  dataloader->AddVariable( Form("%s  := %s",_TreeVariableNames->at(1).Data(), _VariableNames->at(1).Data()), "Expression 2", "",'F' );
  dataloader->AddVariable( _VariableNames->at(2),                "Variable 3", "units", 'F' );
  dataloader->AddVariable( _VariableNames->at(3),                "Variable 4", "units", 'F' );

  TFile* input(0);
  FileStat_t stat;

  TString fname = "./tmva_class_example.root";
  if(!gSystem->GetPathInfo(fname,stat)) {
     input = TFile::Open( fname );
  } else {
     TFile::SetCacheFileDir(".");
     input = TFile::Open("http://root.cern.ch/files/tmva_class_example.root", "CACHEREAD");
  }
  if (input == NULL) {
     cerr << "broken/inaccessible input file" << endl;
  }

  TTree *signal     = (TTree*)input->Get("TreeS");
  TTree *background = (TTree*)input->Get("TreeB");

  dataloader->AddSignalTree(signal);
  dataloader->AddBackgroundTree(background);

  dataloader->SetBackgroundWeightExpression("weight");

  TCut mycuts = "";
  TCut mycutb = "";

  // FIXME:: make options string mutable?
  dataloader->PrepareTrainingAndTestTree( mycuts, mycutb,
                                      "nTrain_Signal=1000:nTrain_Background=1000:nTest_Signal=5000:nTest_Background=5000:SplitMode=Random:NormMode=NumEvents:!V" );

  factory->BookMethod(dataloader, _methodType, _methodTitle, _methodOption);

  factory->TrainAllMethods();

  factory->TestAllMethods();

  factory->EvaluateAllMethods();

  _theMethod = dynamic_cast<TMVA::MethodBase*> (factory->GetMethod(dataloader->GetName(), _methodTitle));

  if (_methodType == TMVA::Types::kCuts) {
     // ToDo make class variable _theEffi
     Double_t err=0.;
     Double_t effi = _theMethod->GetEfficiency("Efficiency:0.1", Types::kTesting,err);
#ifdef COUTDEBUG
     std::cout << "Cuts Signal effi at for Background effi of 0.1 = " << effi<<" low limit="<<_lowROCLimit<<" high limit="<<_upROCLimit<<std::endl;
#endif
     test_(effi <= _upROCLimit && effi>=_lowROCLimit);
  }
  else {
     _ROCValue = _theMethod->GetROCIntegral();
#ifdef COUTDEBUG
     std::cout << "ROC integral = "<<_ROCValue <<" low limit="<<_lowROCLimit<<" high limit="<<_upROCLimit<<std::endl;
#endif
     if (!ROCIntegralWithinInterval()){
        std::cout << "failure in " << _methodTitle<<", ROC integral = "<<_ROCValue <<" low limit="<<_lowROCLimit<<" high limit="<<_upROCLimit<<std::endl;
     }
     test_(ROCIntegralWithinInterval());
  }
  outputFile->Close();
  delete dataloader; 
  delete factory;

  if (outputFile) delete outputFile;

  // Reader tests
  const int nTest=6; // 3 reader usages + 3 tests with additional readers
  float testTreeVal,readerVal=0.;
  vector<float>  testvar(_VariableNames->size());
  vector<float>  dummy(_VariableNames->size());
  vector<float>  dummy2(_VariableNames->size());
  vector<float>  testvarFloat(_VariableNames->size());
  vector<double> testvarDouble(_VariableNames->size());

  // setup test tree access
  TFile* testFile = new TFile("weights/TMVA.root");
  TTree* testTree = (TTree*)(testFile->GetDirectory("dataset")->Get("TestTree"));
  for (UInt_t i=0;i<_VariableNames->size();i++)
     testTree->SetBranchAddress(_TreeVariableNames->at(i),&testvar[i]);
  testTree->SetBranchAddress(_methodTitle.Data(),&testTreeVal);

  std::vector<TString> variableNames2;
  variableNames2.push_back("var0");
  variableNames2.push_back("var1");
  TFile* testFile2 = new TFile("weights/ByHand.root");
  TTree* testTree2 = (TTree*)(testFile2->GetDirectory("dataset")->Get("TestTree"));
  testTree2->SetBranchAddress("var0",&dummy[0]);
  testTree2->SetBranchAddress("var1",&dummy[1]);

  TString readerName = _methodTitle + TString(" method");
  TString readerOption="!Color:Silent";
  TString dir    = "dataset/weights/TMVAUnitTesting_";
  TString weightfile=dir+_methodTitle+".weights.xml";
  TString weightfile2="dataset/weights/ByHand_BDT.weights.xml"; //TMVATest3VarF2VarI_BDT.weights.xml
  TString readerName2 = "BDT method";
  double diff, maxdiff = 0., sumdiff=0., previousVal=0.;
  int stuckCount=0, nevt= TMath::Min((int) testTree->GetEntries(),100);
  const float effS=0.301;

  TMVA::Reader* reader2=0;
  std::vector< TMVA::Reader* > reader(nTest);
  for (int iTest=0;iTest<nTest;iTest++){
     //std::cout << "iTest="<<iTest<<std::endl;
     if (iTest==0){
        reader[iTest] = new TMVA::Reader( readerOption );
        for (UInt_t i=0;i<_VariableNames->size();i++)
           reader[iTest]->AddVariable( _VariableNames->at(i),&testvar[i]);
        reader[iTest] ->BookMVA( readerName, weightfile) ;
     }
     else if (iTest==1 || iTest ==2) {
        reader[iTest] = new TMVA::Reader( *_VariableNames, readerOption );
        reader[iTest] ->BookMVA( readerName, weightfile) ;
     }
     else if (iTest==3) { // multiple reader
        reader[iTest] = new TMVA::Reader( *_VariableNames, readerOption );
        reader2 = new TMVA::Reader( variableNames2, readerOption );
        reader[iTest]->BookMVA( readerName, weightfile) ;
        reader2->BookMVA( readerName2, weightfile2) ;
     }
     else if (iTest==4) { // multiple reader
        reader[iTest] = new TMVA::Reader( readerOption );
        for (UInt_t i=0;i<_VariableNames->size();i++)
           reader[iTest]->AddVariable( _VariableNames->at(i),&testvar[i]);
        reader[iTest] ->BookMVA( readerName, weightfile) ;
        reader2 = new TMVA::Reader( readerOption );
        for (UInt_t j=0;j<variableNames2.size();j++) reader2->AddVariable( variableNames2.at(j),&dummy[j]);
        reader2->BookMVA( readerName2, weightfile2) ;
     }
     else if (iTest==5) { // multiple reader
        reader2 = new TMVA::Reader( readerOption );
        for (UInt_t j=0;j<variableNames2.size();j++) reader2->AddVariable( variableNames2.at(j),&dummy[j]);
        reader[iTest] = new TMVA::Reader( readerOption );
        for (UInt_t i=0;i<_VariableNames->size();i++)
           reader[iTest]->AddVariable( _VariableNames->at(i),&testvar[i]);
        reader[iTest] ->BookMVA( readerName, weightfile) ;
        reader2->BookMVA( readerName2, weightfile2) ;
     }
     else {
        std::cout <<"error, itest not known"<<std::endl;
        std::exit(1);
     }


     // run the reader application and compare to test tree
     for (Long64_t ievt=0;ievt<nevt;ievt++) {
        testTree->GetEntry(ievt);
        if (testTree2) testTree2->GetEntry(ievt);

        for (UInt_t i=0;i<_VariableNames->size();i++){
           testvarDouble[i]= testvar[i];
           testvarFloat[i]= testvar[i];
        }

        if (iTest==0){
           if (_methodType==Types::kCuts)
              readerVal = reader[iTest]->EvaluateMVA( readerName, effS );
           else readerVal=reader[iTest]->EvaluateMVA( readerName);
        }
        else if (iTest==1){
           if (_methodType==Types::kCuts)
              readerVal = reader[iTest]->EvaluateMVA( testvarFloat, readerName, effS );
           else readerVal=reader[iTest]->EvaluateMVA( testvarFloat, readerName);
        }
        else if (iTest==2){
           if (_methodType==Types::kCuts)
              readerVal = reader[iTest]->EvaluateMVA( testvarDouble, readerName, effS );
           else readerVal=reader[iTest]->EvaluateMVA( testvarDouble, readerName);
        }
        else if (iTest==3 ){
           double dummy3 = reader2->EvaluateMVA( testvarDouble, readerName2);
           if (_methodType==Types::kCuts)
              readerVal = reader[iTest]->EvaluateMVA( testvarDouble, readerName, effS );
           else readerVal=reader[iTest]->EvaluateMVA( testvarDouble, readerName);
           dummy3 += reader2->EvaluateMVA( testvarDouble, readerName2);
        }
        else if (iTest==4){
           double dummy4 = reader2->EvaluateMVA( testvarDouble, readerName);
           if (_methodType==Types::kCuts)
              readerVal = reader[iTest]->EvaluateMVA( testvarDouble, readerName, effS );
           else readerVal=reader[iTest]->EvaluateMVA( testvarDouble, readerName);
           dummy4 += reader2->EvaluateMVA( testvarDouble, readerName);
        }
        else if (iTest==5){
           double dummy5 = reader2->EvaluateMVA( readerName2);
           if (_methodType==Types::kCuts)
              readerVal = reader[iTest]->EvaluateMVA( readerName, effS );
           else readerVal=reader[iTest]->EvaluateMVA( readerName);
           dummy5 += reader2->EvaluateMVA( readerName2);
        }
        else {
           std::cout << "ERROR, undefined iTest value "<<iTest<<endl;
           exit(1);
        }
        if (_methodType!=Types::kCuts){
           diff = TMath::Abs(readerVal-testTreeVal);
           maxdiff = diff > maxdiff ? diff : maxdiff;
           sumdiff += diff;
        }
        if (ievt>0 && iTest ==0 && TMath::Abs(readerVal-previousVal)<1.e-6) stuckCount++;
        if (iTest ==0 ) previousVal=readerVal;
     }

  }
  Bool_t ok=false;
  sumdiff=sumdiff/nevt;
  if (_methodType!=Types::kCuts){
     test_(maxdiff <1.e-4);
     test_(sumdiff <1.e-5);
     test_(stuckCount<nevt/10);
     if (maxdiff <1.e-4 && sumdiff <1.e-5 && stuckCount<nevt/10) ok=true;
  }
  if (_methodType==Types::kCuts){
     test_(stuckCount<nevt-20);
     test_(sumdiff <0.005);
     if (stuckCount<nevt-20 && sumdiff <0.005) ok=true;
  }
  testFile->Close();

  for (int i=0;i<nTest;i++) delete reader[i];
  if (reader2) delete reader2;

  if (!ok){
     cout << "Failure in reader test "<< _methodTitle <<": maxdiff="<<maxdiff<<", sumdiff="<<sumdiff<<" stuckcount="<<stuckCount<<endl;
  }
#ifdef COUTDEBUG
  if (ok){
     cout << "end of reader test maxdiff="<<maxdiff<<", sumdiff="<<sumdiff<<" stuckcount="<<stuckCount<<endl;
  }
#endif

  bool _DoTestCCode=true;

  // use: grep -A5  'MakeClassSpecific' ../tmva/src/Method*.cxx

  if (_methodType==Types::kCuts  // non-implemented makeclass methods BayesClassifier CFMlpANN Committee Cuts KNN PDERS RuleFit SVM
      || _methodType==Types::kBayesClassifier
      || _methodType==Types::kCFMlpANN
      || _methodType==Types::kCuts
      || _methodType==Types::kKNN
      || _methodType==Types::kPDERS
      || _methodType==Types::kRuleFit
      || _methodType==Types::kPDEFoam
      || _methodTitle == "BoostedFisher"
      ) _DoTestCCode=false;

#ifndef FULL
  _DoTestCCode=false;
#endif

  if (_DoTestCCode){
#ifdef COUTDEBUG
     cout << "starting standalone c-code test"<<endl;
#endif
     // create generic macro
     TString macroName=Form("testmakeclass_%s",_methodTitle.Data());
     TString macroFileName=TString("weights/")+macroName+TString(".C");
     TString methodTypeName = Types::Instance().GetMethodName(_methodType);
     FileStat_t stat2;
     if(!gSystem->GetPathInfo(macroFileName.Data(),stat2)) {
        gSystem->Unlink(macroFileName.Data());
        //gSystem->Exec(Form("rm %s",macroFileName.Data()));
     }
     ofstream fout( macroFileName );
     fout << "// generic macro file to test TMVA reader and standalone C code " << std::endl;
     fout << "#include \"TFile.h\""<<std::endl;
     fout << "#include \"TTree.h\""<<std::endl;
     fout << "#include <vector>"<<std::endl;
     fout << Form("#include \"weights/TMVAUnitTesting_%s.class.C\"",_methodTitle.Data()) << std::endl;
     fout << Form("bool %s(){",macroName.Data()) << std::endl;
     fout << "std::vector<std::string> vars(4);" << std::endl; // fix me 4
     fout << "std::vector<double> val(4);" << std::endl;  // fix me 4
     fout << "bool ok=true;" << std::endl;  // fix me 4
     for (UInt_t i=0;i<_VariableNames->size();i++)
        fout << Form("vars[%d]=\"%s\";",i,_VariableNames->at(i).Data()) << std::endl;
     fout << Form("Read%s  aa(vars);", _methodTitle.Data()) << std::endl;
     fout << "TFile* testFile = new TFile(\"weights/TMVA.root\");" << std::endl; // fix me hardcode TMVA.root
     fout << " TTree* testTree = (TTree*)(testFile->Get(\"TestTree\"));" << std::endl;
     fout << Form("vector<float> testvar(%d);",(Int_t) _VariableNames->size()) << std::endl;
     fout << Form("vector<double> testvarDouble(%d);", (Int_t) _VariableNames->size()) << std::endl;
     for (UInt_t j=0;j<_VariableNames->size();j++)
        fout << Form("testTree->SetBranchAddress(\"%s\",&testvar[%d]);",_TreeVariableNames->at(j).Data(),j) << std::endl;
     fout << "float testTreeVal,diff,nrm,maxdiff=0.,sumdiff=0.;" << std::endl;
     fout << Form("testTree->SetBranchAddress(\"%s\",&testTreeVal);",_methodTitle.Data()) << std::endl;
     fout << "Long64_t nevt= TMath::Min((int) testTree->GetEntries(),100);" << std::endl;
     fout << "  for (Long64_t ievt=0; ievt<nevt;ievt++) {" << std::endl;
     fout << "    testTree->GetEntry(ievt);" << std::endl;
     fout << Form("for (UInt_t i=0;i<%d;i++) testvarDouble[i]= testvar[i];",(Int_t) _VariableNames->size()) << std::endl;
     fout << "double ccode_val = aa.GetMvaValue(testvarDouble);" << std::endl;

     fout << "diff = TMath::Abs(ccode_val-testTreeVal);" << std::endl;
     fout << "nrm = TMath::Max(TMath::Abs(ccode_val),1.);" << std::endl;
     fout << "diff = diff/nrm;" << std::endl;
     fout << "if (diff>1.2) std::cout << \"ccode_val=\" << ccode_val <<\"testval=\" << testTreeVal <<std::endl;"<<std::endl;
     fout << "maxdiff = diff > maxdiff ? diff : maxdiff;" << std::endl;
     fout << "sumdiff += diff;" << std::endl;
     fout << "}" << std::endl;
     fout << "sumdiff=sumdiff/testTree->GetEntries();" << std::endl;
     fout << "if (maxdiff >1.e-2) std::cout << \"maxdiff=\"<<maxdiff<< \", sumdiff=\"<<sumdiff<<std::endl;" << std::endl;
     fout << "if (sumdiff >2.e-4) ok=false;" << std::endl;
     fout << "testFile->Close();" << std::endl;
     fout << "if (!ok) {" << std::endl;
     fout << "std::cout << \"maxdiff=\"<<maxdiff<< \", sumdiff=\"<<sumdiff<<std::endl;}" << std::endl;
     fout << "return ok;" << std::endl;
     fout << "}" << std::endl;

     gROOT->ProcessLine(Form(".L %s+",macroFileName.Data()));
     test_(gROOT->ProcessLine(Form("%s()",macroName.Data())));
  }

}
// including file tmvaut/RegressionUnitTestWithDeviation.h
#ifndef REGRESSIONUNITTESTWITHDEVIATION_H
#define REGRESSIONUNITTESTWITHDEVIATION_H

// Author: Christoph Rosemann  Oct 2010
// TMVA unit tests
//
// this class acts as interface to create, train and evaluate the method
// specified in the constructor
// additionally the regression performance is evaluated

#include <string>
#include <iostream>
#include <cassert>

#include "TTree.h"
#include "TString.h"

#include "TMVA/Factory.h"
#include "TMVA/MethodBase.h"
#include "TMVA/Types.h"



namespace UnitTesting
{
  class RegressionUnitTestWithDeviation : public UnitTest
  {
  public:
    RegressionUnitTestWithDeviation(const TMVA::Types::EMVA& theMethod, const TString& methodTitle, const TString& theOption,
                                    double lowFullLimit = 0., double upFullLimit = 10., double low90PercentLimit = 0., double up90PercentLimit = 0.,
                                    const std::string & name="", const std::string & filename="", std::ostream* osptr = &std::cout);
    virtual ~RegressionUnitTestWithDeviation();

    virtual void run();

  protected:
    TTree*          theTree;

  private:
    TMVA::Factory* _factory;
    TMVA::MethodBase* _theMethod;
    TMVA::Types::EMVA _methodType;
    TString _methodTitle;
    TString _methodOption;

    double _lowerFullDeviationLimit;
    double _upperFullDeviationLimit;
    double _lower90PercentDeviationLimit;
    double _upper90PercentDeviationLimit;

    double _theFullDeviation;
    double _the90PercentDeviation;

    bool DeviationWithinLimits();

    // disallow copy constructor and assignment
    RegressionUnitTestWithDeviation(const RegressionUnitTestWithDeviation&);
    RegressionUnitTestWithDeviation& operator=(const RegressionUnitTestWithDeviation&);
  };
} // namespace UnitTesting
#endif // REGRESSIONUNITTESTWITHDEVIATION_H
// including file tmvaut/RegressionUnitTestWithDeviation.cxx

#include "TFile.h"
#include "TSystem.h"
#include "TMVA/MethodBase.h"
#include "TMVA/Reader.h"
#include <cstdlib>

using namespace std;
using namespace UnitTesting;
using namespace TMVA;

RegressionUnitTestWithDeviation::RegressionUnitTestWithDeviation(
   const Types::EMVA &theMethod, const TString &methodTitle, const TString &theOption, double lowFullLimit,
   double upFullLimit, double low90PercentLimit, double up90PercentLimit, const std::string & /* xname */,
   const std::string & /* filename */, std::ostream * /* sptr */)
   : UnitTest(string("Regression_") + string(methodTitle.Data()), __FILE__), _methodType(theMethod),
     _methodTitle(methodTitle), _methodOption(theOption), _lowerFullDeviationLimit(lowFullLimit),
     _upperFullDeviationLimit(upFullLimit), _lower90PercentDeviationLimit(low90PercentLimit),
     _upper90PercentDeviationLimit(up90PercentLimit)
{
}


RegressionUnitTestWithDeviation::~RegressionUnitTestWithDeviation()
{
}

bool RegressionUnitTestWithDeviation::DeviationWithinLimits()
{
   return (_the90PercentDeviation<= _upper90PercentDeviationLimit) && (_the90PercentDeviation >= _lower90PercentDeviationLimit) && (_theFullDeviation <= _upperFullDeviationLimit) && (_theFullDeviation>= _lowerFullDeviationLimit);
}

void RegressionUnitTestWithDeviation::run()
{
   // FIXME:: create _this_ file or rather somewhere else?
   TString outfileName( "weights/TMVARegUT.root" );
   TFile* outputFile = TFile::Open( outfileName, "RECREATE" );

   // FIXME:: if file can't be created do something more?
   if(!outputFile)
      return;

   // FIXME:: make the factory option mutable?
   // absolute silence options:
   string factoryOptions( "!V:Silent:Transformations=I;D;P;G,D:AnalysisType=Regression:!Color:!DrawProgressBar" );

   Factory* factory = new Factory( "TMVARegressionUnitTesting", outputFile, factoryOptions );
   DataLoader * dataloader = new DataLoader("dataset"); 

   dataloader->AddVariable( "var1", "Variable 1", "units", 'F' ); // fix me
   dataloader->AddVariable( "var2", "Variable 2", "units", 'F' ); // fix me
   TString _targetname="fvalue";
   dataloader->AddTarget  ( _targetname.Data() ); // fix me _targetname.Data()

   TFile* input(0);
   FileStat_t stat;

   TString fname = "./tmva_reg_example.root";
   if(!gSystem->GetPathInfo(fname,stat)) {
      input = TFile::Open( fname );
   } else {
      TFile::SetCacheFileDir(".");
      input = TFile::Open("http://root.cern.ch/files/tmva_reg_example.root", "CACHEREAD");
   }
   if (input == NULL) {
      cerr << "broken/inaccessible input file" << endl;
   }

   TTree *regTree = (TTree*)input->Get("TreeR");

   Double_t regWeight  = 1.0;
   dataloader->AddRegressionTree( regTree, regWeight );
   dataloader->SetWeightExpression( "var1", "Regression" );
   TCut mycut = ""; // for example: TCut mycut = "abs(var1)<0.5 && abs(var2-0.5)<1";

   dataloader->PrepareTrainingAndTestTree( mycut, "nTrain_Regression=500:nTest_Regression=500:SplitMode=Random:NormMode=NumEvents:!V" );

   factory->BookMethod(dataloader, _methodType, _methodTitle, _methodOption);

   factory->TrainAllMethods();
   factory->TestAllMethods();
   factory->EvaluateAllMethods();

   _theMethod = dynamic_cast<TMVA::MethodBase*> (factory->GetMethod(dataloader->GetName(), _methodTitle));

   _theMethod->GetRegressionDeviation(0,TMVA::Types::kTesting, _theFullDeviation,_the90PercentDeviation);
   if (DeviationWithinLimits()){
#ifdef COUTDEBUG
   cout << "deviation, dev90= " << _theFullDeviation << ", " <<  _the90PercentDeviation << endl;
   cout << "Full limits " << _lowerFullDeviationLimit      << " "
        << _upperFullDeviationLimit
        << ", 90% limits "  << _lower90PercentDeviationLimit << " "
        << _upper90PercentDeviationLimit << endl;
#endif
   }
   else {
      cout << "Failure "<<_methodTitle<<", deviation, dev90= " << _theFullDeviation << ", " <<  _the90PercentDeviation << endl;
   cout << "Full limits " << _lowerFullDeviationLimit      << " "
        << _upperFullDeviationLimit
        << ", 90% limits "  << _lower90PercentDeviationLimit << " "
        << _upper90PercentDeviationLimit << endl;
   }
   test_(DeviationWithinLimits());

   outputFile->Close();
   delete dataloader; 
   delete factory;

   // reader tests

   // setup test tree access
   TFile* testFile = new TFile("weights/TMVARegUT.root"); // fix me hardcoded file name
   TTree* testTree = (TTree*)(testFile->GetDirectory("dataset")->Get("TestTree"));
   const int nTest=3; // 3 reader usages
   float testTarget,readerVal=0.;

   vector<TString>* _VariableNames = new std::vector<TString>(0); // fix me, move to constructor
   _VariableNames->push_back("var1");
   _VariableNames->push_back("var2");

   vector<float>  testvar(_VariableNames->size());
   vector<float>  dummy(_VariableNames->size());
   vector<float>  dummy2(_VariableNames->size());
   vector<float>  testvarFloat(_VariableNames->size());
   vector<double> testvarDouble(_VariableNames->size());
   for (UInt_t i=0;i<_VariableNames->size();i++)
      testTree->SetBranchAddress(_VariableNames->at(i),&testvar[i]);
   testTree->SetBranchAddress(_methodTitle.Data(),&testTarget);

   TString readerName = _methodTitle + TString(" method");
   TString dir    = "dataset/weights/TMVARegressionUnitTesting_";
   TString weightfile=dir+_methodTitle+".weights.xml";
   double diff, maxdiff = 0., sumdiff=0., previousVal=0.;
   int stuckCount=0, nevt= TMath::Min((int) testTree->GetEntries(),50);

   std::vector< TMVA::Reader* > reader(nTest);
   for (int iTest=0;iTest<nTest;iTest++){
      //std::cout << "iTest="<<iTest<<std::endl;
      reader[iTest] = new TMVA::Reader( "!Color:Silent" );
      for (UInt_t i=0;i<_VariableNames->size();i++)
         reader[iTest]->AddVariable( _VariableNames->at(i),&testvar[i]);

      reader[iTest] ->BookMVA( readerName, weightfile) ;

      // run the reader application and compare to test tree
      for (Long64_t ievt=0;ievt<nevt;ievt++) {
         testTree->GetEntry(ievt);
         for (UInt_t i=0;i<_VariableNames->size();i++){
            testvarDouble[i]= testvar[i];
            testvarFloat[i]= testvar[i];
         }

         if (iTest==0){ readerVal=(reader[iTest]->EvaluateRegression( readerName))[0];}
         else if (iTest==1){ readerVal=(reader[iTest]->EvaluateRegression( readerName)).at(0);}
         else if (iTest==2){ readerVal=reader[iTest]->EvaluateRegression( 0, readerName);}
         else {
            std::cout << "ERROR, undefined iTest value "<<iTest<<endl;
            exit(1);
         }

         diff = TMath::Abs(readerVal-testTarget);
         maxdiff = diff > maxdiff ? diff : maxdiff;
         sumdiff += diff;
         if (ievt>0 && iTest ==0 && TMath::Abs(readerVal-previousVal)<1.e-6) stuckCount++;
         //if (ievt<3) std::cout << "i="<<iTest<<", readerVal="<<readerVal<<" testTarget"<<testTarget<<" diff="<<diff<<std::endl;

         if (iTest ==0 ) previousVal=readerVal;
      }

   }

   sumdiff=sumdiff/nevt;

   test_(maxdiff <1.e-4);
   test_(sumdiff <1.e-5);
   test_(stuckCount<nevt/10);

   testFile->Close();

   for (int i=0;i<nTest;i++) delete reader[i];

#ifdef COUTDEBUG
   cout << "end of reader test maxdiff="<<maxdiff<<", sumdiff="<<sumdiff<<" stuckcount="<<stuckCount<<endl;
#endif
}
// including file tmvaut/MethodUnitTestWithComplexData.h
#ifndef METHODUNITTESTCOMPLEXDATA_H
#define METHODUNITTESTCOMPLEXDATA_H

// Author: Eckhard von Toerne, uses Christoph Rosemann's MethodUnitTest as example  Nov 2010
// TMVA unit tests
//
// this class acts as interface to create, train and evaluate the method
// specified in the constructor
// as additional argument the limits of the ROC integral can be given
// to determine the performance

#include <string>
#include <iostream>
#include <cassert>

#include "TTree.h"
#include "TString.h"

#include "TMVA/Factory.h"
#include "TMVA/MethodBase.h"
#include "TMVA/Types.h"



namespace UnitTesting
{
   class MethodUnitTestWithComplexData : public UnitTest
   {
   public:
      MethodUnitTestWithComplexData(const TString& treestring, const TString& preparestring,
                                    const TMVA::Types::EMVA& theMethod, const TString& methodTitle, const TString& theOption,
                                    double lowLimit = 0., double upLimit = 1.,
                                    const std::string & name="", const std::string & filename="", std::ostream* osptr = &std::cout);
      virtual ~MethodUnitTestWithComplexData();

      virtual void run();

   protected:
      TTree*  theTree;

   private:
      TMVA::Factory* _factory;
      TMVA::MethodBase* _theMethod;
      TMVA::Types::EMVA _methodType;
      TString _treeString;
      TString _prepareString;
      TString _methodTitle;
      TString _methodOption;

      double _upROCLimit;
      double _lowROCLimit;
      double _ROCValue;

      bool ROCIntegralWithinInterval();
      bool create_data(const char* filename, int nmax=20000);
      // disallow copy constructor and assignment
      MethodUnitTestWithComplexData(const MethodUnitTestWithComplexData&);
      MethodUnitTestWithComplexData& operator=(const MethodUnitTestWithComplexData&);
   };
} // namespace UnitTesting
#endif // METHODUNITTESTCOMPLEXDATA_H
// including file tmvaut/MethodUnitTestWithComplexData.cxx

#include "TFile.h"
#include "TMVA/MethodBase.h"

using namespace std;
using namespace UnitTesting;
using namespace TMVA;

MethodUnitTestWithComplexData::MethodUnitTestWithComplexData(const TString &treestring, const TString &preparestring,
                                                             const Types::EMVA &theMethod, const TString &methodTitle,
                                                             const TString &theOption, double lowLimit, double upLimit,
                                                             const std::string & /* xname */,
                                                             const std::string & /* filename */,
                                                             std::ostream * /* sptr */)
   : UnitTest(string("ComplexData_") + string(methodTitle.Data()) + string(treestring.Data()), __FILE__),
     _methodType(theMethod), _treeString(treestring), _prepareString(preparestring), _methodTitle(methodTitle),
     _methodOption(theOption), _upROCLimit(upLimit), _lowROCLimit(lowLimit)
{
    theTree = nullptr;
    _theMethod = nullptr;
    _factory = nullptr;
    _ROCValue = 0.;
}


MethodUnitTestWithComplexData::~MethodUnitTestWithComplexData()
{
}

bool MethodUnitTestWithComplexData::ROCIntegralWithinInterval()
{
   return (_ROCValue <= _upROCLimit) && (_ROCValue >= _lowROCLimit);
}

void MethodUnitTestWithComplexData::run()
{
  // FIXME:: create _this_ file or rather somewhere else?
  TString outfileName( "weights/TMVA.root" );
  TFile* outputFile = TFile::Open( outfileName, "RECREATE" );

// FIXME:: if file can't be created do something more?
  if(!outputFile)
    return;

// FIXME:: make the factory option mutable?
// absolute silence options:
  string factoryOptions( "!V:Silent:Transformations=I;D;P;G,D:AnalysisType=Classification:!Color:!DrawProgressBar" );

  Factory* factory = new Factory( "TMVAUnitTesting", outputFile, factoryOptions );
  DataLoader * dataloader = new DataLoader("dataset"); 

  dataloader->AddVariable( "var0",  "Variable 0", 'F' );
  dataloader->AddVariable( "var1",  "Variable 1", 'F' );
  dataloader->AddVariable( "var2",  "Variable 2", 'F' );
  dataloader->AddVariable( "var3",  "Variable 3", 'F' );
  dataloader->AddSpectator( "is1", 'I' );
  dataloader->AddSpectator( "evtno", 'I' );

  TFile* input(0);
// FIXME:: give the filename of the sample somewhere else?
  TString fname = "weights/tmva_complex_data.root";
  input = TFile::Open( fname );
  if (input == NULL) create_data("weights/tmva_complex_data.root");
  input = TFile::Open( fname );
  if (input == NULL)
    {
      cerr << "broken/inaccessible input file" << endl;
    }

  TTree *sig1     = (TTree*)input->Get("TreeS1");
  TTree *sig2     = (TTree*)input->Get("TreeS2");
  TTree *sigfull  = (TTree*)input->Get("TreeSFull");
  TTree *bgd1     = (TTree*)input->Get("TreeB1");
  TTree *bgd2     = (TTree*)input->Get("TreeB2");
  TTree *bgdfull  = (TTree*)input->Get("TreeBFull");

  if (_treeString.Contains("sig1"))    dataloader->AddSignalTree(sig1);
  if (_treeString.Contains("sig2"))    dataloader->AddSignalTree(sig2);
  if (_treeString.Contains("sigfull")) dataloader->AddSignalTree(sigfull);
  if (_treeString.Contains("bgd1"))    dataloader->AddBackgroundTree(bgd1);
  if (_treeString.Contains("bgd2"))    dataloader->AddBackgroundTree(bgd2);
  if (_treeString.Contains("bgdfull")) dataloader->AddBackgroundTree(bgdfull);

  dataloader->SetSignalWeightExpression("weight");
  dataloader->SetBackgroundWeightExpression("weight");

  TCut mycuts = "";
  TCut mycutb = "";
  if (_prepareString=="") _prepareString = "nTrain_Signal=200:nTrain_Background=200:SplitMode=Random:NormMode=NumEvents:!V" ;
  dataloader->PrepareTrainingAndTestTree( mycuts, mycutb, _prepareString);

  factory->BookMethod(dataloader, _methodType, _methodTitle, _methodOption);

  factory->TrainAllMethods();
  factory->TestAllMethods();
  factory->EvaluateAllMethods();

  _theMethod = dynamic_cast<TMVA::MethodBase*> (factory->GetMethod(dataloader->GetName(), _methodTitle));

  if (_methodType == TMVA::Types::kCuts) {
     // ToDo make class variable _theEffi
     Double_t err=0.;
     Double_t effi = _theMethod->GetEfficiency("Efficiency:0.1", Types::kTesting,err);
#ifdef COUTDEBUG
     std::cout << "Cuts Signal effi at for Background effi of 0.1 = " << effi<<" low limit="<<_lowROCLimit<<" high limit="<<_upROCLimit<<std::endl;
#endif
     test_(effi <= _upROCLimit && effi>=_lowROCLimit);
  }
  else {
     _ROCValue = _theMethod->GetROCIntegral();
#ifdef COUTDEBUG
     std::cout << "ROC integral = "<<_ROCValue <<" low limit="<<_lowROCLimit<<" high limit="<<_upROCLimit<<std::endl;
#endif
     test_(ROCIntegralWithinInterval());
  }
  outputFile->Close();
  delete dataloader; 
  delete factory;
}

bool MethodUnitTestWithComplexData::create_data(const char* filename, int nmax)
{
   TFile* dataFile = TFile::Open(filename,"RECREATE");
   int nvar = 4;
   int nsig = 0, nbgd=0;
   Float_t weight=1;
   Float_t xvar[100];
   int is1,evtno=0;
   // create signal and background trees
   TTree* treeS1 = new TTree( "TreeS1", "TreeS1", 1 );
   TTree* treeB1 = new TTree( "TreeB1", "TreeB1", 1 );
   TTree* treeS2 = new TTree( "TreeS2", "TreeS2", 1 );
   TTree* treeB2 = new TTree( "TreeB2", "TreeB2", 1 );
   TTree* treeSFull = new TTree( "TreeSFull", "TreeSFull", 1 );
   TTree* treeBFull = new TTree( "TreeBFull", "TreeBFull", 1 );
   for (Int_t ivar=0; ivar<nvar; ivar++) {
      treeS1->Branch( TString(Form( "var%i", ivar )).Data(), &xvar[ivar], TString(Form( "var%i/F", ivar)).Data() );
      treeB1->Branch( TString(Form( "var%i", ivar )).Data(), &xvar[ivar], TString(Form( "var%i/F", ivar)).Data() );
      treeS2->Branch( TString(Form( "var%i", ivar )).Data(), &xvar[ivar], TString(Form( "var%i/F", ivar)).Data() );
      treeB2->Branch( TString(Form( "var%i", ivar )).Data(), &xvar[ivar], TString(Form( "var%i/F", ivar)).Data() );
      treeBFull->Branch( TString(Form( "var%i", ivar )).Data(), &xvar[ivar], TString(Form( "var%i/F", ivar)).Data() );
      treeSFull->Branch( TString(Form( "var%i", ivar )).Data(), &xvar[ivar], TString(Form( "var%i/F", ivar)).Data() );
   }
   treeS1->Branch("weight", &weight, "weight/F");
   treeB1->Branch("weight", &weight, "weight/F");
   treeS2->Branch("weight", &weight, "weight/F");
   treeB2->Branch("weight", &weight, "weight/F");
   treeSFull->Branch("weight", &weight, "weight/F");
   treeBFull->Branch("weight", &weight, "weight/F");

   treeS1->Branch("is1", &is1, "is1/I");
   treeB1->Branch("is1", &is1, "is1/I");
   treeS2->Branch("is1", &is1, "is1/I");
   treeB2->Branch("is1", &is1, "is1/I");
   treeSFull->Branch("is1", &is1, "is1/I");
   treeBFull->Branch("is1", &is1, "is1/I");

   treeS1->Branch("evtno", &evtno, "evtno/I");
   treeB1->Branch("evtno", &evtno, "evtno/I");
   treeS2->Branch("evtno", &evtno, "evtno/I");
   treeB2->Branch("evtno", &evtno, "evtno/I");
   treeSFull->Branch("evtno", &evtno, "evtno/I");
   treeBFull->Branch("evtno", &evtno, "evtno/I");

   TRandom R( 100 );
   do {
      for (Int_t ivar=0; ivar<nvar-1; ivar++) { xvar[ivar]=2.*R.Rndm()-1.;}
      Float_t xout = xvar[0]+xvar[1]+xvar[2]*xvar[1]-xvar[0]*xvar[1]*xvar[1];
      xvar[3] = xout + 4. *R.Rndm()-2.;
      bool is = (TMath::Abs(xout)<0.3);
      if (is) is1=1; else is1=0;
      bool isSignal;
      if (is) isSignal = (R.Rndm()<0.5);
      else isSignal =  (xout>0);
      //if (nsig<10) cout << "xout = " << xout<< (isSignal? " signal": " bbg")  << endl;
      if (isSignal) {
         treeSFull->Fill();
         if (is) treeS1->Fill();
         else treeS2->Fill();
         nsig++;
         evtno++;
      }
      else {
         treeBFull->Fill();
         if (is) treeB1->Fill();
         else treeB2->Fill();
         nbgd++;
         evtno++;
      }
   } while ( nsig < nmax || nbgd < nmax);

   dataFile->Write();
   dataFile->Close();
   return true;
}



//Author: Attila Bagoly <battila93@gmail.com>

#ifndef UTIPythonInteractive_H
#define UTIPythonInteractive_H

#include <vector>
#include "TMVA/MethodBase.h"

/**
Unit test for TMVA::IPythonInteractive located in TMVA/MethodBase.h
*/
class utIPythonInteractive : public UnitTesting::UnitTest{
public:
  utIPythonInteractive();
  void run();
private:
  void testInit();
  void testMethods();
  
  TMVA::IPythonInteractive * ipyi;
  std::vector<TString> titles;
  std::vector<Double_t> xvec;
  std::vector<Double_t> y1vec, y2vec;
  int N;
};

#endif


#include <random>
#include "TGraph.h"
#include "TMultiGraph.h"

///////////////////////////////////////////////////////////////////////////////////////////////////
///// Standard constructor
utIPythonInteractive::utIPythonInteractive() : UnitTesting::UnitTest("IPythonInteractive", __FILE__)
{
  ipyi = nullptr;
  N = 1000;
  titles.push_back("Training Error");
  titles.push_back("Testing Error");
  std::uniform_real_distribution<double> unif(0, 1);
  std::default_random_engine re;
  for(int i=0;i<N;i++){
    xvec.push_back(i);
    y1vec.push_back(unif(re));
    y2vec.push_back(unif(re));
  }
  
}

///////////////////////////////////////////////////////////////////////////////////////////////////
///// Run tests
void utIPythonInteractive::run()
{
  testInit();
  testMethods();
}

///////////////////////////////////////////////////////////////////////////////////////////////////
///// Testing creating IPythonInteractive object and initialization.
void utIPythonInteractive::testInit()
{
  ipyi = new TMVA::IPythonInteractive();
  test_(ipyi->Get() != NULL);
  
  ipyi->Init(titles);
  test_(!ipyi->NotInitialized());
}

///////////////////////////////////////////////////////////////////////////////////////////////////
///// Adding datas to IPythonInteractive and testing if it got all of them correctly.
void utIPythonInteractive::testMethods()
{
  for(int i=0;i<N;i++){
    ipyi->AddPoint(xvec[i], y1vec[i], y2vec[i]);
    TList * graphs = ipyi->Get()->GetListOfFunctions();
    TIter next(graphs);
    int j=0;
  	TObject *obj;
    while ((obj = (TObject*)next())){
      TGraph * gr = dynamic_cast<TGraph*>(obj);
      test_(gr!=nullptr);
      if (gr==nullptr) continue;
      test_(gr->GetN()==(i+1));
      Double_t x, y;
      test_(gr->GetPoint(i, x, y)!=-1);
      test_(x==xvec[i]);
      test_(j==0 ? y==y1vec[i] : y==y2vec[i]);
      j++;
	  }
  }
}



// including file stressTMVA.cxx
// Authors: Christoph Rosemann, Eckhard von Toerne   July 2010
// TMVA unit tests

#include "Riostream.h"
#include "TSystem.h"
#include "TROOT.h"
#include "TBenchmark.h"
#include "TApplication.h"











#include "TMVA/Types.h"

using namespace UnitTesting;
using namespace std;

void addClassificationTests( UnitTestSuite& TMVA_test, bool full=true)
{
   TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kCuts, "CutsGA",
                                                      "H:!V:FitMethod=GA:CutRangeMin[0]=-10:CutRangeMax[0]=10:VarProp[1]=FMax:EffSel:Steps=20:Cycles=4:PopSize=300:SC_steps=10:SC_rate=5:SC_factor=0.95" , 0.4, 0.98) );

   if (full){
      TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kCuts, "Cuts",
                                                         "!H:!V:FitMethod=MC:EffSel:SampleSize=20000:VarProp=FSmart", 0.4, 0.98) );
      TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kCuts, "CutsD",
                                                         "!H:!V:FitMethod=MC:EffSel:SampleSize=20000:VarProp=FSmart:VarTransform=Decorrelate" , 0.6, 0.98) );
      TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kCuts, "CutsPCA", "!H:!V:FitMethod=MC:EffSel:SampleSize=20000:VarProp=FSmart:VarTransform=PCA" , 0.4, 0.98) );
      TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kCuts, "CutsSA",
                                                         "!H:!V:FitMethod=SA:EffSel:MaxCalls=15000:KernelTemp=IncAdaptive:InitialTemp=1e+6:MinTemp=1e-6:Eps=1e-10:UseDefaultScale" , 0.4, 0.98) );
      TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kLikelihood, "Likelihood",
                                                         "H:!V:TransformOutput:PDFInterpol=Spline2:NSmoothSig[0]=20:NSmoothBkg[0]=20:NSmoothBkg[1]=10:NSmooth=1:NAvEvtPerBin=50" , 0.7, 0.98) );
   }
   TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kLikelihood, "LikelihoodD",
                                                      "!H:!V:!TransformOutput:PDFInterpol=Spline2:NSmoothSig[0]=20:NSmoothBkg[0]=20:NSmooth=5:NAvEvtPerBin=50:VarTransform=Decorrelate" , 0.88, 0.98) );
   if (full){
      TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kLikelihood, "LikelihoodPCA",
                                                         "!H:!V:!TransformOutput:PDFInterpol=Spline2:NSmoothSig[0]=20:NSmoothBkg[0]=20:NSmooth=5:NAvEvtPerBin=50:VarTransform=PCA" , 0.88, 0.98) );
      TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kLikelihood, "LikelihoodMIX",
                                                         "!H:!V:!TransformOutput:PDFInterpolSig[0]=KDE:PDFInterpolBkg[0]=KDE:PDFInterpolSig[1]=KDE:PDFInterpolBkg[1]=KDE:PDFInterpolSig[2]=Spline2:PDFInterpolBkg[2]=Spline2:PDFInterpolSig[3]=Spline2:PDFInterpolBkg[3]=Spline2:KDEtype=Gauss:KDEiter=Nonadaptive:KDEborder=None:NAvEvtPerBin=50" , 0.7, 0.98) );
   }
   TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kPDERS, "PDERS",
                                                      "!H:!V:NormTree=T:VolumeRangeMode=Adaptive:KernelEstimator=Gauss:GaussSigma=0.1:NEventsMin=100:NEventsMax=600" , 0.8, 0.98) );
   if (full) TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kPDERS, "PDERSkNN",
                                                                "!H:!V:VolumeRangeMode=kNN:KernelEstimator=Gauss:GaussSigma=0.3:NEventsMin=400:NEventsMax=600" , 0.8, 0.98) );
   if (full) TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kPDERS, "PDERSD",
                                                                "!H:!V:VolumeRangeMode=Adaptive:KernelEstimator=Gauss:GaussSigma=0.3:NEventsMin=100:NEventsMax=600:VarTransform=Decorrelate" , 0.88, 0.98) );
   if (full) TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kPDERS, "PDERSPCA",
                                                                "!H:!V:VolumeRangeMode=Adaptive:KernelEstimator=Gauss:GaussSigma=0.3:NEventsMin=100:NEventsMax=600:VarTransform=PCA" , 0.88, 0.98) );
   TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kPDEFoam, "PDEFoam",
                                                      "H:!V:SigBgSeparate=F:TailCut=0.001:VolFrac=0.0333:nActiveCells=500:nSampl=2000:nBin=5:Nmin=100:Kernel=None:Compress=T" , 0.8, 0.98) );
   TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kKNN, "KNN",
                                                      "H:nkNN=20:ScaleFrac=0.8:SigmaFact=1.0:Kernel=Gaus:UseKernel=F:UseWeight=T:!Trim" , 0.8, 0.98) );
   if (full) TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kHMatrix, "HMatrix", "!H:!V:VarTransform=G" , 0.88, 0.98) );
   TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kFisher, "Fisher",
                                                      "H:!V:Fisher:CreateMVAPdfs:PDFInterpolMVAPdf=Spline2:NbinsMVAPdf=60:NsmoothMVAPdf=10" , 0.88, 0.98) );
   if (full) TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kFisher, "FisherG", "H:!V:VarTransform=Gauss" , 0.88, 0.98) );
   TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kFisher, "BoostedFisher",
                                                      "H:!V:Boost_Num=10:Boost_Transform=log:Boost_Type=AdaBoost:Boost_AdaBoostBeta=0.2", 0.88, 0.98) );
   TMVA_test.addTest(new MethodUnitTestWithROCLimits(TMVA::Types::kLD, "LD","!H:!V", 0.88, 0.98) );
   if (full) TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kLD, "LD2", "H:!V:VarTransform=None" , 0.88, 0.98) );
   if (full) TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kLD, "LDN", "H:!V:VarTransform=N" , 0.88, 0.98) );

   TString baseFDAstring="!H:!V:Formula=(0)+(1)*x0+(2)*x1+(3)*x2+(4)*x3:ParRanges=(-1,1);(-10,10);(-10,10);(-10,10);(-10,10):";
   if (full) TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kFDA, "FDA_MC",
                                                                baseFDAstring+"FitMethod=MC:SampleSize=5000:Sigma=0.1" , 0.8, 0.98) );
   if (full) TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kFDA, "FDA_GA",
                                                                baseFDAstring+"FitMethod=GA:PopSize=100:Cycles=3:Steps=20:Trim=True:SaveBestGen=1" , 0.88, 0.98) );
   if (full) TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kFDA, "FDA_SA",
                                                                baseFDAstring+"FitMethod=SA:MaxCalls=5000:KernelTemp=IncAdaptive:InitialTemp=1e+6:MinTemp=1e-6:Eps=1e-10:UseDefaultScale" , 0.88, 0.98) );
   TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kMLP, "MLP", "H:!V:NeuronType=tanh:VarTransform=N:NCycles=200:HiddenLayers=N+5:TestRate=5:!UseRegulator" , 0.88, 0.98) );
   TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kMLP, "MLPBFGS", "H:!V:NeuronType=tanh:VarTransform=N:NCycles=200:HiddenLayers=N+5:TestRate=5:TrainingMethod=BFGS:!UseRegulator" , 0.88, 0.98) );
   if (full) TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kMLP, "MLPBNN", "H:!V:NeuronType=tanh:VarTransform=N:NCycles=200:HiddenLayers=N+5:TestRate=5:TrainingMethod=BFGS:UseRegulator" , 0.88, 0.98) ); // BFGS training with bayesian regulators
   if (full) TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kCFMlpANN, "CFMlpANN", "!H:!V:NCycles=200:HiddenLayers=N+1,N"  , 0.7, 0.98) ); // n_cycles:#nodes:#nodes:...
   if (full) TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kTMlpANN, "TMlpANN", "!H:!V:NCycles=200:HiddenLayers=N+1,N:LearningMethod=BFGS:ValidationFraction=0.3"  , 0.7, 0.98) ); // n_cycles:#nodes:#nodes:...
   TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kSVM, "SVM", "Gamma=0.25:Tol=0.001:VarTransform=Norm" , 0.88, 0.98) );
   TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kBDT, "BDTG",
                                                      "!H:!V:NTrees=400:BoostType=Grad:Shrinkage=0.10:UseBaggedBoost:GradBaggingFraction=0.6:SeparationType=GiniIndex:nCuts=20:MaxDepth=2" , 0.88, 0.98) );
   TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kBDT, "BDT",
                                                      "!H:!V:NTrees=400:nEventsMin=100:MaxDepth=3:BoostType=AdaBoost:SeparationType=GiniIndex:nCuts=10:PruneMethod=NoPruning" , 0.88, 0.98) );
   if (full) TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kBDT, "BDTB",
                                                                "!H:!V:NTrees=400:nEventsMin=100:BoostType=Bagging:SeparationType=GiniIndex:nCuts=20:PruneMethod=NoPruning" , 0.8, 0.98) );
   if (full) TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kBDT, "BDTD",
                                                                "!H:!V:NTrees=400:nEventsMin=200:MaxDepth=3:BoostType=AdaBoost:SeparationType=GiniIndex:nCuts=10:PruneMethod=NoPruning:VarTransform=Decorrelate" , 0.88, 0.98) );
   if (full) TMVA_test.addTest(new MethodUnitTestWithROCLimits( TMVA::Types::kRuleFit, "RuleFit",
                                                                "H:!V:RuleFitModule=RFTMVA:Model=ModRuleLinear:MinImp=0.001:RuleMinDist=0.001:NTrees=20:fEventsMin=0.01:fEventsMax=0.5:GDTau=-1.0:GDTauPrec=0.01:GDStep=0.01:GDNSteps=10000:GDErrScale=1.02" , 0.88, 0.98) );

   TString config = "!H:V:VarTransform=N:ErrorStrategy=CROSSENTROPY"
      ":WeightInitialization=XAVIER"
      ":Layout=LINEAR|64,LINEAR|64,LINEAR|64,LINEAR"
      ":TrainingStrategy=LearningRate=0.1,Momentum=0.9, ConvergenceSteps=20,"
      "BatchSize=256,Regularization=None,TestRepetitions=5, Multithreading=True"
      "|LearningRate=0.01,Momentum=0.5,ConvergenceSteps=20,BatchSize=256,"
      "Regularization=None,TestRepetitions=5, Multithreading=True"
      "|LearningRate=0.003,Momentum=0.5,ConvergenceSteps=20,BatchSize=256,"
      "Regularization=None,TestRepetitions=5, Multithreading=True"
      "|LearningRate=0.001,Momentum=0.0,ConvergenceSteps=20,BatchSize=256,"
      "Regularization=None,TestRepetitions=5, Multithreading=True";
   TString configCpu      = "Architecture=CPU:" + config;
   TString configGpu      = "Architecture=GPU:" + config;

#ifdef R__HAS_TMVACPU
   TMVA_test.addTest(new MethodUnitTestWithROCLimits(
                         TMVA::Types::kDL, "DNN CPU", configCpu, 0.85, 0.98)
                     );
#endif
#ifdef R__HAS_TMVAGPU
   TMVA_test.addTest(new MethodUnitTestWithROCLimits(
                         TMVA::Types::kDL, "DNN GPU", configGpu, 0.85, 0.98)
                     );
#endif
}

void addRegressionTests( UnitTestSuite& TMVA_test, bool full=true)
{
   TMVA_test.addTest(new RegressionUnitTestWithDeviation( TMVA::Types::kLD, "LD", "!H:!V:VarTransform=None",      15., 25.,    10., 20. ));
   //                       full low/high , 90 low/high
   TMVA_test.addTest(new RegressionUnitTestWithDeviation( TMVA::Types::kMLP, "MLPBFGSN", "!H:!V:VarTransform=Norm:NeuronType=tanh:NCycles=300:HiddenLayers=N+20:TestRate=6:TrainingMethod=BFGS:Sampling=0.3:SamplingEpoch=0.8:ConvergenceImprove=1e-7:ConvergenceTests=15:!UseRegulator:VarTransform=N" , 0.4, 0.85, 0.3, 0.55 ));
   if (full) TMVA_test.addTest(new RegressionUnitTestWithDeviation( TMVA::Types::kBDT, "BDTG","!H:!V:NTrees=1000::BoostType=Grad:Shrinkage=0.3:!UseBaggedBoost:SeparationType=GiniIndex:nCuts=20:MinNodeSize=.2:MaxDepth=3" ,  5., 8., 3., 5. ));
   TMVA_test.addTest(new RegressionUnitTestWithDeviation( TMVA::Types::kBDT, "BDTG2","!H:!V:NTrees=2000::BoostType=Grad:Shrinkage=0.1:UseBaggedBoost:GradBaggingFraction=0.5:nCuts=20:MaxDepth=3" ,  2., 5., 1., 3. ));

   if (!full) return;

   TMVA_test.addTest(new RegressionUnitTestWithDeviation( TMVA::Types::kPDERS, "PDERS", "!H:!V:NormTree=T:VolumeRangeMode=Adaptive:KernelEstimator=Gauss:GaussSigma=1.0:NEventsMin=10:NEventsMax=60:VarTransform=None", 10., 15., 5., 10. ));
   TMVA_test.addTest(new RegressionUnitTestWithDeviation( TMVA::Types::kPDERS, "PDERSkNN", "!H:!V:VolumeRangeMode=kNN:KernelEstimator=Gauss:GaussSigma=1.0:NEventsMin=10:NEventsMax=60" , 10., 15., 5., 10. ));
   TMVA_test.addTest(new RegressionUnitTestWithDeviation( TMVA::Types::kPDEFoam, "PDEFoam", "!H:!V:MultiTargetRegression=F:TargetSelection=Mpv:TailCut=0.001:VolFrac=0.0333:nActiveCells=500:nSampl=5000:nBin=7:Compress=T:Kernel=Gauss:Nmin=10:VarTransform=None", 10., 15., 4., 6. ));
   TMVA_test.addTest(new RegressionUnitTestWithDeviation( TMVA::Types::kKNN, "KNN",  "nkNN=20:ScaleFrac=0.8:SigmaFact=1.0:Kernel=Gaus:UseKernel=F:UseWeight=T:!Trim" , 10., 15., 4., 6. ));
   TString baseRegFDAstring="!H:!V:Formula=(0)+(1)*x0+(2)*x1+(3)*x0*x1+(4)*x0*x0+(5)*x1*x1:ParRanges=(-1,1);(-2,2);(-2,2);(-2,2);(-2,2);(-2,2):";
   TMVA_test.addTest(new RegressionUnitTestWithDeviation( TMVA::Types::kFDA, "FDA_MC", baseRegFDAstring+"FitMethod=MC:SampleSize=1000:Sigma=0.1:VarTransform=N", 15., 25., 10., 20. ));
   TMVA_test.addTest(new RegressionUnitTestWithDeviation( TMVA::Types::kFDA, "FDA_GA", baseRegFDAstring+"FitMethod=GA:PopSize=100:Cycles=3:Steps=30:Trim=True:SaveBestGen=1:VarTransform=Norm",  0.5, 1.0, 0.5 , 0.8 ));
   TMVA_test.addTest(new RegressionUnitTestWithDeviation( TMVA::Types::kFDA, "FDA_MT", baseRegFDAstring+"FitMethod=MINUIT:ErrorLevel=1:PrintLevel=-1:FitStrategy=2:UseImprove:UseMinos:SetBatch" , 100., 250., 100., 200. ));
   TMVA_test.addTest(new RegressionUnitTestWithDeviation( TMVA::Types::kFDA, "FDA_GAMT",baseRegFDAstring+"FitMethod=GA:Converger=MINUIT:ErrorLevel=1:PrintLevel=-1:FitStrategy=0:UseImprove:UseMinos:SetBatch:Cycles=1:PopSize=20:Steps=5:Trim" ,  100., 250., 100., 220. ));
   TMVA_test.addTest(new RegressionUnitTestWithDeviation( TMVA::Types::kMLP, "MLPBFGS", "!H:!V:VarTransform=Norm:NeuronType=tanh:NCycles=300:HiddenLayers=N+20:TestRate=6:TrainingMethod=BFGS:Sampling=0.3:SamplingEpoch=0.8:ConvergenceImprove=1e-6:ConvergenceTests=15:!UseRegulator" , 0.4, 0.8, 0.2, 0.5 ));
   // this does not work satisfactory TMVA_test.addTest(new RegressionUnitTestWithDeviation( TMVA::Types::kMLP, "MLP", "!H:!V:VarTransform=Norm:NeuronType=tanh:NCycles=300:HiddenLayers=N+20:TestRate=6:TrainingMethod=BP:Sampling=0.3:SamplingEpoch=0.8:ConvergenceImprove=1e-6:ConvergenceTests=15:!UseRegulator" , 0.4, 0.8, 0.2, 0.5 ));
   // SVM regression does not work TMVA_test.addTest(new RegressionUnitTestWithDeviation( TMVA::Types::kSVM, "SVM", "Gamma=0.25:Tol=0.001:VarTransform=Norm" , 0., 1., 0., 1. ));
   TMVA_test.addTest(new RegressionUnitTestWithDeviation( TMVA::Types::kBDT, "BDT","!H:!V",  8., 15., 5., 10. ));
   TMVA_test.addTest(new RegressionUnitTestWithDeviation( TMVA::Types::kBDT, "BDTN","!H:!V:VarTransform=N",  8., 15., 5., 10. ));
   TMVA_test.addTest(new RegressionUnitTestWithDeviation( TMVA::Types::kBDT, "BDT2","!H:!V:NTrees=500:nEventsMin=20:BoostType=AdaBoostR2:SeparationType=GiniIndex:nCuts=20:PruneMethod=CostComplexity:PruneStrength=3", 15., 20., 10., 20. ));
}

void addDataInputTests( UnitTestSuite& TMVA_test, bool full=true)
{
   if (!full) return;

   TString lhstring = "!H:!V:!TransformOutput:PDFInterpol=Spline2:NSmoothSig[0]=20:NSmoothBkg[0]=20:NSmooth=5:NAvEvtPerBin=50:VarTransform=Decorrelate";

   TMVA_test.addTest(new MethodUnitTestWithComplexData(TString("sig1_bgd1"), TString("nTrain_Signal=500:nTrain_Background=500:SplitMode=random:NormMode=NumEvents:!V"), TMVA::Types::kLikelihood, "LikelihoodD", lhstring , 0.48, 0.52) );
   TMVA_test.addTest(new MethodUnitTestWithComplexData(TString("sig1_bgd1"), TString("nTrain_Signal=500:nTrain_Background=500:SplitMode=block:NormMode=NumEvents:!V"), TMVA::Types::kLikelihood, "LikelihoodD", lhstring , 0.48, 0.52) );
   TMVA_test.addTest(new MethodUnitTestWithComplexData(TString("sig1_bgd1"), TString("nTrain_Signal=500:nTrain_Background=500:SplitMode=alternate:NormMode=NumEvents:!V"), TMVA::Types::kLikelihood, "LikelihoodD", lhstring , 0.48, 0.52) );

   TMVA_test.addTest(new MethodUnitTestWithComplexData(TString("sigfull_bgdfull"), TString("nTrain_Signal=500:nTrain_Background=500:SplitMode=Random:NormMode=NumEvents:!V"), TMVA::Types::kLikelihood, "LikelihoodD", lhstring , 0.9, 0.95) );
   TMVA_test.addTest(new MethodUnitTestWithComplexData(TString("sigfull_bgdfull"), TString("nTrain_Signal=500:nTrain_Background=500:SplitMode=alternate:NormMode=NumEvents:!V"), TMVA::Types::kLikelihood, "LikelihoodD", lhstring , 0.9, 0.95) );
   TMVA_test.addTest(new MethodUnitTestWithComplexData(TString("sigfull_bgdfull"), TString("nTrain_Signal=500:nTrain_Background=500:SplitMode=block:NormMode=NumEvents:!V"), TMVA::Types::kLikelihood, "LikelihoodD", lhstring , 0.9, 0.95) );

   TMVA_test.addTest(new MethodUnitTestWithComplexData(TString("sig1_sig2_bgd1_bgd2"), TString("nTrain_Signal=500:nTrain_Background=500:nTest_Signal=500:nTest_Background=500:SplitMode=random:NormMode=NumEvents:!V"), TMVA::Types::kLikelihood, "LikelihoodD", lhstring , 0.9, 0.95) );
   TMVA_test.addTest(new MethodUnitTestWithComplexData(TString("sig1_sig2_bgd1_bgd2"), TString("nTrain_Signal=500:nTrain_Background=500:nTest_Signal=500:nTest_Background=500:SplitMode=block:NormMode=NumEvents:!V"), TMVA::Types::kLikelihood, "LikelihoodD", lhstring , 0.2, 0.45) );

   TMVA_test.addTest(new MethodUnitTestWithComplexData(TString("sig1_sig2_bgd1_bgd2"), TString("nTrain_Signal=500:nTrain_Background=500:nTest_Signal=500:nTest_Background=500:SplitMode=alternate:NormMode=NumEvents:!V"), TMVA::Types::kLikelihood, "LikelihoodD", lhstring , 0.45, 0.52) );

   TMVA_test.addTest(new MethodUnitTestWithComplexData(TString("sig1_sig2_bgd1_bgd2"), TString("SplitMode=random:NormMode=NumEvents:!V"), TMVA::Types::kLikelihood, "LikelihoodD", lhstring , 0.9, 0.95) );
   TMVA_test.addTest(new MethodUnitTestWithComplexData(TString("sig1_sig2_bgd1_bgd2"), TString("SplitMode=alternate:NormMode=NumEvents:!V"), TMVA::Types::kLikelihood, "LikelihoodD", lhstring , 0.9, 0.95) );
   TMVA_test.addTest(new MethodUnitTestWithComplexData(TString("sig1_sig2_bgd1_bgd2"), TString("SplitMode=block:NormMode=NumEvents:!V"), TMVA::Types::kLikelihood, "LikelihoodD", lhstring , 0.9, 0.994) );
}

void addComplexClassificationTests( UnitTestSuite& TMVA_test, bool full=true )
{
   if (!full) return;
   TString trees="sigfull_bgdfull";
   TString prep="nTrain_Signal=2000:nTrain_Background=2000:nTest_Signal=1000:nTest_Background=1000:!V";
   // complex data tests Fisher for comparison
   TMVA_test.addTest(new MethodUnitTestWithComplexData( trees, prep,TMVA::Types::kFisher, "Fisher", "H:!V:VarTransform=Gauss", 0.93, 0.945) );
   // complex data tests with MLP
   TMVA_test.addTest(new MethodUnitTestWithComplexData(trees, prep, TMVA::Types::kMLP, "MLP", "H:!V:RandomSeed=9:NeuronType=tanh:VarTransform=N:NCycles=50:HiddenLayers=N+10:TestRate=5:TrainingMethod=BFGS:!UseRegulator" , 0.955, 0.975) );
   TMVA_test.addTest(new MethodUnitTestWithComplexData(trees, prep, TMVA::Types::kMLP, "MLP", "H:!V:RandomSeed=9:NeuronType=tanh:VarTransform=N:NCycles=50:HiddenLayers=N+10:TestRate=5:TrainingMethod=BP:!UseRegulator" , 0.955, 0.975) );
   // BDT
   TMVA_test.addTest(new MethodUnitTestWithComplexData(trees, prep, TMVA::Types::kBDT, "BDTG8_50", "!H:!V:NTrees=50:BoostType=Grad:Shrinkage=0.30:UseBaggedBoost:BaggedSampleFraction=0.6:nCuts=20:MaxDepth=3:SeparationType=GiniIndex" , 0.950, 0.975) );
   // SVM
   TMVA_test.addTest(new MethodUnitTestWithComplexData(trees, prep, TMVA::Types::kSVM, "SVM", "Gamma=0.4:Tol=0.001" , 0.955, 0.975) );
}

//#include <fenv.h>

int main(int argc, char **argv)
{

//feenableexcept (FE_DIVBYZERO | FE_OVERFLOW | FE_INVALID);

   gROOT->SetBatch();
   TApplication theApp("App", &argc, argv);
   gBenchmark = new TBenchmark();
   gBenchmark->Start("stress");
   bool full=false;
#ifdef FULL
   full=true;
   //std::cout << running longer tests<<std::endl;
#endif

   UnitTestSuite TMVA_test("TMVA unit testing");

   TMVA_test.intro();

   TMVA_test.addTest(new utEvent);
   TMVA_test.addTest(new utVariableInfo);
   TMVA_test.addTest(new utDataSetInfo);
   TMVA_test.addTest(new utDataSet);
   TMVA_test.addTest(new utFactory);
   TMVA_test.addTest(new utReader);
   TMVA_test.addTest(new utReaderMT);

   addClassificationTests(TMVA_test, full);
   addRegressionTests(TMVA_test, full);
   addDataInputTests(TMVA_test, full);
   addComplexClassificationTests(TMVA_test, full);
   
   TMVA_test.addTest(new utIPythonInteractive);

   // run all
   ROOT::EnableThreadSafety();
   TMVA_test.run();

#ifdef COUTDEBUG
   long int nFail = TMVA_test.report();
   cout << "Total number of failures: " << nFail << endl;
   cout << "************************************************************************************************" << endl;
#else
   TMVA_test.report();
#endif

#ifndef NOCLEANUP
   //FileStat_t stat;
   //if(!gSystem->GetPathInfo("./weights",stat)) {
#ifdef WIN32
   gSystem->Exec("erase /f /q weights\\*.*");
#else
   gSystem->Exec("rm -rf weights/*");
#endif
#endif
   gBenchmark->Stop("stress");
   Bool_t UNIX = strcmp(gSystem->GetName(), "Unix") == 0;
   printf("******************************************************************\n");
   if (UNIX) {
      TString sp = gSystem->GetFromPipe("uname -a");
      sp.Resize(60);
      printf("*  SYS: %s\n",sp.Data());
      if (strstr(gSystem->GetBuildNode(),"Linux")) {
         sp = gSystem->GetFromPipe("lsb_release -d -s");
         printf("*  SYS: %s\n",sp.Data());
      }
      if (strstr(gSystem->GetBuildNode(),"Darwin")) {
         sp  = gSystem->GetFromPipe("sw_vers -productVersion");
         sp += " Mac OS X ";
         printf("*  SYS: %s\n",sp.Data());
      }
   } else {
      const char *os = gSystem->Getenv("OS");
      if (!os) printf("*  SYS: Windows 95\n");
      else     printf("*  SYS: %s %s \n",os,gSystem->Getenv("PROCESSOR_IDENTIFIER"));
   }

   //printf("******************************************************************\n");
   //gBenchmark->Print("stress");
   Float_t ct = gBenchmark->GetCpuTime("stress");
   printf("******************************************************************\n");
   printf("*  CPUTIME   =%6.1f   *  Root%-8s  %d/%d\n",ct       ,gROOT->GetVersion(),gROOT->GetVersionDate(),gROOT->GetVersionTime());
   printf("******************************************************************\n");
}
