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 <RooFitImplHelpers.h>
46
47#include <iostream>
48#include <memory>
49#include <unordered_map>
50
51namespace {
52
53/// Utility function that returns true if 'object server' is a server
54/// to exactly one of the RooAbsArgs in 'exclLVBranches'
55bool servesExclusively(const RooAbsArg *server, const RooArgSet &exclLVBranches, const RooArgSet &allBranches)
56{
57 // Determine if given server serves exclusively exactly one of the given nodes in exclLVBranches
58
59 // Special case, no LV servers available
60 if (exclLVBranches.empty())
61 return false;
62
63 // If server has no clients and is not an LValue itself, return false
64 if (!server->hasClients() && exclLVBranches.find(server->GetName())) {
65 return false;
66 }
67
68 // WVE must check for value relations only here!!!!
69
70 // Loop over all clients
71 Int_t numLVServ(0);
72 for (const auto client : server->valueClients()) {
73 // If client is not an LValue, recurse
74 if (!(exclLVBranches.find(client->GetName()) == client)) {
75 if (allBranches.find(client->GetName()) == client) {
76 if (!servesExclusively(client, exclLVBranches, allBranches)) {
77 // Client is a non-LValue that doesn't have an exclusive LValue server
78 return false;
79 }
80 }
81 } else {
82 // Client is an LValue
83 numLVServ++;
84 }
85 }
86
87 return (numLVServ == 1);
88}
89
90struct ServerToAdd {
91 ServerToAdd(RooAbsArg *theArg, bool isShape) : arg{theArg}, isShapeServer{isShape} {}
92 RooAbsArg *arg = nullptr;
93 bool isShapeServer = false;
94};
95
96void addObservableToServers(RooAbsReal const &function, RooAbsArg &leaf, std::vector<ServerToAdd> &serversToAdd,
97 const char *rangeName)
98{
99 auto leaflv = dynamic_cast<RooAbsRealLValue *>(&leaf);
100 if (leaflv && leaflv->getBinning(rangeName).isParameterized()) {
101 oocxcoutD(&function, Integration)
102 << function.GetName() << " : Observable " << leaf.GetName()
103 << " has parameterized binning, add value dependence of boundary objects rather than shape of leaf"
104 << std::endl;
105 if (leaflv->getBinning(rangeName).lowBoundFunc()) {
106 serversToAdd.emplace_back(leaflv->getBinning(rangeName).lowBoundFunc(), false);
107 }
108 if (leaflv->getBinning(rangeName).highBoundFunc()) {
109 serversToAdd.emplace_back(leaflv->getBinning(rangeName).highBoundFunc(), false);
110 }
111 } else {
112 oocxcoutD(&function, Integration) << function.GetName() << ": Adding observable " << leaf.GetName()
113 << " as shape dependent" << std::endl;
114 serversToAdd.emplace_back(&leaf, true);
115 }
116}
117
118void addParameterToServers(RooAbsReal const &function, RooAbsArg &leaf, std::vector<ServerToAdd> &serversToAdd,
119 bool isShapeServer)
120{
121 if (!isShapeServer) {
122 oocxcoutD(&function, Integration) << function.GetName() << ": Adding parameter " << leaf.GetName()
123 << " as value dependent" << std::endl;
124 } else {
125 oocxcoutD(&function, Integration) << function.GetName() << ": Adding parameter " << leaf.GetName()
126 << " as shape dependent" << std::endl;
127 }
128 serversToAdd.emplace_back(&leaf, isShapeServer);
129}
130
131enum class MarkedState { Dependent, Independent, AlreadyAdded };
132
133/// Mark all args that recursively are value clients of "dep".
134void unmarkDepValueClients(RooAbsArg const &dep, std::unordered_map<RooAbsArg const *, std::size_t> const &indexMap,
135 std::vector<MarkedState> &marked)
136{
137 auto found = indexMap.find(&dep);
138 if (found == indexMap.end())
139 return;
140 marked[found->second] = MarkedState::Dependent;
141
142 // Iterative depth-first traversal of the value clients within the
143 // computation graph, visiting every arg at most once.
144 std::vector<RooAbsArg const *> stack{&dep};
145 while (!stack.empty()) {
146 RooAbsArg const *arg = stack.back();
147 stack.pop_back();
148 for (RooAbsArg *client : arg->valueClients()) {
149 auto foundClient = indexMap.find(client);
150 if (foundClient != indexMap.end() && marked[foundClient->second] != MarkedState::Dependent) {
151 marked[foundClient->second] = MarkedState::Dependent;
152 stack.push_back(client);
153 }
154 }
155 }
156}
157
158std::vector<ServerToAdd>
159getValueAndShapeServers(RooAbsReal const &function, RooArgSet const &depList, const char *rangeName)
160{
161 std::vector<ServerToAdd> serversToAdd;
162
163 // Get the full computation graph and sort it topologically
164 RooArgList allArgsList;
165 function.treeNodeServerList(&allArgsList, nullptr, true, true, /*valueOnly=*/false, false);
166 RooArgSet allArgs{allArgsList};
167 allArgs.sortTopologically();
168
169 // Maps from arg to index in allArgs for constant-time lookups. Two maps,
170 // because the graph can contain same-name instances (e.g. cloned sub-trees
171 // from projections): dependent client chains are matched by instance,
172 // while the final server matching is done by name.
173 std::unordered_map<RooAbsArg const *, std::size_t> indexMap;
174 std::unordered_map<TNamed const *, std::size_t> indexMapByName;
175 indexMap.reserve(allArgs.size());
176 indexMapByName.reserve(allArgs.size());
177 for (std::size_t i = 0; i < allArgs.size(); ++i) {
178 indexMap.emplace(allArgs[i], i);
179 indexMapByName.emplace(allArgs[i]->namePtr(), i);
180 }
181
182 // Figure out what are all the value servers only
183 RooArgList allValueArgsList;
184 function.treeNodeServerList(&allValueArgsList, nullptr, true, true, /*valueOnly=*/true, false);
185 RooArgSet allValueArgs{allValueArgsList};
186
187 // All "marked" args will be added as value servers to the integral
188 std::vector<MarkedState> marked(allArgs.size(), MarkedState::Independent);
189 // We don't want to consider the function itself
190 if (auto foundFunc = indexMap.find(&function); foundFunc != indexMap.end()) {
191 marked[foundFunc->second] = MarkedState::Dependent;
192 }
193
194 // Mark all args that are (indirect) value servers of the integration
195 // variable or the integration variable itself. If something was marked,
196 // it means the integration variable was in the compute graph and we will
197 // add it to the server list.
198 for (RooAbsArg *dep : depList) {
199 if (RooAbsArg *depInArgs = allArgs.find(dep->GetName())) {
200 unmarkDepValueClients(*depInArgs, indexMap, marked);
201 addObservableToServers(function, *depInArgs, serversToAdd, rangeName);
202 }
203 }
204
205 // We are adding all independent direct servers of the args depending on the
206 // integration variables
207 for (std::size_t i = 0; i < allArgs.size(); ++i) {
208 if (marked[i] == MarkedState::Dependent) {
209 for (RooAbsArg *server : allArgs[i]->servers()) {
210 auto found = indexMapByName.find(server->namePtr());
211 if (found != indexMapByName.end() && marked[found->second] == MarkedState::Independent) {
212 addParameterToServers(function, *server, serversToAdd, !allValueArgs.find(*server));
213 marked[found->second] = MarkedState::AlreadyAdded;
214 }
215 }
216 }
217 }
218
219 return serversToAdd;
220}
221
222void fillAnIntOKDepList(RooAbsReal const &function, RooArgSet const &intDeps, RooArgSet &anIntOKDepList,
223 const RooArgSet &allBranches)
224{
225 // If any of the branches in the computation graph of the function depend on
226 // the integrated variable, we can't do analytical integration. The only
227 // case where this would work is if the branch is an l-value with known
228 // Jacobian, but this case is already handled in step B) in the constructor
229 // by reexpressing the original integration variables in terms of
230 // higher-order l-values if possible.
231 RooArgSet filteredIntDeps;
232 for (RooAbsArg *intDep : intDeps) {
233 bool depOK = true;
234 for (RooAbsArg *branch : allBranches) {
235 // It's ok if the branch is the integration variable itself
236 if (intDep->namePtr() != branch->namePtr() && branch->dependsOnValue(*intDep)) {
237 depOK = false;
238 }
239 if (!depOK) break;
240 }
241 if (depOK) {
242 filteredIntDeps.add(*intDep);
243 }
244 }
245
246 for (const auto arg : function.servers()) {
247
248 // Dependent or parameter?
249 if (!arg->dependsOnValue(filteredIntDeps)) {
250 continue;
251 } else if (!arg->isValueServer(function) && !arg->isShapeServer(function)) {
252 // Skip arg if it is neither value or shape server
253 continue;
254 }
255
256 bool depOK(false);
257 // Check for integratable AbsRealLValue
258
259 if (arg->isDerived()) {
260 RooAbsRealLValue *realArgLV = dynamic_cast<RooAbsRealLValue *>(arg);
261 RooAbsCategoryLValue *catArgLV = dynamic_cast<RooAbsCategoryLValue *>(arg);
262 if ((realArgLV && filteredIntDeps.find(realArgLV->GetName()) &&
263 (realArgLV->isJacobianOK(filteredIntDeps) != 0)) ||
264 catArgLV) {
265
266 // Derived LValue with valid jacobian
267 depOK = true;
268
269 // Now, check for overlaps
270 bool overlapOK = true;
271 for (const auto otherArg : function.servers()) {
272 // skip comparison with self
273 if (arg == otherArg)
274 continue;
275 if (dynamic_cast<RooConstVar const *>(otherArg))
276 continue;
277 if (arg->overlaps(*otherArg, true)) {
278 }
279 }
280 // coverity[DEADCODE]
281 if (!overlapOK)
282 depOK = false;
283 }
284 } else {
285 // Fundamental types are always OK
286 depOK = true;
287 }
288
289 // Add server to list of dependents that are OK for analytical integration
290 if (depOK) {
291 anIntOKDepList.add(*arg, true);
292 oocxcoutI(&function, Integration)
293 << function.GetName() << ": Observable " << arg->GetName()
294 << " is suitable for analytical integration (if supported by p.d.f)" << std::endl;
295 }
296 }
297}
298
299} // namespace
300
302
303////////////////////////////////////////////////////////////////////////////////
304
308
309////////////////////////////////////////////////////////////////////////////////
310/// Construct integral of 'function' over observables in 'depList'
311/// in range 'rangeName' with normalization observables 'funcNormSet'
312/// (for p.d.f.s). In the integral is performed to the maximum extent
313/// possible the internal (analytical) integrals advertised by function.
314/// The other integrations are performed numerically. The optional
315/// config object prescribes how these numeric integrations are configured.
316///
317/// \note If pdf component selection was globally overridden to always include
318/// all components (either with RooAbsReal::globalSelectComp(bool) or a
319/// RooAbsReal::GlobalSelectComponentRAII), then any created integral will
320/// ignore component selections during its lifetime. This is especially useful
321/// when creating normalization or projection integrals.
322RooRealIntegral::RooRealIntegral(const char *name, const char *title,
323 const RooAbsReal& function, const RooArgSet& depList,
324 const RooArgSet* funcNormSet, const RooNumIntConfig* config,
325 const char* rangeName) :
326 RooAbsReal(name,title),
327 _valid(true),
328 _respectCompSelect{!_globalSelectComp},
329 _sumList("!sumList","Categories to be summed numerically",this,false,false),
330 _intList("!intList","Variables to be integrated numerically",this,false,false),
331 _anaList("!anaList","Variables to be integrated analytically",this,false,false),
332 _jacList("!jacList","Jacobian product term",this,false,false),
333 _facList("!facList","Variables independent of function",this,false,true),
334 _function("!func","Function to be integrated",this,false,false),
335 _iconfig(const_cast<RooNumIntConfig*>(config)),
336 _sumCat("!sumCat","SuperCategory for summation",this,false,false),
337 _rangeName(const_cast<TNamed*>(RooNameReg::ptr(rangeName)))
338{
339 // A) Check that all dependents are lvalues
340 //
341 // B) Check if list of dependents can be re-expressed in
342 // lvalues that are higher in the expression tree
343 //
344 // C) Check for dependents that the PDF insists on integrating
345 // analytically itself
346 //
347 // D) Make list of servers that can be integrated analytically
348 // Add all parameters/dependents as value/shape servers
349 //
350 // E) Interact with function to make list of objects actually integrated analytically
351 //
352 // F) Make list of numerical integration variables consisting of:
353 // - Category dependents of RealLValues in analytical integration
354 // - Leaf nodes server lists of function server that are not analytically integrated
355 // - Make Jacobian list for analytically integrated RealLValues
356 //
357 // G) Split numeric list in integration list and summation list
358 //
359
360 oocxcoutI(&function,Integration) << "RooRealIntegral::ctor(" << GetName() << ") Constructing integral of function "
361 << function.GetName() << " over observables" << depList << " with normalization "
362 << (funcNormSet?*funcNormSet:RooArgSet()) << " with range identifier "
363 << (rangeName?rangeName:"<none>") << std::endl ;
364
365
366 // Choose same expensive object cache as integrand
368// std::cout << "RRI::ctor(" << GetName() << ") setting expensive object cache to " << &expensiveObjectCache() << " as taken from " << function.GetName() << std::endl ;
369
370 // Use objects integrator configuration if none is specified
371 if (!_iconfig) _iconfig = const_cast<RooNumIntConfig*>(function.getIntegratorConfig());
372
373 // Save private copy of funcNormSet, if supplied, excluding factorizing terms
374 if (funcNormSet) {
375 _funcNormSet = std::make_unique<RooArgSet>();
376 for (const auto nArg : *funcNormSet) {
377 if (function.dependsOn(*nArg)) {
378 _funcNormSet->addClone(*nArg) ;
379 }
380 }
381 }
382
383 //_funcNormSet = funcNormSet ? (RooArgSet*)funcNormSet->snapshot(false) : 0 ;
384
385 // Make internal copy of dependent list
386 RooArgSet intDepList(depList) ;
387
388 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
389 // * A) Check that all dependents are lvalues and filter out any
390 // dependents that the PDF doesn't explicitly depend on
391 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
392
393 for (auto arg : intDepList) {
394 if(!arg->isLValue()) {
395 coutE(InputArguments) << ClassName() << "::" << GetName() << ": cannot integrate non-lvalue ";
396 arg->Print("1");
397 _valid= false;
398 }
399 if (!function.dependsOn(*arg)) {
400 std::unique_ptr<RooAbsArg> argClone{static_cast<RooAbsArg*>(arg->Clone())};
401 _facList.add(*argClone);
402 addOwnedComponents(std::move(argClone));
403 }
404 }
405
406 if (!_facList.empty()) {
407 oocxcoutI(&function,Integration) << function.GetName() << ": Factorizing observables are " << _facList << std::endl ;
408 }
409
410
411 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
412 // * B) Check if list of dependents can be re-expressed in *
413 // * lvalues that are higher in the expression tree *
414 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
415
416
417 // Initial fill of list of LValue branches
418 RooArgSet exclLVBranches("exclLVBranches") ;
419 RooArgSet branchList;
420 function.branchNodeServerList(&branchList) ;
421
422 RooArgList branchListVDAll;
423 function.treeNodeServerList(&branchListVDAll,nullptr,true,false,/*valueOnly=*/true);
424 // The branchListVD is similar to branchList but considers only value
425 // dependence, and we want to exclude the function itself
426 RooArgSet branchListVD;
427 branchListVD.reserve(branchListVDAll.size());
428 for (RooAbsArg *branch : branchListVDAll) {
429 if (branch != &function) {
430 // The branchListVDAll is a RooArgList, so it's not de-duplicated yet.
431 // Add elements to the branchListVD with the "silent" flag, so it
432 // de-duplicates while adding without printing errors.
433 branchListVD.add(*branch, /*silent=*/true);
434 }
435 }
436
437 for (auto branch: branchList) {
438 RooAbsRealLValue *realArgLV = dynamic_cast<RooAbsRealLValue*>(branch) ;
439 RooAbsCategoryLValue *catArgLV = dynamic_cast<RooAbsCategoryLValue*>(branch) ;
440 if ((realArgLV && (realArgLV->isJacobianOK(intDepList)!=0)) || catArgLV) {
441 exclLVBranches.add(*branch) ;
442 }
443 }
444 exclLVBranches.remove(depList,true,true) ;
445
446 // Initial fill of list of LValue leaf servers (put in intDepList, but the
447 // instances that are in the actual computation graph of the function)
448 RooArgSet exclLVServers("exclLVServers") ;
449 function.getObservables(&intDepList, exclLVServers);
450
451 // Obtain mutual exclusive dependence by iterative reduction
452 bool converged(false) ;
453 while(!converged) {
454 converged=true ;
455
456 // Reduce exclLVServers to only those serving exclusively exclLVBranches
457 std::vector<RooAbsArg*> toBeRemoved;
458 for (auto server : exclLVServers) {
459 if (!servesExclusively(server,exclLVBranches,branchListVD)) {
460 toBeRemoved.push_back(server);
461 converged=false ;
462 }
463 }
464 exclLVServers.remove(toBeRemoved.begin(), toBeRemoved.end());
465
466 // Reduce exclLVBranches to only those depending exclusively on exclLVservers
467 // Attention: counting loop, since erasing from container
468 for (std::size_t i=0; i < exclLVBranches.size(); ++i) {
469 const RooAbsArg* branch = exclLVBranches[i];
470 RooArgSet brDepList;
471 branch->getObservables(&intDepList, brDepList);
472 RooArgSet bsList(brDepList,"bsList") ;
473 bsList.remove(exclLVServers,true,true) ;
474 if (!bsList.empty()) {
475 exclLVBranches.remove(*branch,true,true) ;
476 --i;
477 converged=false ;
478 }
479 }
480 }
481
482 // Eliminate exclLVBranches that do not depend on any LVServer
483 // Attention: Counting loop, since modifying container
484 for (std::size_t i=0; i < exclLVBranches.size(); ++i) {
485 const RooAbsArg* branch = exclLVBranches[i];
486 if (!branch->dependsOnValue(exclLVServers)) {
487 exclLVBranches.remove(*branch,true,true) ;
488 --i;
489 }
490 }
491
492 // Replace exclusive lvalue branch servers with lvalue branches
493 // WVE Don't do this for binned distributions - deal with this using numeric integration with transformed bin boundaries
494 if (!exclLVServers.empty() && !function.isBinnedDistribution(exclLVBranches)) {
495 intDepList.remove(exclLVServers) ;
496 intDepList.add(exclLVBranches) ;
497 }
498
499
500 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
501 // * C) Check for dependents that the PDF insists on integrating *
502 // analytically itself *
503 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
504
505 RooArgSet anIntOKDepList ;
506 for (auto arg : intDepList) {
507 if (function.forceAnalyticalInt(*arg)) {
508 anIntOKDepList.add(*arg) ;
509 }
510 }
511
512 if (!anIntOKDepList.empty()) {
513 oocxcoutI(&function,Integration) << function.GetName() << ": Observables that function forcibly requires to be integrated internally " << anIntOKDepList << std::endl ;
514 }
515
516
517 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
518 // * D) Make list of servers that can be integrated analytically *
519 // Add all parameters/dependents as value/shape servers *
520 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
521
522 auto serversToAdd = getValueAndShapeServers(function, depList, rangeName);
523 fillAnIntOKDepList(function, intDepList, anIntOKDepList, branchListVD);
524 // We will not add the servers just now, because it makes only sense to add
525 // them once we have made sure that this integral is not operating in
526 // pass-through mode. It will be done at the end of this constructor.
527
528 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
529 // * E) interact with function to make list of objects actually integrated analytically *
530 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
531
533
534 // Avoid confusion -- if mode is zero no analytical integral is defined regardless of contents of _anaList
535 if (_mode==0) {
537 }
538
539 if (_mode!=0) {
540 oocxcoutI(&function,Integration) << function.GetName() << ": Function integrated observables " << _anaList << " internally with code " << _mode << std::endl ;
541 }
542
543 // WVE kludge: synchronize dset for use in analyticalIntegral
544 // LM : I think this is needed only if _funcNormSet is not an empty set
545 if (_funcNormSet && !_funcNormSet->empty()) {
546 function.getVal(_funcNormSet.get()) ;
547 }
548
549 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
550 // * F) Make list of numerical integration variables consisting of: *
551 // * - Category dependents of RealLValues in analytical integration *
552 // * - Expanded server lists of server that are not analytically integrated *
553 // * Make Jacobian list with analytically integrated RealLValues *
554 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
555
556 // Loop over actually analytically integrated dependents
557 for (const auto arg : _anaList) {
558
559 // Process only derived RealLValues
560 if (dynamic_cast<RooAbsRealLValue const *>(arg) && arg->isDerived() && !arg->isFundamental()) {
561
562 // Add to list of Jacobians to calculate
563 _jacList.add(*arg) ;
564
565 // Add category dependent of LValueReal used in integration
566 std::unique_ptr<RooArgSet> argDepList{arg->getObservables(&intDepList)};
567 for (const auto argDep : *argDepList) {
568 if (dynamic_cast<RooAbsCategoryLValue const *>(argDep) && intDepList.contains(*argDep)) {
569 addNumIntDep(*argDep);
570 }
571 }
572 }
573 }
574
575
576 // If nothing was integrated analytically, swap back LVbranches for LVservers for subsequent numeric integration
577 if (_anaList.empty()) {
578 if (!exclLVServers.empty()) {
579 //cout << "NUMINT phase analList is empty. exclLVServers = " << exclLVServers << std::endl ;
580 intDepList.remove(exclLVBranches) ;
581 intDepList.add(exclLVServers) ;
582 }
583 }
584 //cout << "NUMINT intDepList = " << intDepList << std::endl ;
585
586 // Loop again over function servers to add remaining numeric integrations
587 for (const auto arg : function.servers()) {
588
589 // Process only servers that are not treated analytically
590 if (!_anaList.find(arg->GetName()) && arg->dependsOn(intDepList)) {
591
592 // Process only derived RealLValues
593 if (dynamic_cast<RooAbsLValue*>(arg) && arg->isDerived() && intDepList.contains(*arg)) {
594 addNumIntDep(*arg) ;
595 } else {
596
597 // WVE this will only get the observables, but not l-value transformations
598 // Expand server in final dependents
599 auto argDeps = std::unique_ptr<RooArgSet>(arg->getObservables(&intDepList));
600
601 // Add final dependents, that are not forcibly integrated analytically,
602 // to numerical integration list
603 for (const auto dep : *argDeps) {
604 if (!_anaList.find(dep->GetName())) {
605 addNumIntDep(*dep);
606 }
607 }
608 }
609 }
610 }
611
612 if (!_anaList.empty()) {
613 oocxcoutI(&function,Integration) << function.GetName() << ": Observables " << _anaList << " are analytically integrated with code " << _mode << std::endl ;
614 }
615 if (!_intList.empty()) {
616 oocxcoutI(&function,Integration) << function.GetName() << ": Observables " << _intList << " are numerically integrated" << std::endl ;
617 }
618 if (!_sumList.empty()) {
619 oocxcoutI(&function,Integration) << function.GetName() << ": Observables " << _sumList << " are numerically summed" << std::endl ;
620 }
621
622
623 // Determine operating mode
624 if (!_intList.empty() || !_sumList.empty()) {
625 // Numerical and optional Analytical integration
627 } else if (!_anaList.empty()) {
628 // Purely analytical integration
630 } else {
631 // No integration performed, where the function is a direct value server
633 _function._valueServer = true;
634 }
635 // We are only setting the function proxy now that it's clear if it's a value
636 // server or not.
637 _function.setArg(const_cast<RooAbsReal&>(function));
638
639 // Determine auto-dirty status
641
642 // Create value caches for _intList and _sumList
645
646
647 if (!_sumList.empty()) {
648 _sumCat.addOwned(std::make_unique<RooSuperCategory>(Form("%s_sumCat",GetName()),"sumCat",_sumList));
649 }
650
651 // Only if we are not in pass-through mode we need to add the shape and value
652 // servers separately.
654 for(auto const& toAdd : serversToAdd) {
655 addServer(*toAdd.arg, !toAdd.isShapeServer, toAdd.isShapeServer);
656 }
657 }
658
659}
660
661////////////////////////////////////////////////////////////////////////////////
662/// Set appropriate cache operation mode for integral depending on cache operation
663/// mode of server objects
664
666{
667 // If any of our servers are is forcedDirty or a projectedDependent, then we need to be ADirty
668 for (const auto server : _serverList) {
669 if (server->isValueServer(*this)) {
670 RooArgSet leafSet ;
671 server->leafNodeServerList(&leafSet) ;
672 for (const auto leaf : leafSet) {
673 if (leaf->operMode()==ADirty && leaf->isValueServer(*this)) {
675 break ;
676 }
677 if (leaf->getAttribute("projectedDependent")) {
679 break ;
680 }
681 }
682 }
683 }
684}
685
686////////////////////////////////////////////////////////////////////////////////
687/// (Re)Initialize numerical integration engine if necessary. Return true if
688/// successful, or otherwise false.
689
691{
692 // if we already have an engine, check if it still works for the present limits.
693 if(_numIntEngine) {
694 if(_numIntEngine->isValid() && _numIntEngine->checkLimits() && !_restartNumIntEngine ) return true;
695 // otherwise, cleanup the old engine
696 _numIntEngine.reset();
697 _numIntegrand.reset();
698 }
699
700 // All done if there are no arguments to integrate numerically
701 if(_intList.empty()) return true;
702
703 // Bind the appropriate analytic integral of our RooRealVar object to
704 // those of its arguments that will be integrated out numerically.
705 if(_mode != 0) {
706 std::unique_ptr<RooAbsReal> analyticalPart{_function->createIntegral(_anaList, *actualFuncNormSet(), RooNameReg::str(_rangeName))};
707 _numIntegrand = std::make_unique<RooRealBinding>(*analyticalPart,_intList,nullptr,false,_rangeName);
708 const_cast<RooRealIntegral*>(this)->addOwnedComponents(std::move(analyticalPart));
709 }
710 else {
711 _numIntegrand = std::make_unique<RooRealBinding>(*_function,_intList,actualFuncNormSet(),false,_rangeName);
712 }
713 if(nullptr == _numIntegrand || !_numIntegrand->isValid()) {
714 coutE(Integration) << ClassName() << "::" << GetName() << ": failed to create valid integrand." << std::endl;
715 return false;
716 }
717
718 // Create appropriate numeric integrator using factory
719 bool isBinned = _function->isBinnedDistribution(_intList) ;
720 std::string integratorName = RooNumIntFactory::instance().getIntegratorName(*_numIntegrand,*_iconfig,0,isBinned);
722
723 if(_numIntEngine == nullptr || !_numIntEngine->isValid()) {
724 coutE(Integration) << ClassName() << "::" << GetName() << ": failed to create valid integrator." << std::endl;
725 return false;
726 }
727
728 cxcoutI(NumericIntegration) << "RooRealIntegral::init(" << GetName() << ") using numeric integrator "
729 << integratorName << " to calculate Int" << _intList << std::endl ;
730
731 if (_intList.size()>3) {
732 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 ;
733 }
734
735 _restartNumIntEngine = false ;
736 return true;
737}
738
739////////////////////////////////////////////////////////////////////////////////
740/// Copy constructor
741
743 : RooAbsReal(other, name),
744 _valid(other._valid),
745 _respectCompSelect(other._respectCompSelect),
746 _sumList("!sumList", this, other._sumList),
747 _intList("!intList", this, other._intList),
748 _anaList("!anaList", this, other._anaList),
749 _jacList("!jacList", this, other._jacList),
750 _facList("!facList", "Variables independent of function", this, false, true),
751 _function("!func", this, other._function),
752 _iconfig(other._iconfig),
753 _sumCat("!sumCat", this, other._sumCat),
754 _mode(other._mode),
755 _intOperMode(other._intOperMode),
756 _rangeName(other._rangeName)
757{
758 // The factorized observables are clones owned by the original integral, so
759 // the copy needs its own clones to stay valid when the original is deleted.
760 for (RooAbsArg *arg : other._facList) {
761 removeServer(*arg, true);
762 std::unique_ptr<RooAbsArg> argClone{static_cast<RooAbsArg *>(arg->Clone())};
763 _facList.add(*argClone);
764 addOwnedComponents(std::move(argClone));
765 }
766
767 if(other._funcNormSet) {
768 _funcNormSet = std::make_unique<RooArgSet>();
769 other._funcNormSet->snapshot(*_funcNormSet, false);
770 }
771
772 other._intList.snapshot(_saveInt) ;
773 other._sumList.snapshot(_saveSum) ;
774
775}
776
777////////////////////////////////////////////////////////////////////////////////
778
782
783////////////////////////////////////////////////////////////////////////////////
784
785RooFit::OwningPtr<RooAbsReal> RooRealIntegral::createIntegral(const RooArgSet& iset, const RooArgSet* nset, const RooNumIntConfig* cfg, const char* rangeName) const
786{
787 // Handle special case of no integration with default algorithm
788 if (iset.empty()) {
789 return RooAbsReal::createIntegral(iset,nset,cfg,rangeName) ;
790 }
791
792 // Special handling of integral of integral, return RooRealIntegral that represents integral over all dimensions in one pass
793 RooArgSet isetAll(iset) ;
794 isetAll.add(_sumList) ;
795 isetAll.add(_intList) ;
796 isetAll.add(_anaList) ;
797 isetAll.add(_facList) ;
798
799 const RooArgSet* newNormSet(nullptr) ;
800 std::unique_ptr<RooArgSet> tmp;
801 if (nset && !_funcNormSet) {
802 newNormSet = nset ;
803 } else if (!nset && _funcNormSet) {
804 newNormSet = _funcNormSet.get();
805 } else if (nset && _funcNormSet) {
806 tmp = std::make_unique<RooArgSet>();
807 tmp->add(*nset) ;
808 tmp->add(*_funcNormSet,true) ;
809 newNormSet = tmp.get();
810 }
811 return _function->createIntegral(isetAll,newNormSet,cfg,rangeName);
812}
813
814////////////////////////////////////////////////////////////////////////////////
815/// Return value of object. If the cache is clean, return the
816/// cached value, otherwise recalculate on the fly and refill
817/// the cache
818
819double RooRealIntegral::getValV(const RooArgSet* nset) const
820{
821// // fast-track clean-cache processing
822// if (_operMode==AClean) {
823// return _value ;
824// }
825
826 if (nset && nset->uniqueId().value() != _lastNormSetId) {
827 const_cast<RooRealIntegral*>(this)->setProxyNormSet(nset);
828 _lastNormSetId = nset->uniqueId().value();
829 }
830
832 _value = traceEval(nset) ;
833 }
834
835 return _value ;
836}
837
838////////////////////////////////////////////////////////////////////////////////
839/// Perform the integration and return the result
840
842{
844
845 double retVal(0) ;
846 switch (_intOperMode) {
847
848 case Hybrid:
849 {
850 // try to initialize our numerical integration engine
851 if(!(_valid= initNumIntegrator())) {
852 coutE(Integration) << ClassName() << "::" << GetName()
853 << ":evaluate: cannot initialize numerical integrator" << std::endl;
854 return 0;
855 }
856
857 // Not clear why this is still needed
858 RooArgList serverList;
859 _function->treeNodeServerList(&serverList, nullptr, true, true, false, true);
860
861 for (auto *arg : serverList) {
862 arg->syncCache();
863 }
864
865 // Save current integral dependent values
868
869 // Evaluate sum/integral
870 retVal = sum() ;
871
872 // Restore integral dependent values
875 break ;
876 }
877 case Analytic:
878 {
880 cxcoutD(Tracing) << "RooRealIntegral::evaluate_analytic(" << GetName()
881 << ")func = " << _function->ClassName() << "::" << _function->GetName()
882 << " raw = " << retVal << " _funcNormSet = " << (_funcNormSet?*_funcNormSet:RooArgSet()) << std::endl ;
883
884
885 break ;
886 }
887
888 case PassThrough:
889 {
890 // In pass through mode, the RooRealIntegral should have registered the
891 // function as a value server, because we directly depend on its value.
892 assert(_function.isValueServer());
893 // There should be no other servers besides the actual function and the
894 // factorized observables that the function doesn't depend on but are
895 // integrated over later.
896 assert(servers().size() == _facList.size() + 1);
897
899 break ;
900 }
901 }
902
903
904 // Multiply answer with integration ranges of factorized variables
905 for (const auto arg : _facList) {
906 // Multiply by fit range for 'real' dependents
907 if (auto argLV = dynamic_cast<RooAbsRealLValue *>(arg)) {
908 retVal *= (argLV->getMax(intRange()) - argLV->getMin(intRange())) ;
909 }
910 // Multiply by number of states for category dependents
911 if (auto argLV = dynamic_cast<RooAbsCategoryLValue *>(arg)) {
912 retVal *= argLV->numTypes() ;
913 }
914 }
915
916
917 if (dologD(Tracing)) {
918 cxcoutD(Tracing) << "RooRealIntegral::evaluate(" << GetName() << ") anaInt = " << _anaList << " numInt = " << _intList << _sumList << " mode = " ;
919 switch(_intOperMode) {
920 case Hybrid: ccoutD(Tracing) << "Hybrid" ; break ;
921 case Analytic: ccoutD(Tracing) << "Analytic" ; break ;
922 case PassThrough: ccoutD(Tracing) << "PassThrough" ; break ;
923 }
924
925 ccxcoutD(Tracing) << "raw*fact = " << retVal << std::endl ;
926 }
927
928 return retVal ;
929}
930
931////////////////////////////////////////////////////////////////////////////////
932/// Return product of jacobian terms originating from analytical integration
933
935{
936 if (_jacList.empty()) {
937 return 1 ;
938 }
939
940 double jacProd(1) ;
941 for (const auto elm : _jacList) {
942 auto arg = static_cast<const RooAbsRealLValue*>(elm);
943 jacProd *= arg->jacobian() ;
944 }
945
946 // Take std::abs() here: if jacobian is negative, min and max are swapped and analytical integral
947 // will be positive, so must multiply with positive jacobian.
948 return std::abs(jacProd) ;
949}
950
951////////////////////////////////////////////////////////////////////////////////
952/// Perform summation of list of category dependents to be integrated
953
955{
956 if (!_sumList.empty()) {
957 // Add integrals for all permutations of categories summed over
958 double total(0) ;
959
960 RooSuperCategory* sumCat = static_cast<RooSuperCategory*>(_sumCat.first()) ;
961 for (const auto& nameIdx : *sumCat) {
962 sumCat->setIndex(nameIdx);
963 if (!_rangeName || sumCat->inRange(RooNameReg::str(_rangeName))) {
965 }
966 }
967
968 return total ;
969
970 } else {
971 // Simply return integral
972 double ret = integrate() / jacobianProduct() ;
973 return ret ;
974 }
975}
976
977////////////////////////////////////////////////////////////////////////////////
978/// Perform hybrid numerical/analytical integration over all real-valued dependents
979
981{
982 if (!_numIntEngine) {
983 // Trivial case, fully analytical integration
985 } else {
986 return _numIntEngine->calculate() ;
987 }
988}
989
990////////////////////////////////////////////////////////////////////////////////
991/// Intercept server redirects and reconfigure internal object accordingly
992
994 bool mustReplaceAll, bool nameChange, bool isRecursive)
995{
996 _restartNumIntEngine = true ;
997
999
1000 // Update contents value caches for _intList and _sumList
1005
1006 // Delete parameters cache if we have one
1007 _params.reset();
1008
1009 return RooAbsReal::redirectServersHook(newServerList, mustReplaceAll, nameChange, isRecursive);
1010}
1011
1012////////////////////////////////////////////////////////////////////////////////
1013
1015{
1016 if (!_params) {
1017 _params = std::make_unique<RooArgSet>("params") ;
1018
1019 RooArgSet params ;
1020 for (const auto server : _serverList) {
1021 if (server->isValueServer(*this)) _params->add(*server) ;
1022 }
1023 }
1024
1025 return *_params ;
1026}
1027
1028////////////////////////////////////////////////////////////////////////////////
1029/// Check if current value is valid
1030
1031bool RooRealIntegral::isValidReal(double /*value*/, bool /*printError*/) const
1032{
1033 return true ;
1034}
1035
1036////////////////////////////////////////////////////////////////////////////////
1037/// Check if component selection is allowed
1038
1042
1043////////////////////////////////////////////////////////////////////////////////
1044/// Set component selection to be allowed/forbidden
1045
1049
1050////////////////////////////////////////////////////////////////////////////////
1051/// Customized printing of arguments of a RooRealIntegral to more intuitively reflect the contents of the
1052/// integration operation
1053
1054void RooRealIntegral::printMetaArgs(std::ostream& os) const
1055{
1056 if (!intVars().empty()) {
1057 os << "Int " ;
1058 }
1059 os << _function->GetName() ;
1060 if (_funcNormSet) {
1061 os << "_Norm" << *_funcNormSet << " " ;
1062 }
1063
1064 // List internally integrated observables and factorizing observables as analytically integrated
1065 RooArgSet tmp(_anaList) ;
1066 tmp.add(_facList) ;
1067 if (!tmp.empty()) {
1068 os << "d[Ana]" << tmp << " ";
1069 }
1070
1071 // List numerically integrated and summed observables as numerically integrated
1072 RooArgSet tmp2(_intList) ;
1073 tmp2.add(_sumList) ;
1074 if (!tmp2.empty()) {
1075 os << " d[Num]" << tmp2 << " ";
1076 }
1077}
1078
1079////////////////////////////////////////////////////////////////////////////////
1080/// Print the state of this object to the specified output stream.
1081
1082void RooRealIntegral::printMultiline(std::ostream& os, Int_t contents, bool verbose, TString indent) const
1083{
1084 RooAbsReal::printMultiline(os,contents,verbose,indent) ;
1085 os << indent << "--- RooRealIntegral ---" << std::endl;
1086 os << indent << " Integrates ";
1088 TString deeper(indent);
1089 deeper.Append(" ");
1090 os << indent << " operating mode is "
1091 << (_intOperMode==Hybrid?"Hybrid":(_intOperMode==Analytic?"Analytic":"PassThrough")) << std::endl ;
1092 os << indent << " Summed discrete args are " << _sumList << std::endl ;
1093 os << indent << " Numerically integrated args are " << _intList << std::endl;
1094 os << indent << " Analytically integrated args using mode " << _mode << " are " << _anaList << std::endl ;
1095 os << indent << " Arguments included in Jacobian are " << _jacList << std::endl ;
1096 os << indent << " Factorized arguments are " << _facList << std::endl ;
1097 os << indent << " Function normalization set " ;
1098 if (_funcNormSet) {
1099 _funcNormSet->Print("1") ;
1100 } else {
1101 os << "<none>";
1102 }
1103
1104 os << std::endl ;
1105}
1106
1107////////////////////////////////////////////////////////////////////////////////
1108/// Global switch to cache all integral values that integrate at least ndim dimensions numerically
1109
1111{
1112 _cacheAllNDim = ndim;
1113}
1114
1115////////////////////////////////////////////////////////////////////////////////
1116/// Return minimum dimensions of numeric integration for which values are cached.
1117
1122
1123std::unique_ptr<RooAbsArg>
1128
1129/// Sort numeric integration variables in summation and integration lists.
1130/// To be used during construction.
1132{
1133 if (dynamic_cast<RooAbsRealLValue const *>(&arg)) {
1134 _intList.add(arg, true);
1135 } else if (dynamic_cast<RooAbsCategoryLValue const *>(&arg)) {
1136 _sumList.add(arg, true);
1137 }
1138}
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)
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:60
static void indent(ostringstream &buf, int indent_level)
static unsigned int total
char name[80]
Definition TGX11.cxx:142
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2571
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:77
RooExpensiveObjectCache & expensiveObjectCache() const
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:239
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.
const TNamed * namePtr() const
De-duplicated pointer to this object's name.
Definition RooAbsArg.h:483
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:162
void removeServer(RooAbsArg &server, bool force=false)
Unregister another RooAbsArg as a server to us, ie, declare that we no longer depend on its value and...
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:419
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:186
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:146
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:105
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:98
bool getAttribute(const Text_t *name) const
Check if a named attribute is set. By default, all attributes are unset.
bool isValueOrShapeDirtyAndClear() const
Definition RooAbsArg.h:370
bool hasClients() const
Definition RooAbsArg.h:129
void setProxyNormSet(const RooArgSet *nset)
Forward a change in the cached normalization argset to all the registered proxies.
void branchNodeServerList(RooAbsCollection *list, const RooAbsArg *arg=nullptr, bool recurseNonDerived=false) const
Fill supplied list with all branch nodes of the arg tree starting with ourself as top node.
TObject * Clone(const char *newname=nullptr) const override
Make a clone of an object using the Streamer facility.
Definition RooAbsArg.h:89
RefCountList_t _serverList
Definition RooAbsArg.h:545
void leafNodeServerList(RooAbsCollection *list, const RooAbsArg *arg=nullptr, bool recurseNonDerived=false) const
Fill supplied list with all leaf nodes of the arg tree, starting with ourself as top node.
virtual bool isFundamental() const
Is this object a fundamental type that can be added to a dataset? Fundamental-type subclasses overrid...
Definition RooAbsArg.h:176
bool isValueServer(const RooAbsArg &arg) const
Check if this is serving values to arg.
Definition RooAbsArg.h:158
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:399
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.
bool contains(const char *name) const
Check if collection contains an argument with a specific name.
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.
virtual bool remove(const RooAbsArg &var, bool silent=false, bool matchByNameOnly=false)
Remove the specified argument from our list.
void sortTopologically()
Sort collection topologically: the servers of any RooAbsArg will be before that RooAbsArg in the coll...
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
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
void reserve(Storage_t::size_type count)
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 ...
virtual bool isJacobianOK(const RooArgSet &depList) const
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
virtual Int_t getAnalyticalIntegralWN(RooArgSet &allVars, RooArgSet &analVars, const RooArgSet *normSet, const char *rangeName=nullptr) const
Variant of getAnalyticalIntegral that is also passed the normalization set that should be applied to ...
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().
virtual bool forceAnalyticalInt(const RooAbsArg &) const
Definition RooAbsReal.h:170
double _value
Cache for current value of object.
Definition RooAbsReal.h:541
double traceEval(const RooArgSet *set) const
Calculate current value of object, with error tracing wrapper.
RooFit::UniqueId< RooArgSet >::Value_t _lastNormSetId
!
Definition RooAbsReal.h:548
virtual double analyticalIntegralWN(Int_t code, const RooArgSet *normSet, const char *rangeName=nullptr) const
Implements the actual analytical integral(s) advertised by getAnalyticalIntegral.
const RooNumIntConfig * getIntegratorConfig() const
Return the numeric integration configuration used for this object.
virtual bool isBinnedDistribution(const RooArgSet &) const
Tests if the distribution is binned. Unless overridden by derived classes, this always returns false.
Definition RooAbsReal.h:343
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.
std::unique_ptr< RooAbsIntegrator > createIntegrator(RooAbsFunc &func, const RooNumIntConfig &config, int ndim=0, bool isBinned=false) const
Construct a numeric integrator instance that operates on function 'func' and is configured with 'conf...
std::string getIntegratorName(RooAbsFunc &func, const RooNumIntConfig &config, int ndim=0, bool isBinned=false) const
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 setIndex(value_type index, bool printError=true) override
Set the value of the super category to the specified index.
bool inRange(const char *rangeName) const override
Check that all input category states are in the given range.
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:226
Basic string class.
Definition TString.h:137
TString & Append(const char *cs)
Definition TString.h:582
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