// @(#)root/fumili:$Id$
// Author: L. Moneta Wed Oct 25 16:28:55 2006

/**********************************************************************
 *                                                                    *
 * Copyright (c) 2006  LCG ROOT Math Team, CERN/PH-SFT                *
 *                                                                    *
 *                                                                    *
 **********************************************************************/

// Implementation file for class TFumiliMinimizer

#include "TFumiliMinimizer.h"
#include "Math/IFunction.h"
#include "Math/Util.h"
#include "TError.h"

#include "TFumili.h"

#include <iostream>
#include <cassert>
#include <algorithm>
#include <functional>


// setting USE_FUMILI_FUNCTION will use the Derivatives provided by Fumili
// instead of what proided in FitUtil::EvalChi2Residual
// t.d.: use still standard Chi2 but replace model function
// with a gradient function where gradient is computed by TFumili
// since TFumili knows the step size can calculate it better
// Derivative in FUmili are very fast (1 extra call for each parameter)
// + 1 function evaluation
//
//#define USE_FUMILI_FUNCTION
#ifdef USE_FUMILI_FUNCTION
bool gUseFumiliFunction = true;
//#include "FumiliFunction.h"
// fit method function used in TFumiliMinimizer

#include "Fit/PoissonLikelihoodFCN.h"
#include "Fit/LogLikelihoodFCN.h"
#include "Fit/Chi2FCN.h"
#include "TF1.h"
#include "TFumili.h"

template<class MethodFunc>
class FumiliFunction  : public ROOT::Math::FitMethodFunction {

   typedef ROOT::Math::FitMethodFunction::BaseFunction BaseFunction;

public:
   FumiliFunction(TFumili * fumili,  const ROOT::Math::FitMethodFunction * func) :
      ROOT::Math::FitMethodFunction(func->NDim(), func->NPoints() ),
      fFumili(fumili),
      fObjFunc(0)
   {
      fObjFunc = dynamic_cast<const MethodFunc *>(func);
      assert(fObjFunc != 0);

      // create TF1 class from model function
      fModFunc = new TF1("modfunc",ROOT::Math::ParamFunctor( &fObjFunc->ModelFunction() ) );
      fFumili->SetUserFunc(fModFunc);
   }

   ROOT::Math::FitMethodFunction::Type_t Type() const { return fObjFunc->Type();  }

   FumiliFunction * Clone() const { return new FumiliFunction(fFumili, fObjFunc); }


   // recalculate data elemet using Fumili stuff
   double DataElement(const double * /*par */, unsigned int i, double * g) const {

      // parameter values are inside TFumili

      // suppose type is bin likelihood
      unsigned int npar = fObjFunc->NDim();
      double  y = 0;
      double invError = 0;
      const double *x = fObjFunc->Data().GetPoint(i,y,invError);
      double fval  = fFumili->EvalTFN(g,const_cast<double *>( x));
      fFumili->Derivatives(g, const_cast<double *>( x));

      if ( fObjFunc->Type() == ROOT::Math::FitMethodFunction::kLogLikelihood) {
         double logPdf =   y * ROOT::Math::Util::EvalLog( fval) - fval;
         for (unsigned int k = 0; k < npar; ++k) {
            g[k] *= ( y/fval - 1.) ;//* pdfval;
         }

 //         std::cout << "x = " << x[0] << " logPdf = " << logPdf << " grad";
//          for (unsigned int ipar = 0; ipar < npar; ++ipar)
//             std::cout << g[ipar] << "\t";
//          std::cout << std::endl;

         return logPdf;
      }
      else if (fObjFunc->Type() == ROOT::Math::FitMethodFunction::kLeastSquare ) {
         double resVal = (y-fval)*invError;
         for (unsigned int k = 0; k < npar; ++k) {
            g[k] *= -invError;
         }
         return resVal;
      }

      return 0;
   }


private:

   double DoEval(const double *x ) const {
      return (*fObjFunc)(x);
   }

   TFumili * fFumili;
   const MethodFunc * fObjFunc;
   TF1 * fModFunc;

};
#else
bool gUseFumiliFunction = false;
#endif
//______________________________________________________________________________
//
//  TFumiliMinimizer class implementing the ROOT::Math::Minimizer interface using
//  TFumili.
//  This class is normally instantiates using the plug-in manager
//  (plug-in with name Fumili or TFumili)
//  In addition the user can choose the minimizer algorithm: Migrad (the default one), Simplex, or Minimize (combined Migrad + Simplex)
//
//__________________________________________________________________________________________

// initialize the static instances

ROOT::Math::FitMethodFunction * TFumiliMinimizer::fgFunc = 0;
ROOT::Math::FitMethodGradFunction * TFumiliMinimizer::fgGradFunc = 0;
TFumili * TFumiliMinimizer::fgFumili = 0;


ClassImp(TFumiliMinimizer)


TFumiliMinimizer::TFumiliMinimizer(int  ) :
   fDim(0),
   fNFree(0),
   fMinVal(0),
   fEdm(-1),
   fFumili(0)
{
   // Constructor for TFumiliMinimier class

   // construct with npar = 0 (by default a value of 25 is used in TFumili for allocating the arrays)
#ifdef USE_STATIC_TMINUIT
   // allocate here only the first time
   if (fgFumili == 0) fgFumili =  new TFumili(0);
   fFumili = fgFumili;
#else
   if (fFumili) delete fFumili;
   fFumili =  new TFumili(0);
   fgFumili = fFumili;
#endif

}


TFumiliMinimizer::~TFumiliMinimizer()
{
   // Destructor implementation.
   if (fFumili) delete fFumili;
}

TFumiliMinimizer::TFumiliMinimizer(const TFumiliMinimizer &) :
   Minimizer()
{
   // Implementation of copy constructor (it is private).
}

TFumiliMinimizer & TFumiliMinimizer::operator = (const TFumiliMinimizer &rhs)
{
   // Implementation of assignment operator (private)
   if (this == &rhs) return *this;  // time saving self-test
   return *this;
}



void TFumiliMinimizer::SetFunction(const  ROOT::Math::IMultiGenFunction & func) {
   // Set the objective function to be minimized, by passing a function object implement the
   // basic multi-dim Function interface. In this case the derivatives will be
   // calculated by Fumili

   // Here a TFumili instance is created since only at this point we know the number of parameters
   // needed to create TFumili
   fDim = func.NDim();
   fFumili->SetParNumber(fDim);

   // for Fumili the fit method function interface is required
   const ROOT::Math::FitMethodFunction * fcnfunc = dynamic_cast<const ROOT::Math::FitMethodFunction *>(&func);
   if (!fcnfunc) {
      Error("SetFunction","Wrong Fit method function type used for Fumili");
      return;
   }
   // assign to the static pointer (NO Thread safety here)
   fgFunc = const_cast<ROOT::Math::FitMethodFunction *>(fcnfunc);
   fgGradFunc = 0;
   fFumili->SetFCN(&TFumiliMinimizer::Fcn);

#ifdef USE_FUMILI_FUNCTION
   if (gUseFumiliFunction) {
      if (fcnfunc->Type() == ROOT::Math::FitMethodFunction::kLogLikelihood)
         fgFunc = new FumiliFunction<ROOT::Fit::PoissonLikelihoodFCN<ROOT::Math::FitMethodFunction::BaseFunction> >(fFumili,fcnfunc);
      else if (fcnfunc->Type() == ROOT::Math::FitMethodFunction::kLeastSquare)
         fgFunc = new FumiliFunction<ROOT::Fit::Chi2FCN<ROOT::Math::FitMethodFunction::BaseFunction> >(fFumili,fcnfunc);
   }
#endif

}

void TFumiliMinimizer::SetFunction(const  ROOT::Math::IMultiGradFunction & func) {
   // Set the objective function to be minimized, by passing a function object implement the
   // multi-dim gradient Function interface. In this case the function derivatives are provided
   // by the user via this interface and there not calculated by Fumili.

   fDim = func.NDim();
   fFumili->SetParNumber(fDim);

   // for Fumili the fit method function interface is required
   const ROOT::Math::FitMethodGradFunction * fcnfunc = dynamic_cast<const ROOT::Math::FitMethodGradFunction *>(&func);
   if (!fcnfunc) {
      Error("SetFunction","Wrong Fit method function type used for Fumili");
      return;
   }
   // assign to the static pointer (NO Thread safety here)
   fgFunc = 0;
   fgGradFunc = const_cast<ROOT::Math::FitMethodGradFunction  *>(fcnfunc);
   fFumili->SetFCN(&TFumiliMinimizer::Fcn);

}

void TFumiliMinimizer::Fcn( int & , double * g , double & f, double * x , int /* iflag */) {
   // implementation of FCN static function used internally by TFumili.
   // Adapt IMultiGenFunction interface to TFumili FCN static function
   f = TFumiliMinimizer::EvaluateFCN(const_cast<double*>(x),g);
}

// void TFumiliMinimizer::FcnGrad( int &, double * g, double & f, double * x , int iflag ) {
//    // implementation of FCN static function used internally by TFumili.
//    // Adapt IMultiGradFunction interface to TFumili FCN static function in the case of user
//    // provided gradient.
//    ROOT::Math::IMultiGradFunction * gFunc = dynamic_cast<ROOT::Math::IMultiGradFunction *> ( fgFunc);

//    assert(gFunc != 0);
//    f = gFunc->operator()(x);

//    // calculates also derivatives
//    if (iflag == 2) gFunc->Gradient(x,g);
// }

double TFumiliMinimizer::EvaluateFCN(const double * x, double * grad) {
   // function callaed to evaluate the FCN at the value x
   // calculates also the matrices of the second derivatives of the objective function needed by FUMILI


   //typedef FumiliFCNAdapter::Function Function;



   // reset
//    assert(grad.size() == npar);
//    grad.assign( npar, 0.0);
//    hess.assign( hess.size(), 0.0);

   double sum = 0;
   unsigned int ndata = 0;
   unsigned int npar = 0;
   if (fgFunc) {
      ndata = fgFunc->NPoints();
      npar = fgFunc->NDim();
      fgFunc->UpdateNCalls();
   }
   else if (fgGradFunc) {
      ndata = fgGradFunc->NPoints();
      npar = fgGradFunc->NDim();
      fgGradFunc->UpdateNCalls();
   }

   // eventually store this matrix as static member to optimize speed
   std::vector<double> gf(npar);
   std::vector<double> hess(npar*(npar+1)/2);

   // reset gradients
   for (unsigned int ipar = 0; ipar < npar; ++ipar)
      grad[ipar] = 0;


   //loop on the data points
//#define DEBUG
#ifdef DEBUG
   std::cout << "=============================================";
   std::cout << "par = ";
   for (unsigned int ipar = 0; ipar < npar; ++ipar)
      std::cout << x[ipar] << "\t";
   std::cout << std::endl;
   if (fgFunc) std::cout << "type " << fgFunc->Type() << std::endl;
#endif


   // assume for now least-square
   // since TFumili doet not use errodef I must diveide chi2 by 2
   if ( (fgFunc && fgFunc->Type() == ROOT::Math::FitMethodFunction::kLeastSquare) ||
        (fgGradFunc && fgGradFunc->Type() == ROOT::Math::FitMethodGradFunction::kLeastSquare) ) {

      double fval = 0;
      for (unsigned int i = 0; i < ndata; ++i) {
         // calculate data element and gradient
         // DataElement returns (f-y)/s and gf is derivatives of model function multiplied by (-1/sigma)
         if (gUseFumiliFunction) {
            fval = fgFunc->DataElement( x, i, &gf[0]);
         }
         else {
            if (fgFunc != 0)
               fval = fgFunc->DataElement(x, i, &gf[0]);
            else
               fval = fgGradFunc->DataElement(x, i, &gf[0]);
         }

         // t.b.d should protect for bad  values of fval
         sum += fval*fval;

         // to be check (TFumili uses a factor of 1/2 for chi2)

         for (unsigned int j = 0; j < npar; ++j) {
            grad[j] +=  fval * gf[j];
            for (unsigned int k = j; k < npar; ++ k) {
               int idx =  j + k*(k+1)/2;
               hess[idx] += gf[j] * gf[k];
            }
         }
      }
   }
   else if ( (fgFunc && fgFunc->Type() == ROOT::Math::FitMethodFunction::kLogLikelihood) ||
             (fgGradFunc && fgGradFunc->Type() == ROOT::Math::FitMethodGradFunction::kLogLikelihood) ) {



      double fval = 0;

      //std::cout << "\t x "  << x[0] << "  " << x[1] << "  " << x[2] << std::endl;

      for (unsigned int i = 0; i < ndata; ++i) {

         if (gUseFumiliFunction) {
            fval = fgFunc->DataElement( x, i, &gf[0]);
         }
         else {
            // calculate data element and gradient
            if (fgFunc != 0)
               fval = fgFunc->DataElement(x, i, &gf[0]);
            else
               fval = fgGradFunc->DataElement(x, i, &gf[0]);
         }

         // protect for small values of fval
         //      std::cout << i << "  "  << fval << " log " << " grad " << gf[0] << "  " << gf[1] << "  " << gf[2] << std::endl;
//         sum -= ROOT::Math::Util::EvalLog(fval);
         sum -= fval;

         for (unsigned int j = 0; j < npar; ++j) {
            double gfj = gf[j];// / fval;
            grad[j] -= gfj;
            for (unsigned int k = j; k < npar; ++ k) {
               int idx =  j + k*(k+1)/2;
               hess[idx] +=  gfj * gf[k];// / (fval );
            }
         }
      }
   }
   else {
      Error("EvaluateFCN"," type of fit method is not supported, it must be chi2 or log-likelihood");
   }

   // now TFumili excludes fixed prameter in second-derivative matrix
   // ned to get them using the static instance of TFumili
   double * zmatrix = fgFumili->GetZ();
   double * pl0 = fgFumili->GetPL0(); // parameter limits
   assert(zmatrix != 0);
   assert(pl0 != 0);
   unsigned int k = 0;
   unsigned int l = 0;
   for (unsigned int i = 0; i < npar; ++i) {
         for (unsigned int j = 0; j <= i; ++j) {
            if (pl0[i] > 0 && pl0[j] > 0) { // only for non-fixed parameters
               zmatrix[l++] = hess[k];
            }
            k++;
         }
   }

#ifdef DEBUG
   std::cout << "FCN value " << sum << " grad ";
   for (unsigned int ipar = 0; ipar < npar; ++ipar)
      std::cout << grad[ipar] << "\t";
   std::cout << std::endl << std::endl;
#endif


   return 0.5*sum; // fumili multiply then by 2

}



bool TFumiliMinimizer::SetVariable(unsigned int ivar, const std::string & name, double val, double step) {
   // set a free variable.
   if (fFumili == 0) {
      Error("SetVariableValue","invalid TFumili pointer. Set function first ");
      return false;
   }
#ifdef DEBUG
   std::cout << "set variable " << ivar << " " << name << " value " << val << " step " << step << std::endl;
#endif

   int ierr = fFumili->SetParameter(ivar , name.c_str(), val, step, 0., 0. );
   if (ierr) {
      Error("SetVariable","Error for parameter %d ",ivar);
      return false;
   }
   return true;
}

bool TFumiliMinimizer::SetLimitedVariable(unsigned int ivar, const std::string & name, double val, double step, double lower, double upper) {
   // set a limited variable.
   if (fFumili == 0) {
      Error("SetVariableValue","invalid TFumili pointer. Set function first ");
      return false;
   }
#ifdef DEBUG
   std::cout << "set limited variable " << ivar << " " << name << " value " << val << " step " << step << std::endl;
#endif
   int ierr = fFumili->SetParameter(ivar, name.c_str(), val, step, lower, upper );
   if (ierr) {
      Error("SetLimitedVariable","Error for parameter %d ",ivar);
      return false;
   }
   return true;
}
#ifdef LATER
bool Fumili2Minimizer::SetLowerLimitedVariable(unsigned int ivar , const std::string & name , double val , double step , double lower ) {
    // add a lower bounded variable as a double bound one, using a very large number for the upper limit
   double s = val-lower;
   double upper = s*1.0E15;
   if (s != 0)  upper = 1.0E15;
   return SetLimitedVariable(ivar, name, val, step, lower,upper);
}
#endif


bool TFumiliMinimizer::SetFixedVariable(unsigned int ivar, const std::string & name, double val) {
   // set a fixed variable.
   if (fFumili == 0) {
      Error("SetVariableValue","invalid TFumili pointer. Set function first ");
      return false;
   }


   int ierr = fFumili->SetParameter(ivar, name.c_str(), val, 0., val, val );
   fFumili->FixParameter(ivar);

#ifdef DEBUG
   std::cout << "Fix variable " << ivar << " " << name << " value " << std::endl;
#endif

   if (ierr) {
      Error("SetFixedVariable","Error for parameter %d ",ivar);
      return false;
   }
   return true;
}

bool TFumiliMinimizer::SetVariableValue(unsigned int ivar, double val) {
   // set the variable value
   if (fFumili == 0) {
      Error("SetVariableValue","invalid TFumili pointer. Set function first ");
      return false;
   }
   TString name = fFumili->GetParName(ivar);
   double  oldval, verr, vlow, vhigh = 0;
   int ierr = fFumili->GetParameter( ivar, &name[0], oldval, verr, vlow, vhigh);
   if (ierr) {
      Error("SetVariableValue","Error for parameter %d ",ivar);
      return false;
   }
#ifdef DEBUG
   std::cout << "set variable " << ivar << " " << name << " value "
             << val << " step " <<  verr << std::endl;
#endif

   ierr = fFumili->SetParameter(ivar , name , val, verr, vlow, vhigh );
   if (ierr) {
      Error("SetVariableValue","Error for parameter %d ",ivar);
      return false;
   }
   return true;
}

bool TFumiliMinimizer::Minimize() {
   // perform the minimization using the algorithm chosen previously by the user
   // By default Migrad is used.
   // Return true if the found minimum is valid and update internal chached values of
   // minimum values, errors and covariance matrix.

   if (fFumili == 0) {
      Error("SetVariableValue","invalid TFumili pointer. Set function first ");
      return false;
   }

   // need to set static instance to be used when calling FCN
   fgFumili = fFumili;


   double arglist[10];

   // error cannot be set in TFumili (always the same)
//    arglist[0] = ErrorUp();
//    fFumili->ExecuteCommand("SET Err",arglist,1);

   int printlevel = PrintLevel();
   // not implemented in TFumili yet
   //arglist[0] = printlevel - 1;
   //fFumili->ExecuteCommand("SET PRINT",arglist,1,ierr);

   // suppress warning in case Printlevel() == 0
   if (printlevel == 0)    fFumili->ExecuteCommand("SET NOW",arglist,0);
   else fFumili->ExecuteCommand("SET WAR",arglist,0);


   // minimize: use ExecuteCommand instead of Minimize to set tolerance and maxiter

   arglist[0] = MaxFunctionCalls();
   arglist[1] = Tolerance();

   if (printlevel > 0)
      std::cout << "Minimize using TFumili with tolerance = " << Tolerance()
                << " max calls " << MaxFunctionCalls() << std::endl;

   int iret = fFumili->ExecuteCommand("MIGRAD",arglist,2);
   fStatus = iret;
   //int iret = fgFumili->Minimize();

   // Hesse and IMP not implemented
//    // run improved if needed
//    if (ierr == 0 && fType == ROOT::Fumili::kMigradImproved)
//       fFumili->mnexcm("IMPROVE",arglist,1,ierr);

//    // check if Hesse needs to be run
//    if (ierr == 0 && IsValidError() ) {
//       fFumili->mnexcm("HESSE",arglist,1,ierr);
//    }


   int ntot;
   int nfree;
   double errdef = 0; // err def is not used by Fumili
   fFumili->GetStats(fMinVal,fEdm,errdef,nfree,ntot);

   if (printlevel > 0)
      fFumili->PrintResults(printlevel,fMinVal);


   assert (static_cast<unsigned int>(ntot) == fDim);
   assert( nfree == fFumili->GetNumberFreeParameters() );
   fNFree = nfree;


   // get parameter values and correlation matrix
   // fumili stores only lower part of diagonal matrix of the free parameters
   fParams.resize( fDim);
   fErrors.resize( fDim);
   fCovar.resize(fDim*fDim);
   const double * cv = fFumili->GetCovarianceMatrix();
   unsigned int l = 0;
   for (unsigned int i = 0; i < fDim; ++i) {
      fParams[i] = fFumili->GetParameter( i );
      fErrors[i] = fFumili->GetParError( i );

      if ( !fFumili->IsFixed(i) ) {
         for (unsigned int j = 0; j <=i ; ++j) {
            if ( !fFumili->IsFixed(j) ) {
               fCovar[i*fDim + j] = cv[l];
               fCovar[j*fDim + i] = fCovar[i*fDim + j];
               l++;
            }
         }
      }
   }

   return (iret==0) ? true : false;
}


//    } // end namespace Fit

// } // end namespace ROOT

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