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
20#include <algorithm> // std::find, std::min, std::max
21#include <iterator> // std::distance
22#include <memory>
23#include <stdexcept>
24#include <string>
25#include <cmath>
26
27#include "RtypesCore.h"
28#include "TError.h" // R__ASSERT
29#include "TList.h" // RMergeableFill::Merge
30
31namespace ROOT {
32namespace Detail {
33namespace RDF {
34
35// Fwd declarations for RMergeableValue
36template <typename T>
37class RMergeableValue;
38
39template <typename T>
40class RMergeableVariations;
41
42template <typename T, typename... Ts>
43std::unique_ptr<RMergeableValue<T>> MergeValues(std::unique_ptr<RMergeableValue<T>> OutputMergeable,
44 std::unique_ptr<RMergeableValue<Ts>>... InputMergeables);
45
46template <typename T, typename... Ts>
48
49template <typename T, typename... Ts>
51
52/**
53\class ROOT::Detail::RDF::RMergeableValueBase
54\brief Base class of RMergeableValue.
55\ingroup dataframe
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*/
142template <typename T>
144 // Friend function declarations
145 template <typename T1, typename... Ts>
146 friend std::unique_ptr<RMergeableValue<T1>> MergeValues(std::unique_ptr<RMergeableValue<T1>> OutputMergeable,
147 std::unique_ptr<RMergeableValue<Ts>>... InputMergeables);
148 template <typename T1, typename... Ts>
150
151 /////////////////////////////////////////////////////////////////////////////
152 /// \brief Aggregate the information contained in another RMergeableValue
153 /// into this.
154 ///
155 /// Virtual function reimplemented in all the subclasses.
156 ///
157 /// \note All the `Merge` methods in the RMergeableValue family are private.
158 /// To merge multiple RMergeableValue objects please use [MergeValues]
159 /// (namespaceROOT_1_1Detail_1_1RDF.html#af16fefbe2d120983123ddf8a1e137277).
160 virtual void Merge(const RMergeableValue<T> &) = 0;
161
162protected:
164
165public:
166 /**
167 Constructor taking the action result by const reference. This involves a
168 copy of the result into the data member, but gives full ownership of data
169 to the mergeable.
170 */
172 /**
173 Default constructor. Needed to allow serialization of ROOT objects. See
174 [TBufferFile::WriteObjectClass]
175 (classTBufferFile.html#a209078a4cb58373b627390790bf0c9c1)
176 */
177 RMergeableValue() = default;
182 /////////////////////////////////////////////////////////////////////////////
183 /// \brief Retrieve the result wrapped by this mergeable.
184 const T &GetValue() const { return fValue; }
185};
186
187/**
188\class ROOT::Detail::RDF::RMergeableCount
189\ingroup dataframe
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).
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\ingroup dataframe
240\brief Specialization of RMergeableValue for histograms and statistics.
241
242This subclass is responsible for merging results coming from the following
243actions:
244- [Graph](classROOT_1_1RDF_1_1RInterface.html#a804b466ebdbddef5c7e3400cc6b89301)
245- [Histo{1D,2D,3D}]
246 (classROOT_1_1RDF_1_1RInterface.html#a247ca3aeb7ce5b95015b7fae72983055)
247- [HistoND](classROOT_1_1RDF_1_1RInterface.html#a0c9956a0f48c26f8e4294e17376c7fea)
248- [HistoNSparseD](classROOT_1_1RDF_1_1RInterface.html)
249- [Profile{1D,2D}]
250 (classROOT_1_1RDF_1_1RInterface.html#a8ef7dc16b0e9f7bc9cfbe2d9e5de0cef)
251- [Stats](classROOT_1_1RDF_1_1RInterface.html#abc68922c464e472f5f856e8981955af6)
252
253*/
254template <typename T>
256
257 // RDataFrame's generic Fill method supports two possible signatures for Merge.
258 // Templated to create a dependent type to SFINAE on - in reality, `U` will always be `T`.
259 // This overload handles Merge(TCollection*)...
261 auto DoMerge(const RMergeableFill<U> &other, int /*toincreaseoverloadpriority*/)
262 -> decltype(((U &)this->fValue).Merge((TCollection *)nullptr), void())
263 {
264 TList l; // The `Merge` method accepts a TList
265 l.Add(const_cast<U *>(&other.fValue)); // Ugly but needed because of the signature of TList::Add
266 this->fValue.Merge(&l); // if `T == TH1D` Eventually calls TH1::ExtendAxis that creates new instances of TH1D
267 }
268
269 // ...and this one handles Merge(const std::vector<T*> &)
270 template <typename U>
271 auto DoMerge(const RMergeableFill<U> &other, double /*todecreaseoverloadpriority*/)
272 -> decltype(this->fValue.Merge(std::vector<U *>{}), void())
273 {
274 this->fValue.Merge({const_cast<U *>(&other.fValue)});
275 }
276
277 /////////////////////////////////////////////////////////////////////////////
278 /// \brief Aggregate the information contained in another RMergeableValue
279 /// into this.
280 /// \param[in] other Another RMergeableValue object.
281 /// \throws std::invalid_argument If the cast of the other object to the same
282 /// type as this one fails.
283 ///
284 /// The other RMergeableValue object is cast to the same type as this object.
285 /// This is needed to make sure that only results of the same type of action
286 /// are merged together. The function then calls the right `Merge` method
287 /// according to the class of the fValue data member.
288 ///
289 /// \note All the `Merge` methods in the RMergeableValue family are private.
290 /// To merge multiple RMergeableValue objects please use [MergeValues]
291 /// (namespaceROOT_1_1Detail_1_1RDF.html#af16fefbe2d120983123ddf8a1e137277).
292 void Merge(const RMergeableValue<T> &other) final
293 {
294 try {
295 const auto &othercast = dynamic_cast<const RMergeableFill<T> &>(other);
296 DoMerge(othercast, /*toselecttherightoverload=*/0);
297 } catch (const std::bad_cast &) {
298 throw std::invalid_argument("Results from different actions cannot be merged together.");
299 }
300 }
301
302public:
303 /////////////////////////////////////////////////////////////////////////////
304 /// \brief Constructor that initializes data members.
305 /// \param[in] value The action result.
307 /**
308 Default constructor. Needed to allow serialization of ROOT objects. See
309 [TBufferFile::WriteObjectClass]
310 (classTBufferFile.html#a209078a4cb58373b627390790bf0c9c1)
311 */
312 RMergeableFill() = default;
317};
318
319template <typename T>
321
322 void Merge(const RMergeableValue<T> &other) final
323 {
324 try {
325 const auto &othercast = dynamic_cast<const RMergeableMax<T> &>(other);
326 this->fValue = std::max(this->fValue, othercast.fValue);
327 } catch (const std::bad_cast &) {
328 throw std::invalid_argument("Results from different actions cannot be merged together.");
329 }
330 }
331
332public:
333 /////////////////////////////////////////////////////////////////////////////
334 /// \brief Constructor that initializes data members.
335 /// \param[in] value The action result.
337 /**
338 Default constructor. Needed to allow serialization of ROOT objects. See
339 [TBufferFile::WriteObjectClass]
340 (classTBufferFile.html#a209078a4cb58373b627390790bf0c9c1)
341 */
342 RMergeableMax() = default;
343 RMergeableMax(const RMergeableMax &) = delete;
347};
348
349/**
350\class ROOT::Detail::RDF::RMergeableMean
351\ingroup dataframe
352\brief Specialization of RMergeableValue for the
353[Mean](classROOT_1_1RDF_1_1RInterface.html#ade6b020284f2f4fe9d3b09246b5f376a)
354action.
355
356This subclass is responsible for merging results coming from Mean actions. Other
357than the result itself, the number of entries that were used to compute that
358mean is also stored in the object.
359*/
360class RMergeableMean final : public RMergeableValue<Double_t> {
361 ULong64_t fCounts; ///< The number of entries used to compute the mean.
362
363 /////////////////////////////////////////////////////////////////////////////
364 /// \brief Aggregate the information contained in another RMergeableValue
365 /// into this.
366 /// \param[in] other Another RMergeableValue object.
367 /// \throws std::invalid_argument If the cast of the other object to the same
368 /// type as this one fails.
369 ///
370 /// The other RMergeableValue object is cast to the same type as this object.
371 /// This is needed to make sure that only results of the same type of action
372 /// are merged together. The function then computes the weighted mean of the
373 /// two means held by the mergeables.
374 ///
375 /// \note All the `Merge` methods in the RMergeableValue family are private.
376 /// To merge multiple RMergeableValue objects please use [MergeValues]
377 /// (namespaceROOT_1_1Detail_1_1RDF.html#af16fefbe2d120983123ddf8a1e137277).
379 {
380 try {
381 const auto &othercast = dynamic_cast<const RMergeableMean &>(other);
382 const auto &othervalue = othercast.fValue;
383 const auto &othercounts = othercast.fCounts;
384
385 // Compute numerator and denumerator of the weighted mean
386 const auto num = this->fValue * fCounts + othervalue * othercounts;
387 const auto denum = static_cast<Double_t>(fCounts + othercounts);
388
389 // Update data members
390 this->fValue = num / denum;
392 } catch (const std::bad_cast &) {
393 throw std::invalid_argument("Results from different actions cannot be merged together.");
394 }
395 }
396
397public:
398 /////////////////////////////////////////////////////////////////////////////
399 /// \brief Constructor that initializes data members.
400 /// \param[in] value The action result.
401 /// \param[in] counts The number of entries used to compute that result.
403 /**
404 Default constructor. Needed to allow serialization of ROOT objects. See
405 [TBufferFile::WriteObjectClass]
406 (classTBufferFile.html#a209078a4cb58373b627390790bf0c9c1)
407 */
408 RMergeableMean() = default;
413};
414
415template <typename T>
417
418 void Merge(const RMergeableValue<T> &other) final
419 {
420 try {
421 const auto &othercast = dynamic_cast<const RMergeableMin<T> &>(other);
422 this->fValue = std::min(this->fValue, othercast.fValue);
423 } catch (const std::bad_cast &) {
424 throw std::invalid_argument("Results from different actions cannot be merged together.");
425 }
426 }
427
428public:
429 /////////////////////////////////////////////////////////////////////////////
430 /// \brief Constructor that initializes data members.
431 /// \param[in] value The action result.
433 /**
434 Default constructor. Needed to allow serialization of ROOT objects. See
435 [TBufferFile::WriteObjectClass]
436 (classTBufferFile.html#a209078a4cb58373b627390790bf0c9c1)
437 */
438 RMergeableMin() = default;
439 RMergeableMin(const RMergeableMin &) = delete;
443};
444
445/**
446\class ROOT::Detail::RDF::RMergeableStdDev
447\ingroup dataframe
448\brief Specialization of RMergeableValue for the
449[StdDev](classROOT_1_1RDF_1_1RInterface.html#a482c4e4f81fe1e421c016f89cd281572)
450action.
451
452This class also stores information about the number of entries and the average
453used to compute the standard deviation.
454*/
455class RMergeableStdDev final : public RMergeableValue<Double_t> {
456 ULong64_t fCounts; ///< Number of entries of the set.
457 Double_t fMean; ///< Average of the set.
458
459 /////////////////////////////////////////////////////////////////////////////
460 /// \brief Aggregate the information contained in another RMergeableValue
461 /// into this.
462 /// \param[in] other Another RMergeableValue object.
463 /// \throws std::invalid_argument If the cast of the other object to the same
464 /// type as this one fails.
465 ///
466 /// The other RMergeableValue object is cast to the same type as this object.
467 /// This is needed to make sure that only results of the same type of action
468 /// are merged together. The function then computes the aggregated standard
469 /// deviation of the two samples using an algorithm by
470 /// [Chan et al. (1979)]
471 /// (http://i.stanford.edu/pub/cstr/reports/cs/tr/79/773/CS-TR-79-773.pdf)
472 ///
473 /// \note All the `Merge` methods in the RMergeableValue family are private.
474 /// To merge multiple RMergeableValue objects please use [MergeValues]
475 /// (namespaceROOT_1_1Detail_1_1RDF.html#af16fefbe2d120983123ddf8a1e137277).
477 {
478 try {
479 const auto &othercast = dynamic_cast<const RMergeableStdDev &>(other);
480 const auto &othercounts = othercast.fCounts;
481 const auto &othermean = othercast.fMean;
482
483 // Compute the aggregated variance using an algorithm by Chan et al.
484 // See https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
485 const auto thisvariance = std::pow(this->fValue, 2);
486 const auto othervariance = std::pow(othercast.fValue, 2);
487
488 const auto delta = othermean - fMean;
489
490 const auto m_a = thisvariance * (fCounts - 1);
491 const auto m_b = othervariance * (othercounts - 1);
492
493 const auto sumcounts = static_cast<Double_t>(fCounts + othercounts);
494
495 const auto M2 = m_a + m_b + std::pow(delta, 2) * fCounts * othercounts / sumcounts;
496
497 const auto meannum = fMean * fCounts + othermean * othercounts;
498
499 // Update the data members
500 this->fValue = std::sqrt(M2 / (sumcounts - 1));
503 } catch (const std::bad_cast &) {
504 throw std::invalid_argument("Results from different actions cannot be merged together.");
505 }
506 }
507
508public:
509 /////////////////////////////////////////////////////////////////////////////
510 /// \brief Constructor that initializes data members.
511 /// \param[in] value The action result.
512 /// \param[in] counts The number of entries of the set.
513 /// \param[in] mean The average of the set.
518 /**
519 Default constructor. Needed to allow serialization of ROOT objects. See
520 [TBufferFile::WriteObjectClass]
521 (classTBufferFile.html#a209078a4cb58373b627390790bf0c9c1)
522 */
523 RMergeableStdDev() = default;
528};
529
530template <typename T>
532
533 void Merge(const RMergeableValue<T> &other) final
534 {
535 try {
536 const auto &othercast = dynamic_cast<const RMergeableSum<T> &>(other);
537 this->fValue += othercast.fValue;
538 } catch (const std::bad_cast &) {
539 throw std::invalid_argument("Results from different actions cannot be merged together.");
540 }
541 }
542
543public:
544 /////////////////////////////////////////////////////////////////////////////
545 /// \brief Constructor that initializes data members.
546 /// \param[in] value The action result.
548 /**
549 Default constructor. Needed to allow serialization of ROOT objects. See
550 [TBufferFile::WriteObjectClass]
551 (classTBufferFile.html#a209078a4cb58373b627390790bf0c9c1)
552 */
553 RMergeableSum() = default;
554 RMergeableSum(const RMergeableSum &) = delete;
558};
559
560/**
561\class ROOT::Detail::RDF::RMergeableVariationsBase
562\ingroup dataframe
563\brief A container for variation names and variation results.
564
565The class stores two vectors: one with the variation names, the other with
566corresponding mergeable variation values. These are retrieved from an RVariedAction
567(resulting from a call to ROOT::RDF::VariationsFor). The results are stored as
568type-erased RMergeableValueBase objects.
569*/
571protected:
572 std::vector<std::string> fKeys{};
573 std::vector<std::unique_ptr<RMergeableValueBase>> fValues{};
574
575public:
576 /**
577 Default constructor. Needed to allow serialization of ROOT objects. See
578 [TBufferFile::WriteObjectClass]
579 (classTBufferFile.html#a209078a4cb58373b627390790bf0c9c1)
580 */
584 /////////////////////////////////////////////////////////////////////////////
585 /// \brief Constructor that moves the data members from the input object.
586 /// \param[in] other The container from which the data members are moved.
587 ///
588 /// This constructor is needed as an helper in the RMergeableVariations
589 /// constructor that takes an RMergeableVariationsBase as input.
595 ~RMergeableVariationsBase() override = default;
596
597 /////////////////////////////////////////////////////////////////////////////
598 /// \brief Constructor that initializes data members.
599 /// \param[in] keys The names of the variations.
600 /// \param[in] values The mergeable values containing the results of the
601 /// variations.
602 RMergeableVariationsBase(std::vector<std::string> &&keys, std::vector<std::unique_ptr<RMergeableValueBase>> &&values)
603 : fKeys{std::move(keys)}, fValues{std::move(values)}
604 {
605 }
606
607 /////////////////////////////////////////////////////////////////////////////
608 /// \brief Add an entry for the "nominal" value.
609 ///
610 /// The way client code is structured, the nominal value is provided separately from the others.
611 void AddNominal(std::unique_ptr<RMergeableValueBase> value)
612 {
613 fKeys.insert(fKeys.begin(), "nominal");
614 fValues.insert(fValues.begin(), std::move(value));
615 }
616};
617
618/**
619\class ROOT::Detail::RDF::RMergeableVariations
620\ingroup dataframe
621\brief A container for variation names and variation results that knows how to
622 merge with others of the same type.
623\tparam T Type of the action result.
624*/
625template <typename T>
627
628 template <typename T1, typename... Ts>
629 friend void
631
632 /////////////////////////////////////////////////////////////////////////////
633 /// \brief Aggregate the information contained in another RMergeableVariations
634 /// into this.
635 /// \param[in] other The other mergeable.
636 ///
637 /// Iterates over all values of the current object and calls
638 /// ROOT::Detail::RDF::MergeValues to merge with the corresponding value of
639 /// the other object.
640 ///
641 /// \note All the `Merge` methods in the RMergeableValue family are private.
642 /// To merge multiple RMergeableValue objects please use ROOT::Detail::RDF::MergeValues
644 {
645 R__ASSERT(fKeys == other.fKeys && "Mergeable variations have different names.");
646
647 for (std::size_t i = 0; i < fValues.size(); i++) {
648 // Cast to concrete types according to MergeValues signature
649 MergeValues(static_cast<RMergeableValue<T> &>(*fValues[i]),
650 static_cast<const RMergeableValue<T> &>(*other.fValues[i]));
651 }
652 }
653
654public:
655 /**
656 Default constructor. Needed to allow serialization of ROOT objects. See
657 [TBufferFile::WriteObjectClass]
658 (classTBufferFile.html#a209078a4cb58373b627390790bf0c9c1)
659 */
666
667 /////////////////////////////////////////////////////////////////////////////
668 /// \brief Constructor that initializes data members.
669 /// \param[in] base The container of the names and values.
670 ///
671 /// The variation names and values are moved from the base container into this.
673
674 /////////////////////////////////////////////////////////////////////////////
675 /// \brief Get the list of variation names.
676 const std::vector<std::string> &GetKeys() const { return fKeys; }
677 /////////////////////////////////////////////////////////////////////////////
678 /// \brief Get the final value from the mergeable corresponding to a certain
679 /// variation name.
680 /// \param[in] variationName The name.
681 ///
682 /// The variation name is used to retrieve the corresponding RMergeableValue
683 /// contained in this object. From that, the actual value is retrieved by
684 /// calling the ROOT::Detail::RDF::RMergeableValue::GetValue function.
685 const T &GetVariation(const std::string &variationName) const
686 {
687 auto it = std::find(std::begin(fKeys), std::end(fKeys), variationName);
688 if (it == std::end(fKeys)) {
689 throw std::runtime_error("RMergeableVariations: no result with key \"" + variationName + "\".");
690 } else {
691 auto pos = std::distance(std::begin(fKeys), it);
692 return static_cast<const RMergeableValue<T> &>(*fValues[pos]).GetValue();
693 }
694 }
695};
696
697/// \cond HIDDEN_SYMBOLS
698// What follows mimics C++17 std::conjunction without using recursive template instantiations.
699// Used in `MergeValues` to check that all the mergeables hold values of the same type.
700template <bool...>
701struct bool_pack {
702};
703template <class... Ts>
704using conjunction = std::is_same<bool_pack<true, Ts::value...>, bool_pack<Ts::value..., true>>;
705/// \endcond
706
707////////////////////////////////////////////////////////////////////////////////
708/// \brief Merge multiple RMergeableValue objects into one.
709/// \param[in] OutputMergeable The mergeable object where all the information
710/// will be aggregated.
711/// \param[in] InputMergeables Other mergeables containing the partial results.
712/// \returns An RMergeableValue holding the aggregated value wrapped in an
713/// `std::unique_ptr`.
714///
715/// This is the recommended way of merging multiple RMergeableValue objects.
716/// This overload takes ownership of the mergeables and gives back to the user
717/// a mergeable with the aggregated information. All the mergeables with the
718/// partial results get destroyed in the process.
719///
720/// Example usage:
721/// ~~~{.cpp}
722/// using namespace ROOT::Detail::RDF;
723/// // mh1, mh2, mh3 are std::unique_ptr<RMergeableValue<TH1D>>
724/// auto mergedptr = MergeValues(std::move(mh1), std::move(mh2), std::move(mh3));
725/// const auto &mergedhisto = mergedptr->GetValue(); // Final merged histogram
726/// // Do stuff with it
727/// mergedhisto.Draw();
728/// ~~~
729template <typename T, typename... Ts>
730std::unique_ptr<RMergeableValue<T>> MergeValues(std::unique_ptr<RMergeableValue<T>> OutputMergeable,
731 std::unique_ptr<RMergeableValue<Ts>>... InputMergeables)
732{
733 // Check all mergeables have the same template type
734 static_assert(conjunction<std::is_same<Ts, T>...>::value, "Values must all be of the same type.");
735
736 // Using dummy array initialization inspired by https://stackoverflow.com/a/25683817
737 using expander = int[];
738 // Cast to void to suppress unused-value warning in Clang
739 (void)expander{0, (OutputMergeable->Merge(*InputMergeables), 0)...};
740
741 return OutputMergeable;
742}
743
744////////////////////////////////////////////////////////////////////////////////
745/// \brief Merge multiple RMergeableValue objects into one.
746/// \param[in,out] OutputMergeable The mergeable object where all the
747/// information will be aggregated.
748/// \param[in] InputMergeables Other mergeables containing the partial results.
749///
750/// This overload modifies the mergeable objects in-place. The ownership is left
751/// to the caller. The first argument to the function will get all the
752/// values contained in the other arguments merged into itself. This is a
753/// convenience overload introduced for the ROOT Python API.
754///
755/// Example usage:
756/// ~~~{.cpp}
757/// // mh1, mh2, mh3 are std::unique_ptr<RMergeableValue<TH1D>>
758/// ROOT::Detail::RDF::MergeValues(*mh1, *mh2, *mh3);
759/// const auto &mergedhisto = mh1->GetValue(); // Final merged histogram
760/// // Do stuff with it
761/// mergedhisto.Draw();
762/// ~~~
763template <typename T, typename... Ts>
765{
766 // Check all mergeables are of the same type
767 static_assert(conjunction<std::is_same<Ts, T>...>::value, "Values must all be of the same type.");
768
769 // Using dummy array initialization inspired by https://stackoverflow.com/a/25683817
770 using expander = int[];
771 // Cast to void to suppress unused-value warning in Clang
772 (void)expander{0, (OutputMergeable.Merge(InputMergeables), 0)...};
773}
774
775////////////////////////////////////////////////////////////////////////////////
776/// \brief Merge multiple RMergeableVariations objects into one.
777/// \param[in,out] OutputMergeable The mergeable object where all the
778/// information will be aggregated.
779/// \param[in] InputMergeables Other mergeables containing the partial results.
780///
781/// This overload modifies the mergeable objects in-place. The ownership is left
782/// to the caller. The first argument to the function will get all the
783/// values contained in the other arguments merged into itself. This is a
784/// convenience overload introduced for the ROOT Python API.
785///
786/// Example usage:
787/// ~~~{.cpp}
788/// // mv1, mv2 are std::unique_ptr<RMergeableVariations<TH1D>>
789/// ROOT::Detail::RDF::MergeValues(*mv1, *mv2);
790/// const auto &keys = mv1->GetKeys(); // Names of the variations
791/// // Do stuff with the variations
792/// for(const auto &key: keys){
793/// const auto &histo = mv1->GetVariation(key); // Varied histogram
794/// std::cout << histo.GetEntries() << "\n";
795/// }
796/// ~~~
797template <typename T, typename... Ts>
799{
800 // Check all mergeables are of the same type
801 static_assert(conjunction<std::is_same<Ts, T>...>::value, "Values must all be of the same type.");
802
803 // Using dummy array initialization inspired by https://stackoverflow.com/a/25683817
804 using expander = int[];
805 // Cast to void to suppress unused-value warning in Clang
806 (void)expander{0, (OutputMergeable.Merge(InputMergeables), 0)...};
807}
808} // namespace RDF
809} // namespace Detail
810} // namespace ROOT
811
812#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 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