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 <RooChangeTracker.h>
33#include <RooNaNPacker.h>
34#include <RooFit/Evaluator.h>
35
37
38namespace RooFit {
39namespace TestStatistics {
40
41namespace {
42
44{
46 return {&pdf, &data};
47 }
48 // For the evaluation with the BatchMode, the pdf needs to be "compiled" for
49 // a given normalization set.
50 return {RooFit::Detail::compileForNormSet(pdf, *data.get()), &data};
51}
52
53} // namespace
54
57 : RooAbsL(clonePdfData(*pdf, *data, evalBackend), data->numEntries(), 1, extended)
58{
59 std::unique_ptr<RooArgSet> params(pdf->getParameters(data));
60 paramTracker_ = std::make_unique<RooChangeTracker>("chtracker", "change tracker", *params, true);
61
63 evaluator_ = std::make_unique<RooFit::Evaluator>(*pdf_, evalBackend.value() == RooFit::EvalBackend::Value::Cuda);
64 std::stack<std::vector<double>>{}.swap(_vectorBuffers);
65 // Zero-weight events must not be skipped here: the probabilities from
66 // the evaluator are indexed by the original event indices, aligned with
67 // the weights obtained from RooAbsData::getWeightBatch(). Events with
68 // zero weight are skipped in the summation instead.
69 auto dataSpans =
70 RooFit::BatchModeDataHelpers::getDataSpans(*data, "", nullptr, /*skipZeroWeights=*/false,
71 /*takeGlobalObservablesFromData=*/false, _vectorBuffers);
72 for (auto const &item : dataSpans) {
73 evaluator_->setInput(item.first->GetName(), item.second, false);
74 }
75 }
76}
77
79 : RooAbsL(other),
80 apply_weight_squared(other.apply_weight_squared),
81 _first(other._first),
82 lastSection_(other.lastSection_),
83 cachedResult_(other.cachedResult_),
84 evaluator_(other.evaluator_)
85{
86 paramTracker_ = std::make_unique<RooChangeTracker>(*other.paramTracker_);
87}
88
90
91//////////////////////////////////////////////////////////////////////////////////
92
93/// Returns true if value was changed, false otherwise.
95{
98 return true;
99 }
100 // setValueDirty();
101 return false;
102}
103
104namespace {
105
106using ComputeResult = std::pair<ROOT::Math::KahanSum<double>, double>;
107
108// Copy of RooNLLVar::computeScalarFunc.
110 std::size_t stepSize, std::size_t firstEvent, std::size_t lastEvent,
111 RooAbsPdf const *offsetPdf = nullptr)
112{
116
117 for (auto i = firstEvent; i < lastEvent; i += stepSize) {
118 dataClone->get(i);
119
120 double weight = dataClone->weight(); // FIXME
121
122 if (0. == weight * weight)
123 continue;
124 if (weightSq)
125 weight = dataClone->weightSquared();
126
127 double logProba = pdfClone->getLogVal(normSet);
128
129 if (offsetPdf) {
130 logProba -= offsetPdf->getLogVal(normSet);
131 }
132
133 const double term = -weight * logProba;
134
135 kahanWeight.Add(weight);
136 kahanProb.Add(term);
137 packedNaN.accumulate(term);
138 }
139
140 if (packedNaN.getPayload() != 0.) {
141 // Some events with evaluation errors. Return "badness" of errors.
142 return {ROOT::Math::KahanSum<double>{packedNaN.getNaNWithPayload()}, kahanWeight.Sum()};
143 }
144
145 return {kahanProb, kahanWeight.Sum()};
146}
147
148// Similar to computeScalarFunc, but the probabilities were already evaluated
149// as a batch, and the weights are also retrieved as batches instead of looping
150// over RooAbsData::get(i), which loads every column of the dataset only to
151// then read a single weight.
152ComputeResult computeBatchFunc(std::span<const double> probas, RooAbsData *dataClone, bool weightSq,
153 std::size_t stepSize, std::size_t firstEvent, std::size_t lastEvent)
154{
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> weights = dataClone->getWeightBatch(firstEvent, nEvents, /*sumW2=*/false);
162 std::span<const double> weightsSumW2 =
163 weightSq ? dataClone->getWeightBatch(firstEvent, nEvents, /*sumW2=*/true) : std::span<const double>{};
164
165 for (auto i = firstEvent; i < lastEvent; i += stepSize) {
166 double weight = weights.empty() ? 1.0 : weights[i - firstEvent];
167
168 if (0. == weight * weight)
169 continue;
170 if (weightSq)
171 weight = weightsSumW2.empty() ? 1.0 : weightsSumW2[i - firstEvent];
172
173 double logProba = std::log(probas[i]);
174 const double term = -weight * logProba;
175
176 kahanWeight.Add(weight);
177 kahanProb.Add(term);
178 packedNaN.accumulate(term);
179 }
180
181 if (packedNaN.getPayload() != 0.) {
182 // Some events with evaluation errors. Return "badness" of errors.
183 return {ROOT::Math::KahanSum<double>{packedNaN.getNaNWithPayload()}, kahanWeight.Sum()};
184 }
185
186 return {kahanProb, kahanWeight.Sum()};
187}
188
189} // namespace
190
191//////////////////////////////////////////////////////////////////////////////////
192/// Calculate and return likelihood on subset of data from firstEvent to lastEvent
193/// processed with a step size of 'stepSize'. If this an extended likelihood and
194/// and the zero event is processed the extended term is added to the return
195/// likelihood.
196///
198RooUnbinnedL::evaluatePartition(Section events, std::size_t /*components_begin*/, std::size_t /*components_end*/)
199{
200 // Throughout the calculation, we use Kahan's algorithm for summing to
201 // prevent loss of precision - this is a factor four more expensive than
202 // straight addition, but since evaluating the PDF is usually much more
203 // expensive than that, we tolerate the additional cost...
205 double sumWeight;
207
208 // Do not reevaluate likelihood if parameters nor event range have changed
209 if (!paramTracker_->hasChanged(true) && events == lastSection_ &&
210 (cachedResult_.Sum() != 0 || cachedResult_.Carry() != 0))
211 return cachedResult_;
212
213 if (evaluator_) {
214 // Here, we have a memory allocation that should be avoided when this
215 // code needs to be optimized.
216 std::span<const double> probas = evaluator_->run();
217 std::tie(result, sumWeight) =
218 computeBatchFunc(probas, data_.get(), apply_weight_squared, 1, events.begin(N_events_), events.end(N_events_));
219 } else {
220 std::tie(result, sumWeight) = computeScalarFunc(pdf_.get(), data_.get(), normSet_.get(), apply_weight_squared, 1,
221 events.begin(N_events_), events.end(N_events_));
222 }
223
224 // include the extended maximum likelihood term, if requested
225 if (extended_ && events.begin_fraction == 0) {
226 result += pdf_->extendedTerm(*data_, apply_weight_squared);
227 }
228
229 // If part of simultaneous PDF normalize probability over
230 // number of simultaneous PDFs: -sum(log(p/n)) = -sum(log(p)) + N*log(n)
231 if (sim_count_ > 1) {
232 result += sumWeight * log(1.0 * sim_count_);
233 }
234
235 // At the end of the first full calculation, wire the caches. This doesn't
236 // need to be done in BatchMode with the RooFit driver.
237 if (_first && !evaluator_) {
238 _first = false;
239 pdf_->wireAllCaches();
240 }
241
246 lastSection_ = events;
247 }
248 return result;
249}
250
251} // namespace TestStatistics
252} // 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
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_
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
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
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.