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