66 ClassImp(RooAbsOptTestStatistic);
73 RooAbsOptTestStatistic:: RooAbsOptTestStatistic()
109 RooAbsOptTestStatistic::RooAbsOptTestStatistic(
const char *name,
const char *title, RooAbsReal& real, RooAbsData& indata,
110 const RooArgSet& projDeps,
const char* rangeName,
const char* addCoefRangeName,
111 Int_t nCPU, RooFit::MPSplit interleave, Bool_t verbose, Bool_t splitCutRange, Bool_t ) :
112 RooAbsTestStatistic(name,title,real,indata,projDeps,rangeName, addCoefRangeName, nCPU, interleave, verbose, splitCutRange),
119 if (operMode()!=Slave) {
136 initSlave(real,indata,projDeps,rangeName,addCoefRangeName) ;
142 RooAbsOptTestStatistic::RooAbsOptTestStatistic(
const RooAbsOptTestStatistic& other,
const char* name) :
143 RooAbsTestStatistic(other,name), _sealed(other._sealed), _sealNotice(other._sealNotice), _optimized(kFALSE)
146 if (operMode()!=Slave) {
151 _normSet = other._normSet ? ((RooArgSet*) other._normSet->snapshot()) : 0 ;
164 initSlave(*other._funcClone,*other._dataClone,other._projDeps?*other._projDeps:RooArgSet(),other._rangeName.c_str(),other._addCoefRangeName.c_str()) ;
171 void RooAbsOptTestStatistic::initSlave(RooAbsReal& real, RooAbsData& indata,
const RooArgSet& projDeps,
const char* rangeName,
172 const char* addCoefRangeName)
174 RooArgSet obs(*indata.get()) ;
175 obs.remove(projDeps,kTRUE,kTRUE) ;
183 _funcClone = (RooAbsReal*) real.cloneTree() ;
187 _funcObsSet = _funcClone->getObservables(indata) ;
189 if (_funcClone->getAttribute(
"BinnedLikelihood")) {
190 _funcClone->setAttribute(
"BinnedLikelihoodActive") ;
194 RooArgSet* origParams = (RooArgSet*) real.getParameters(indata) ;
195 _funcClone->recursiveRedirectServers(*origParams) ;
198 if (projDeps.getSize()>0) {
199 RooArgSet *projDataDeps = (RooArgSet*) _funcObsSet->selectCommon(projDeps) ;
200 projDataDeps->setAttribAll(
"projectedDependent") ;
201 delete projDataDeps ;
208 RooProdPdf* pdfWithCons =
dynamic_cast<RooProdPdf*
>(_funcClone) ;
211 RooArgSet* connPars = pdfWithCons->getConnectedParameters(*indata.get()) ;
213 _paramSet.removeAll() ;
214 _paramSet.add(*connPars) ;
219 _paramSet.add(*origParams) ;
226 _normSet = (RooArgSet*) indata.get()->snapshot(kFALSE) ;
230 for (std::size_t i = 0; i < _funcObsSet->size(); ++i) {
231 auto realDepRLV =
dynamic_cast<const RooAbsRealLValue*
>((*_funcObsSet)[i]);
232 if (realDepRLV && realDepRLV->isDerived()) {
234 realDepRLV->leafNodeServerList(&tmp2, 0, kTRUE);
235 _funcObsSet->add(tmp2,kTRUE);
246 const RooArgSet* dataDepSet = indata.get() ;
247 for (
const auto arg : *_funcObsSet) {
250 RooRealVar* realReal =
dynamic_cast<RooRealVar*
>(arg) ;
251 if (!realReal) continue ;
252 RooRealVar* datReal =
dynamic_cast<RooRealVar*
>(dataDepSet->find(realReal->GetName())) ;
253 if (!datReal) continue ;
257 if (!realReal->getBinning().lowBoundFunc() && realReal->getMin()<(datReal->getMin()-1e-6)) {
258 coutE(InputArguments) <<
"RooAbsOptTestStatistic: ERROR minimum of FUNC observable " << arg->GetName()
259 <<
"(" << realReal->getMin() <<
") is smaller than that of "
260 << arg->GetName() <<
" in the dataset (" << datReal->getMin() <<
")" << endl ;
261 RooErrorHandler::softAbort() ;
265 if (!realReal->getBinning().highBoundFunc() && realReal->getMax()>(datReal->getMax()+1e-6)) {
266 coutE(InputArguments) <<
"RooAbsOptTestStatistic: ERROR maximum of FUNC observable " << arg->GetName()
267 <<
" is larger than that of " << arg->GetName() <<
" in the dataset" << endl ;
268 RooErrorHandler::softAbort() ;
275 if (rangeName && strlen(rangeName)) {
276 _dataClone = ((RooAbsData&)indata).reduce(RooFit::SelectVars(*_funcObsSet),RooFit::CutRange(rangeName)) ;
279 _dataClone = (RooAbsData*) indata.Clone() ;
288 RooArgSet* origObsSet = real.getObservables(indata) ;
289 RooArgSet* dataObsSet = (RooArgSet*) _dataClone->get() ;
290 if (rangeName && strlen(rangeName)) {
291 cxcoutI(Fitting) <<
"RooAbsOptTestStatistic::ctor(" << GetName() <<
") constructing test statistic for sub-range named " << rangeName << endl ;
295 for (
const auto arg : *_funcObsSet) {
297 RooRealVar* realObs =
dynamic_cast<RooRealVar*
>(arg) ;
301 if (!(addCoefRangeName && strlen(addCoefRangeName))) {
302 realObs->setRange(Form(
"NormalizationRangeFor%s",rangeName),realObs->getMin(),realObs->getMax()) ;
308 realObs->setRange(realObs->getMin(rangeName),realObs->getMax(rangeName)) ;
313 RooRealVar* dataObs = (RooRealVar*) dataObsSet->find(realObs->GetName()) ;
314 dataObs->setRange(realObs->getMin(rangeName),realObs->getMax(rangeName)) ;
318 const char* origAttrib = real.getStringAttribute(
"fitrange") ;
320 real.setStringAttribute(
"fitrange",Form(
"%s,fit_%s",origAttrib,GetName())) ;
322 real.setStringAttribute(
"fitrange",Form(
"fit_%s",GetName())) ;
324 RooRealVar* origObs = (RooRealVar*) origObsSet->find(arg->GetName()) ;
326 origObs->setRange(Form(
"fit_%s",GetName()),realObs->getMin(rangeName),realObs->getMax(rangeName)) ;
337 RooDataHist* tmph =
dynamic_cast<RooDataHist*
>(_dataClone) ;
339 tmph->cacheValidEntries() ;
343 if (rangeName && strlen(rangeName)) {
346 _funcClone->fixAddCoefNormalization(*_dataClone->get(),kFALSE) ;
348 if (addCoefRangeName && strlen(addCoefRangeName)) {
349 cxcoutI(Fitting) <<
"RooAbsOptTestStatistic::ctor(" << GetName()
350 <<
") fixing interpretation of coefficients of any RooAddPdf component to range " << addCoefRangeName << endl ;
351 _funcClone->fixAddCoefRange(addCoefRangeName,kFALSE) ;
353 cxcoutI(Fitting) <<
"RooAbsOptTestStatistic::ctor(" << GetName()
354 <<
") fixing interpretation of coefficients of any RooAddPdf to full domain of observables " << endl ;
355 _funcClone->fixAddCoefRange(Form(
"NormalizationRangeFor%s",rangeName),kFALSE) ;
361 _dataClone->attachBuffers(*_funcObsSet) ;
362 setEventCount(_dataClone->numEntries()) ;
372 if (projDeps.getSize()>0) {
374 _projDeps = (RooArgSet*) projDeps.snapshot(kFALSE) ;
377 _normSet->remove(*_projDeps,kTRUE,kTRUE) ;
380 RooArgSet *projDataDeps = (RooArgSet*) _funcObsSet->selectCommon(*_projDeps) ;
381 projDataDeps->setAttribAll(
"projectedDependent") ;
382 delete projDataDeps ;
386 coutI(Optimization) <<
"RooAbsOptTestStatistic::ctor(" << GetName() <<
") optimizing internal clone of p.d.f for likelihood evaluation."
387 <<
"Lazy evaluation and associated change tracking will disabled for all nodes that depend on observables" << endl ;
401 _funcClone->getVal(_normSet) ;
418 RooAbsOptTestStatistic::~RooAbsOptTestStatistic()
420 if (operMode()==Slave) {
440 Double_t RooAbsOptTestStatistic::combinedValue(RooAbsReal** array, Int_t n)
const
443 Double_t sum(0), carry(0);
444 for (Int_t i = 0; i < n; ++i) {
445 Double_t y = array[i]->getValV();
446 carry +=
reinterpret_cast<RooAbsOptTestStatistic*
>(array[i])->getCarry();
448 const Double_t t = sum + y;
449 carry = (t - sum) - y;
461 Bool_t RooAbsOptTestStatistic::redirectServersHook(
const RooAbsCollection& newServerList, Bool_t mustReplaceAll, Bool_t nameChange, Bool_t isRecursive)
463 RooAbsTestStatistic::redirectServersHook(newServerList,mustReplaceAll,nameChange,isRecursive) ;
464 if (operMode()!=Slave)
return kFALSE ;
465 Bool_t ret = _funcClone->recursiveRedirectServers(newServerList,kFALSE,nameChange) ;
474 void RooAbsOptTestStatistic::printCompactTreeHook(ostream& os,
const char* indent)
476 RooAbsTestStatistic::printCompactTreeHook(os,indent) ;
477 if (operMode()!=Slave) return ;
478 TString indent2(indent) ;
479 indent2 +=
"opt >>" ;
480 _funcClone->printCompactTree(os,indent2.Data()) ;
481 os << indent2 <<
" dataset clone = " << _dataClone <<
" first obs = " << _dataClone->get()->first() << endl ;
493 void RooAbsOptTestStatistic::constOptimizeTestStatistic(ConstOpCode opcode, Bool_t doAlsoTrackingOpt)
498 RooAbsTestStatistic::constOptimizeTestStatistic(opcode,doAlsoTrackingOpt);
499 if (operMode()!=Slave) return ;
501 if (_dataClone->hasFilledCache() && _dataClone->store()->cacheOwner()!=
this) {
502 if (opcode==Activate) {
503 cxcoutW(Optimization) <<
"RooAbsOptTestStatistic::constOptimize(" << GetName()
504 <<
") dataset cache is owned by another object, no constant term optimization can be applied" << endl ;
509 if (!allowFunctionCache()) {
510 if (opcode==Activate) {
511 cxcoutI(Optimization) <<
"RooAbsOptTestStatistic::constOptimize(" << GetName()
512 <<
") function caching prohibited by test statistic, no constant term optimization is applied" << endl ;
517 if (_dataClone->hasFilledCache() && opcode==Activate) {
523 cxcoutI(Optimization) <<
"RooAbsOptTestStatistic::constOptimize(" << GetName()
524 <<
") optimizing evaluation of test statistic by finding all nodes in p.d.f that depend exclusively"
525 <<
" on observables and constant parameters and precalculating their values" << endl ;
526 optimizeConstantTerms(kTRUE,doAlsoTrackingOpt) ;
530 cxcoutI(Optimization) <<
"RooAbsOptTestStatistic::constOptimize(" << GetName()
531 <<
") deactivating optimization of constant terms in test statistic" << endl ;
532 optimizeConstantTerms(kFALSE) ;
536 cxcoutI(Optimization) <<
"RooAbsOptTestStatistic::constOptimize(" << GetName()
537 <<
") one ore more parameter were changed from constant to floating or vice versa, "
538 <<
"re-evaluating constant term optimization" << endl ;
539 optimizeConstantTerms(kFALSE) ;
540 optimizeConstantTerms(kTRUE,doAlsoTrackingOpt) ;
544 cxcoutI(Optimization) <<
"RooAbsOptTestStatistic::constOptimize(" << GetName()
545 <<
") the value of one ore more constant parameter were changed re-evaluating constant term optimization" << endl ;
547 _dataClone->store()->forceCacheUpdate() ;
567 void RooAbsOptTestStatistic::optimizeCaching()
573 _funcClone->getVal(_normSet) ;
576 _funcClone->optimizeCacheMode(*_funcObsSet) ;
579 _dataClone->setDirtyProp(kFALSE) ;
582 _dataClone->optimizeReadingWithCaching(*_funcClone, RooArgSet(),requiredExtraObservables()) ;
596 void RooAbsOptTestStatistic::optimizeConstantTerms(Bool_t activate, Bool_t applyTrackingOpt)
606 _funcClone->getVal(_normSet) ;
612 RooArgSet trackNodes ;
617 if (applyTrackingOpt) {
618 if (!dynamic_cast<RooVectorDataStore*>(_dataClone->store())) {
619 coutW(Optimization) <<
"RooAbsOptTestStatistic::optimizeConstantTerms(" << GetName()
620 <<
") WARNING Cache-and-track optimization (Optimize level 2) is only available for datasets"
621 <<
" implement in terms of RooVectorDataStore - ignoring this option for current dataset" << endl ;
622 applyTrackingOpt = kFALSE ;
626 if (applyTrackingOpt) {
628 _funcClone->branchNodeServerList(&branches) ;
629 for (
auto arg : branches) {
630 arg->setCacheAndTrackHints(trackNodes);
633 RooArgSet* constNodes = (RooArgSet*) trackNodes.selectByAttrib(
"Constant",kTRUE) ;
634 trackNodes.remove(*constNodes) ;
638 trackNodes.setAttribAll(
"CacheAndTrack",kTRUE) ;
642 _cachedNodes.removeAll() ;
644 _funcClone->findConstantNodes(*_dataClone->get(),_cachedNodes) ;
651 _dataClone->cacheArgs(
this,_cachedNodes,_normSet,!_funcClone->getAttribute(
"BinnedLikelihood")) ;
658 for (
auto cacheArg : _cachedNodes) {
659 cacheArg->setOperMode(RooAbsArg::AClean) ;
670 RooArgSet* constNodes = (RooArgSet*) _cachedNodes.selectByAttrib(
"ConstantExpressionCached",kTRUE) ;
671 RooArgSet actualTrackNodes(_cachedNodes) ;
672 actualTrackNodes.remove(*constNodes) ;
673 if (constNodes->getSize()>0) {
674 if (constNodes->getSize()<20) {
675 coutI(Minimization) <<
" The following expressions have been identified as constant and will be precalculated and cached: " << *constNodes << endl ;
677 coutI(Minimization) <<
" A total of " << constNodes->getSize() <<
" expressions have been identified as constant and will be precalculated and cached." << endl ;
685 if (actualTrackNodes.getSize()>0) {
686 if (actualTrackNodes.getSize()<20) {
687 coutI(Minimization) <<
" The following expressions will be evaluated in cache-and-track mode: " << actualTrackNodes << endl ;
689 coutI(Minimization) <<
" A total of " << constNodes->getSize() <<
" expressions will be evaluated in cache-and-track-mode." << endl ;
695 _dataClone->optimizeReadingWithCaching(*_funcClone, _cachedNodes,requiredExtraObservables()) ;
702 _dataClone->resetCache() ;
705 _dataClone->setArgStatus(*_dataClone->get(),kTRUE) ;
711 _dataClone->setDirtyProp(kFALSE) ;
713 _cachedNodes.removeAll() ;
716 _optimized = kFALSE ;
729 Bool_t RooAbsOptTestStatistic::setDataSlave(RooAbsData& indata, Bool_t cloneData, Bool_t ownNewData)
732 if (operMode()==SimMaster) {
747 if (!cloneData && _rangeName.size()>0) {
748 coutW(InputArguments) <<
"RooAbsOptTestStatistic::setData(" << GetName() <<
") WARNING: test statistic was constructed with range selection on data, "
749 <<
"ignoring request to _not_ clone the input dataset" << endl ;
755 if (_rangeName.size()==0) {
756 _dataClone = (RooAbsData*) indata.reduce(*indata.get()) ;
758 _dataClone = ((RooAbsData&)indata).reduce(RooFit::SelectVars(*indata.get()),RooFit::CutRange(_rangeName.c_str())) ;
765 _dataClone = &indata ;
766 _ownData = ownNewData ;
771 _dataClone->attachBuffers(*_funcObsSet) ;
772 _dataClone->setDirtyProp(kFALSE) ;
776 if (_cachedNodes.getSize()>0) {
777 _dataClone->cacheArgs(
this,_cachedNodes,_normSet) ;
781 setEventCount(indata.numEntries()) ;
795 RooAbsData& RooAbsOptTestStatistic::data()
798 Bool_t notice = (sealNotice() && strlen(sealNotice())) ;
799 coutW(ObjectHandling) <<
"RooAbsOptTestStatistic::data(" << GetName()
800 <<
") WARNING: object sealed by creator - access to data is not permitted: "
801 << (notice?sealNotice():
"<no user notice>") << endl ;
802 static RooDataSet dummy (
"dummy",
"dummy",RooArgSet()) ;
811 const RooAbsData& RooAbsOptTestStatistic::data()
const
814 Bool_t notice = (sealNotice() && strlen(sealNotice())) ;
815 coutW(ObjectHandling) <<
"RooAbsOptTestStatistic::data(" << GetName()
816 <<
") WARNING: object sealed by creator - access to data is not permitted: "
817 << (notice?sealNotice():
"<no user notice>") << endl ;
818 static RooDataSet dummy (
"dummy",
"dummy",RooArgSet()) ;