Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RooUnbinnedL.cxx
Go to the documentation of this file.
1/*
2 * Project: RooFit
3 * Authors:
4 * PB, Patrick Bos, Netherlands eScience Center, p.bos@esciencecenter.nl
5 *
6 * Copyright (c) 2021, CERN
7 *
8 * Redistribution and use in source and binary forms,
9 * with or without modification, are permitted according to the terms
10 * listed in LICENSE (http://roofit.sourceforge.net/license.txt)
11 */
12
13/**
14\file RooUnbinnedL.cxx
15\class RooUnbinnedL
16\ingroup Roofitcore
17
18A -log(likelihood) calculation from a dataset
19(assumed to be unbinned) and a PDF. The NLL is calculated as
20\f[
21 \sum_\mathrm{data} -\log( \mathrm{pdf}(x_\mathrm{data}))
22\f]
23In extended mode, a
24\f$ N_\mathrm{expect} - N_\mathrm{observed}*log(N_\mathrm{expect}) \f$ term is added.
25**/
26
28
29#include <RooAbsData.h>
30#include <RooAbsPdf.h>
31#include <RooAbsDataStore.h>
32#include <RooBatchCompute.h>
33#include <RooChangeTracker.h>
34#include <RooNaNPacker.h>
35#include <RooFit/Evaluator.h>
36
38
39namespace RooFit {
40namespace TestStatistics {
41
42namespace {
43
45{
47 return {&pdf, &data};
48 }
49 // For the evaluation with the BatchMode, the pdf needs to be "compiled" for
50 // a given normalization set.
51 return {RooFit::Detail::compileForNormSet(pdf, *data.get()), &data};
52}
53
54} // namespace
55
58 : RooAbsL(clonePdfData(*pdf, *data, evalBackend), data->numEntries(), 1, extended)
59{
60 std::unique_ptr<RooArgSet> params(pdf->getParameters(data));
61 paramTracker_ = std::make_unique<RooChangeTracker>("chtracker", "change tracker", *params, true);
62
64 evaluator_ = std::make_unique<RooFit::Evaluator>(*pdf_, evalBackend.value() == RooFit::EvalBackend::Value::Cuda);
65 std::stack<std::vector<double>>{}.swap(_vectorBuffers);
66 // Zero-weight events must not be skipped here: the probabilities from
67 // the evaluator are indexed by the original event indices, aligned with
68 // the weights obtained from RooAbsData::getWeightBatch(). Events with
69 // zero weight are skipped in the summation instead.
70 auto dataSpans =
71 RooFit::BatchModeDataHelpers::getDataSpans(*data, "", nullptr, /*skipZeroWeights=*/false,
72 /*takeGlobalObservablesFromData=*/false, _vectorBuffers);
73 for (auto const &item : dataSpans) {
74 evaluator_->setInput(item.first->GetName(), item.second, false);
75 }
76 }
77}
78
80 : RooAbsL(other),
81 apply_weight_squared(other.apply_weight_squared),
82 _first(other._first),
83 lastSection_(other.lastSection_),
84 cachedResult_(other.cachedResult_),
85 evaluator_(other.evaluator_)
86{
87 paramTracker_ = std::make_unique<RooChangeTracker>(*other.paramTracker_);
88}
89
91
92//////////////////////////////////////////////////////////////////////////////////
93
94/// Returns true if value was changed, false otherwise.
96{
99 return true;
100 }
101 // setValueDirty();
102 return false;
103}
104
105namespace {
106
107using ComputeResult = std::pair<ROOT::Math::KahanSum<double>, double>;
108
109// Copy of RooNLLVar::computeScalarFunc.
111 std::size_t stepSize, std::size_t firstEvent, std::size_t lastEvent,
112 RooAbsPdf const *offsetPdf = nullptr)
113{
117
118 for (auto i = firstEvent; i < lastEvent; i += stepSize) {
119 dataClone->get(i);
120
121 double weight = dataClone->weight(); // FIXME
122
123 if (0. == weight * weight)
124 continue;
125 if (weightSq)
126 weight = dataClone->weightSquared();
127
128 double logProba = pdfClone->getLogVal(normSet);
129
130 if (offsetPdf) {
131 logProba -= offsetPdf->getLogVal(normSet);
132 }
133
134 const double term = -weight * logProba;
135
136 kahanWeight.Add(weight);
137 kahanProb.Add(term);
138 packedNaN.accumulate(term);
139 }
140
141 if (packedNaN.getPayload() != 0.) {
142 // Some events with evaluation errors. Return "badness" of errors.
143 return {ROOT::Math::KahanSum<double>{packedNaN.getNaNWithPayload()}, kahanWeight.Sum()};
144 }
145
146 return {kahanProb, kahanWeight.Sum()};
147}
148
149// Similar to computeScalarFunc, but the probabilities were already evaluated
150// as a batch, and the weights are also retrieved as batches instead of looping
151// over RooAbsData::get(i), which loads every column of the dataset only to
152// then read a single weight. The reduction is done with the same vectorized
153// RooBatchCompute::reduceNLL() that RooNLLVarNew uses in the standard
154// evaluation backend, including its RooNaNPacker-based error propagation.
155ComputeResult computeBatchFunc(std::span<const double> probas, RooAbsData *dataClone, bool weightSq,
156 std::size_t firstEvent, std::size_t lastEvent, std::vector<double> &unitWeights,
157 RooBatchCompute::Config const &cfg)
158{
159 const std::size_t nEvents = lastEvent - firstEvent;
160 // Empty spans mean the dataset is unweighted, i.e. all weights are one.
161 std::span<const double> dataWeights = dataClone->getWeightBatch(firstEvent, nEvents, /*sumW2=*/weightSq);
162
163 double sumWeight;
164 const double *weightData = nullptr;
165 std::size_t nWeights = 0;
166 if (dataWeights.empty()) {
167 if (unitWeights.size() < nEvents) {
168 unitWeights.assign(nEvents, 1.0);
169 }
170 weightData = unitWeights.data();
171 nWeights = nEvents;
172 sumWeight = nEvents;
173 } else {
174 weightData = dataWeights.data();
175 nWeights = dataWeights.size();
177 }
178 std::span<const double> weights{weightData, nWeights};
179
180 std::span<const double> probasInRange{probas.data() + firstEvent, nEvents};
181
182 auto out = RooBatchCompute::reduceNLL(cfg, probasInRange, weights, {});
183 return {ROOT::Math::KahanSum<double>{out.nllSum, out.nllSumCarry}, sumWeight};
184}
185
186} // namespace
187
188//////////////////////////////////////////////////////////////////////////////////
189/// Calculate and return likelihood on subset of data from firstEvent to lastEvent
190/// processed with a step size of 'stepSize'. If this an extended likelihood and
191/// and the zero event is processed the extended term is added to the return
192/// likelihood.
193///
195RooUnbinnedL::evaluatePartition(Section events, std::size_t /*components_begin*/, std::size_t /*components_end*/)
196{
197 // Throughout the calculation, we use Kahan's algorithm for summing to
198 // prevent loss of precision - this is a factor four more expensive than
199 // straight addition, but since evaluating the PDF is usually much more
200 // expensive than that, we tolerate the additional cost...
202 double sumWeight;
204
205 // Do not reevaluate likelihood if parameters nor event range have changed
206 if (!paramTracker_->hasChanged(true) && events == lastSection_ &&
207 (cachedResult_.Sum() != 0 || cachedResult_.Carry() != 0))
208 return cachedResult_;
209
210 if (evaluator_) {
211 // Here, we have a memory allocation that should be avoided when this
212 // code needs to be optimized.
213 std::span<const double> probas = evaluator_->run();
214 std::tie(result, sumWeight) = computeBatchFunc(probas, data_.get(), apply_weight_squared, events.begin(N_events_),
216 } else {
217 std::tie(result, sumWeight) = computeScalarFunc(pdf_.get(), data_.get(), normSet_.get(), apply_weight_squared, 1,
218 events.begin(N_events_), events.end(N_events_));
219 }
220
221 // include the extended maximum likelihood term, if requested
222 if (extended_ && events.begin_fraction == 0) {
223 result += pdf_->extendedTerm(*data_, apply_weight_squared);
224 }
225
226 // If part of simultaneous PDF normalize probability over
227 // number of simultaneous PDFs: -sum(log(p/n)) = -sum(log(p)) + N*log(n)
228 if (sim_count_ > 1) {
229 result += sumWeight * log(1.0 * sim_count_);
230 }
231
232 // At the end of the first full calculation, wire the caches. This doesn't
233 // need to be done in BatchMode with the RooFit driver.
234 if (_first && !evaluator_) {
235 _first = false;
236 pdf_->wireAllCaches();
237 }
238
243 lastSection_ = events;
244 }
245 return result;
246}
247
248} // namespace TestStatistics
249} // namespace RooFit
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
The Kahan summation is a compensated summation algorithm, which significantly reduces numerical error...
Definition Util.h:141
T Sum() const
Definition Util.h:259
T Carry() const
Definition Util.h:269
RooFit::OwningPtr< RooArgSet > getParameters(const RooAbsData *data, bool stripDisconnected=true) const
Create a list of leaf nodes in the arg tree starting with ourself as top node that don't match any of...
Abstract base class for binned and unbinned datasets.
Definition RooAbsData.h:55
Abstract interface for all probability density functions.
Definition RooAbsPdf.h:32
static ErrorLoggingMode evalErrorLoggingMode()
Return current evaluation error logging mode.
static Int_t numEvalErrors()
Return the number of logged evaluation errors since the last clearing.
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:24
Minimal configuration struct to steer the evaluation of a single node with the RooBatchCompute librar...
std::shared_ptr< RooAbsData > data_
Definition RooAbsL.h:136
std::unique_ptr< RooArgSet > normSet_
Pointer to set with observables used for normalization.
Definition RooAbsL.h:137
std::shared_ptr< RooAbsPdf > pdf_
Definition RooAbsL.h:135
ROOT::Math::KahanSum< double > cachedResult_
std::vector< double > _unitWeights
! all-ones weights for unweighted data in batched evaluation
bool setApplyWeightSquared(bool flag)
Returns true if value was changed, false otherwise.
ROOT::Math::KahanSum< double > evaluatePartition(Section events, std::size_t components_begin, std::size_t components_end) override
Calculate and return likelihood on subset of data from firstEvent to lastEvent processed with a step ...
RooUnbinnedL(RooAbsPdf *pdf, RooAbsData *data, RooAbsL::Extended extended=RooAbsL::Extended::Auto, RooFit::EvalBackend evalBackend=RooFit::EvalBackend(RooFit::EvalBackend::Value::Legacy))
std::unique_ptr< RooChangeTracker > paramTracker_
bool apply_weight_squared
Apply weights squared?
std::stack< std::vector< double > > _vectorBuffers
std::shared_ptr< RooFit::Evaluator > evaluator_
! For batched evaluation
double reduceSum(Config cfg, InputArr input, size_t n)
ReduceNLLOutput reduceNLL(Config cfg, std::span< const double > probas, std::span< const double > weights, std::span< const double > offsetProbas)
std::unique_ptr< T > compileForNormSet(T const &arg, RooArgSet const &normSet)
The namespace RooFit contains mostly switches that change the behaviour of functions of PDFs (or othe...
Definition CodegenImpl.h:73
void probas(TString dataset, TString fin="TMVA.root", Bool_t useTMVAStyle=kTRUE)
A part of some range delimited by two fractional points between 0 and 1 (inclusive).
Definition RooAbsL.h:64
std::size_t begin(std::size_t N_total) const
Definition RooAbsL.h:72
std::size_t end(std::size_t N_total) const
Definition RooAbsL.h:74
Little struct that can pack a float into the unused bits of the mantissa of a NaN double.