Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RooRealIntegral.cxx
Go to the documentation of this file.
1/*****************************************************************************
2 * Project: RooFit *
3 * Package: RooFitCore *
4 * @(#)root/roofitcore:$Id$
5 * Authors: *
6 * WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu *
7 * DK, David Kirkby, UC Irvine, dkirkby@uci.edu *
8 * *
9 * Copyright (c) 2000-2005, Regents of the University of California *
10 * and Stanford University. All rights reserved. *
11 * *
12 * Redistribution and use in source and binary forms, *
13 * with or without modification, are permitted according to the terms *
14 * listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
15 *****************************************************************************/
16
17/**
18\file RooRealIntegral.cxx
19\class RooRealIntegral
20\ingroup Roofitcore
21
22Performs hybrid numerical/analytical integrals of RooAbsReal objects.
23The class performs none of the actual integration, but only manages the logic
24of what variables can be integrated analytically, accounts for eventual jacobian
25terms and defines what numerical integrations needs to be done to complement the
26analytical integral.
27The actual analytical integrations (if any) are done in the PDF themselves, the numerical
28integration is performed in the various implementations of the RooAbsIntegrator base class.
29**/
30
31#include <RooRealIntegral.h>
32
34#include <RooAbsRealLValue.h>
35#include <RooConstVar.h>
36#include <RooDouble.h>
38#include <RooInvTransform.h>
39#include <RooMsgService.h>
40#include <RooNameReg.h>
41#include <RooNumIntConfig.h>
42#include <RooNumIntFactory.h>
43#include <RooRealBinding.h>
44#include <RooSuperCategory.h>
45#include <RooTrace.h>
46#include <RooFitImplHelpers.h>
47
48#include <iostream>
49#include <memory>
50#include <unordered_map>
51
52namespace {
53
54/// Utility function that returns true if 'object server' is a server
55/// to exactly one of the RooAbsArgs in 'exclLVBranches'
57{
58 // Determine if given server serves exclusively exactly one of the given nodes in exclLVBranches
59
60 // Special case, no LV servers available
61 if (exclLVBranches.empty())
62 return false;
63
64 // If server has no clients and is not an LValue itself, return false
65 if (!server->hasClients() && exclLVBranches.find(server->GetName())) {
66 return false;
67 }
68
69 // WVE must check for value relations only here!!!!
70
71 // Loop over all clients
73 for (const auto client : server->valueClients()) {
74 // If client is not an LValue, recurse
75 if (!(exclLVBranches.find(client->GetName()) == client)) {
76 if (allBranches.find(client->GetName()) == client) {
78 // Client is a non-LValue that doesn't have an exclusive LValue server
79 return false;
80 }
81 }
82 } else {
83 // Client is an LValue
84 numLVServ++;
85 }
86 }
87
88 return (numLVServ == 1);
89}
90
91struct ServerToAdd {
92 ServerToAdd(RooAbsArg *theArg, bool isShape) : arg{theArg}, isShapeServer{isShape} {}
93 RooAbsArg *arg = nullptr;
94 bool isShapeServer = false;
95};
96
97void addObservableToServers(RooAbsReal const &function, RooAbsArg &leaf, std::vector<ServerToAdd> &serversToAdd,
98 const char *rangeName)
99{
100 auto leaflv = dynamic_cast<RooAbsRealLValue *>(&leaf);
101 if (leaflv && leaflv->getBinning(rangeName).isParameterized()) {
102 oocxcoutD(&function, Integration)
103 << function.GetName() << " : Observable " << leaf.GetName()
104 << " has parameterized binning, add value dependence of boundary objects rather than shape of leaf"
105 << std::endl;
106 if (leaflv->getBinning(rangeName).lowBoundFunc()) {
107 serversToAdd.emplace_back(leaflv->getBinning(rangeName).lowBoundFunc(), false);
108 }
109 if (leaflv->getBinning(rangeName).highBoundFunc()) {
110 serversToAdd.emplace_back(leaflv->getBinning(rangeName).highBoundFunc(), false);
111 }
112 } else {
113 oocxcoutD(&function, Integration) << function.GetName() << ": Adding observable " << leaf.GetName()
114 << " as shape dependent" << std::endl;
115 serversToAdd.emplace_back(&leaf, true);
116 }
117}
118
119void addParameterToServers(RooAbsReal const &function, RooAbsArg &leaf, std::vector<ServerToAdd> &serversToAdd,
120 bool isShapeServer)
121{
122 if (!isShapeServer) {
123 oocxcoutD(&function, Integration) << function.GetName() << ": Adding parameter " << leaf.GetName()
124 << " as value dependent" << std::endl;
125 } else {
126 oocxcoutD(&function, Integration) << function.GetName() << ": Adding parameter " << leaf.GetName()
127 << " as shape dependent" << std::endl;
128 }
129 serversToAdd.emplace_back(&leaf, isShapeServer);
130}
131
132enum class MarkedState { Dependent, Independent, AlreadyAdded };
133
134/// Mark all args that recursively are value clients of "dep".
135void unmarkDepValueClients(RooAbsArg const &dep, std::unordered_map<RooAbsArg const *, std::size_t> const &indexMap,
136 std::vector<MarkedState> &marked)
137{
138 auto found = indexMap.find(&dep);
139 if (found == indexMap.end())
140 return;
141 marked[found->second] = MarkedState::Dependent;
142
143 // Iterative depth-first traversal of the value clients within the
144 // computation graph, visiting every arg at most once.
145 std::vector<RooAbsArg const *> stack{&dep};
146 while (!stack.empty()) {
147 RooAbsArg const *arg = stack.back();
148 stack.pop_back();
149 for (RooAbsArg *client : arg->valueClients()) {
150 auto foundClient = indexMap.find(client);
151 if (foundClient != indexMap.end() && marked[foundClient->second] != MarkedState::Dependent) {
152 marked[foundClient->second] = MarkedState::Dependent;
153 stack.push_back(client);
154 }
155 }
156 }
157}
158
159std::vector<ServerToAdd>
160getValueAndShapeServers(RooAbsReal const &function, RooArgSet const &depList, const char *rangeName)
161{
162 std::vector<ServerToAdd> serversToAdd;
163
164 // Get the full computation graph and sort it topologically
166 function.treeNodeServerList(&allArgsList, nullptr, true, true, /*valueOnly=*/false, false);
168 allArgs.sortTopologically();
169
170 // Maps from arg to index in allArgs for constant-time lookups. Two maps,
171 // because the graph can contain same-name instances (e.g. cloned sub-trees
172 // from projections): dependent client chains are matched by instance,
173 // while the final server matching is done by name.
174 std::unordered_map<RooAbsArg const *, std::size_t> indexMap;
175 std::unordered_map<TNamed const *, std::size_t> indexMapByName;
176 indexMap.reserve(allArgs.size());
177 indexMapByName.reserve(allArgs.size());
178 for (std::size_t i = 0; i < allArgs.size(); ++i) {
179 indexMap.emplace(allArgs[i], i);
180 indexMapByName.emplace(allArgs[i]->namePtr(), i);
181 }
182
183 // Figure out what are all the value servers only
185 function.treeNodeServerList(&allValueArgsList, nullptr, true, true, /*valueOnly=*/true, false);
187
188 // All "marked" args will be added as value servers to the integral
189 std::vector<MarkedState> marked(allArgs.size(), MarkedState::Independent);
190 // We don't want to consider the function itself
191 if (auto foundFunc = indexMap.find(&function); foundFunc != indexMap.end()) {
192 marked[foundFunc->second] = MarkedState::Dependent;
193 }
194
195 // Mark all args that are (indirect) value servers of the integration
196 // variable or the integration variable itself. If something was marked,
197 // it means the integration variable was in the compute graph and we will
198 // add it to the server list.
199 for (RooAbsArg *dep : depList) {
200 if (RooAbsArg *depInArgs = allArgs.find(dep->GetName())) {
203 }
204 }
205
206 // We are adding all independent direct servers of the args depending on the
207 // integration variables
208 for (std::size_t i = 0; i < allArgs.size(); ++i) {
209 if (marked[i] == MarkedState::Dependent) {
210 for (RooAbsArg *server : allArgs[i]->servers()) {
211 auto found = indexMapByName.find(server->namePtr());
212 if (found != indexMapByName.end() && marked[found->second] == MarkedState::Independent) {
214 marked[found->second] = MarkedState::AlreadyAdded;
215 }
216 }
217 }
218 }
219
220 return serversToAdd;
221}
222
224 const RooArgSet &allBranches)
225{
226 // If any of the branches in the computation graph of the function depend on
227 // the integrated variable, we can't do analytical integration. The only
228 // case where this would work is if the branch is an l-value with known
229 // Jacobian, but this case is already handled in step B) in the constructor
230 // by reexpressing the original integration variables in terms of
231 // higher-order l-values if possible.
233 for (RooAbsArg *intDep : intDeps) {
234 bool depOK = true;
235 for (RooAbsArg *branch : allBranches) {
236 // It's ok if the branch is the integration variable itself
237 if (intDep->namePtr() != branch->namePtr() && branch->dependsOnValue(*intDep)) {
238 depOK = false;
239 }
240 if (!depOK) break;
241 }
242 if (depOK) {
244 }
245 }
246
247 for (const auto arg : function.servers()) {
248
249 // Dependent or parameter?
250 if (!arg->dependsOnValue(filteredIntDeps)) {
251 continue;
252 } else if (!arg->isValueServer(function) && !arg->isShapeServer(function)) {
253 // Skip arg if it is neither value or shape server
254 continue;
255 }
256
257 bool depOK(false);
258 // Check for integratable AbsRealLValue
259
260 if (arg->isDerived()) {
261 RooAbsRealLValue *realArgLV = dynamic_cast<RooAbsRealLValue *>(arg);
262 RooAbsCategoryLValue *catArgLV = dynamic_cast<RooAbsCategoryLValue *>(arg);
263 if ((realArgLV && filteredIntDeps.find(realArgLV->GetName()) &&
264 (realArgLV->isJacobianOK(filteredIntDeps) != 0)) ||
265 catArgLV) {
266
267 // Derived LValue with valid jacobian
268 depOK = true;
269
270 // Now, check for overlaps
271 bool overlapOK = true;
272 for (const auto otherArg : function.servers()) {
273 // skip comparison with self
274 if (arg == otherArg)
275 continue;
276 if (dynamic_cast<RooConstVar const *>(otherArg))
277 continue;
278 if (arg->overlaps(*otherArg, true)) {
279 }
280 }
281 // coverity[DEADCODE]
282 if (!overlapOK)
283 depOK = false;
284 }
285 } else {
286 // Fundamental types are always OK
287 depOK = true;
288 }
289
290 // Add server to list of dependents that are OK for analytical integration
291 if (depOK) {
292 anIntOKDepList.add(*arg, true);
293 oocxcoutI(&function, Integration)
294 << function.GetName() << ": Observable " << arg->GetName()
295 << " is suitable for analytical integration (if supported by p.d.f)" << std::endl;
296 }
297 }
298}
299
300} // namespace
301
303
304////////////////////////////////////////////////////////////////////////////////
305
310
311////////////////////////////////////////////////////////////////////////////////
312/// Construct integral of 'function' over observables in 'depList'
313/// in range 'rangeName' with normalization observables 'funcNormSet'
314/// (for p.d.f.s). In the integral is performed to the maximum extent
315/// possible the internal (analytical) integrals advertised by function.
316/// The other integrations are performed numerically. The optional
317/// config object prescribes how these numeric integrations are configured.
318///
319/// \Note If pdf component selection was globally overridden to always include
320/// all components (either with RooAbsReal::globalSelectComp(bool) or a
321/// RooAbsReal::GlobalSelectComponentRAII), then any created integral will
322/// ignore component selections during its lifetime. This is especially useful
323/// when creating normalization or projection integrals.
324RooRealIntegral::RooRealIntegral(const char *name, const char *title,
325 const RooAbsReal& function, const RooArgSet& depList,
326 const RooArgSet* funcNormSet, const RooNumIntConfig* config,
327 const char* rangeName) :
328 RooAbsReal(name,title),
329 _valid(true),
330 _respectCompSelect{!_globalSelectComp},
331 _sumList("!sumList","Categories to be summed numerically",this,false,false),
332 _intList("!intList","Variables to be integrated numerically",this,false,false),
333 _anaList("!anaList","Variables to be integrated analytically",this,false,false),
334 _jacList("!jacList","Jacobian product term",this,false,false),
335 _facList("!facList","Variables independent of function",this,false,true),
336 _function("!func","Function to be integrated",this,false,false),
337 _iconfig(const_cast<RooNumIntConfig*>(config)),
338 _sumCat("!sumCat","SuperCategory for summation",this,false,false),
339 _rangeName(const_cast<TNamed*>(RooNameReg::ptr(rangeName)))
340{
341 // A) Check that all dependents are lvalues
342 //
343 // B) Check if list of dependents can be re-expressed in
344 // lvalues that are higher in the expression tree
345 //
346 // C) Check for dependents that the PDF insists on integrating
347 // analytically itself
348 //
349 // D) Make list of servers that can be integrated analytically
350 // Add all parameters/dependents as value/shape servers
351 //
352 // E) Interact with function to make list of objects actually integrated analytically
353 //
354 // F) Make list of numerical integration variables consisting of:
355 // - Category dependents of RealLValues in analytical integration
356 // - Leaf nodes server lists of function server that are not analytically integrated
357 // - Make Jacobian list for analytically integrated RealLValues
358 //
359 // G) Split numeric list in integration list and summation list
360 //
361
362 oocxcoutI(&function,Integration) << "RooRealIntegral::ctor(" << GetName() << ") Constructing integral of function "
363 << function.GetName() << " over observables" << depList << " with normalization "
364 << (funcNormSet?*funcNormSet:RooArgSet()) << " with range identifier "
365 << (rangeName?rangeName:"<none>") << std::endl ;
366
367
368 // Choose same expensive object cache as integrand
369 setExpensiveObjectCache(function.expensiveObjectCache()) ;
370// std::cout << "RRI::ctor(" << GetName() << ") setting expensive object cache to " << &expensiveObjectCache() << " as taken from " << function.GetName() << std::endl ;
371
372 // Use objects integrator configuration if none is specified
373 if (!_iconfig) _iconfig = const_cast<RooNumIntConfig*>(function.getIntegratorConfig());
374
375 // Save private copy of funcNormSet, if supplied, excluding factorizing terms
376 if (funcNormSet) {
377 _funcNormSet = std::make_unique<RooArgSet>();
378 for (const auto nArg : *funcNormSet) {
379 if (function.dependsOn(*nArg)) {
380 _funcNormSet->addClone(*nArg) ;
381 }
382 }
383 }
384
385 //_funcNormSet = funcNormSet ? (RooArgSet*)funcNormSet->snapshot(false) : 0 ;
386
387 // Make internal copy of dependent list
389
390 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
391 // * A) Check that all dependents are lvalues and filter out any
392 // dependents that the PDF doesn't explicitly depend on
393 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
394
395 for (auto arg : intDepList) {
396 if(!arg->isLValue()) {
397 coutE(InputArguments) << ClassName() << "::" << GetName() << ": cannot integrate non-lvalue ";
398 arg->Print("1");
399 _valid= false;
400 }
401 if (!function.dependsOn(*arg)) {
402 std::unique_ptr<RooAbsArg> argClone{static_cast<RooAbsArg*>(arg->Clone())};
404 addOwnedComponents(std::move(argClone));
405 }
406 }
407
408 if (!_facList.empty()) {
409 oocxcoutI(&function,Integration) << function.GetName() << ": Factorizing observables are " << _facList << std::endl ;
410 }
411
412
413 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
414 // * B) Check if list of dependents can be re-expressed in *
415 // * lvalues that are higher in the expression tree *
416 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
417
418
419 // Initial fill of list of LValue branches
420 RooArgSet exclLVBranches("exclLVBranches") ;
422 function.branchNodeServerList(&branchList) ;
423
425 function.treeNodeServerList(&branchListVDAll,nullptr,true,false,/*valueOnly=*/true);
426 // The branchListVD is similar to branchList but considers only value
427 // dependence, and we want to exclude the function itself
429 branchListVD.reserve(branchListVDAll.size());
431 if (branch != &function) {
432 // The branchListVDAll is a RooArgList, so it's not de-duplicated yet.
433 // Add elements to the branchListVD with the "silent" flag, so it
434 // de-duplicates while adding without printing errors.
435 branchListVD.add(*branch, /*silent=*/true);
436 }
437 }
438
439 for (auto branch: branchList) {
442 if ((realArgLV && (realArgLV->isJacobianOK(intDepList)!=0)) || catArgLV) {
443 exclLVBranches.add(*branch) ;
444 }
445 }
446 exclLVBranches.remove(depList,true,true) ;
447
448 // Initial fill of list of LValue leaf servers (put in intDepList, but the
449 // instances that are in the actual computation graph of the function)
450 RooArgSet exclLVServers("exclLVServers") ;
451 function.getObservables(&intDepList, exclLVServers);
452
453 // Obtain mutual exclusive dependence by iterative reduction
454 bool converged(false) ;
455 while(!converged) {
457
458 // Reduce exclLVServers to only those serving exclusively exclLVBranches
459 std::vector<RooAbsArg*> toBeRemoved;
460 for (auto server : exclLVServers) {
462 toBeRemoved.push_back(server);
464 }
465 }
467
468 // Reduce exclLVBranches to only those depending exclusively on exclLVservers
469 // Attention: counting loop, since erasing from container
470 for (std::size_t i=0; i < exclLVBranches.size(); ++i) {
471 const RooAbsArg* branch = exclLVBranches[i];
473 branch->getObservables(&intDepList, brDepList);
474 RooArgSet bsList(brDepList,"bsList") ;
475 bsList.remove(exclLVServers,true,true) ;
476 if (!bsList.empty()) {
477 exclLVBranches.remove(*branch,true,true) ;
478 --i;
480 }
481 }
482 }
483
484 // Eliminate exclLVBranches that do not depend on any LVServer
485 // Attention: Counting loop, since modifying container
486 for (std::size_t i=0; i < exclLVBranches.size(); ++i) {
487 const RooAbsArg* branch = exclLVBranches[i];
488 if (!branch->dependsOnValue(exclLVServers)) {
489 exclLVBranches.remove(*branch,true,true) ;
490 --i;
491 }
492 }
493
494 // Replace exclusive lvalue branch servers with lvalue branches
495 // WVE Don't do this for binned distributions - deal with this using numeric integration with transformed bin boundaroes
496 if (!exclLVServers.empty() && !function.isBinnedDistribution(exclLVBranches)) {
497 intDepList.remove(exclLVServers) ;
499 }
500
501
502 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
503 // * C) Check for dependents that the PDF insists on integrating *
504 // analytically itself *
505 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
506
508 for (auto arg : intDepList) {
509 if (function.forceAnalyticalInt(*arg)) {
510 anIntOKDepList.add(*arg) ;
511 }
512 }
513
514 if (!anIntOKDepList.empty()) {
515 oocxcoutI(&function,Integration) << function.GetName() << ": Observables that function forcibly requires to be integrated internally " << anIntOKDepList << std::endl ;
516 }
517
518
519 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
520 // * D) Make list of servers that can be integrated analytically *
521 // Add all parameters/dependents as value/shape servers *
522 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
523
526 // We will not add the servers just now, because it makes only sense to add
527 // them once we have made sure that this integral is not operating in
528 // pass-through mode. It will be done at the end of this constructor.
529
530 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
531 // * E) interact with function to make list of objects actually integrated analytically *
532 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
533
534 _mode = function.getAnalyticalIntegralWN(anIntOKDepList,_anaList,_funcNormSet.get(),RooNameReg::str(_rangeName)) ;
535
536 // Avoid confusion -- if mode is zero no analytical integral is defined regardless of contents of _anaList
537 if (_mode==0) {
539 }
540
541 if (_mode!=0) {
542 oocxcoutI(&function,Integration) << function.GetName() << ": Function integrated observables " << _anaList << " internally with code " << _mode << std::endl ;
543 }
544
545 // WVE kludge: synchronize dset for use in analyticalIntegral
546 // LM : I think this is needed only if _funcNormSet is not an empty set
547 if (_funcNormSet && !_funcNormSet->empty()) {
548 function.getVal(_funcNormSet.get()) ;
549 }
550
551 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
552 // * F) Make list of numerical integration variables consisting of: *
553 // * - Category dependents of RealLValues in analytical integration *
554 // * - Expanded server lists of server that are not analytically integrated *
555 // * Make Jacobian list with analytically integrated RealLValues *
556 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
557
558 // Loop over actually analytically integrated dependents
559 for (const auto arg : _anaList) {
560
561 // Process only derived RealLValues
562 if (dynamic_cast<RooAbsRealLValue const *>(arg) && arg->isDerived() && !arg->isFundamental()) {
563
564 // Add to list of Jacobians to calculate
565 _jacList.add(*arg) ;
566
567 // Add category dependent of LValueReal used in integration
568 std::unique_ptr<RooArgSet> argDepList{arg->getObservables(&intDepList)};
569 for (const auto argDep : *argDepList) {
570 if (dynamic_cast<RooAbsCategoryLValue const *>(argDep) && intDepList.contains(*argDep)) {
572 }
573 }
574 }
575 }
576
577
578 // If nothing was integrated analytically, swap back LVbranches for LVservers for subsequent numeric integration
579 if (_anaList.empty()) {
580 if (!exclLVServers.empty()) {
581 //cout << "NUMINT phase analList is empty. exclLVServers = " << exclLVServers << std::endl ;
582 intDepList.remove(exclLVBranches) ;
584 }
585 }
586 //cout << "NUMINT intDepList = " << intDepList << std::endl ;
587
588 // Loop again over function servers to add remaining numeric integrations
589 for (const auto arg : function.servers()) {
590
591 // Process only servers that are not treated analytically
592 if (!_anaList.find(arg->GetName()) && arg->dependsOn(intDepList)) {
593
594 // Process only derived RealLValues
595 if (dynamic_cast<RooAbsLValue*>(arg) && arg->isDerived() && intDepList.contains(*arg)) {
596 addNumIntDep(*arg) ;
597 } else {
598
599 // WVE this will only get the observables, but not l-value transformations
600 // Expand server in final dependents
601 auto argDeps = std::unique_ptr<RooArgSet>(arg->getObservables(&intDepList));
602
603 // Add final dependents, that are not forcibly integrated analytically,
604 // to numerical integration list
605 for (const auto dep : *argDeps) {
606 if (!_anaList.find(dep->GetName())) {
608 }
609 }
610 }
611 }
612 }
613
614 if (!_anaList.empty()) {
615 oocxcoutI(&function,Integration) << function.GetName() << ": Observables " << _anaList << " are analytically integrated with code " << _mode << std::endl ;
616 }
617 if (!_intList.empty()) {
618 oocxcoutI(&function,Integration) << function.GetName() << ": Observables " << _intList << " are numerically integrated" << std::endl ;
619 }
620 if (!_sumList.empty()) {
621 oocxcoutI(&function,Integration) << function.GetName() << ": Observables " << _sumList << " are numerically summed" << std::endl ;
622 }
623
624
625 // Determine operating mode
626 if (!_intList.empty() || !_sumList.empty()) {
627 // Numerical and optional Analytical integration
629 } else if (!_anaList.empty()) {
630 // Purely analytical integration
632 } else {
633 // No integration performed, where the function is a direct value server
635 _function._valueServer = true;
636 }
637 // We are only setting the function proxy now that it's clear if it's a value
638 // server or not.
639 _function.setArg(const_cast<RooAbsReal&>(function));
640
641 // Determine auto-dirty status
643
644 // Create value caches for _intList and _sumList
647
648
649 if (!_sumList.empty()) {
650 _sumCat.addOwned(std::make_unique<RooSuperCategory>(Form("%s_sumCat",GetName()),"sumCat",_sumList));
651 }
652
653 // Only if we are not in pass-through mode we need to add the shape and value
654 // servers separately.
656 for(auto const& toAdd : serversToAdd) {
657 addServer(*toAdd.arg, !toAdd.isShapeServer, toAdd.isShapeServer);
658 }
659 }
660
662}
663
664////////////////////////////////////////////////////////////////////////////////
665/// Set appropriate cache operation mode for integral depending on cache operation
666/// mode of server objects
667
669{
670 // If any of our servers are is forcedDirty or a projectedDependent, then we need to be ADirty
671 for (const auto server : _serverList) {
672 if (server->isValueServer(*this)) {
674 server->leafNodeServerList(&leafSet) ;
675 for (const auto leaf : leafSet) {
676 if (leaf->operMode()==ADirty && leaf->isValueServer(*this)) {
678 break ;
679 }
680 if (leaf->getAttribute("projectedDependent")) {
682 break ;
683 }
684 }
685 }
686 }
687}
688
689////////////////////////////////////////////////////////////////////////////////
690/// (Re)Initialize numerical integration engine if necessary. Return true if
691/// successful, or otherwise false.
692
694{
695 // if we already have an engine, check if it still works for the present limits.
696 if(_numIntEngine) {
697 if(_numIntEngine->isValid() && _numIntEngine->checkLimits() && !_restartNumIntEngine ) return true;
698 // otherwise, cleanup the old engine
699 _numIntEngine.reset();
700 _numIntegrand.reset();
701 }
702
703 // All done if there are no arguments to integrate numerically
704 if(_intList.empty()) return true;
705
706 // Bind the appropriate analytic integral of our RooRealVar object to
707 // those of its arguments that will be integrated out numerically.
708 if(_mode != 0) {
710 _numIntegrand = std::make_unique<RooRealBinding>(*analyticalPart,_intList,nullptr,false,_rangeName);
711 const_cast<RooRealIntegral*>(this)->addOwnedComponents(std::move(analyticalPart));
712 }
713 else {
714 _numIntegrand = std::make_unique<RooRealBinding>(*_function,_intList,actualFuncNormSet(),false,_rangeName);
715 }
716 if(nullptr == _numIntegrand || !_numIntegrand->isValid()) {
717 coutE(Integration) << ClassName() << "::" << GetName() << ": failed to create valid integrand." << std::endl;
718 return false;
719 }
720
721 // Create appropriate numeric integrator using factory
723 std::string integratorName = RooNumIntFactory::instance().getIntegratorName(*_numIntegrand,*_iconfig,0,isBinned);
725
726 if(_numIntEngine == nullptr || !_numIntEngine->isValid()) {
727 coutE(Integration) << ClassName() << "::" << GetName() << ": failed to create valid integrator." << std::endl;
728 return false;
729 }
730
731 cxcoutI(NumericIntegration) << "RooRealIntegral::init(" << GetName() << ") using numeric integrator "
732 << integratorName << " to calculate Int" << _intList << std::endl ;
733
734 if (_intList.size()>3) {
735 cxcoutI(NumericIntegration) << "RooRealIntegral::init(" << GetName() << ") evaluation requires " << _intList.size() << "-D numeric integration step. Evaluation may be slow, sufficient numeric precision for fitting & minimization is not guaranteed" << std::endl ;
736 }
737
739 return true;
740}
741
742////////////////////////////////////////////////////////////////////////////////
743/// Copy constructor
744
747 _valid(other._valid),
748 _respectCompSelect(other._respectCompSelect),
749 _sumList("!sumList", this, other._sumList),
750 _intList("!intList", this, other._intList),
751 _anaList("!anaList", this, other._anaList),
752 _jacList("!jacList", this, other._jacList),
753 _facList("!facList", this, other._facList),
754 _function("!func", this, other._function),
755 _iconfig(other._iconfig),
756 _sumCat("!sumCat", this, other._sumCat),
757 _mode(other._mode),
758 _intOperMode(other._intOperMode),
759 _rangeName(other._rangeName)
760{
761 if(other._funcNormSet) {
762 _funcNormSet = std::make_unique<RooArgSet>();
763 other._funcNormSet->snapshot(*_funcNormSet, false);
764 }
765
766 other._intList.snapshot(_saveInt) ;
767 other._sumList.snapshot(_saveSum) ;
768
770}
771
772////////////////////////////////////////////////////////////////////////////////
773
778
779////////////////////////////////////////////////////////////////////////////////
780
782{
783 // Handle special case of no integration with default algorithm
784 if (iset.empty()) {
785 return RooAbsReal::createIntegral(iset,nset,cfg,rangeName) ;
786 }
787
788 // Special handling of integral of integral, return RooRealIntegral that represents integral over all dimensions in one pass
790 isetAll.add(_sumList) ;
791 isetAll.add(_intList) ;
792 isetAll.add(_anaList) ;
793 isetAll.add(_facList) ;
794
795 const RooArgSet* newNormSet(nullptr) ;
796 std::unique_ptr<RooArgSet> tmp;
797 if (nset && !_funcNormSet) {
798 newNormSet = nset ;
799 } else if (!nset && _funcNormSet) {
800 newNormSet = _funcNormSet.get();
801 } else if (nset && _funcNormSet) {
802 tmp = std::make_unique<RooArgSet>();
803 tmp->add(*nset) ;
804 tmp->add(*_funcNormSet,true) ;
805 newNormSet = tmp.get();
806 }
808}
809
810////////////////////////////////////////////////////////////////////////////////
811/// Return value of object. If the cache is clean, return the
812/// cached value, otherwise recalculate on the fly and refill
813/// the cache
814
815double RooRealIntegral::getValV(const RooArgSet* nset) const
816{
817// // fast-track clean-cache processing
818// if (_operMode==AClean) {
819// return _value ;
820// }
821
822 if (nset && nset->uniqueId().value() != _lastNormSetId) {
823 const_cast<RooRealIntegral*>(this)->setProxyNormSet(nset);
824 _lastNormSetId = nset->uniqueId().value();
825 }
826
828 _value = traceEval(nset) ;
829 }
830
831 return _value ;
832}
833
834////////////////////////////////////////////////////////////////////////////////
835/// Perform the integration and return the result
836
838{
840
841 double retVal(0) ;
842 switch (_intOperMode) {
843
844 case Hybrid:
845 {
846 // try to initialize our numerical integration engine
847 if(!(_valid= initNumIntegrator())) {
848 coutE(Integration) << ClassName() << "::" << GetName()
849 << ":evaluate: cannot initialize numerical integrator" << std::endl;
850 return 0;
851 }
852
853 // Find any function dependents that are "AClean" and switch them temporarily to "Auto".
854 // We do this by compute graph traversal and RAII objects on the heap,
855 // which seems quite expensive, but is not as bad as it looks because:
856 // 1. The sub-graphs representing numerically-integrated functions
857 // are usually small
858 // 2. The numerical integration itself dominates the runtime of the
859 // evaluation.
860 // 3. The operMode is only "AClean" if we use the constant term
861 // optimization of the legacy test statistics.
862 // 4. Once the legacy test statistics are deprecated and removed,
863 // this code block can go away (TODO when that happens).
864 // Note: in the past, the "AClean" states were changed with a global
865 // setDirtyInhibit(true) before evaluating the numeric integral. While
866 // this avoids the bookkeeping overhead, it actually changes the oper
867 // mode of all nodes to "ADirty" and not to "Auto", resulting in
868 // significant performance loss in case the target function benefits
869 // from caching subgraph results (e.g. for nested numeric integrals).
871 _function->treeNodeServerList(&serverList, nullptr, true, true, false, true);
873
874 for (auto *arg : serverList) {
875 arg->syncCache();
876 if (arg->operMode() == RooAbsArg::AClean) {
877 operModeRAII.change(arg, RooAbsArg::Auto);
878 }
879 }
880
881 // Save current integral dependent values
884
885 // Evaluate sum/integral
886 retVal = sum() ;
887
888 // This must happen BEFORE restoring dependents, otherwise no dirty state propagation in restore step
889 operModeRAII.clear();
890
891 // Restore integral dependent values
894 break ;
895 }
896 case Analytic:
897 {
899 cxcoutD(Tracing) << "RooRealIntegral::evaluate_analytic(" << GetName()
900 << ")func = " << _function->ClassName() << "::" << _function->GetName()
901 << " raw = " << retVal << " _funcNormSet = " << (_funcNormSet?*_funcNormSet:RooArgSet()) << std::endl ;
902
903
904 break ;
905 }
906
907 case PassThrough:
908 {
909 // In pass through mode, the RooRealIntegral should have registered the
910 // function as a value server, because we directly depend on its value.
912 // There should be no other servers besides the actual function and the
913 // factorized observables that the function doesn't depend on but are
914 // integrated over later.
915 assert(servers().size() == _facList.size() + 1);
916
918 break ;
919 }
920 }
921
922
923 // Multiply answer with integration ranges of factorized variables
924 for (const auto arg : _facList) {
925 // Multiply by fit range for 'real' dependents
926 if (auto argLV = dynamic_cast<RooAbsRealLValue *>(arg)) {
927 retVal *= (argLV->getMax(intRange()) - argLV->getMin(intRange())) ;
928 }
929 // Multiply by number of states for category dependents
930 if (auto argLV = dynamic_cast<RooAbsCategoryLValue *>(arg)) {
931 retVal *= argLV->numTypes() ;
932 }
933 }
934
935
936 if (dologD(Tracing)) {
937 cxcoutD(Tracing) << "RooRealIntegral::evaluate(" << GetName() << ") anaInt = " << _anaList << " numInt = " << _intList << _sumList << " mode = " ;
938 switch(_intOperMode) {
939 case Hybrid: ccoutD(Tracing) << "Hybrid" ; break ;
940 case Analytic: ccoutD(Tracing) << "Analytic" ; break ;
941 case PassThrough: ccoutD(Tracing) << "PassThrough" ; break ;
942 }
943
944 ccxcoutD(Tracing) << "raw*fact = " << retVal << std::endl ;
945 }
946
947 return retVal ;
948}
949
950////////////////////////////////////////////////////////////////////////////////
951/// Return product of jacobian terms originating from analytical integration
952
954{
955 if (_jacList.empty()) {
956 return 1 ;
957 }
958
959 double jacProd(1) ;
960 for (const auto elm : _jacList) {
961 auto arg = static_cast<const RooAbsRealLValue*>(elm);
962 jacProd *= arg->jacobian() ;
963 }
964
965 // Take std::abs() here: if jacobian is negative, min and max are swapped and analytical integral
966 // will be positive, so must multiply with positive jacobian.
967 return std::abs(jacProd) ;
968}
969
970////////////////////////////////////////////////////////////////////////////////
971/// Perform summation of list of category dependents to be integrated
972
974{
975 if (!_sumList.empty()) {
976 // Add integrals for all permutations of categories summed over
977 double total(0) ;
978
980 for (const auto& nameIdx : *sumCat) {
981 sumCat->setIndex(nameIdx);
982 if (!_rangeName || sumCat->inRange(RooNameReg::str(_rangeName))) {
984 }
985 }
986
987 return total ;
988
989 } else {
990 // Simply return integral
991 double ret = integrate() / jacobianProduct() ;
992 return ret ;
993 }
994}
995
996////////////////////////////////////////////////////////////////////////////////
997/// Perform hybrid numerical/analytical integration over all real-valued dependents
998
1000{
1001 if (!_numIntEngine) {
1002 // Trivial case, fully analytical integration
1004 } else {
1005 return _numIntEngine->calculate() ;
1006 }
1007}
1008
1009////////////////////////////////////////////////////////////////////////////////
1010/// Intercept server redirects and reconfigure internal object accordingly
1011
1013 bool mustReplaceAll, bool nameChange, bool isRecursive)
1014{
1016
1018
1019 // Update contents value caches for _intList and _sumList
1024
1025 // Delete parameters cache if we have one
1026 _params.reset();
1027
1029}
1030
1031////////////////////////////////////////////////////////////////////////////////
1032
1034{
1035 if (!_params) {
1036 _params = std::make_unique<RooArgSet>("params") ;
1037
1038 RooArgSet params ;
1039 for (const auto server : _serverList) {
1040 if (server->isValueServer(*this)) _params->add(*server) ;
1041 }
1042 }
1043
1044 return *_params ;
1045}
1046
1047////////////////////////////////////////////////////////////////////////////////
1048/// Check if current value is valid
1049
1050bool RooRealIntegral::isValidReal(double /*value*/, bool /*printError*/) const
1051{
1052 return true ;
1053}
1054
1055////////////////////////////////////////////////////////////////////////////////
1056/// Check if component selection is allowed
1057
1061
1062////////////////////////////////////////////////////////////////////////////////
1063/// Set component selection to be allowed/forbidden
1064
1068
1069////////////////////////////////////////////////////////////////////////////////
1070/// Customized printing of arguments of a RooRealIntegral to more intuitively reflect the contents of the
1071/// integration operation
1072
1073void RooRealIntegral::printMetaArgs(std::ostream& os) const
1074{
1075 if (!intVars().empty()) {
1076 os << "Int " ;
1077 }
1078 os << _function->GetName() ;
1079 if (_funcNormSet) {
1080 os << "_Norm" << *_funcNormSet << " " ;
1081 }
1082
1083 // List internally integrated observables and factorizing observables as analytically integrated
1085 tmp.add(_facList) ;
1086 if (!tmp.empty()) {
1087 os << "d[Ana]" << tmp << " ";
1088 }
1089
1090 // List numerically integrated and summed observables as numerically integrated
1092 tmp2.add(_sumList) ;
1093 if (!tmp2.empty()) {
1094 os << " d[Num]" << tmp2 << " ";
1095 }
1096}
1097
1098////////////////////////////////////////////////////////////////////////////////
1099/// Print the state of this object to the specified output stream.
1100
1101void RooRealIntegral::printMultiline(std::ostream& os, Int_t contents, bool verbose, TString indent) const
1102{
1103 RooAbsReal::printMultiline(os,contents,verbose,indent) ;
1104 os << indent << "--- RooRealIntegral ---" << std::endl;
1105 os << indent << " Integrates ";
1108 deeper.Append(" ");
1109 os << indent << " operating mode is "
1110 << (_intOperMode==Hybrid?"Hybrid":(_intOperMode==Analytic?"Analytic":"PassThrough")) << std::endl ;
1111 os << indent << " Summed discrete args are " << _sumList << std::endl ;
1112 os << indent << " Numerically integrated args are " << _intList << std::endl;
1113 os << indent << " Analytically integrated args using mode " << _mode << " are " << _anaList << std::endl ;
1114 os << indent << " Arguments included in Jacobian are " << _jacList << std::endl ;
1115 os << indent << " Factorized arguments are " << _facList << std::endl ;
1116 os << indent << " Function normalization set " ;
1117 if (_funcNormSet) {
1118 _funcNormSet->Print("1") ;
1119 } else {
1120 os << "<none>";
1121 }
1122
1123 os << std::endl ;
1124}
1125
1126////////////////////////////////////////////////////////////////////////////////
1127/// Global switch to cache all integral values that integrate at least ndim dimensions numerically
1128
1130{
1131 _cacheAllNDim = ndim;
1132}
1133
1134////////////////////////////////////////////////////////////////////////////////
1135/// Return minimum dimensions of numeric integration for which values are cached.
1136
1141
1142std::unique_ptr<RooAbsArg>
1147
1148/// Sort numeric integration variables in summation and integration lists.
1149/// To be used during construction.
1151{
1152 if (dynamic_cast<RooAbsRealLValue const *>(&arg)) {
1153 _intList.add(arg, true);
1154 } else if (dynamic_cast<RooAbsCategoryLValue const *>(&arg)) {
1155 _sumList.add(arg, true);
1156 }
1157}
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
#define cxcoutI(a)
#define cxcoutD(a)
#define oocxcoutD(o, a)
#define dologD(a)
#define coutE(a)
#define ccxcoutD(a)
#define ccoutD(a)
#define oocxcoutI(o, a)
#define TRACE_DESTROY
Definition RooTrace.h:24
#define TRACE_CREATE
Definition RooTrace.h:23
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:59
static void indent(ostringstream &buf, int indent_level)
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
static unsigned int total
char name[80]
Definition TGX11.cxx:145
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2496
Scope guard that temporarily changes the operation mode of one or more RooAbsArg instances.
const_iterator begin() const
const_iterator end() const
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:76
bool overlaps(const RooAbsArg &testArg, bool valueOnly=false) const
Test if any of the nodes of tree are shared with that of the given tree.
void Print(Option_t *options=nullptr) const override
Print the object to the defaultPrintStream().
Definition RooAbsArg.h:238
bool dependsOn(const RooAbsCollection &serverList, const RooAbsArg *ignoreArg=nullptr, bool valueOnly=false) const
Test whether we depend on (ie, are served by) any object in the specified collection.
virtual void syncCache(const RooArgSet *nset=nullptr)=0
void setOperMode(OperMode mode, bool recurseADirty=true)
Set the operation mode of this node.
bool isShapeServer(const RooAbsArg &arg) const
Check if this is serving shape to arg.
Definition RooAbsArg.h:161
RooFit::OwningPtr< RooArgSet > getObservables(const RooArgSet &set, bool valueOnly=true) const
Given a set of possible observables, return the observables that this PDF depends on.
virtual void setExpensiveObjectCache(RooExpensiveObjectCache &cache)
Definition RooAbsArg.h:439
bool addOwnedComponents(const RooAbsCollection &comps)
Take ownership of the contents of 'comps'.
virtual bool isLValue() const
Is this argument an l-value, i.e., can it appear on the left-hand side of an assignment expression?...
Definition RooAbsArg.h:185
virtual std::unique_ptr< RooAbsArg > compileForNormSet(RooArgSet const &normSet, RooFit::Detail::CompileContext &ctx) const
const RefCountList_t & servers() const
List of all servers of this object.
Definition RooAbsArg.h:145
bool dependsOnValue(const RooAbsCollection &serverList, const RooAbsArg *ignoreArg=nullptr) const
Check whether this object depends on values from an element in the serverList.
Definition RooAbsArg.h:104
void addServer(RooAbsArg &server, bool valueProp=true, bool shapeProp=false, std::size_t refCount=1)
Register another RooAbsArg as a server to us, ie, declare that we depend on it.
virtual bool isDerived() const
Does value or shape of this arg depend on any other arg?
Definition RooAbsArg.h:97
bool isValueOrShapeDirtyAndClear() const
Definition RooAbsArg.h:390
void setProxyNormSet(const RooArgSet *nset)
Forward a change in the cached normalization argset to all the registered proxies.
TObject * Clone(const char *newname=nullptr) const override
Make a clone of an object using the Streamer facility.
Definition RooAbsArg.h:88
RefCountList_t _serverList
Definition RooAbsArg.h:565
virtual bool isFundamental() const
Is this object a fundamental type that can be added to a dataset? Fundamental-type subclasses overrid...
Definition RooAbsArg.h:175
bool isValueServer(const RooAbsArg &arg) const
Check if this is serving values to arg.
Definition RooAbsArg.h:157
void treeNodeServerList(RooAbsCollection *list, const RooAbsArg *arg=nullptr, bool doBranch=true, bool doLeaf=true, bool valueOnly=false, bool recurseNonDerived=false) const
Fill supplied list with nodes of the arg tree, following all server links, starting with ourself as t...
OperMode operMode() const
Query the operation mode of this node.
Definition RooAbsArg.h:419
Abstract base class for objects that represent a discrete value that can be set from the outside,...
Abstract container object that can hold multiple RooAbsArg objects.
RooFit::UniqueId< RooAbsCollection > const & uniqueId() const
Returns a unique ID that is different for every instantiated RooAbsCollection.
virtual void removeAll()
Remove all arguments from our set, deleting them if we own them.
void assign(const RooAbsCollection &other) const
Sets the value, cache and constant attribute of any argument in our set that also appears in the othe...
Storage_t::size_type size() const
RooAbsArg * first() const
RooAbsArg * find(const char *name) const
Find object with given name in list.
Abstract base class for objects that are lvalues, i.e.
Abstract base class for objects that represent a real value that may appear on the left hand side of ...
Abstract base class for objects that represent a real value and implements functionality common to al...
Definition RooAbsReal.h:63
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition RooAbsReal.h:107
void printMultiline(std::ostream &os, Int_t contents, bool verbose=false, TString indent="") const override
Structure printing.
bool redirectServersHook(const RooAbsCollection &newServerList, bool mustReplaceAll, bool nameChange, bool isRecursiveStep) override
Function that is called at the end of redirectServers().
double _value
Cache for current value of object.
Definition RooAbsReal.h:569
double traceEval(const RooArgSet *set) const
Calculate current value of object, with error tracing wrapper.
RooFit::UniqueId< RooArgSet >::Value_t _lastNormSetId
!
Definition RooAbsReal.h:576
virtual double analyticalIntegralWN(Int_t code, const RooArgSet *normSet, const char *rangeName=nullptr) const
Implements the actual analytical integral(s) advertised by getAnalyticalIntegral.
virtual bool isBinnedDistribution(const RooArgSet &) const
Tests if the distribution is binned. Unless overridden by derived classes, this always returns false.
Definition RooAbsReal.h:370
RooFit::OwningPtr< RooAbsReal > createIntegral(const RooArgSet &iset, const RooCmdArg &arg1, const RooCmdArg &arg2={}, const RooCmdArg &arg3={}, const RooCmdArg &arg4={}, const RooCmdArg &arg5={}, const RooCmdArg &arg6={}, const RooCmdArg &arg7={}, const RooCmdArg &arg8={}) const
Create an object that represents the integral of the function over one or more observables listed in ...
RooArgList is a container object that can hold multiple RooAbsArg objects.
Definition RooArgList.h:22
bool _valueServer
If true contents is value server of owner.
Definition RooArgProxy.h:80
bool isValueServer() const
Returns true of contents is value server of owner.
Definition RooArgProxy.h:60
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:24
RooArgSet * snapshot(bool deepCopy=true) const
Use RooAbsCollection::snapshot(), but return as RooArgSet.
Definition RooArgSet.h:159
void removeAll() override
Remove all argument inset using remove(const RooAbsArg&).
bool addOwned(RooAbsArg &var, bool silent=false) override
Overloaded RooCollection_t::addOwned() method insert object into owning set and registers object as s...
bool add(const RooAbsArg &var, bool valueServer, bool shapeServer, bool silent)
Overloaded RooCollection_t::add() method insert object into set and registers object as server to own...
Represents a constant real-valued object.
Definition RooConstVar.h:23
Registry for const char* names.
Definition RooNameReg.h:26
static const char * str(const TNamed *ptr)
Return C++ string corresponding to given TNamed pointer.
Definition RooNameReg.h:39
Holds the configuration parameters of the various numeric integrators used by RooRealIntegral.
static RooNumIntFactory & instance()
Static method returning reference to singleton instance of factory.
virtual void printStream(std::ostream &os, Int_t contents, StyleOption style, TString indent="") const
Print description of object on ostream, printing contents set by contents integer,...
Performs hybrid numerical/analytical integrals of RooAbsReal objects.
RooNumIntConfig * _iconfig
bool initNumIntegrator() const
(Re)Initialize numerical integration engine if necessary.
RooArgSet const * funcNormSet() const
RooFit::OwningPtr< RooAbsReal > createIntegral(const RooArgSet &iset, const RooArgSet *nset=nullptr, const RooNumIntConfig *cfg=nullptr, const char *rangeName=nullptr) const override
Create an object that represents the integral of the function over one or more observables listed in ...
void setAllowComponentSelection(bool allow)
Set component selection to be allowed/forbidden.
RooRealProxy _function
Function being integrated.
RooArgSet intVars() const
RooSetProxy _intList
Set of continuous observables over which is integrated numerically.
virtual double sum() const
Perform summation of list of category dependents to be integrated.
RooSetProxy _facList
Set of observables on which function does not depends, which are integrated nevertheless.
std::unique_ptr< RooArgSet > _params
! cache for set of parameters
static void setCacheAllNumeric(Int_t ndim)
Global switch to cache all integral values that integrate at least ndim dimensions numerically.
IntOperMode _intOperMode
integration operation mode
double evaluate() const override
Perform the integration and return the result.
const RooArgSet & parameters() const
std::unique_ptr< RooAbsFunc > _numIntegrand
!
void addNumIntDep(RooAbsArg const &arg)
Sort numeric integration variables in summation and integration lists.
RooSetProxy _jacList
Set of lvalue observables over which is analytically integration that have a non-unit Jacobian.
bool isValidReal(double value, bool printError=false) const override
Check if current value is valid.
double getValV(const RooArgSet *set=nullptr) const override
Return value of object.
RooSetProxy _anaList
Set of observables over which is integrated/summed analytically.
bool redirectServersHook(const RooAbsCollection &newServerList, bool mustReplaceAll, bool nameChange, bool isRecursive) override
Intercept server redirects and reconfigure internal object accordingly.
RooSetProxy _sumList
Set of discrete observable over which is summed numerically.
~RooRealIntegral() override
void printMetaArgs(std::ostream &os) const override
Customized printing of arguments of a RooRealIntegral to more intuitively reflect the contents of the...
void printMultiline(std::ostream &os, Int_t contents, bool verbose=false, TString indent="") const override
Print the state of this object to the specified output stream.
std::unique_ptr< RooAbsIntegrator > _numIntEngine
!
virtual double integrate() const
Perform hybrid numerical/analytical integration over all real-valued dependents.
RooListProxy _sumCat
!
virtual double jacobianProduct() const
Return product of jacobian terms originating from analytical integration.
static Int_t getCacheAllNumeric()
Return minimum dimensions of numeric integration for which values are cached.
static Int_t _cacheAllNDim
! Cache all integrals with given numeric dimension
RooArgSet const * actualFuncNormSet() const
std::unique_ptr< RooArgSet > _funcNormSet
Optional normalization set passed to function.
std::unique_ptr< RooAbsArg > compileForNormSet(RooArgSet const &normSet, RooFit::Detail::CompileContext &ctx) const override
void autoSelectDirtyMode()
Set appropriate cache operation mode for integral depending on cache operation mode of server objects...
const char * intRange() const
bool getAllowComponentSelection() const
Check if component selection is allowed.
Joins several RooAbsCategoryLValue objects into a single category.
bool setArg(T &newRef)
Change object held in proxy into newRef.
The TNamed class is the base class for all named ROOT classes.
Definition TNamed.h:29
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:224
Basic string class.
Definition TString.h:138
void function(const Char_t *name_, T fun, const Char_t *docstring=0)
Definition RExports.h:168
T * OwningPtr
An alias for raw pointers for indicating that the return type of a RooFit function is an owning point...
Definition Config.h:35
constexpr Value_t value() const
Return numerical value of ID.
Definition UniqueId.h:59