LArSoft  v07_13_02
Liquid Argon Software toolkit - http://larsoft.org/
StatCollector.h
Go to the documentation of this file.
1 
13 #ifndef LARDATA_UTILITIES_STATCOLLECTOR_H
14 #define LARDATA_UTILITIES_STATCOLLECTOR_H
15 
16 // C/C++ standard libraries
17 #include <cmath> // std::sqrt()
18 #include <array>
19 #include <tuple>
20 #include <limits> // std::numeric_limits<>
21 #include <initializer_list>
22 #include <iterator> // std::begin(), std::end()
23 #include <utility> // std::forward()
24 #include <algorithm> // std::for_each()
25 #include <stdexcept> // std::range_error
26 
27 
28 namespace lar {
29  namespace util {
30 
31 
33  struct identity {
34  template<typename T>
35  constexpr auto operator()(T&& v) const noexcept
36  -> decltype(std::forward<T>(v))
37  {
38  return std::forward<T>(v);
39  } // operator()
40  }; // class identity
41 
42 
43  namespace details {
44 
47  template <typename W>
48  class WeightTracker {
49  public:
50  using Weight_t = W;
51 
53  void add(Weight_t weight) { ++n; w += weight; }
54 
56  void clear() { n= 0; w = Weight_t(0); }
57 
59  int N() const { return n; }
60 
62  Weight_t Weights() const { return w; }
63 
69  Weight_t AverageWeight() const;
70 
71 
73  template <typename V>
74  static constexpr V sqr(V const& v) { return v*v; }
75 
76  protected:
77  int n = 0;
79 
80  }; // class WeightTracker<>
81 
82 
92  template <unsigned int PWR, typename T, typename W = T>
93  class DataTracker {
94  public:
95  static constexpr unsigned int Power = PWR;
96  static_assert(Power >= 1, "DataTracker must have at least power 1");
97 
98  using Data_t = T;
99  using Weight_t = T;
100 
103 
105  void add(Data_t v, Weight_t w)
106  {
107  Weight_t x = w;
108  for (size_t i = 0; i < Power; ++i) sums[i] += (x *= v);
109  }
110 
112  void clear() { sums.fill(Data_t(0)); }
113 
115  template <unsigned int N>
116  Weight_t SumN() const
117  {
118  static_assert
119  ((N > 0) && (N <= Power), "Invalid sum of power requested");
120  return sums[N - 1];
121  } // SumN()
122 
124  Weight_t Sum(unsigned int n) const { return sums[n - 1]; }
125 
127  Weight_t Sum() const { return SumN<1>(); }
128 
129  protected:
130  std::array<Weight_t, Power> sums;
131 
132  }; // class DataTracker<>
133 
134 
140  template <typename T, typename W = T, unsigned int PWR = 2>
141  class DataTracker2: public DataTracker<PWR, T, W> {
143  public:
144  using Base_t::Power;
145  static_assert(Power >= 2, "DataTracker2 must have Power >= 2");
146  using Weight_t = typename Base_t::Weight_t;
147 
149  Weight_t SumSq() const
150  { return Base_t::sums[1]; }
151  //{ return Base_t::SumN<2>(); } // I can't make gcc 4.9.1 digest this...
152 
153  }; // class DataTracker2
154 
160  template <typename T, typename W = T, unsigned int PWR = 3>
161  class DataTracker3: public DataTracker2<T, W, PWR> {
163  public:
164  using Base_t::Power;
165  static_assert(Power >= 3, "DataTracker3 must have Power >= 3");
166  using Weight_t = typename Base_t::Weight_t;
167 
170  { return Base_t::sums[2]; }
171  //{ return Base_t::SumN<3>(); } // I can't make gcc 4.9.1 digest this...
172 
173  }; // class DataTracker3
174 
175  } // namespace details
176 
177 
178 
242  template <typename T, typename W = T>
243  class StatCollector: protected details::WeightTracker<W> {
245  using Base_t::sqr;
246  public:
248  using Data_t = T;
249  using Weight_t = typename Base_t::Weight_t;
250 
251  // default constructor, destructor and all the rest
252 
255 
257  void add(Data_t value, Weight_t weight = Weight_t(1.0));
258 
268  template <typename Iter>
269  void add_unweighted(Iter begin, Iter end)
270  { add_unweighted(begin, end, identity()); }
271 
285  template <typename Iter, typename Pred>
286  void add_unweighted(Iter begin, Iter end, Pred extractor);
287 
302  template <typename Cont, typename Pred>
303  void add_unweighted(Cont cont, Pred extractor)
304  { add_unweighted(std::begin(cont), std::end(cont), extractor); }
305 
315  template <typename Cont>
316  void add_unweighted(Cont cont)
317  { add_unweighted(std::begin(cont), std::end(cont)); }
318 
319 
343  template <
344  typename VIter, typename WIter,
345  typename VPred, typename WPred = identity
346  >
347  void add_weighted(
348  VIter begin_value, VIter end_value,
349  WIter begin_weight,
350  VPred value_extractor,
351  WPred weight_extractor = WPred()
352  );
353 
354 
367  template <typename Iter>
368  void add_weighted(Iter begin, Iter end);
369 
379  template <typename Cont>
380  void add_weighted(Cont cont)
381  { add_weighted(std::begin(cont), std::end(cont)); }
382 
384 
386  void clear();
387 
390 
392  int N() const { return Base_t::N(); }
393 
395  Weight_t Weights() const { return Base_t::Weights(); }
396 
398  Weight_t Sum() const { return x.Sum(); }
399 
401  Weight_t SumSq() const { return x.SumSq(); }
402 
408  Weight_t Average() const;
409 
415  Weight_t Variance() const;
416 
423  Weight_t RMS() const;
424 
425 
431  Weight_t AverageWeight() const { return Base_t::AverageWeight(); }
432 
434 
435 
436  protected:
438 
440 
441  }; // class StatCollector<>
442 
443 
476  template <typename T, typename W = T>
478  public:
480  using Base_t::sqr;
481  public:
483  using Data_t = T;
484  using Weight_t = typename Base_t::Weight_t;
485 
486  using Pair_t = std::tuple<Data_t, Data_t>;
487  using WeightedPair_t = std::tuple<Data_t, Data_t, Weight_t>;
488 
489  // default constructor, destructor and all the rest
490 
493 
495  void add(Data_t x, Data_t y, Weight_t weight = Weight_t(1.0));
497 
499  { add(std::get<0>(value), std::get<1>(value), weight); }
500 
501  void add(WeightedPair_t value)
502  { add(std::get<0>(value), std::get<1>(value), std::get<2>(value)); }
504 
514  template <typename Iter>
515  void add_unweighted(Iter begin, Iter end)
516  { add_unweighted(begin, end, identity()); }
517 
531  template <typename Iter, typename Pred>
532  void add_unweighted(Iter begin, Iter end, Pred extractor);
533 
548  template <typename Cont, typename Pred>
549  void add_unweighted(Cont cont, Pred extractor)
550  { add_unweighted(std::begin(cont), std::end(cont), extractor); }
551 
561  template <typename Cont>
562  void add_unweighted(Cont cont)
563  { add_unweighted(std::begin(cont), std::end(cont)); }
564 
565 
589  template <
590  typename VIter, typename WIter,
591  typename VPred, typename WPred = identity
592  >
593  void add_weighted(
594  VIter begin_value, VIter end_value,
595  WIter begin_weight,
596  VPred value_extractor,
597  WPred weight_extractor = WPred()
598  );
599 
600 
612  template <typename Iter>
613  void add_weighted(Iter begin, Iter end);
614 
624  template <typename Cont>
625  void add_weighted(Cont cont)
626  { add_weighted(std::begin(cont), std::end(cont)); }
627 
629 
631  void clear();
632 
635 
637  int N() const { return Base_t::N(); }
638 
640  Weight_t Weights() const { return Base_t::Weights(); }
641 
643  Weight_t SumX() const { return x.Sum(); }
644 
646  Weight_t SumY() const { return y.Sum(); }
647 
649  Weight_t SumSqX() const { return x.SumSq(); }
650 
652  Weight_t SumSqY() const { return y.SumSq(); }
653 
655  Weight_t SumXY() const { return sum_xy; }
656 
662  Weight_t AverageX() const;
663 
669  Weight_t AverageY() const;
670 
676  Weight_t VarianceX() const;
677 
683  Weight_t VarianceY() const;
684 
690  Weight_t Covariance() const;
691 
698  Weight_t RMSx() const;
699 
706  Weight_t RMSy() const;
707 
708 
715  Weight_t LinearCorrelation() const;
716 
717 
723  Weight_t AverageWeight() const { return Base_t::AverageWeight(); }
724 
726 
727  protected:
729 
732  Weight_t sum_xy = Weight_t(0);
733 
734  }; // class StatCollector2D<>
735 
736 
737 
747  template <typename T>
749  public:
750  using Data_t = T;
752 
754  MinMaxCollector() = default;
756 
758  MinMaxCollector(std::initializer_list<Data_t> init)
759  { add(init); }
760 
767  template <typename Iter>
769  { add(begin, end); }
771 
772 
773  // default copy and move constructor and assignment, and destructor
774 
777 
782  This_t& add(Data_t value);
783 
789  This_t& add(std::initializer_list<Data_t> values);
790 
798  template <typename Iter>
799  This_t& add(Iter begin, Iter end);
801 
802 
804  bool has_data() const { return minimum <= maximum; }
805 
807  Data_t min() const { return minimum; }
808 
810  Data_t max() const { return maximum; }
811 
812 
814  void clear();
815 
816  protected:
819 
822 
823  }; // class MinMaxCollector<>
824 
825 
826  } // namespace util
827 } // namespace lar
828 
829 
830 //==============================================================================
831 //=== template implementation
832 //==============================================================================
833 
834 
835 //******************************************************************************
836 //*** details::WeightTracker<>
837 //***
838 
839 template <typename W>
842 {
843  if (N() == 0)
844  throw std::range_error("WeightTracker<>::AverageWeight(): divide by 0");
845  return Weights() / N();
846 } // details::WeightTracker<W>::AverageWeight()
847 
848 
849 //******************************************************************************
850 //*** StatCollector<>
851 //***
852 
853 template <typename T, typename W>
855  (Data_t value, Weight_t weight /* = Weight_t(1.0) */)
856 {
857  Base_t::add(weight);
858  x.add(value, weight);
859 } // StatCollector<T, W>::add()
860 
861 
862 template <typename T, typename W>
863 template <typename Iter, typename Pred>
865  (Iter begin, Iter end, Pred extractor)
866 {
867  std::for_each
868  (begin, end, [this, extractor](auto item) { this->add(extractor(item)); });
869 } // StatCollector<T, W>::add_unweighted(Iter, Iter, Pred)
870 
871 
872 template <typename T, typename W>
873 template <typename VIter, typename WIter, typename VPred, typename WPred>
875  VIter begin_value, VIter end_value,
876  WIter begin_weight,
877  VPred value_extractor,
878  WPred weight_extractor /* = WPred() */
879 ) {
880  while (begin_value != end_value) {
881  add(value_extractor(*begin_value), weight_extractor(*begin_weight));
882  ++begin_value;
883  ++begin_weight;
884  } // while
885 } // StatCollector<T, W>::add_weighted(VIter, VIter, WIter, VPred, WPred)
886 
887 
888 template <typename T, typename W>
889 template <typename Iter>
891 
892  std::for_each(begin, end, [this](auto p) { this->add(p.first, p.second); });
893 
894 } // StatCollector<T, W>::add_weighted(Iter, Iter)
895 
896 
897 
898 template <typename T, typename W>
900  Base_t::clear();
901  x.clear();
902 } // StatCollector<T, W>::clear()
903 
904 
905 template <typename T, typename W>
908 {
909  if (Weights() == Weight_t(0))
910  throw std::range_error("StatCollector<>::Average(): divide by 0");
911  return Sum() / Weights();
912 } // StatCollector<T, W>::Average()
913 
914 
915 template <typename T, typename W>
918 {
919  if (Weights() == Weight_t(0))
920  throw std::range_error("StatCollector<>::Variance(): divide by 0");
921  return std::max(Weight_t(0), (SumSq() - sqr(Sum()) / Weights()) / Weights());
922 } // StatCollector<T, W>::Variance()
923 
924 
925 template <typename T, typename W>
928 {
929  const Weight_t rms2 = Variance();
930  if (rms2 < Weight_t(0)) return 0.;
931 // throw std::range_error("StatCollector<>::RMS(): negative RMS^2");
932  return std::sqrt(rms2);
933 } // StatCollector<T, W>::RMS()
934 
935 
936 
937 //******************************************************************************
938 //*** StatCollector2D<>
939 //***
940 
941 template <typename T, typename W>
943  (Data_t x_value, Data_t y_value, Weight_t weight /* = Weight_t(1.0) */)
944 {
945  Base_t::add(weight);
946  x.add(x_value, weight);
947  y.add(y_value, weight);
948  sum_xy += weight * x_value * y_value;
949 } // StatCollector2D<T, W>::add()
950 
951 
952 template <typename T, typename W>
953 template <typename Iter, typename Pred>
955  (Iter begin, Iter end, Pred extractor)
956 {
957  std::for_each
958  (begin, end, [this, extractor](auto item) { this->add(extractor(item)); });
959 } // StatCollector2D<T, W>::add_unweighted(Iter, Iter, Pred)
960 
961 
962 template <typename T, typename W>
963 template <typename VIter, typename WIter, typename VPred, typename WPred>
965  VIter begin_value, VIter end_value,
966  WIter begin_weight,
967  VPred value_extractor,
968  WPred weight_extractor /* = WPred() */
969 ) {
970  while (begin_value != end_value) {
971  add(value_extractor(*begin_value), weight_extractor(*begin_weight));
972  ++begin_value;
973  ++begin_weight;
974  } // while
975 } // StatCollector2D<T, W>::add_weighted(VIter, VIter, WIter, VPred, WPred)
976 
977 
978 template <typename T, typename W>
979 template <typename Iter>
981 
982  std::for_each(begin, end, [this](auto p) { this->add(p); });
983 
984 } // StatCollector2D<T, W>::add_weighted(Iter, Iter)
985 
986 
987 
988 template <typename T, typename W>
990  Base_t::clear();
991  x.clear();
992  y.clear();
993  sum_xy = Weight_t(0);
994 } // StatCollector<T, W>::clear()
995 
996 
997 template <typename T, typename W>
1000 {
1001  if (Weights() == Weight_t(0))
1002  throw std::range_error("StatCollector2D<>::AverageX(): divide by 0");
1003  return SumX() / Weights();
1004 } // StatCollector2D<T, W>::AverageX()
1005 
1006 
1007 template <typename T, typename W>
1010 {
1011  if (Weights() == Weight_t(0))
1012  throw std::range_error("StatCollector2D<>::VarianceX(): divide by 0");
1013  return (SumSqX() - sqr(SumX()) / Weights()) / Weights();
1014 } // StatCollector2D<T, W>::VarianceX()
1015 
1016 
1017 template <typename T, typename W>
1020 {
1021  const Weight_t rms2 = VarianceX();
1022  if (rms2 < Weight_t(0)) return 0.;
1023 // throw std::range_error("StatCollector2D<>::RMSx(): negative RMS^2");
1024  return std::sqrt(rms2);
1025 } // StatCollector2D<T, W>::RMSx()
1026 
1027 
1028 template <typename T, typename W>
1031 {
1032  if (Weights() == Weight_t(0))
1033  throw std::range_error("StatCollector2D<>::AverageY(): divide by 0");
1034  return SumY() / Weights();
1035 } // StatCollector2D<T, W>::AverageY()
1036 
1037 
1038 template <typename T, typename W>
1041 {
1042  if (Weights() == Weight_t(0))
1043  throw std::range_error("StatCollector2D<>::VarianceY(): divide by 0");
1044  return (SumSqY() - sqr(SumY()) / Weights()) / Weights();
1045 } // StatCollector2D<T, W>::VarianceY()
1046 
1047 
1048 template <typename T, typename W>
1051 {
1052  if (Weights() == Weight_t(0))
1053  throw std::range_error("StatCollector2D<>::Covariance(): divide by 0");
1054  return (SumXY() - SumX() * SumY() / Weights()) / Weights();
1055 } // StatCollector2D<T, W>::VarianceY()
1056 
1057 
1058 template <typename T, typename W>
1061 {
1062  const Weight_t rms2 = VarianceY();
1063  if (rms2 < Weight_t(0)) return 0.;
1064 // throw std::range_error("StatCollector2D<>::RMSy(): negative RMS^2");
1065  return std::sqrt(rms2);
1066 } // StatCollector2D<T, W>::RMSy()
1067 
1068 
1069 template <typename T, typename W>
1072 {
1073  if (Weights() == Data_t(0))
1074  throw std::range_error("StatCollector2D<>::LinearCorrelation(): divide by 0");
1075 
1076  const Weight_t var_prod = VarianceX() * VarianceY();
1077  if (var_prod <= Weight_t(0))
1078  throw std::range_error("StatCollector2D<>::LinearCorrelation(): variance is 0");
1079 
1080  return Covariance() / std::sqrt(var_prod);
1081 } // StatCollector2D<T, W>::LinearCorrelation()
1082 
1083 
1084 
1085 //******************************************************************************
1086 //*** MinMaxCollector
1087 //***
1088 
1089 template <typename T>
1091 {
1092  if (value < minimum) minimum = value;
1093  if (value > maximum) maximum = value;
1094  return *this;
1095 } // lar::util::MinMaxCollector<T>::add
1096 
1097 
1098 template <typename T>
1100  (std::initializer_list<Data_t> values)
1101  { return add(values.begin(), values.end()); }
1102 
1103 
1104 template <typename T> template <typename Iter>
1106  (Iter begin, Iter end)
1107 {
1108  std::for_each(begin, end, [this](Data_t value) { this->add(value); });
1109  return *this;
1110 } // lar::util::MinMaxCollector<T>::add(Iter)
1111 
1112 
1113 template <typename T>
1117 } // lar::util::MinMaxCollector<T>::clear()
1118 
1119 //******************************************************************************
1120 
1121 
1122 #endif // LARDATA_UTILITIES_STATCOLLECTOR_H
Float_t x
Definition: compare.C:6
Weight_t Weights() const
Returns the sum of the weights.
Definition: StatCollector.h:62
void add(Data_t v, Weight_t w)
Adds the specified weight to the statistics.
Data_t max() const
Returns the accumulated maximum, or a very small number if no values.
void add_unweighted(Cont cont)
Adds all entries from a container, with weight 1.
bool has_data() const
Returns whether at least one datum has been added.
int N() const
Returns the number of entries added.
Definition: StatCollector.h:59
Namespace for general, non-LArSoft-specific utilities.
Definition: PIDAAlg.h:17
This_t & add(Data_t value)
Include a single value in the statistics.
void add_unweighted(Cont cont, Pred extractor)
Adds all entries from a container, with weight 1.
void add_weighted(VIter begin_value, VIter end_value, WIter begin_weight, VPred value_extractor, WPred weight_extractor=WPred())
Adds entries from a sequence with individually specified weights.
MinMaxCollector(std::initializer_list< Data_t > init)
Constructor: starts with parsing the specified data.
Weight_t SumSqY() const
Returns the weighted sum of the square of the y values.
void add(Data_t x, Data_t y, Weight_t weight=Weight_t(1.0))
Adds one entry with specified values and weight.
Weight_t AverageWeight() const
Returns the arithmetic average of the weights.
static constexpr V sqr(V const &v)
Returns the square of the specified value.
Definition: StatCollector.h:74
Weight_t SumSq() const
Returns the weighted sum of the square of the entries.
Float_t y
Definition: compare.C:6
Weight_t AverageWeight() const
Returns the arithmetic average of the weights.
void add(Pair_t value, Weight_t weight=Weight_t(1.0))
Adds one entry with specified values and weight.
Weight_t SumXY() const
Returns the weighted sum of the product of x and y values.
Weight_t SumCube() const
Returns the weighted sum of the square of the entries.
STL namespace.
MinMaxCollector(Iter begin, Iter end)
Include a sequence of values in the statistics.
Weight_t Covariance() const
Returns the covariance of the (x, y) pair.
typename Base_t::Weight_t Weight_t
type of the weight
Variable_t x
accumulator for variable x
void add(Weight_t weight)
Adds the specified weight to the statistics.
Definition: StatCollector.h:53
Weight_t RMS() const
Returns the root mean square.
Weight_t VarianceY() const
Returns the variance of the y values.
Variable_t y
accumulator for variable y
DataTracker()
Default constructor.
Weight_t Average() const
Returns the value average.
Weight_t Sum(unsigned int n) const
Returns the sum of the values to the power n (1 <= n <= 2, no check)
void add_unweighted(Iter begin, Iter end)
Adds entries from a sequence with weight 1.
void clear()
Resets the count.
Definition: StatCollector.h:56
Keeps track of the minimum and maximum value we observed.
T sqr(T v)
void add_unweighted(Cont cont, Pred extractor)
Adds all entries from a container, with weight 1.
Weight_t Variance() const
Returns the square of the RMS of the values.
Data_t min() const
Returns the accumulated minimum, or a very large number if no values.
Int_t max
Definition: plot.C:27
Weight_t Sum() const
Returns the weighted sum of the values.
int N() const
Returns the number of entries added.
Weight_t AverageWeight() const
Returns the arithmetic average of the weights.
Weight_t AverageY() const
Returns the y value average.
void add_weighted(Cont cont)
Adds entries from a sequence with individually specified weights.
Weight_t SumSqX() const
Returns the weighted sum of the square of the x values.
std::vector< evd::details::RawDigitInfo_t >::const_iterator begin(RawDigitCacheDataClass const &cache)
void add_unweighted(Iter begin, Iter end)
Adds entries from a sequence with weight 1.
A unary functor returning its own argument (any type)
Definition: StatCollector.h:33
Weight_t SumN() const
Returns the sum of the values to the power N (1 <= N <= 2)
Weight_t AverageX() const
Returns the x value average.
float Data_t
type of data we collect
Weight_t SumSq() const
Returns the weighted sum of the square of the values.
Class tracking sums of variables up to a specified power.
Definition: StatCollector.h:93
int N() const
Returns the number of entries added.
Weight_t SumX() const
Returns the weighted sum of the x values.
void clear()
Clears all the statistics.
constexpr auto operator()(T &&v) const noexcept-> decltype(std::forward< T >(v))
Definition: StatCollector.h:35
void add_weighted(Cont cont)
Adds entries from a sequence with individually specified weights.
std::tuple< Data_t, Data_t > Pair_t
void clear()
Resets the count.
void clear()
Removes all statistics and reinitializes the object.
double weight
Definition: plottest35.C:25
void add(WeightedPair_t value)
Adds one entry with specified values and weight.
void add_weighted(VIter begin_value, VIter end_value, WIter begin_weight, VPred value_extractor, WPred weight_extractor=WPred())
Adds entries from a sequence with individually specified weights.
std::string value(boost::any const &)
Variable_t x
accumulator for variable x
LArSoft-specific namespace.
Int_t min
Definition: plot.C:26
Weight_t SumY() const
Returns the weighted sum of the y values.
Class tracking sums of variables up to power 2.
Collects statistics on two homogeneous quantities (weighted)
Weight_t LinearCorrelation() const
Returns the linear correlation.
T Data_t
type of the data
Weight_t RMSy() const
Returns the standard deviation of the y sample.
Char_t n[5]
std::vector< evd::details::RawDigitInfo_t >::const_iterator end(RawDigitCacheDataClass const &cache)
typename Base_t::Weight_t Weight_t
type of the weight
Weight_t RMSx() const
Returns the standard deviation of the x sample.
Weight_t Weights() const
Returns the sum of the weights.
Weight_t VarianceX() const
Returns the variance of the x values.
Weight_t Sum() const
Returns the weighted sum of the entries.
void add_unweighted(Cont cont)
Adds all entries from a container, with weight 1.
void clear()
Clears all the statistics.
Float_t w
Definition: plot.C:23
Collects statistics on a single quantity (weighted)
Class tracking sums of variables up to power 2.
vec_iX clear()
Weight_t Weights() const
Returns the sum of the weights.
void add(Data_t value, Weight_t weight=Weight_t(1.0))
Adds one entry with specified value and weight.
std::tuple< Data_t, Data_t, Weight_t > WeightedPair_t
std::array< Weight_t, Power > sums
T Data_t
type of the data