Logo ROOT  
Reference Guide
Loading...
Searching...
No Matches
RMergeableValue.hxx
Go to the documentation of this file.
1/**
2 \file ROOT/RDF/RMergeableValue.hxx
3 \author Vincenzo Eduardo Padulano
4 \author Enrico Guiraud
5 \date 2020-06
6*/
7
8/*************************************************************************
9 * Copyright (C) 1995-2022, Rene Brun and Fons Rademakers. *
10 * All rights reserved. *
11 * *
12 * For the licensing terms see $ROOTSYS/LICENSE. *
13 * For the list of contributors see $ROOTSYS/README/CREDITS. *
14 *************************************************************************/
15
16#ifndef ROOT_RDF_RMERGEABLEVALUE
17#define ROOT_RDF_RMERGEABLEVALUE
18
20
21#include <algorithm> // std::find, std::min, std::max
22#include <iterator> // std::distance
23#include <memory>
24#include <stdexcept>
25#include <string>
26#include <cmath>
27
28#include "RtypesCore.h"
29#include "TError.h" // R__ASSERT
30#include "TList.h" // RMergeableFill::Merge
31
32namespace ROOT {
33namespace Detail {
34namespace RDF {
35
36// Fwd declarations for RMergeableValue
37template <typename T>
38class RMergeableValue;
39
40template <typename T>
42
43template <typename T, typename... Ts>
44std::unique_ptr<RMergeableValue<T>> MergeValues(std::unique_ptr<RMergeableValue<T>> OutputMergeable,
45 std::unique_ptr<RMergeableValue<Ts>>... InputMergeables);
46
47template <typename T, typename... Ts>
48void MergeValues(RMergeableValue<T> &OutputMergeable, const RMergeableValue<Ts> &... InputMergeables);
49
50template <typename T, typename... Ts>
51void MergeValues(RMergeableVariations<T> &OutputMergeable, const RMergeableVariations<Ts> &... InputMergeables);
52
53/**
54\class ROOT::Detail::RDF::RMergeableValueBase
55\brief Base class of RMergeableValue.
56Base class of the mergeable RDataFrame results family of classes. Provides a
57non-templated custom type to allow passing a `std::unique_ptr` to the mergeable
58object along the call chain. This class is never used in the public API and has
59no meaning for the final user.
60*/
62public:
63 virtual ~RMergeableValueBase() = default;
64 /**
65 Default constructor. Needed to allow serialization of ROOT objects. See
66 [TBufferFile::WriteObjectClass]
67 (classTBufferFile.html#a209078a4cb58373b627390790bf0c9c1)
68 */
74};
75
76/**
77\class ROOT::Detail::RDF::RMergeableValue
78\ingroup dataframe
79\brief A result of an RDataFrame execution, that knows how to merge with other
80results of the same type.
81\tparam T Type of the action result.
82
83Results of the execution of an RDataFrame computation graph do not natively
84know how to merge with other results of the same type. In a distributed
85environment it is often needed to have a merging mechanism for partial results
86coming from the execution of an analysis on different chunks of the same dataset
87that has happened on different executors. In order to achieve this,
88RMergeableValue stores the result of the RDataFrame action and has a `Merge`
89method to allow the aggregation of information coming from another similar
90result into the current.
91
92A mergeable value can be retrieved from an RResultPtr through the
93[GetMergeableValue]
94(namespaceROOT_1_1Detail_1_1RDF.html#a8b3a9c7b416826acc952d78a56d14ecb) free
95function and a sequence of mergeables can be merged together with the helper
96function [MergeValues]
97(namespaceROOT_1_1Detail_1_1RDF.html#af16fefbe2d120983123ddf8a1e137277).
98All the classes and functions involved are inside the `ROOT::Detail::RDF`
99namespace.
100
101In a nutshell:
102~~~{.cpp}
103using namespace ROOT::Detail::RDF;
104ROOT::RDataFrame d("myTree", "file_*.root");
105auto h1 = d.Histo1D("Branch_A");
106auto h2 = d.Histo1D("Branch_A");
107
108// Retrieve mergeables from the `RResultPtr`s
109auto mergeableh1 = GetMergeableValue(h1);
110auto mergeableh2 = GetMergeableValue(h2);
111
112// Merge the values and get another mergeable back
113auto mergedptr = MergeValues(std::move(mergeableh1), std::move(mergeableh2));
114
115// Retrieve the merged TH1D object
116const auto &mergedhisto = mergedptr->GetValue();
117~~~
118
119Though this snippet can run on a single thread of a single machine, it is
120straightforward to generalize it to a distributed case, e.g. where `mergeableh1`
121and `mergeableh2` are created on separate machines and sent to a `reduce`
122process where the `MergeValues` function is called. The final user would then
123just be given the final merged result coming from `mergedptr->GetValue`.
124
125RMergeableValue is the base class for all the different specializations that may
126be needed according to the peculiarities of the result types. The following
127subclasses, their names hinting at the action operation of the result, are
128currently available:
129
130- RMergeableCount
131- RMergeableFill, responsible for the following actions:
132 - Graph
133 - Histo{1,2,3}D
134 - Profile{1,2}D
135 - Stats
136- RMergeableMax
137- RMergeableMean
138- RMergeableMin
139- RMergeableStdDev
140- RMergeableSum
141- RMergeableReport
142*/
143template <typename T>
145 // Friend function declarations
146 template <typename T1, typename... Ts>
147 friend std::unique_ptr<RMergeableValue<T1>> MergeValues(std::unique_ptr<RMergeableValue<T1>> OutputMergeable,
148 std::unique_ptr<RMergeableValue<Ts>>... InputMergeables);
149 template <typename T1, typename... Ts>
150 friend void MergeValues(RMergeableValue<T1> &OutputMergeable, const RMergeableValue<Ts> &... InputMergeables);
151
152 /////////////////////////////////////////////////////////////////////////////
153 /// \brief Aggregate the information contained in another RMergeableValue
154 /// into this.
155 ///
156 /// Virtual function reimplemented in all the subclasses.
157 ///
158 /// \note All the `Merge` methods in the RMergeableValue family are private.
159 /// To merge multiple RMergeableValue objects please use [MergeValues]
160 /// (namespaceROOT_1_1Detail_1_1RDF.html#af16fefbe2d120983123ddf8a1e137277).
161 virtual void Merge(const RMergeableValue<T> &) = 0;
162
163protected:
165
166public:
167 /**
168 Constructor taking the action result by const reference. This involves a
169 copy of the result into the data member, but gives full ownership of data
170 to the mergeable.
171 */
172 RMergeableValue(const T &value) : fValue{value} {}
173 /**
174 Default constructor. Needed to allow serialization of ROOT objects. See
175 [TBufferFile::WriteObjectClass]
176 (classTBufferFile.html#a209078a4cb58373b627390790bf0c9c1)
177 */
178 RMergeableValue() = default;
183 /////////////////////////////////////////////////////////////////////////////
184 /// \brief Retrieve the result wrapped by this mergeable.
185 const T &GetValue() const { return fValue; }
186};
187
188/**
189\class ROOT::Detail::RDF::RMergeableCount
190\brief Specialization of RMergeableValue for the
191[Count](classROOT_1_1RDF_1_1RInterface.html#a9678150c9c18cddd7b599690ba854734)
192action.
193*/
194class RMergeableCount final : public RMergeableValue<ULong64_t> {
195 /////////////////////////////////////////////////////////////////////////////
196 /// \brief Aggregate the information contained in another RMergeableValue
197 /// into this.
198 /// \param[in] other Another RMergeableValue object.
199 /// \throws std::invalid_argument If the cast of the other object to the same
200 /// type as this one fails.
201 ///
202 /// The other RMergeableValue object is cast to the same type as this object.
203 /// This is needed to make sure that only results of the same type of action
204 /// are merged together. Then the two results are added together to update
205 /// the value held by the current object.
206 ///
207 /// \note All the `Merge` methods in the RMergeableValue family are private.
208 /// To merge multiple RMergeableValue objects please use [MergeValues]
209 /// (namespaceROOT_1_1Detail_1_1RDF.html#af16fefbe2d120983123ddf8a1e137277).
210 void Merge(const RMergeableValue<ULong64_t> &other) final
211 {
212 try {
213 const auto &othercast = dynamic_cast<const RMergeableCount &>(other);
214 this->fValue += othercast.fValue;
215 } catch (const std::bad_cast &) {
216 throw std::invalid_argument("Results from different actions cannot be merged together.");
217 }
218 }
219
220public:
221 /////////////////////////////////////////////////////////////////////////////
222 /// \brief Constructor that initializes data members.
223 /// \param[in] value The action result.
225 /**
226 Default constructor. Needed to allow serialization of ROOT objects. See
227 [TBufferFile::WriteObjectClass]
228 (classTBufferFile.html#a209078a4cb58373b627390790bf0c9c1)
229 */
230 RMergeableCount() = default;
235};
236
237/**
238\class ROOT::Detail::RDF::RMergeableFill
239\brief Specialization of RMergeableValue for histograms and statistics.
240
241This subclass is responsible for merging results coming from the following
242actions:
243- [Graph](classROOT_1_1RDF_1_1RInterface.html#a804b466ebdbddef5c7e3400cc6b89301)
244- [Histo{1D,2D,3D}]
245 (classROOT_1_1RDF_1_1RInterface.html#a247ca3aeb7ce5b95015b7fae72983055)
246- [HistoND](classROOT_1_1RDF_1_1RInterface.html#a0c9956a0f48c26f8e4294e17376c7fea)
247- [HistoNSparseD](classROOT_1_1RDF_1_1RInterface.html)
248- [Profile{1D,2D}]
249 (classROOT_1_1RDF_1_1RInterface.html#a8ef7dc16b0e9f7bc9cfbe2d9e5de0cef)
250- [Stats](classROOT_1_1RDF_1_1RInterface.html#abc68922c464e472f5f856e8981955af6)
251
252*/
253template <typename T>
254class RMergeableFill final : public RMergeableValue<T> {
255
256 // RDataFrame's generic Fill method supports two possible signatures for Merge.
257 // Templated to create a dependent type to SFINAE on - in reality, `U` will always be `T`.
258 // This overload handles Merge(TCollection*)...
259 template <typename U, std::enable_if_t<std::is_base_of<TObject, U>::value, int> = 0>
260 auto DoMerge(const RMergeableFill<U> &other, int /*toincreaseoverloadpriority*/)
261 -> decltype(((U &)this->fValue).Merge((TCollection *)nullptr), void())
262 {
263 TList l; // The `Merge` method accepts a TList
264 l.Add(const_cast<U *>(&other.fValue)); // Ugly but needed because of the signature of TList::Add
265 this->fValue.Merge(&l); // if `T == TH1D` Eventually calls TH1::ExtendAxis that creates new instances of TH1D
266 }
267
268 // ...and this one handles Merge(const std::vector<T*> &)
269 template <typename U>
270 auto DoMerge(const RMergeableFill<U> &other, double /*todecreaseoverloadpriority*/)
271 -> decltype(this->fValue.Merge(std::vector<U *>{}), void())
272 {
273 this->fValue.Merge({const_cast<U *>(&other.fValue)});
274 }
275
276 /////////////////////////////////////////////////////////////////////////////
277 /// \brief Aggregate the information contained in another RMergeableValue
278 /// into this.
279 /// \param[in] other Another RMergeableValue object.
280 /// \throws std::invalid_argument If the cast of the other object to the same
281 /// type as this one fails.
282 ///
283 /// The other RMergeableValue object is cast to the same type as this object.
284 /// This is needed to make sure that only results of the same type of action
285 /// are merged together. The function then calls the right `Merge` method
286 /// according to the class of the fValue data member.
287 ///
288 /// \note All the `Merge` methods in the RMergeableValue family are private.
289 /// To merge multiple RMergeableValue objects please use [MergeValues]
290 /// (namespaceROOT_1_1Detail_1_1RDF.html#af16fefbe2d120983123ddf8a1e137277).
291 void Merge(const RMergeableValue<T> &other) final
292 {
293 try {
294 const auto &othercast = dynamic_cast<const RMergeableFill<T> &>(other);
295 DoMerge(othercast, /*toselecttherightoverload=*/0);
296 } catch (const std::bad_cast &) {
297 throw std::invalid_argument("Results from different actions cannot be merged together.");
298 }
299 }
300
301public:
302 /////////////////////////////////////////////////////////////////////////////
303 /// \brief Constructor that initializes data members.
304 /// \param[in] value The action result.
305 RMergeableFill(const T &value) : RMergeableValue<T>(value) {}
306 /**
307 Default constructor. Needed to allow serialization of ROOT objects. See
308 [TBufferFile::WriteObjectClass]
309 (classTBufferFile.html#a209078a4cb58373b627390790bf0c9c1)
310 */
311 RMergeableFill() = default;
316};
317
318template <typename T>
319class RMergeableMax final : public RMergeableValue<T> {
320
321 void Merge(const RMergeableValue<T> &other) final
322 {
323 try {
324 const auto &othercast = dynamic_cast<const RMergeableMax<T> &>(other);
325 this->fValue = std::max(this->fValue, othercast.fValue);
326 } catch (const std::bad_cast &) {
327 throw std::invalid_argument("Results from different actions cannot be merged together.");
328 }
329 }
330
331public:
332 /////////////////////////////////////////////////////////////////////////////
333 /// \brief Constructor that initializes data members.
334 /// \param[in] value The action result.
335 RMergeableMax(const T &value) : RMergeableValue<T>(value) {}
336 /**
337 Default constructor. Needed to allow serialization of ROOT objects. See
338 [TBufferFile::WriteObjectClass]
339 (classTBufferFile.html#a209078a4cb58373b627390790bf0c9c1)
340 */
341 RMergeableMax() = default;
342 RMergeableMax(const RMergeableMax &) = delete;
346};
347
348/**
349\class ROOT::Detail::RDF::RMergeableMean
350\brief Specialization of RMergeableValue for the
351[Mean](classROOT_1_1RDF_1_1RInterface.html#ade6b020284f2f4fe9d3b09246b5f376a)
352action.
353
354This subclass is responsible for merging results coming from Mean actions. Other
355than the result itself, the number of entries that were used to compute that
356mean is also stored in the object.
357*/
358class RMergeableMean final : public RMergeableValue<Double_t> {
359 ULong64_t fCounts; ///< The number of entries used to compute the mean.
360
361 /////////////////////////////////////////////////////////////////////////////
362 /// \brief Aggregate the information contained in another RMergeableValue
363 /// into this.
364 /// \param[in] other Another RMergeableValue object.
365 /// \throws std::invalid_argument If the cast of the other object to the same
366 /// type as this one fails.
367 ///
368 /// The other RMergeableValue object is cast to the same type as this object.
369 /// This is needed to make sure that only results of the same type of action
370 /// are merged together. The function then computes the weighted mean of the
371 /// two means held by the mergeables.
372 ///
373 /// \note All the `Merge` methods in the RMergeableValue family are private.
374 /// To merge multiple RMergeableValue objects please use [MergeValues]
375 /// (namespaceROOT_1_1Detail_1_1RDF.html#af16fefbe2d120983123ddf8a1e137277).
376 void Merge(const RMergeableValue<Double_t> &other) final
377 {
378 try {
379 const auto &othercast = dynamic_cast<const RMergeableMean &>(other);
380 const auto &othervalue = othercast.fValue;
381 const auto &othercounts = othercast.fCounts;
382
383 // Compute numerator and denumerator of the weighted mean
384 const auto num = this->fValue * fCounts + othervalue * othercounts;
385 const auto denum = static_cast<Double_t>(fCounts + othercounts);
386
387 // Update data members
388 this->fValue = num / denum;
389 fCounts += othercounts;
390 } catch (const std::bad_cast &) {
391 throw std::invalid_argument("Results from different actions cannot be merged together.");
392 }
393 }
394
395public:
396 /////////////////////////////////////////////////////////////////////////////
397 /// \brief Constructor that initializes data members.
398 /// \param[in] value The action result.
399 /// \param[in] counts The number of entries used to compute that result.
401 /**
402 Default constructor. Needed to allow serialization of ROOT objects. See
403 [TBufferFile::WriteObjectClass]
404 (classTBufferFile.html#a209078a4cb58373b627390790bf0c9c1)
405 */
406 RMergeableMean() = default;
411};
412
413template <typename T>
414class RMergeableMin final : public RMergeableValue<T> {
415
416 void Merge(const RMergeableValue<T> &other) final
417 {
418 try {
419 const auto &othercast = dynamic_cast<const RMergeableMin<T> &>(other);
420 this->fValue = std::min(this->fValue, othercast.fValue);
421 } catch (const std::bad_cast &) {
422 throw std::invalid_argument("Results from different actions cannot be merged together.");
423 }
424 }
425
426public:
427 /////////////////////////////////////////////////////////////////////////////
428 /// \brief Constructor that initializes data members.
429 /// \param[in] value The action result.
430 RMergeableMin(const T &value) : RMergeableValue<T>(value) {}
431 /**
432 Default constructor. Needed to allow serialization of ROOT objects. See
433 [TBufferFile::WriteObjectClass]
434 (classTBufferFile.html#a209078a4cb58373b627390790bf0c9c1)
435 */
436 RMergeableMin() = default;
437 RMergeableMin(const RMergeableMin &) = delete;
441};
442
443/**
444\class ROOT::Detail::RDF::RMergeableStdDev
445\brief Specialization of RMergeableValue for the
446[StdDev](classROOT_1_1RDF_1_1RInterface.html#a482c4e4f81fe1e421c016f89cd281572)
447action.
448
449This class also stores information about the number of entries and the average
450used to compute the standard deviation.
451*/
452class RMergeableStdDev final : public RMergeableValue<Double_t> {
453 ULong64_t fCounts; ///< Number of entries of the set.
454 Double_t fMean; ///< Average of the set.
455
456 /////////////////////////////////////////////////////////////////////////////
457 /// \brief Aggregate the information contained in another RMergeableValue
458 /// into this.
459 /// \param[in] other Another RMergeableValue object.
460 /// \throws std::invalid_argument If the cast of the other object to the same
461 /// type as this one fails.
462 ///
463 /// The other RMergeableValue object is cast to the same type as this object.
464 /// This is needed to make sure that only results of the same type of action
465 /// are merged together. The function then computes the aggregated standard
466 /// deviation of the two samples using an algorithm by
467 /// [Chan et al. (1979)]
468 /// (http://i.stanford.edu/pub/cstr/reports/cs/tr/79/773/CS-TR-79-773.pdf)
469 ///
470 /// \note All the `Merge` methods in the RMergeableValue family are private.
471 /// To merge multiple RMergeableValue objects please use [MergeValues]
472 /// (namespaceROOT_1_1Detail_1_1RDF.html#af16fefbe2d120983123ddf8a1e137277).
473 void Merge(const RMergeableValue<Double_t> &other) final
474 {
475 try {
476 const auto &othercast = dynamic_cast<const RMergeableStdDev &>(other);
477 const auto &othercounts = othercast.fCounts;
478 const auto &othermean = othercast.fMean;
479
480 // Compute the aggregated variance using an algorithm by Chan et al.
481 // See https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
482 const auto thisvariance = std::pow(this->fValue, 2);
483 const auto othervariance = std::pow(othercast.fValue, 2);
484
485 const auto delta = othermean - fMean;
486
487 const auto m_a = thisvariance * (fCounts - 1);
488 const auto m_b = othervariance * (othercounts - 1);
489
490 const auto sumcounts = static_cast<Double_t>(fCounts + othercounts);
491
492 const auto M2 = m_a + m_b + std::pow(delta, 2) * fCounts * othercounts / sumcounts;
493
494 const auto meannum = fMean * fCounts + othermean * othercounts;
495
496 // Update the data members
497 this->fValue = std::sqrt(M2 / (sumcounts - 1));
498 fMean = meannum / sumcounts;
499 fCounts += othercounts;
500 } catch (const std::bad_cast &) {
501 throw std::invalid_argument("Results from different actions cannot be merged together.");
502 }
503 }
504
505public:
506 /////////////////////////////////////////////////////////////////////////////
507 /// \brief Constructor that initializes data members.
508 /// \param[in] value The action result.
509 /// \param[in] counts The number of entries of the set.
510 /// \param[in] mean The average of the set.
512 : RMergeableValue<Double_t>(value), fCounts{counts}, fMean{mean}
513 {
514 }
515 /**
516 Default constructor. Needed to allow serialization of ROOT objects. See
517 [TBufferFile::WriteObjectClass]
518 (classTBufferFile.html#a209078a4cb58373b627390790bf0c9c1)
519 */
520 RMergeableStdDev() = default;
525};
526
527template <typename T>
528class RMergeableSum final : public RMergeableValue<T> {
529
530 void Merge(const RMergeableValue<T> &other) final
531 {
532 try {
533 const auto &othercast = dynamic_cast<const RMergeableSum<T> &>(other);
534 this->fValue += othercast.fValue;
535 } catch (const std::bad_cast &) {
536 throw std::invalid_argument("Results from different actions cannot be merged together.");
537 }
538 }
539
540public:
541 /////////////////////////////////////////////////////////////////////////////
542 /// \brief Constructor that initializes data members.
543 /// \param[in] value The action result.
544 RMergeableSum(const T &value) : RMergeableValue<T>(value) {}
545 /**
546 Default constructor. Needed to allow serialization of ROOT objects. See
547 [TBufferFile::WriteObjectClass]
548 (classTBufferFile.html#a209078a4cb58373b627390790bf0c9c1)
549 */
550 RMergeableSum() = default;
551 RMergeableSum(const RMergeableSum &) = delete;
555};
556
557/**
558\brief Specialization of RMergeableValue for the
559[Report](https://root.cern/doc/master/classROOT_1_1RDF_1_1RCutFlowReport.html)
560action.
561
562This subclass is responsible for merging results coming from Report actions. Other
563than the result itself, the vector of TCutInfos is stored in the object.
564*/
565class RMergeableReport final : public RMergeableValue<ROOT::RDF::RCutFlowReport> {
566
567 std::vector<ROOT::RDF::TCutInfo> fCutInfoVec;
569 {
571 const auto &othercast = dynamic_cast<const RMergeableReport &>(other);
572
573 for (unsigned long i = 0; i < fCutInfoVec.size(); i++) {
574
575 auto accumulated_pass = this->fCutInfoVec[i].GetPass() + othercast.fCutInfoVec[i].GetPass();
576 auto accumulated_all = this->fCutInfoVec[i].GetAll() + othercast.fCutInfoVec[i].GetAll();
577
578 // Updating the RCutFlowReport cut by cut
579 // Adding a cut which has an appropriate name and accumulated pass and all.
580 // We only want to merge reports that have the same cuts (given by their cut names).
581 if (this->fCutInfoVec[i].GetName() == othercast.fCutInfoVec[i].GetName()) {
582 // Adding a cut which has an appropriate name and accumulated pass and all
583 report.AddCut({this->fCutInfoVec[i].GetName(), accumulated_pass, accumulated_all});
584 } else {
585 throw std::runtime_error("Cutflow report with different cut names cannot be merged.");
586 }
587 }
588 this->fValue = report;
589 }
590
591public:
592 /////////////////////////////////////////////////////////////////////////////
593 /// \brief Constructor that initializes data members.
594 /// \param[in] value The action result.
595 /// \param[in] cutinfovec The vector of TCutInfos.
596 RMergeableReport(ROOT::RDF::RCutFlowReport value, std::vector<ROOT::RDF::TCutInfo> cutinfovec)
597 : RMergeableValue<ROOT::RDF::RCutFlowReport>(value), fCutInfoVec{cutinfovec}
598 {
599 }
600
601 /**
602 Default constructor. Needed to allow serialization of ROOT objects. See
603 [TBufferFile::WriteObjectClass]
604 (classTBufferFile.html#a209078a4cb58373b627390790bf0c9c1)
605 */
606 RMergeableReport() = default;
611};
612
613/**
614\class ROOT::Detail::RDF::RMergeableVariationsBase
615\brief A container for variation names and variation results.
616
617The class stores two vectors: one with the variation names, the other with
618corresponding mergeable variation values. These are retrieved from an RVariedAction
619(resulting from a call to ROOT::RDF::VariationsFor). The results are stored as
620type-erased RMergeableValueBase objects.
621*/
623protected:
624 std::vector<std::string> fKeys{};
625 std::vector<std::unique_ptr<RMergeableValueBase>> fValues{};
626
627public:
628 /**
629 Default constructor. Needed to allow serialization of ROOT objects. See
630 [TBufferFile::WriteObjectClass]
631 (classTBufferFile.html#a209078a4cb58373b627390790bf0c9c1)
632 */
636 /////////////////////////////////////////////////////////////////////////////
637 /// \brief Constructor that moves the data members from the input object.
638 /// \param[in] other The container from which the data members are moved.
639 ///
640 /// This constructor is needed as an helper in the RMergeableVariations
641 /// constructor that takes an RMergeableVariationsBase as input.
643 : fKeys{std::move(other.fKeys)}, fValues{std::move(other.fValues)}
644 {
645 }
647 ~RMergeableVariationsBase() override = default;
648
649 /////////////////////////////////////////////////////////////////////////////
650 /// \brief Constructor that initializes data members.
651 /// \param[in] keys The names of the variations.
652 /// \param[in] values The mergeable values containing the results of the
653 /// variations.
654 RMergeableVariationsBase(std::vector<std::string> &&keys, std::vector<std::unique_ptr<RMergeableValueBase>> &&values)
655 : fKeys{std::move(keys)}, fValues{std::move(values)}
656 {
657 }
658
659 /////////////////////////////////////////////////////////////////////////////
660 /// \brief Add an entry for the "nominal" value.
661 ///
662 /// The way client code is structured, the nominal value is provided separately from the others.
663 void AddNominal(std::unique_ptr<RMergeableValueBase> value)
664 {
665 fKeys.insert(fKeys.begin(), "nominal");
666 fValues.insert(fValues.begin(), std::move(value));
667 }
668};
669
670/**
671\class ROOT::Detail::RDF::RMergeableVariations
672\brief A container for variation names and variation results that knows how to
673 merge with others of the same type.
674\tparam T Type of the action result.
675*/
676template <typename T>
678
679 template <typename T1, typename... Ts>
680 friend void
681 MergeValues(RMergeableVariations<T1> &OutputMergeable, const RMergeableVariations<Ts> &... InputMergeables);
682
683 /////////////////////////////////////////////////////////////////////////////
684 /// \brief Aggregate the information contained in another RMergeableVariations
685 /// into this.
686 /// \param[in] other The other mergeable.
687 ///
688 /// Iterates over all values of the current object and calls
689 /// ROOT::Detail::RDF::MergeValues to merge with the corresponding value of
690 /// the other object.
691 ///
692 /// \note All the `Merge` methods in the RMergeableValue family are private.
693 /// To merge multiple RMergeableValue objects please use ROOT::Detail::RDF::MergeValues
695 {
696 R__ASSERT(fKeys == other.fKeys && "Mergeable variations have different names.");
697
698 for (std::size_t i = 0; i < fValues.size(); i++) {
699 // Cast to concrete types according to MergeValues signature
700 MergeValues(static_cast<RMergeableValue<T> &>(*fValues[i]),
701 static_cast<const RMergeableValue<T> &>(*other.fValues[i]));
702 }
703 }
704
705public:
706 /**
707 Default constructor. Needed to allow serialization of ROOT objects. See
708 [TBufferFile::WriteObjectClass]
709 (classTBufferFile.html#a209078a4cb58373b627390790bf0c9c1)
710 */
716 ~RMergeableVariations() final = default;
717
718 /////////////////////////////////////////////////////////////////////////////
719 /// \brief Constructor that initializes data members.
720 /// \param[in] base The container of the names and values.
721 ///
722 /// The variation names and values are moved from the base container into this.
724
725 /////////////////////////////////////////////////////////////////////////////
726 /// \brief Get the list of variation names.
727 const std::vector<std::string> &GetKeys() const { return fKeys; }
728 /////////////////////////////////////////////////////////////////////////////
729 /// \brief Get the final value from the mergeable corresponding to a certain
730 /// variation name.
731 /// \param[in] variationName The name.
732 ///
733 /// The variation name is used to retrieve the corresponding RMergeableValue
734 /// contained in this object. From that, the actual value is retrieved by
735 /// calling the ROOT::Detail::RDF::RMergeableValue::GetValue function.
736 const T &GetVariation(const std::string &variationName) const
737 {
738 auto it = std::find(std::begin(fKeys), std::end(fKeys), variationName);
739 if (it == std::end(fKeys)) {
740 throw std::runtime_error("RMergeableVariations: no result with key \"" + variationName + "\".");
741 } else {
742 auto pos = std::distance(std::begin(fKeys), it);
743 return static_cast<const RMergeableValue<T> &>(*fValues[pos]).GetValue();
744 }
745 }
746};
747
748/// \cond HIDDEN_SYMBOLS
749// What follows mimics C++17 std::conjunction without using recursive template instantiations.
750// Used in `MergeValues` to check that all the mergeables hold values of the same type.
751template <bool...>
752struct bool_pack {
753};
754template <class... Ts>
755using conjunction = std::is_same<bool_pack<true, Ts::value...>, bool_pack<Ts::value..., true>>;
756/// \endcond
757
758////////////////////////////////////////////////////////////////////////////////
759/// \brief Merge multiple RMergeableValue objects into one.
760/// \param[in] OutputMergeable The mergeable object where all the information
761/// will be aggregated.
762/// \param[in] InputMergeables Other mergeables containing the partial results.
763/// \returns An RMergeableValue holding the aggregated value wrapped in an
764/// `std::unique_ptr`.
765///
766/// This is the recommended way of merging multiple RMergeableValue objects.
767/// This overload takes ownership of the mergeables and gives back to the user
768/// a mergeable with the aggregated information. All the mergeables with the
769/// partial results get destroyed in the process.
770///
771/// Example usage:
772/// ~~~{.cpp}
773/// using namespace ROOT::Detail::RDF;
774/// // mh1, mh2, mh3 are std::unique_ptr<RMergeableValue<TH1D>>
775/// auto mergedptr = MergeValues(std::move(mh1), std::move(mh2), std::move(mh3));
776/// const auto &mergedhisto = mergedptr->GetValue(); // Final merged histogram
777/// // Do stuff with it
778/// mergedhisto.Draw();
779/// ~~~
780template <typename T, typename... Ts>
781std::unique_ptr<RMergeableValue<T>> MergeValues(std::unique_ptr<RMergeableValue<T>> OutputMergeable,
782 std::unique_ptr<RMergeableValue<Ts>>... InputMergeables)
783{
784 // Check all mergeables have the same template type
785 static_assert(conjunction<std::is_same<Ts, T>...>::value, "Values must all be of the same type.");
786
787 // Using dummy array initialization inspired by https://stackoverflow.com/a/25683817
788 using expander = int[];
789 // Cast to void to suppress unused-value warning in Clang
790 (void)expander{0, (OutputMergeable->Merge(*InputMergeables), 0)...};
791
792 return OutputMergeable;
793}
794
795////////////////////////////////////////////////////////////////////////////////
796/// \brief Merge multiple RMergeableValue objects into one.
797/// \param[in,out] OutputMergeable The mergeable object where all the
798/// information will be aggregated.
799/// \param[in] InputMergeables Other mergeables containing the partial results.
800///
801/// This overload modifies the mergeable objects in-place. The ownership is left
802/// to the caller. The first argument to the function will get all the
803/// values contained in the other arguments merged into itself. This is a
804/// convenience overload introduced for the ROOT Python API.
805///
806/// Example usage:
807/// ~~~{.cpp}
808/// // mh1, mh2, mh3 are std::unique_ptr<RMergeableValue<TH1D>>
809/// ROOT::Detail::RDF::MergeValues(*mh1, *mh2, *mh3);
810/// const auto &mergedhisto = mh1->GetValue(); // Final merged histogram
811/// // Do stuff with it
812/// mergedhisto.Draw();
813/// ~~~
814template <typename T, typename... Ts>
815void MergeValues(RMergeableValue<T> &OutputMergeable, const RMergeableValue<Ts> &... InputMergeables)
816{
817 // Check all mergeables are of the same type
818 static_assert(conjunction<std::is_same<Ts, T>...>::value, "Values must all be of the same type.");
819
820 // Using dummy array initialization inspired by https://stackoverflow.com/a/25683817
821 using expander = int[];
822 // Cast to void to suppress unused-value warning in Clang
823 (void)expander{0, (OutputMergeable.Merge(InputMergeables), 0)...};
824}
825
826////////////////////////////////////////////////////////////////////////////////
827/// \brief Merge multiple RMergeableVariations objects into one.
828/// \param[in,out] OutputMergeable The mergeable object where all the
829/// information will be aggregated.
830/// \param[in] InputMergeables Other mergeables containing the partial results.
831///
832/// This overload modifies the mergeable objects in-place. The ownership is left
833/// to the caller. The first argument to the function will get all the
834/// values contained in the other arguments merged into itself. This is a
835/// convenience overload introduced for the ROOT Python API.
836///
837/// Example usage:
838/// ~~~{.cpp}
839/// // mv1, mv2 are std::unique_ptr<RMergeableVariations<TH1D>>
840/// ROOT::Detail::RDF::MergeValues(*mv1, *mv2);
841/// const auto &keys = mv1->GetKeys(); // Names of the variations
842/// // Do stuff with the variations
843/// for(const auto &key: keys){
844/// const auto &histo = mv1->GetVariation(key); // Varied histogram
845/// std::cout << histo.GetEntries() << "\n";
846/// }
847/// ~~~
848template <typename T, typename... Ts>
849void MergeValues(RMergeableVariations<T> &OutputMergeable, const RMergeableVariations<Ts> &... InputMergeables)
850{
851 // Check all mergeables are of the same type
852 static_assert(conjunction<std::is_same<Ts, T>...>::value, "Values must all be of the same type.");
853
854 // Using dummy array initialization inspired by https://stackoverflow.com/a/25683817
855 using expander = int[];
856 // Cast to void to suppress unused-value warning in Clang
857 (void)expander{0, (OutputMergeable.Merge(InputMergeables), 0)...};
858}
859} // namespace RDF
860} // namespace Detail
861} // namespace ROOT
862
863#endif // ROOT_RDF_RMERGEABLEVALUE
Basic types used by ROOT and required by TInterpreter.
double Double_t
Double 8 bytes.
Definition RtypesCore.h:73
unsigned long long ULong64_t
Portable unsigned long integer 8 bytes.
Definition RtypesCore.h:84
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
RMergeableCount(const RMergeableCount &)=delete
void Merge(const RMergeableValue< ULong64_t > &other) final
Aggregate the information contained in another RMergeableValue into this.
RMergeableCount()=default
Default constructor.
RMergeableCount(ULong64_t value)
Constructor that initializes data members.
RMergeableCount & operator=(RMergeableCount &&)=delete
RMergeableCount(RMergeableCount &&)=delete
RMergeableCount & operator=(const RMergeableCount &)=delete
auto DoMerge(const RMergeableFill< U > &other, double) -> decltype(this->fValue.Merge(std::vector< U * >{}), void())
auto DoMerge(const RMergeableFill< U > &other, int) -> decltype(((U &) this->fValue).Merge((TCollection *) nullptr), void())
RMergeableFill()=default
Default constructor.
RMergeableFill(RMergeableFill &&)=delete
RMergeableFill(const T &value)
Constructor that initializes data members.
RMergeableFill & operator=(RMergeableFill &&)=delete
void Merge(const RMergeableValue< T > &other) final
Aggregate the information contained in another RMergeableValue into this.
RMergeableFill & operator=(const RMergeableFill &)=delete
RMergeableFill(const RMergeableFill &)=delete
RMergeableMax(const T &value)
Constructor that initializes data members.
void Merge(const RMergeableValue< T > &other) final
Aggregate the information contained in another RMergeableValue into this.
RMergeableMax()=default
Default constructor.
RMergeableMax & operator=(const RMergeableMax &)=delete
RMergeableMax(RMergeableMax &&)=delete
RMergeableMax & operator=(RMergeableMax &&)=delete
RMergeableMax(const RMergeableMax &)=delete
RMergeableMean(Double_t value, ULong64_t counts)
Constructor that initializes data members.
RMergeableMean(const RMergeableMean &)=delete
ULong64_t fCounts
The number of entries used to compute the mean.
RMergeableMean()=default
Default constructor.
RMergeableMean & operator=(const RMergeableMean &)=delete
void Merge(const RMergeableValue< Double_t > &other) final
Aggregate the information contained in another RMergeableValue into this.
RMergeableMean(RMergeableMean &&)=delete
RMergeableMean & operator=(RMergeableMean &&)=delete
RMergeableMin()=default
Default constructor.
RMergeableMin(RMergeableMin &&)=delete
RMergeableMin(const RMergeableMin &)=delete
RMergeableMin(const T &value)
Constructor that initializes data members.
void Merge(const RMergeableValue< T > &other) final
Aggregate the information contained in another RMergeableValue into this.
RMergeableMin & operator=(const RMergeableMin &)=delete
RMergeableMin & operator=(RMergeableMin &&)=delete
RMergeableReport & operator=(const RMergeableReport &)=delete
RMergeableReport()=default
Default constructor.
RMergeableReport(ROOT::RDF::RCutFlowReport value, std::vector< ROOT::RDF::TCutInfo > cutinfovec)
Constructor that initializes data members.
std::vector< ROOT::RDF::TCutInfo > fCutInfoVec
RMergeableReport(const RMergeableReport &)=delete
void Merge(const RMergeableValue< ROOT::RDF::RCutFlowReport > &other) final
Aggregate the information contained in another RMergeableValue into this.
RMergeableReport & operator=(RMergeableReport &&)=delete
RMergeableReport(RMergeableReport &&)=delete
RMergeableStdDev(Double_t value, ULong64_t counts, Double_t mean)
Constructor that initializes data members.
void Merge(const RMergeableValue< Double_t > &other) final
Aggregate the information contained in another RMergeableValue into this.
RMergeableStdDev(const RMergeableStdDev &)=delete
RMergeableStdDev & operator=(RMergeableStdDev &&)=delete
ULong64_t fCounts
Number of entries of the set.
RMergeableStdDev(RMergeableStdDev &&)=delete
Double_t fMean
Average of the set.
RMergeableStdDev & operator=(const RMergeableStdDev &)=delete
RMergeableStdDev()=default
Default constructor.
RMergeableSum()=default
Default constructor.
RMergeableSum(const T &value)
Constructor that initializes data members.
RMergeableSum(const RMergeableSum &)=delete
RMergeableSum & operator=(RMergeableSum &&)=delete
RMergeableSum(RMergeableSum &&)=delete
void Merge(const RMergeableValue< T > &other) final
Aggregate the information contained in another RMergeableValue into this.
RMergeableSum & operator=(const RMergeableSum &)=delete
RMergeableValueBase()=default
Default constructor.
RMergeableValueBase(RMergeableValueBase &&)=delete
RMergeableValueBase & operator=(RMergeableValueBase &&)=delete
RMergeableValueBase & operator=(const RMergeableValueBase &)=delete
RMergeableValueBase(const RMergeableValueBase &)=delete
A result of an RDataFrame execution, that knows how to merge with other results of the same type.
RMergeableValue()=default
Default constructor.
RMergeableValue(const RMergeableValue &)=delete
RMergeableValue(RMergeableValue &&)=delete
const T & GetValue() const
Retrieve the result wrapped by this mergeable.
RMergeableValue & operator=(const RMergeableValue &)=delete
friend void MergeValues(RMergeableValue< T1 > &OutputMergeable, const RMergeableValue< Ts > &... InputMergeables)
friend std::unique_ptr< RMergeableValue< T1 > > MergeValues(std::unique_ptr< RMergeableValue< T1 > > OutputMergeable, std::unique_ptr< RMergeableValue< Ts > >... InputMergeables)
RMergeableValue(const T &value)
Constructor taking the action result by const reference.
virtual void Merge(const RMergeableValue< T > &)=0
Aggregate the information contained in another RMergeableValue into this.
RMergeableValue & operator=(RMergeableValue &&)=delete
RMergeableVariationsBase()=default
Default constructor.
RMergeableVariationsBase & operator=(RMergeableVariationsBase &&)=delete
std::vector< std::unique_ptr< RMergeableValueBase > > fValues
RMergeableVariationsBase(std::vector< std::string > &&keys, std::vector< std::unique_ptr< RMergeableValueBase > > &&values)
Constructor that initializes data members.
void AddNominal(std::unique_ptr< RMergeableValueBase > value)
Add an entry for the "nominal" value.
RMergeableVariationsBase & operator=(const RMergeableVariationsBase &)=delete
RMergeableVariationsBase(const RMergeableVariationsBase &)=delete
RMergeableVariationsBase(RMergeableVariationsBase &&other)
Constructor that moves the data members from the input object.
A container for variation names and variation results that knows how to merge with others of the same...
void Merge(const RMergeableVariations< T > &other)
Aggregate the information contained in another RMergeableVariations into this.
const T & GetVariation(const std::string &variationName) const
Get the final value from the mergeable corresponding to a certain variation name.
RMergeableVariations & operator=(const RMergeableVariations &)=delete
RMergeableVariations()=default
Default constructor.
RMergeableVariations & operator=(RMergeableVariations &&)=delete
const std::vector< std::string > & GetKeys() const
Get the list of variation names.
RMergeableVariations(RMergeableVariations &&)=delete
friend void MergeValues(RMergeableVariations< T1 > &OutputMergeable, const RMergeableVariations< Ts > &... InputMergeables)
RMergeableVariations(const RMergeableVariations &)=delete
void AddCut(TCutInfo &&ci)
Collection abstract base class.
Definition TCollection.h:65
A doubly linked list.
Definition TList.h:38
#define T1
Definition md5.inl:146
std::unique_ptr< RMergeableValue< T > > MergeValues(std::unique_ptr< RMergeableValue< T > > OutputMergeable, std::unique_ptr< RMergeableValue< Ts > >... InputMergeables)
Merge multiple RMergeableValue objects into one.
Special implementation of ROOT::RRangeCast for TCollection, including a check that the cast target ty...
Definition TObject.h:395
double T(double x)
TLine l
Definition textangle.C:4