TFumiliMinimizer.cxx

Go to the documentation of this file.
00001 // @(#)root/fumili:$Id: TFumiliMinimizer.cxx 37067 2010-11-29 14:38:08Z moneta $
00002 // Author: L. Moneta Wed Oct 25 16:28:55 2006
00003 
00004 /**********************************************************************
00005  *                                                                    *
00006  * Copyright (c) 2006  LCG ROOT Math Team, CERN/PH-SFT                *
00007  *                                                                    *
00008  *                                                                    *
00009  **********************************************************************/
00010 
00011 // Implementation file for class TFumiliMinimizer
00012 
00013 #include "TFumiliMinimizer.h"
00014 #include "Math/IFunction.h"
00015 #include "Math/Util.h"
00016 #include "TError.h"
00017 
00018 #include "TFumili.h"
00019 
00020 #include <iostream>
00021 #include <cassert>
00022 #include <algorithm>
00023 #include <functional>
00024 
00025 
00026 // setting USE_FUMILI_FUNCTION will use the Derivatives provided by Fumili
00027 // instead of what proided in FitUtil::EvalChi2Residual
00028 // t.d.: use still standard Chi2 but replace model function 
00029 // with a gradient function where gradient is computed by TFumili
00030 // since TFumili knows the step size can calculate it better 
00031 // Derivative in FUmili are very fast (1 extra call for each parameter) 
00032 // + 1 function evaluation
00033 //
00034 //#define USE_FUMILI_FUNCTION
00035 #ifdef USE_FUMILI_FUNCTION
00036 bool gUseFumiliFunction = true;
00037 //#include "FumiliFunction.h"
00038 // fit method function used in TFumiliMinimizer 
00039 
00040 #include "Fit/PoissonLikelihoodFCN.h"
00041 #include "Fit/LogLikelihoodFCN.h"
00042 #include "Fit/Chi2FCN.h"
00043 #include "TF1.h"
00044 #include "TFumili.h"
00045 
00046 template<class MethodFunc> 
00047 class FumiliFunction  : public ROOT::Math::FitMethodFunction { 
00048 
00049    typedef ROOT::Math::FitMethodFunction::BaseFunction BaseFunction;
00050 
00051 public: 
00052    FumiliFunction(TFumili * fumili,  const ROOT::Math::FitMethodFunction * func) : 
00053       ROOT::Math::FitMethodFunction(func->NDim(), func->NPoints() ),
00054       fFumili(fumili),
00055       fObjFunc(0)
00056    {
00057       fObjFunc = dynamic_cast<const MethodFunc *>(func);
00058       assert(fObjFunc != 0);
00059 
00060       // create TF1 class from model function
00061       fModFunc = new TF1("modfunc",ROOT::Math::ParamFunctor( &fObjFunc->ModelFunction() ) );
00062       fFumili->SetUserFunc(fModFunc);
00063    }
00064 
00065    ROOT::Math::FitMethodFunction::Type_t Type() const { return fObjFunc->Type();  }
00066 
00067    FumiliFunction * Clone() const { return new FumiliFunction(fFumili, fObjFunc); }
00068 
00069 
00070    // recalculate data elemet using Fumili stuff
00071    double DataElement(const double * /*par */, unsigned int i, double * g) const {
00072 
00073       // parameter values are inside TFumili
00074 
00075       // suppose type is bin likelihood
00076       unsigned int npar = fObjFunc->NDim();
00077       double  y = 0;
00078       double invError = 0; 
00079       const double *x = fObjFunc->Data().GetPoint(i,y,invError);
00080       double fval  = fFumili->EvalTFN(g,const_cast<double *>( x));
00081       fFumili->Derivatives(g, const_cast<double *>( x));
00082 
00083       if ( fObjFunc->Type() == ROOT::Math::FitMethodFunction::kLogLikelihood) {
00084          double logPdf =   y * ROOT::Math::Util::EvalLog( fval) - fval; 
00085          for (unsigned int k = 0; k < npar; ++k) {
00086             g[k] *= ( y/fval - 1.) ;//* pdfval; 
00087          }
00088          
00089  //         std::cout << "x = " << x[0] << " logPdf = " << logPdf << " grad"; 
00090 //          for (unsigned int ipar = 0; ipar < npar; ++ipar) 
00091 //             std::cout << g[ipar] << "\t";
00092 //          std::cout << std::endl;
00093          
00094          return logPdf; 
00095       }
00096       else if (fObjFunc->Type() == ROOT::Math::FitMethodFunction::kLeastSquare ) { 
00097          double resVal = (y-fval)*invError; 
00098          for (unsigned int k = 0; k < npar; ++k) {
00099             g[k] *= -invError; 
00100          }
00101          return resVal;
00102       }
00103 
00104       return 0;
00105    }
00106 
00107 
00108 private: 
00109 
00110    double DoEval(const double *x ) const { 
00111       return (*fObjFunc)(x);
00112    }
00113 
00114    TFumili * fFumili; 
00115    const MethodFunc * fObjFunc; 
00116    TF1 * fModFunc; 
00117    
00118 };
00119 #else 
00120 bool gUseFumiliFunction = false;
00121 #endif
00122 //______________________________________________________________________________
00123 //
00124 //  TFumiliMinimizer class implementing the ROOT::Math::Minimizer interface using 
00125 //  TFumili. 
00126 //  This class is normally instantiates using the plug-in manager 
00127 //  (plug-in with name Fumili or TFumili)
00128 //  In addition the user can choose the minimizer algorithm: Migrad (the default one), Simplex, or Minimize (combined Migrad + Simplex)
00129 //  
00130 //__________________________________________________________________________________________
00131 
00132 // initialize the static instances
00133 
00134 ROOT::Math::FitMethodFunction * TFumiliMinimizer::fgFunc = 0; 
00135 ROOT::Math::FitMethodGradFunction * TFumiliMinimizer::fgGradFunc = 0; 
00136 TFumili * TFumiliMinimizer::fgFumili = 0; 
00137 
00138 
00139 ClassImp(TFumiliMinimizer)
00140 
00141 
00142 TFumiliMinimizer::TFumiliMinimizer(int  ) : 
00143    fDim(0),
00144    fNFree(0),
00145    fMinVal(0),
00146    fEdm(-1),
00147    fFumili(0)
00148 {
00149    // Constructor for TFumiliMinimier class 
00150 
00151    // construct with npar = 0 (by default a value of 25 is used in TFumili for allocating the arrays)
00152 #ifdef USE_STATIC_TMINUIT
00153    // allocate here only the first time
00154    if (fgFumili == 0) fgFumili =  new TFumili(0);
00155    fFumili = fgFumili; 
00156 #else
00157    if (fFumili) delete fFumili;  
00158    fFumili =  new TFumili(0);
00159    fgFumili = fFumili; 
00160 #endif
00161 
00162 }
00163 
00164 
00165 TFumiliMinimizer::~TFumiliMinimizer() 
00166 {
00167    // Destructor implementation.
00168    if (fFumili) delete fFumili; 
00169 }
00170 
00171 TFumiliMinimizer::TFumiliMinimizer(const TFumiliMinimizer &) : 
00172    Minimizer()
00173 {
00174    // Implementation of copy constructor (it is private).
00175 }
00176 
00177 TFumiliMinimizer & TFumiliMinimizer::operator = (const TFumiliMinimizer &rhs) 
00178 {
00179    // Implementation of assignment operator (private)
00180    if (this == &rhs) return *this;  // time saving self-test
00181    return *this;
00182 }
00183 
00184 
00185 
00186 void TFumiliMinimizer::SetFunction(const  ROOT::Math::IMultiGenFunction & func) { 
00187    // Set the objective function to be minimized, by passing a function object implement the 
00188    // basic multi-dim Function interface. In this case the derivatives will be 
00189    // calculated by Fumili 
00190 
00191    // Here a TFumili instance is created since only at this point we know the number of parameters 
00192    // needed to create TFumili
00193    fDim = func.NDim();
00194    fFumili->SetParNumber(fDim); 
00195 
00196    // for Fumili the fit method function interface is required
00197    const ROOT::Math::FitMethodFunction * fcnfunc = dynamic_cast<const ROOT::Math::FitMethodFunction *>(&func);
00198    if (!fcnfunc) {
00199       Error("SetFunction","Wrong Fit method function type used for Fumili");
00200       return;
00201    }
00202    // assign to the static pointer (NO Thread safety here)
00203    fgFunc = const_cast<ROOT::Math::FitMethodFunction *>(fcnfunc); 
00204    fgGradFunc = 0; 
00205    fFumili->SetFCN(&TFumiliMinimizer::Fcn);
00206 
00207 #ifdef USE_FUMILI_FUNCTION
00208    if (gUseFumiliFunction) { 
00209       if (fcnfunc->Type() == ROOT::Math::FitMethodFunction::kLogLikelihood)  
00210          fgFunc = new FumiliFunction<ROOT::Fit::PoissonLikelihoodFCN<ROOT::Math::FitMethodFunction::BaseFunction> >(fFumili,fcnfunc);   
00211       else if (fcnfunc->Type() == ROOT::Math::FitMethodFunction::kLeastSquare)
00212          fgFunc = new FumiliFunction<ROOT::Fit::Chi2FCN<ROOT::Math::FitMethodFunction::BaseFunction> >(fFumili,fcnfunc);  
00213    }
00214 #endif   
00215 
00216 }
00217 
00218 void TFumiliMinimizer::SetFunction(const  ROOT::Math::IMultiGradFunction & func) { 
00219    // Set the objective function to be minimized, by passing a function object implement the 
00220    // multi-dim gradient Function interface. In this case the function derivatives are provided  
00221    // by the user via this interface and there not calculated by Fumili. 
00222 
00223    fDim = func.NDim(); 
00224    fFumili->SetParNumber(fDim); 
00225    
00226    // for Fumili the fit method function interface is required
00227    const ROOT::Math::FitMethodGradFunction * fcnfunc = dynamic_cast<const ROOT::Math::FitMethodGradFunction *>(&func);
00228    if (!fcnfunc) {
00229       Error("SetFunction","Wrong Fit method function type used for Fumili");
00230       return;
00231    }
00232    // assign to the static pointer (NO Thread safety here)
00233    fgFunc = 0; 
00234    fgGradFunc = const_cast<ROOT::Math::FitMethodGradFunction  *>(fcnfunc); 
00235    fFumili->SetFCN(&TFumiliMinimizer::Fcn);
00236 
00237 }
00238 
00239 void TFumiliMinimizer::Fcn( int & , double * g , double & f, double * x , int /* iflag */) { 
00240    // implementation of FCN static function used internally by TFumili.
00241    // Adapt IMultiGenFunction interface to TFumili FCN static function
00242    f = TFumiliMinimizer::EvaluateFCN(const_cast<double*>(x),g); 
00243 }
00244 
00245 // void TFumiliMinimizer::FcnGrad( int &, double * g, double & f, double * x , int iflag ) { 
00246 //    // implementation of FCN static function used internally by TFumili.
00247 //    // Adapt IMultiGradFunction interface to TFumili FCN static function in the case of user 
00248 //    // provided gradient.
00249 //    ROOT::Math::IMultiGradFunction * gFunc = dynamic_cast<ROOT::Math::IMultiGradFunction *> ( fgFunc); 
00250 
00251 //    assert(gFunc != 0);
00252 //    f = gFunc->operator()(x);
00253 
00254 //    // calculates also derivatives 
00255 //    if (iflag == 2) gFunc->Gradient(x,g);
00256 // }
00257 
00258 double TFumiliMinimizer::EvaluateFCN(const double * x, double * grad) { 
00259    // function callaed to evaluate the FCN at the value x 
00260    // calculates also the matrices of the second derivatives of the objective function needed by FUMILI
00261    
00262 
00263    //typedef FumiliFCNAdapter::Function Function; 
00264 
00265    
00266 
00267    // reset  
00268 //    assert(grad.size() == npar);
00269 //    grad.assign( npar, 0.0); 
00270 //    hess.assign( hess.size(), 0.0);
00271    
00272    double sum = 0; 
00273    unsigned int ndata = 0; 
00274    unsigned int npar = 0; 
00275    if (fgFunc) { 
00276       ndata = fgFunc->NPoints();
00277       npar = fgFunc->NDim();
00278       fgFunc->UpdateNCalls();
00279    }
00280    else if (fgGradFunc) { 
00281       ndata = fgGradFunc->NPoints();
00282       npar = fgGradFunc->NDim(); 
00283       fgGradFunc->UpdateNCalls();
00284    }
00285 
00286    // eventually store this matrix as static member to optimize speed 
00287    std::vector<double> gf(npar); 
00288    std::vector<double> hess(npar*(npar+1)/2); 
00289 
00290    // reset gradients
00291    for (unsigned int ipar = 0; ipar < npar; ++ipar) 
00292       grad[ipar] = 0;
00293 
00294  
00295    //loop on the data points
00296 //#define DEBUG
00297 #ifdef DEBUG
00298    std::cout << "=============================================";
00299    std::cout << "par = ";
00300    for (unsigned int ipar = 0; ipar < npar; ++ipar) 
00301       std::cout << x[ipar] << "\t";
00302    std::cout << std::endl; 
00303    if (fgFunc) std::cout << "type " << fgFunc->Type() << std::endl; 
00304 #endif
00305 
00306 
00307    // assume for now least-square
00308    // since TFumili doet not use errodef I must diveide chi2 by 2 
00309    if ( (fgFunc && fgFunc->Type() == ROOT::Math::FitMethodFunction::kLeastSquare) || 
00310         (fgGradFunc && fgGradFunc->Type() == ROOT::Math::FitMethodGradFunction::kLeastSquare) ) { 
00311 
00312       double fval = 0; 
00313       for (unsigned int i = 0; i < ndata; ++i) { 
00314          // calculate data element and gradient
00315          // DataElement returns (f-y)/s and gf is derivatives of model function multiplied by (-1/sigma)
00316          if (gUseFumiliFunction) {
00317             fval = fgFunc->DataElement( x, i, &gf[0]);
00318          }
00319          else { 
00320             if (fgFunc != 0) 
00321                fval = fgFunc->DataElement(x, i, &gf[0]);
00322             else 
00323                fval = fgGradFunc->DataElement(x, i, &gf[0]);
00324          }
00325 
00326          // t.b.d should protect for bad  values of fval
00327          sum += fval*fval;
00328 
00329          // to be check (TFumili uses a factor of 1/2 for chi2)
00330 
00331          for (unsigned int j = 0; j < npar; ++j) { 
00332             grad[j] +=  fval * gf[j];
00333             for (unsigned int k = j; k < npar; ++ k) { 
00334                int idx =  j + k*(k+1)/2; 
00335                hess[idx] += gf[j] * gf[k];  
00336             }
00337          }
00338       }
00339    }
00340    else if ( (fgFunc && fgFunc->Type() == ROOT::Math::FitMethodFunction::kLogLikelihood) || 
00341              (fgGradFunc && fgGradFunc->Type() == ROOT::Math::FitMethodGradFunction::kLogLikelihood) ) {  
00342 
00343 
00344 
00345       double fval = 0; 
00346 
00347       //std::cout << "\t x "  << x[0] << "  " << x[1] << "  " << x[2] << std::endl; 
00348 
00349       for (unsigned int i = 0; i < ndata; ++i) { 
00350 
00351          if (gUseFumiliFunction) {
00352             fval = fgFunc->DataElement( x, i, &gf[0]);
00353          }
00354          else { 
00355             // calculate data element and gradient 
00356             if (fgFunc != 0) 
00357                fval = fgFunc->DataElement(x, i, &gf[0]);
00358             else 
00359                fval = fgGradFunc->DataElement(x, i, &gf[0]);
00360          }
00361 
00362          // protect for small values of fval
00363          //      std::cout << i << "  "  << fval << " log " << " grad " << gf[0] << "  " << gf[1] << "  " << gf[2] << std::endl; 
00364 //         sum -= ROOT::Math::Util::EvalLog(fval);
00365          sum -= fval;
00366          
00367          for (unsigned int j = 0; j < npar; ++j) { 
00368             double gfj = gf[j];// / fval; 
00369             grad[j] -= gfj;
00370             for (unsigned int k = j; k < npar; ++ k) { 
00371                int idx =  j + k*(k+1)/2;   
00372                hess[idx] +=  gfj * gf[k];// / (fval );  
00373             }
00374          }
00375       }
00376    }
00377    else { 
00378       Error("EvaluateFCN"," type of fit method is not supported, it must be chi2 or log-likelihood");
00379    }
00380 
00381    // now TFumili excludes fixed prameter in second-derivative matrix
00382    // ned to get them using the static instance of TFumili
00383    double * zmatrix = fgFumili->GetZ(); 
00384    double * pl0 = fgFumili->GetPL0(); // parameter limits
00385    assert(zmatrix != 0); 
00386    assert(pl0 != 0); 
00387    unsigned int k = 0; 
00388    unsigned int l = 0;
00389    for (unsigned int i = 0; i < npar; ++i) { 
00390          for (unsigned int j = 0; j <= i; ++j) { 
00391             if (pl0[i] > 0 && pl0[j] > 0) { // only for non-fixed parameters         
00392                zmatrix[l++] = hess[k]; 
00393             }
00394             k++;
00395          }
00396    }
00397 
00398 #ifdef DEBUG
00399    std::cout << "FCN value " << sum << " grad ";
00400    for (unsigned int ipar = 0; ipar < npar; ++ipar) 
00401       std::cout << grad[ipar] << "\t";
00402    std::cout << std::endl << std::endl;   
00403 #endif
00404 
00405 
00406    return 0.5*sum; // fumili multiply then by 2 
00407 
00408 }
00409 
00410 
00411 
00412 bool TFumiliMinimizer::SetVariable(unsigned int ivar, const std::string & name, double val, double step) { 
00413    // set a free variable.
00414    if (fFumili == 0) { 
00415       Error("SetVariableValue","invalid TFumili pointer. Set function first ");
00416       return false; 
00417    }
00418 #ifdef DEBUG
00419    std::cout << "set variable " << ivar << " " << name << " value " << val << " step " << step << std::endl; 
00420 #endif
00421 
00422    int ierr = fFumili->SetParameter(ivar , name.c_str(), val, step, 0., 0. ); 
00423    if (ierr) { 
00424       Error("SetVariable","Error for parameter %d ",ivar);
00425       return false; 
00426    }
00427    return true; 
00428 }
00429 
00430 bool TFumiliMinimizer::SetLimitedVariable(unsigned int ivar, const std::string & name, double val, double step, double lower, double upper) { 
00431    // set a limited variable.
00432    if (fFumili == 0) { 
00433       Error("SetVariableValue","invalid TFumili pointer. Set function first ");
00434       return false; 
00435    }
00436 #ifdef DEBUG
00437    std::cout << "set limited variable " << ivar << " " << name << " value " << val << " step " << step << std::endl; 
00438 #endif
00439    int ierr = fFumili->SetParameter(ivar, name.c_str(), val, step, lower, upper ); 
00440    if (ierr) { 
00441       Error("SetLimitedVariable","Error for parameter %d ",ivar);
00442       return false; 
00443    }
00444    return true; 
00445 }
00446 #ifdef LATER
00447 bool Fumili2Minimizer::SetLowerLimitedVariable(unsigned int ivar , const std::string & name , double val , double step , double lower ) {
00448     // add a lower bounded variable as a double bound one, using a very large number for the upper limit
00449    double s = val-lower; 
00450    double upper = s*1.0E15; 
00451    if (s != 0)  upper = 1.0E15;
00452    return SetLimitedVariable(ivar, name, val, step, lower,upper);
00453 }
00454 #endif
00455 
00456 
00457 bool TFumiliMinimizer::SetFixedVariable(unsigned int ivar, const std::string & name, double val) { 
00458    // set a fixed variable.
00459    if (fFumili == 0) { 
00460       Error("SetVariableValue","invalid TFumili pointer. Set function first ");
00461       return false; 
00462    }
00463 
00464    
00465    int ierr = fFumili->SetParameter(ivar, name.c_str(), val, 0., val, val ); 
00466    fFumili->FixParameter(ivar);
00467 
00468 #ifdef DEBUG
00469    std::cout << "Fix variable " << ivar << " " << name << " value " << std::endl; 
00470 #endif
00471 
00472    if (ierr) { 
00473       Error("SetFixedVariable","Error for parameter %d ",ivar);
00474       return false; 
00475    }
00476    return true; 
00477 }
00478 
00479 bool TFumiliMinimizer::SetVariableValue(unsigned int ivar, double val) { 
00480    // set the variable value
00481    if (fFumili == 0) { 
00482       Error("SetVariableValue","invalid TFumili pointer. Set function first ");
00483       return false; 
00484    }
00485    TString name = fFumili->GetParName(ivar);
00486    double  oldval, verr, vlow, vhigh = 0; 
00487    int ierr = fFumili->GetParameter( ivar, &name[0], oldval, verr, vlow, vhigh); 
00488    if (ierr) {
00489       Error("SetVariableValue","Error for parameter %d ",ivar);
00490       return false; 
00491    }
00492 #ifdef DEBUG
00493    std::cout << "set variable " << ivar << " " << name << " value " 
00494              << val << " step " <<  verr << std::endl; 
00495 #endif
00496 
00497    ierr = fFumili->SetParameter(ivar , name , val, verr, vlow, vhigh ); 
00498    if (ierr) { 
00499       Error("SetVariableValue","Error for parameter %d ",ivar);
00500       return false; 
00501    }
00502    return true; 
00503 }
00504 
00505 bool TFumiliMinimizer::Minimize() { 
00506    // perform the minimization using the algorithm chosen previously by the user  
00507    // By default Migrad is used. 
00508    // Return true if the found minimum is valid and update internal chached values of 
00509    // minimum values, errors and covariance matrix. 
00510 
00511    if (fFumili == 0) { 
00512       Error("SetVariableValue","invalid TFumili pointer. Set function first ");
00513       return false; 
00514    }
00515 
00516    // need to set static instance to be used when calling FCN 
00517    fgFumili = fFumili; 
00518 
00519 
00520    double arglist[10]; 
00521 
00522    // error cannot be set in TFumili (always the same)
00523 //    arglist[0] = ErrorUp(); 
00524 //    fFumili->ExecuteCommand("SET Err",arglist,1);
00525 
00526    int printlevel = PrintLevel(); 
00527    // not implemented in TFumili yet 
00528    //arglist[0] = printlevel - 1;
00529    //fFumili->ExecuteCommand("SET PRINT",arglist,1,ierr);
00530 
00531    // suppress warning in case Printlevel() == 0
00532    if (printlevel == 0)    fFumili->ExecuteCommand("SET NOW",arglist,0);
00533    else fFumili->ExecuteCommand("SET WAR",arglist,0);
00534 
00535 
00536    // minimize: use ExecuteCommand instead of Minimize to set tolerance and maxiter
00537 
00538    arglist[0] = MaxFunctionCalls(); 
00539    arglist[1] = Tolerance(); 
00540 
00541    if (printlevel > 0) 
00542       std::cout << "Minimize using TFumili with tolerance = " << Tolerance() 
00543                 << " max calls " << MaxFunctionCalls() << std::endl; 
00544 
00545    int iret = fFumili->ExecuteCommand("MIGRAD",arglist,2);
00546    fStatus = iret; 
00547    //int iret = fgFumili->Minimize(); 
00548    
00549    // Hesse and IMP not implemented 
00550 //    // run improved if needed
00551 //    if (ierr == 0 && fType == ROOT::Fumili::kMigradImproved) 
00552 //       fFumili->mnexcm("IMPROVE",arglist,1,ierr);
00553 
00554 //    // check if Hesse needs to be run 
00555 //    if (ierr == 0 && IsValidError() ) { 
00556 //       fFumili->mnexcm("HESSE",arglist,1,ierr);
00557 //    }
00558 
00559 
00560    int ntot; 
00561    int nfree; 
00562    double errdef = 0; // err def is not used by Fumili
00563    fFumili->GetStats(fMinVal,fEdm,errdef,nfree,ntot);
00564 
00565    if (printlevel > 0) 
00566       fFumili->PrintResults(printlevel,fMinVal);
00567 
00568 
00569    assert (static_cast<unsigned int>(ntot) == fDim); 
00570    assert( nfree == fFumili->GetNumberFreeParameters() );
00571    fNFree = nfree;
00572    
00573 
00574    // get parameter values and correlation matrix
00575    // fumili stores only lower part of diagonal matrix of the free parameters
00576    fParams.resize( fDim); 
00577    fErrors.resize( fDim); 
00578    fCovar.resize(fDim*fDim); 
00579    const double * cv = fFumili->GetCovarianceMatrix(); 
00580    unsigned int l = 0; 
00581    for (unsigned int i = 0; i < fDim; ++i) { 
00582       fParams[i] = fFumili->GetParameter( i );  
00583       fErrors[i] = fFumili->GetParError( i );  
00584 
00585       if ( !fFumili->IsFixed(i) ) { 
00586          for (unsigned int j = 0; j <=i ; ++j) { 
00587             if ( !fFumili->IsFixed(j) ) {  
00588                fCovar[i*fDim + j] = cv[l];
00589                fCovar[j*fDim + i] = fCovar[i*fDim + j]; 
00590                l++;
00591             }
00592          }
00593       }
00594    }
00595 
00596    return (iret==0) ? true : false;
00597 }
00598 
00599 
00600 //    } // end namespace Fit
00601 
00602 // } // end namespace ROOT
00603 

Generated on Tue Jul 5 14:30:51 2011 for ROOT_528-00b_version by  doxygen 1.5.1