/***************************************************************************** 
  * Project: RooFit                                                           * 
  *                                                                           * 
  * Copyright (c) 2000-2005, Regents of the University of California          * 
  *                          and Stanford University. All rights reserved.    * 
  *                                                                           * 
  * Redistribution and use in source and binary forms,                        * 
  * with or without modification, are permitted according to the terms        * 
  * listed in LICENSE (http://roofit.sourceforge.net/license.txt)             * 
  *****************************************************************************/ 

//////////////////////////////////////////////////////////////////////////////
//
// BEGIN_HTML
// Class RooProfileLL implements the profile likelihood estimator for
// a given likelihood and set of parameters of interest. The value return by 
// RooProfileLL is the input likelihood nll minimized w.r.t all nuisance parameters
// (which are all parameters except for those listed in the constructor) minus
// the -log(L) of the best fit. Note that this function is slow to evaluate
// as a MIGRAD minimization step is executed for each function evaluation
// END_HTML
//

#include "Riostream.h" 

#include "RooFit.h"
#include "RooProfileLL.h" 
#include "RooAbsReal.h" 
#include "RooMinuit.h"
#include "RooMinimizer.h"
#include "RooMsgService.h"
#include "RooRealVar.h"
#include "RooMsgService.h"

using namespace std ;

ClassImp(RooProfileLL) 


//_____________________________________________________________________________ 
 RooProfileLL::RooProfileLL() : 
   RooAbsReal("RooProfileLL","RooProfileLL"), 
   _nll(), 
   _obs("paramOfInterest","Parameters of interest",this), 
   _par("nuisanceParam","Nuisance parameters",this,kFALSE,kFALSE), 
   _startFromMin(kTRUE), 
   _minimizer(0), 
   _absMinValid(kFALSE), 
   _absMin(0),
   _neval(0)
{ 
  // Default constructor 
  // Should only be used by proof. 
  _piter = _par.createIterator() ; 
  _oiter = _obs.createIterator() ; 
} 


//_____________________________________________________________________________
RooProfileLL::RooProfileLL(const char *name, const char *title, 
			   RooAbsReal& nllIn, const RooArgSet& observables) :
  RooAbsReal(name,title), 
  _nll("input","-log(L) function",this,nllIn),
  _obs("paramOfInterest","Parameters of interest",this),
  _par("nuisanceParam","Nuisance parameters",this,kFALSE,kFALSE),
  _startFromMin(kTRUE),
  _minimizer(0),
  _absMinValid(kFALSE),
  _absMin(0),
  _neval(0)
{ 
  // Constructor of profile likelihood given input likelihood nll w.r.t
  // the given set of variables. The input log likelihood is minimized w.r.t
  // to all other variables of the likelihood at each evaluation and the
  // value of the global log likelihood minimum is always subtracted.

  // Determine actual parameters and observables
  RooArgSet* actualObs = nllIn.getObservables(observables) ;
  RooArgSet* actualPars = nllIn.getParameters(observables) ;

  _obs.add(*actualObs) ;
  _par.add(*actualPars) ;

  delete actualObs ;
  delete actualPars ;

  _piter = _par.createIterator() ;
  _oiter = _obs.createIterator() ;
} 



//_____________________________________________________________________________
RooProfileLL::RooProfileLL(const RooProfileLL& other, const char* name) :  
  RooAbsReal(other,name), 
  _nll("nll",this,other._nll),
  _obs("obs",this,other._obs),
  _par("par",this,other._par),
  _startFromMin(other._startFromMin),
  _minimizer(0),
  _absMinValid(kFALSE),
  _absMin(0),
  _paramFixed(other._paramFixed),
  _neval(0)
{ 
  // Copy constructor

  _piter = _par.createIterator() ;
  _oiter = _obs.createIterator() ;

  _paramAbsMin.addClone(other._paramAbsMin) ;
  _obsAbsMin.addClone(other._obsAbsMin) ;
    
} 



//_____________________________________________________________________________
RooProfileLL::~RooProfileLL()
{
  // Destructor

  // Delete instance of minuit if it was ever instantiated
  if (_minimizer) {
    delete _minimizer ;
  }

  delete _piter ;
  delete _oiter ;
}




//_____________________________________________________________________________
const RooArgSet& RooProfileLL::bestFitParams() const 
{
  validateAbsMin() ;
  return _paramAbsMin ;
}


//_____________________________________________________________________________
const RooArgSet& RooProfileLL::bestFitObs() const 
{
  validateAbsMin() ;
  return _obsAbsMin ;
}




//_____________________________________________________________________________
RooAbsReal* RooProfileLL::createProfile(const RooArgSet& paramsOfInterest) 
{
  // Optimized implementation of createProfile for profile likelihoods.
  // Return profile of original function in terms of stated parameters 
  // of interest rather than profiling recursively.

  return nll().createProfile(paramsOfInterest) ;
}




//_____________________________________________________________________________
void RooProfileLL::initializeMinimizer() const
{
  coutI(Minimization) << "RooProfileLL::evaluate(" << GetName() << ") Creating instance of MINUIT" << endl ;
  
  Bool_t smode = RooMsgService::instance().silentMode() ;
  RooMsgService::instance().setSilentMode(kTRUE) ;
  _minimizer = new MINIMIZER(const_cast<RooAbsReal&>(_nll.arg())) ;
  if (!smode) RooMsgService::instance().setSilentMode(kFALSE) ;
  
  //_minimizer->setPrintLevel(-999) ;
  //_minimizer->setNoWarn() ;
  //_minimizer->setVerbose(1) ;
}



//_____________________________________________________________________________
Double_t RooProfileLL::evaluate() const 
{ 
  // Evaluate profile likelihood by minimizing likelihood w.r.t. all
  // parameters that are not considered observables of this profile
  // likelihood object.

  // Instantiate minimizer if we haven't done that already
  if (!_minimizer) {
    initializeMinimizer() ;
  }

  // Save current value of observables
  RooArgSet* obsSetOrig = (RooArgSet*) _obs.snapshot() ;

  validateAbsMin() ;

  
  // Set all observables constant in the minimization
  const_cast<RooSetProxy&>(_obs).setAttribAll("Constant",kTRUE) ;  
  ccoutP(Eval) << "." ; ccoutP(Eval).flush() ;

  // If requested set initial parameters to those corresponding to absolute minimum
  if (_startFromMin) {
    const_cast<RooProfileLL&>(*this)._par = _paramAbsMin ;
  }

  _minimizer->zeroEvalCount() ;

  //TString minim=::ROOT::Math::MinimizerOptions::DefaultMinimizerType().c_str();
  //TString algorithm = ROOT::Math::MinimizerOptions::DefaultMinimizerAlgo().c_str();
  //if (algorithm == "Migrad") algorithm = "Minimize"; // prefer to use Minimize instead of Migrad
  //_minimizer->minimize(minim.Data(),algorithm.Data());
  
  _minimizer->migrad() ;
  _neval = _minimizer->evalCounter() ;

  // Restore original values and constant status of observables
  TIterator* iter = obsSetOrig->createIterator() ;
  RooRealVar* var ;
  while((var=(RooRealVar*)iter->Next())) {
    RooRealVar* target = (RooRealVar*) _obs.find(var->GetName()) ;
    target->setVal(var->getVal()) ;
    target->setConstant(var->isConstant()) ;
  }
  delete iter ;
  delete obsSetOrig ;

  return _nll - _absMin ; 
} 



//_____________________________________________________________________________
void RooProfileLL::validateAbsMin() const 
{
  // Check that parameters and likelihood value for 'best fit' are still valid. If not,
  // because the best fit has never been calculated, or because constant parameters have
  // changed value or parameters have changed const/float status, the minimum is recalculated

  // Check if constant status of any of the parameters have changed
  if (_absMinValid) {
    _piter->Reset() ;
    RooAbsArg* par ;
    while((par=(RooAbsArg*)_piter->Next())) {
      if (_paramFixed[par->GetName()] != par->isConstant()) {
	cxcoutI(Minimization) << "RooProfileLL::evaluate(" << GetName() << ") constant status of parameter " << par->GetName() << " has changed from " 
				<< (_paramFixed[par->GetName()]?"fixed":"floating") << " to " << (par->isConstant()?"fixed":"floating") 
				<< ", recalculating absolute minimum" << endl ;
	_absMinValid = kFALSE ;
	break ;
      }
    }
  }


  // If we don't have the absolute minimum w.r.t all observables, calculate that first
  if (!_absMinValid) {

    cxcoutI(Minimization) << "RooProfileLL::evaluate(" << GetName() << ") determining minimum likelihood for current configurations w.r.t all observable" << endl ;

    
    if (!_minimizer) {
      initializeMinimizer() ;
    }
    
    // Save current values of non-marginalized parameters
    RooArgSet* obsStart = (RooArgSet*) _obs.snapshot(kFALSE) ;

    // Start from previous global minimum 
    if (_paramAbsMin.getSize()>0) {
      const_cast<RooSetProxy&>(_par).assignValueOnly(_paramAbsMin) ;
    }
    if (_obsAbsMin.getSize()>0) {
      const_cast<RooSetProxy&>(_obs).assignValueOnly(_obsAbsMin) ;
    }

    // Find minimum with all observables floating
    const_cast<RooSetProxy&>(_obs).setAttribAll("Constant",kFALSE) ;  
    
    //TString minim=::ROOT::Math::MinimizerOptions::DefaultMinimizerType().c_str();
    //TString algorithm = ROOT::Math::MinimizerOptions::DefaultMinimizerAlgo().c_str();
    //if (algorithm == "Migrad") algorithm = "Minimize"; // prefer to use Minimize instead of Migrad
    //_minimizer->minimize(minim.Data(),algorithm.Data());
    _minimizer->migrad() ;

    // Save value and remember
    _absMin = _nll ;
    _absMinValid = kTRUE ;

    // Save parameter values at abs minimum as well
    _paramAbsMin.removeAll() ;

    // Only store non-constant parameters here!
    RooArgSet* tmp = (RooArgSet*) _par.selectByAttrib("Constant",kFALSE) ;
    _paramAbsMin.addClone(*tmp) ;
    delete tmp ;

    _obsAbsMin.addClone(_obs) ;

    // Save constant status of all parameters
    _piter->Reset() ;
    RooAbsArg* par ;
    while((par=(RooAbsArg*)_piter->Next())) {
      _paramFixed[par->GetName()] = par->isConstant() ;
    }
    
    if (dologI(Minimization)) {
      cxcoutI(Minimization) << "RooProfileLL::evaluate(" << GetName() << ") minimum found at (" ;

      RooAbsReal* arg ;
      Bool_t first=kTRUE ;
      _oiter->Reset() ;
      while ((arg=(RooAbsReal*)_oiter->Next())) {
	ccxcoutI(Minimization) << (first?"":", ") << arg->GetName() << "=" << arg->getVal() ;	
	first=kFALSE ;
      }      
      ccxcoutI(Minimization) << ")" << endl ;            
    }

    // Restore original parameter values
    const_cast<RooSetProxy&>(_obs) = *obsStart ;
    delete obsStart ;

  }
}



//_____________________________________________________________________________
Bool_t RooProfileLL::redirectServersHook(const RooAbsCollection& /*newServerList*/, Bool_t /*mustReplaceAll*/, 
					 Bool_t /*nameChange*/, Bool_t /*isRecursive*/) 
{ 
  if (_minimizer) {
    delete _minimizer ;
    _minimizer = 0 ;
  }
  return kFALSE ;
} 


 RooProfileLL.cxx:1
 RooProfileLL.cxx:2
 RooProfileLL.cxx:3
 RooProfileLL.cxx:4
 RooProfileLL.cxx:5
 RooProfileLL.cxx:6
 RooProfileLL.cxx:7
 RooProfileLL.cxx:8
 RooProfileLL.cxx:9
 RooProfileLL.cxx:10
 RooProfileLL.cxx:11
 RooProfileLL.cxx:12
 RooProfileLL.cxx:13
 RooProfileLL.cxx:14
 RooProfileLL.cxx:15
 RooProfileLL.cxx:16
 RooProfileLL.cxx:17
 RooProfileLL.cxx:18
 RooProfileLL.cxx:19
 RooProfileLL.cxx:20
 RooProfileLL.cxx:21
 RooProfileLL.cxx:22
 RooProfileLL.cxx:23
 RooProfileLL.cxx:24
 RooProfileLL.cxx:25
 RooProfileLL.cxx:26
 RooProfileLL.cxx:27
 RooProfileLL.cxx:28
 RooProfileLL.cxx:29
 RooProfileLL.cxx:30
 RooProfileLL.cxx:31
 RooProfileLL.cxx:32
 RooProfileLL.cxx:33
 RooProfileLL.cxx:34
 RooProfileLL.cxx:35
 RooProfileLL.cxx:36
 RooProfileLL.cxx:37
 RooProfileLL.cxx:38
 RooProfileLL.cxx:39
 RooProfileLL.cxx:40
 RooProfileLL.cxx:41
 RooProfileLL.cxx:42
 RooProfileLL.cxx:43
 RooProfileLL.cxx:44
 RooProfileLL.cxx:45
 RooProfileLL.cxx:46
 RooProfileLL.cxx:47
 RooProfileLL.cxx:48
 RooProfileLL.cxx:49
 RooProfileLL.cxx:50
 RooProfileLL.cxx:51
 RooProfileLL.cxx:52
 RooProfileLL.cxx:53
 RooProfileLL.cxx:54
 RooProfileLL.cxx:55
 RooProfileLL.cxx:56
 RooProfileLL.cxx:57
 RooProfileLL.cxx:58
 RooProfileLL.cxx:59
 RooProfileLL.cxx:60
 RooProfileLL.cxx:61
 RooProfileLL.cxx:62
 RooProfileLL.cxx:63
 RooProfileLL.cxx:64
 RooProfileLL.cxx:65
 RooProfileLL.cxx:66
 RooProfileLL.cxx:67
 RooProfileLL.cxx:68
 RooProfileLL.cxx:69
 RooProfileLL.cxx:70
 RooProfileLL.cxx:71
 RooProfileLL.cxx:72
 RooProfileLL.cxx:73
 RooProfileLL.cxx:74
 RooProfileLL.cxx:75
 RooProfileLL.cxx:76
 RooProfileLL.cxx:77
 RooProfileLL.cxx:78
 RooProfileLL.cxx:79
 RooProfileLL.cxx:80
 RooProfileLL.cxx:81
 RooProfileLL.cxx:82
 RooProfileLL.cxx:83
 RooProfileLL.cxx:84
 RooProfileLL.cxx:85
 RooProfileLL.cxx:86
 RooProfileLL.cxx:87
 RooProfileLL.cxx:88
 RooProfileLL.cxx:89
 RooProfileLL.cxx:90
 RooProfileLL.cxx:91
 RooProfileLL.cxx:92
 RooProfileLL.cxx:93
 RooProfileLL.cxx:94
 RooProfileLL.cxx:95
 RooProfileLL.cxx:96
 RooProfileLL.cxx:97
 RooProfileLL.cxx:98
 RooProfileLL.cxx:99
 RooProfileLL.cxx:100
 RooProfileLL.cxx:101
 RooProfileLL.cxx:102
 RooProfileLL.cxx:103
 RooProfileLL.cxx:104
 RooProfileLL.cxx:105
 RooProfileLL.cxx:106
 RooProfileLL.cxx:107
 RooProfileLL.cxx:108
 RooProfileLL.cxx:109
 RooProfileLL.cxx:110
 RooProfileLL.cxx:111
 RooProfileLL.cxx:112
 RooProfileLL.cxx:113
 RooProfileLL.cxx:114
 RooProfileLL.cxx:115
 RooProfileLL.cxx:116
 RooProfileLL.cxx:117
 RooProfileLL.cxx:118
 RooProfileLL.cxx:119
 RooProfileLL.cxx:120
 RooProfileLL.cxx:121
 RooProfileLL.cxx:122
 RooProfileLL.cxx:123
 RooProfileLL.cxx:124
 RooProfileLL.cxx:125
 RooProfileLL.cxx:126
 RooProfileLL.cxx:127
 RooProfileLL.cxx:128
 RooProfileLL.cxx:129
 RooProfileLL.cxx:130
 RooProfileLL.cxx:131
 RooProfileLL.cxx:132
 RooProfileLL.cxx:133
 RooProfileLL.cxx:134
 RooProfileLL.cxx:135
 RooProfileLL.cxx:136
 RooProfileLL.cxx:137
 RooProfileLL.cxx:138
 RooProfileLL.cxx:139
 RooProfileLL.cxx:140
 RooProfileLL.cxx:141
 RooProfileLL.cxx:142
 RooProfileLL.cxx:143
 RooProfileLL.cxx:144
 RooProfileLL.cxx:145
 RooProfileLL.cxx:146
 RooProfileLL.cxx:147
 RooProfileLL.cxx:148
 RooProfileLL.cxx:149
 RooProfileLL.cxx:150
 RooProfileLL.cxx:151
 RooProfileLL.cxx:152
 RooProfileLL.cxx:153
 RooProfileLL.cxx:154
 RooProfileLL.cxx:155
 RooProfileLL.cxx:156
 RooProfileLL.cxx:157
 RooProfileLL.cxx:158
 RooProfileLL.cxx:159
 RooProfileLL.cxx:160
 RooProfileLL.cxx:161
 RooProfileLL.cxx:162
 RooProfileLL.cxx:163
 RooProfileLL.cxx:164
 RooProfileLL.cxx:165
 RooProfileLL.cxx:166
 RooProfileLL.cxx:167
 RooProfileLL.cxx:168
 RooProfileLL.cxx:169
 RooProfileLL.cxx:170
 RooProfileLL.cxx:171
 RooProfileLL.cxx:172
 RooProfileLL.cxx:173
 RooProfileLL.cxx:174
 RooProfileLL.cxx:175
 RooProfileLL.cxx:176
 RooProfileLL.cxx:177
 RooProfileLL.cxx:178
 RooProfileLL.cxx:179
 RooProfileLL.cxx:180
 RooProfileLL.cxx:181
 RooProfileLL.cxx:182
 RooProfileLL.cxx:183
 RooProfileLL.cxx:184
 RooProfileLL.cxx:185
 RooProfileLL.cxx:186
 RooProfileLL.cxx:187
 RooProfileLL.cxx:188
 RooProfileLL.cxx:189
 RooProfileLL.cxx:190
 RooProfileLL.cxx:191
 RooProfileLL.cxx:192
 RooProfileLL.cxx:193
 RooProfileLL.cxx:194
 RooProfileLL.cxx:195
 RooProfileLL.cxx:196
 RooProfileLL.cxx:197
 RooProfileLL.cxx:198
 RooProfileLL.cxx:199
 RooProfileLL.cxx:200
 RooProfileLL.cxx:201
 RooProfileLL.cxx:202
 RooProfileLL.cxx:203
 RooProfileLL.cxx:204
 RooProfileLL.cxx:205
 RooProfileLL.cxx:206
 RooProfileLL.cxx:207
 RooProfileLL.cxx:208
 RooProfileLL.cxx:209
 RooProfileLL.cxx:210
 RooProfileLL.cxx:211
 RooProfileLL.cxx:212
 RooProfileLL.cxx:213
 RooProfileLL.cxx:214
 RooProfileLL.cxx:215
 RooProfileLL.cxx:216
 RooProfileLL.cxx:217
 RooProfileLL.cxx:218
 RooProfileLL.cxx:219
 RooProfileLL.cxx:220
 RooProfileLL.cxx:221
 RooProfileLL.cxx:222
 RooProfileLL.cxx:223
 RooProfileLL.cxx:224
 RooProfileLL.cxx:225
 RooProfileLL.cxx:226
 RooProfileLL.cxx:227
 RooProfileLL.cxx:228
 RooProfileLL.cxx:229
 RooProfileLL.cxx:230
 RooProfileLL.cxx:231
 RooProfileLL.cxx:232
 RooProfileLL.cxx:233
 RooProfileLL.cxx:234
 RooProfileLL.cxx:235
 RooProfileLL.cxx:236
 RooProfileLL.cxx:237
 RooProfileLL.cxx:238
 RooProfileLL.cxx:239
 RooProfileLL.cxx:240
 RooProfileLL.cxx:241
 RooProfileLL.cxx:242
 RooProfileLL.cxx:243
 RooProfileLL.cxx:244
 RooProfileLL.cxx:245
 RooProfileLL.cxx:246
 RooProfileLL.cxx:247
 RooProfileLL.cxx:248
 RooProfileLL.cxx:249
 RooProfileLL.cxx:250
 RooProfileLL.cxx:251
 RooProfileLL.cxx:252
 RooProfileLL.cxx:253
 RooProfileLL.cxx:254
 RooProfileLL.cxx:255
 RooProfileLL.cxx:256
 RooProfileLL.cxx:257
 RooProfileLL.cxx:258
 RooProfileLL.cxx:259
 RooProfileLL.cxx:260
 RooProfileLL.cxx:261
 RooProfileLL.cxx:262
 RooProfileLL.cxx:263
 RooProfileLL.cxx:264
 RooProfileLL.cxx:265
 RooProfileLL.cxx:266
 RooProfileLL.cxx:267
 RooProfileLL.cxx:268
 RooProfileLL.cxx:269
 RooProfileLL.cxx:270
 RooProfileLL.cxx:271
 RooProfileLL.cxx:272
 RooProfileLL.cxx:273
 RooProfileLL.cxx:274
 RooProfileLL.cxx:275
 RooProfileLL.cxx:276
 RooProfileLL.cxx:277
 RooProfileLL.cxx:278
 RooProfileLL.cxx:279
 RooProfileLL.cxx:280
 RooProfileLL.cxx:281
 RooProfileLL.cxx:282
 RooProfileLL.cxx:283
 RooProfileLL.cxx:284
 RooProfileLL.cxx:285
 RooProfileLL.cxx:286
 RooProfileLL.cxx:287
 RooProfileLL.cxx:288
 RooProfileLL.cxx:289
 RooProfileLL.cxx:290
 RooProfileLL.cxx:291
 RooProfileLL.cxx:292
 RooProfileLL.cxx:293
 RooProfileLL.cxx:294
 RooProfileLL.cxx:295
 RooProfileLL.cxx:296
 RooProfileLL.cxx:297
 RooProfileLL.cxx:298
 RooProfileLL.cxx:299
 RooProfileLL.cxx:300
 RooProfileLL.cxx:301
 RooProfileLL.cxx:302
 RooProfileLL.cxx:303
 RooProfileLL.cxx:304
 RooProfileLL.cxx:305
 RooProfileLL.cxx:306
 RooProfileLL.cxx:307
 RooProfileLL.cxx:308
 RooProfileLL.cxx:309
 RooProfileLL.cxx:310
 RooProfileLL.cxx:311
 RooProfileLL.cxx:312
 RooProfileLL.cxx:313
 RooProfileLL.cxx:314
 RooProfileLL.cxx:315
 RooProfileLL.cxx:316
 RooProfileLL.cxx:317
 RooProfileLL.cxx:318
 RooProfileLL.cxx:319
 RooProfileLL.cxx:320
 RooProfileLL.cxx:321
 RooProfileLL.cxx:322
 RooProfileLL.cxx:323
 RooProfileLL.cxx:324
 RooProfileLL.cxx:325
 RooProfileLL.cxx:326
 RooProfileLL.cxx:327
 RooProfileLL.cxx:328
 RooProfileLL.cxx:329
 RooProfileLL.cxx:330
 RooProfileLL.cxx:331
 RooProfileLL.cxx:332
 RooProfileLL.cxx:333
 RooProfileLL.cxx:334
 RooProfileLL.cxx:335
 RooProfileLL.cxx:336
 RooProfileLL.cxx:337
 RooProfileLL.cxx:338
 RooProfileLL.cxx:339
 RooProfileLL.cxx:340
 RooProfileLL.cxx:341
 RooProfileLL.cxx:342
 RooProfileLL.cxx:343