/***************************************************************************** 
  * 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 RooProjectedPdf is a RooAbsPdf implementation that represent a projection 
// of a given input p.d.f and the object returned by RooAbsPdf::createProjection.
// <p>
// The actual projection integral for it value and normalization are
// calculated on the fly in getVal() once the normalization observables are known.
// Class RooProjectedPdf can cache projected p.d.f.s for multiple normalization
// observables simultaneously.
// <p>
// The createProjection() method of RooProjectedPdf is overloaded and will
// return a new RooProjectedPdf that performs the projection of itself
// and the requested additional projections in one integration step
// The performance of <pre>f->createProjection(x)->createProjection(y)</pre>
// is therefore identical to that of <pre>f->createProjection(RooArgSet(x,y))</pre>
// END_HTML
//

#include "Riostream.h" 

#include "RooFit.h"
#include "RooProjectedPdf.h" 
#include "RooMsgService.h"
#include "RooAbsReal.h" 
#include "RooRealVar.h"
#include "RooNameReg.h"

using namespace std;

 ClassImp(RooProjectedPdf) 
   ;


//_____________________________________________________________________________
RooProjectedPdf::RooProjectedPdf() : _curNormSet(0)
{
  // Default constructor
}



//_____________________________________________________________________________
 RooProjectedPdf::RooProjectedPdf(const char *name, const char *title, RooAbsReal& _intpdf, const RooArgSet& intObs) :
   RooAbsPdf(name,title), 
   intpdf("!IntegratedPdf","intpdf",this,_intpdf,kFALSE,kFALSE),
   intobs("!IntegrationObservables","intobs",this,kFALSE,kFALSE),
   deps("!Dependents","deps",this,kTRUE,kTRUE),
   _cacheMgr(this,10)
 { 
   // Construct projection of input pdf '_intpdf' over observables 'intObs'

   intobs.add(intObs) ;

   // Add all other dependens of projected p.d.f. directly
   RooArgSet* tmpdeps = _intpdf.getParameters(intObs) ;
   deps.add(*tmpdeps) ;
   delete tmpdeps ;
 } 



//_____________________________________________________________________________
 RooProjectedPdf::RooProjectedPdf(const RooProjectedPdf& other, const char* name) :  
   RooAbsPdf(other,name), 
   intpdf("!IntegratedPdf",this,other.intpdf),
   intobs("!IntegrationObservable",this,other.intobs),
   deps("!Dependents",this,other.deps),
   _cacheMgr(other._cacheMgr,this)
{ 
   // Copy constructor
 } 



//_____________________________________________________________________________
Double_t RooProjectedPdf::getValV(const RooArgSet* set) const 
{
  // Special version of getVal() overrides RooAbsReal::getValF() to save value of current normalization set

  _curNormSet = (RooArgSet*)set ;

  return RooAbsPdf::getValV(set) ;
}



//_____________________________________________________________________________
Double_t RooProjectedPdf::evaluate() const 
{
  // Evaluate projected p.d.f

  // Calculate current unnormalized value of object
  int code ;
  const RooAbsReal* proj = getProjection(&intobs,_curNormSet,0,code) ;
  
  return proj->getVal() ;
}



//_____________________________________________________________________________
const RooAbsReal* RooProjectedPdf::getProjection(const RooArgSet* iset, const RooArgSet* nset, const char* rangeName, int& code) const
{
  // Retrieve object representing projection integral of input p.d.f
  // over observables iset, while normalizing over observables
  // nset. The code argument returned by reference is the unique code
  // defining this particular projection configuration


  // Check if this configuration was created before
  Int_t sterileIdx(-1) ;
  CacheElem* cache = (CacheElem*) _cacheMgr.getObj(iset,nset,&sterileIdx,RooNameReg::ptr(rangeName)) ;
  if (cache) {
    code = _cacheMgr.lastIndex() ;
    return static_cast<const RooAbsReal*>(cache->_projection);
  }

  RooArgSet* nset2 =  intpdf.arg().getObservables(*nset) ;

  if (iset) {
    nset2->add(*iset) ;
  }
  RooAbsReal* proj = intpdf.arg().createIntegral(iset?*iset:RooArgSet(),nset2,0,rangeName) ;
  delete nset2 ;

  cache = new CacheElem ;
  cache->_projection = proj ;

  code = _cacheMgr.setObj(iset,nset,(RooAbsCacheElement*)cache,RooNameReg::ptr(rangeName)) ;

  coutI(Integration) << "RooProjectedPdf::getProjection(" << GetName() << ") creating new projection " << proj->GetName() << " with code " << code << endl ;

  return proj ;
}



//_____________________________________________________________________________
RooAbsPdf* RooProjectedPdf::createProjection(const RooArgSet& iset) 
{
  // Special version of RooAbsReal::createProjection that deals with
  // projections of projections. Instead of integrating twice, a new
  // RooProjectedPdf is returned that is configured to perform the
  // complete integration in one step

  RooArgSet combiset(iset) ;
  combiset.add(intobs) ;
  return static_cast<RooAbsPdf&>( const_cast<RooAbsReal&>(intpdf.arg()) ).createProjection(combiset) ;
}



//_____________________________________________________________________________
Bool_t RooProjectedPdf::forceAnalyticalInt(const RooAbsArg& /*dep*/) const 
{
  // Force RooRealIntegral to relegate integration of all observables to internal logic

  return kTRUE ;
}



//_____________________________________________________________________________
Int_t RooProjectedPdf::getAnalyticalIntegralWN(RooArgSet& allVars, RooArgSet& analVars, const RooArgSet* normSet, const char* rangeName) const 
{ 
  // Mark all requested variables as internally integrated

  analVars.add(allVars) ;
  
  // Create the appropriate integral
  int code ;
  RooArgSet allVars2(allVars) ;
  allVars2.add(intobs) ;
  getProjection(&allVars2,normSet,rangeName,code) ;
  
  return code+1 ; 
} 



//_____________________________________________________________________________
Double_t RooProjectedPdf::analyticalIntegralWN(Int_t code, const RooArgSet* /*normSet*/, const char* rangeName) const 
{ 
  // Return analytical integral represent by appropriate element of projection cache
  
  CacheElem *cache = (CacheElem*) _cacheMgr.getObjByIndex(code-1) ;
  
  if (cache) {
    Double_t ret= cache->_projection->getVal() ;
    return ret ;
  } else {
    
    RooArgSet* vars = getParameters(RooArgSet()) ;
    vars->add(intobs) ;
    RooArgSet* iset = _cacheMgr.nameSet1ByIndex(code-1)->select(*vars) ;
    RooArgSet* nset = _cacheMgr.nameSet2ByIndex(code-1)->select(*vars) ;
    
    Int_t code2(-1) ;
    const RooAbsReal* proj = getProjection(iset,nset,rangeName,code2) ;
    
    delete vars ;
    delete nset ;
    delete iset ;
    
    Double_t ret =  proj->getVal() ;
    return ret ;
  } 
  
} 



//_____________________________________________________________________________
Int_t RooProjectedPdf::getGenerator(const RooArgSet& /*directVars*/, RooArgSet& /*generateVars*/, Bool_t /*staticInitOK*/) const 
 { 
   // No internal generator is implemented
   return 0 ; 
 } 



//_____________________________________________________________________________
void RooProjectedPdf::generateEvent(Int_t /*code*/) 
 { 
   // No internal generator is implemented
   return; 
 } 



//_____________________________________________________________________________
Bool_t RooProjectedPdf::redirectServersHook(const RooAbsCollection& newServerList, Bool_t /*mustReplaceAll*/, 
				       Bool_t /*nameChange*/, Bool_t /*isRecursive*/) 
{
  // Intercept a server redirection all and update list of dependents if necessary 
  // Specifically update the set proxy 'deps' which introduces the dependency
  // on server value dirty flags of ourselves

  // Redetermine explicit list of dependents if intPdf is being replaced
  RooAbsArg* newPdf = newServerList.find(intpdf.arg().GetName()) ;
  if (newPdf) {

    // Determine if set of dependens of new p.d.f is different from old p.d.f.
    RooArgSet olddeps(deps) ;
    RooArgSet* newdeps = newPdf->getParameters(intobs) ;
    RooArgSet* common = (RooArgSet*) newdeps->selectCommon(deps) ;    
    newdeps->remove(*common,kTRUE,kTRUE) ;
    olddeps.remove(*common,kTRUE,kTRUE) ;

    // If so, adjust composition of deps Listproxy
    if (newdeps->getSize()>0) {
      deps.add(*newdeps) ;
    }
    if (olddeps.getSize()>0) {
      deps.remove(olddeps,kTRUE,kTRUE) ;
    }

    delete common ;
    delete newdeps ;
  }

  return kFALSE ;
}



//_____________________________________________________________________________
RooArgList RooProjectedPdf::CacheElem::containedArgs(Action)
{
  // Return RooAbsArg elements contained in projection cache element.
  RooArgList ret(*_projection) ;  
  return ret ;
}



//_____________________________________________________________________________
void RooProjectedPdf::printMetaArgs(ostream& os) const
{
  // Customized printing of arguments of a RooRealIntegral to more intuitively reflect the contents of the
  // integration operation

  os << "Int " << intpdf.arg().GetName() ;
 
  os << " d" ;
  os << intobs ;
  os << " " ;
  
}




//_____________________________________________________________________________
void RooProjectedPdf::CacheElem::printCompactTreeHook(ostream& os, const char* indent, Int_t curElem, Int_t maxElem) 
{
  // Print contents of cache when printing self as part of object tree
  
  if (curElem==0) {
    os << indent << "RooProjectedPdf begin projection cache" << endl ;
  }

  TString indent2(indent) ;
  indent2 += Form("[%d] ",curElem) ;

  _projection->printCompactTree(os,indent2) ;

  if(curElem==maxElem) {
    os << indent << "RooProjectedPdf end projection cache" << endl ;
  }
}


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