OpenVDB  9.0.1
Stats.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 //
4 /// @file Stats.h
5 ///
6 /// @author Ken Museth
7 ///
8 /// @brief Classes to compute statistics and histograms
9 
10 #ifndef OPENVDB_MATH_STATS_HAS_BEEN_INCLUDED
11 #define OPENVDB_MATH_STATS_HAS_BEEN_INCLUDED
12 
13 #include <iosfwd> // for ostringstream
14 #include <openvdb/version.h>
15 #include <openvdb/Exceptions.h>
16 #include <iostream>
17 #include <iomanip>
18 #include <sstream>
19 #include <vector>
20 #include <functional>// for std::less
21 #include "Math.h"
22 
23 namespace openvdb {
25 namespace OPENVDB_VERSION_NAME {
26 namespace math {
27 
28 /// @brief Templated class to compute the minimum and maximum values.
29 template <typename ValueType, typename Less = std::less<ValueType> >
30 class MinMax
31 {
32  using Limits = std::numeric_limits<ValueType>;
33 public:
34 
35  /// @brief Empty constructor
36  ///
37  /// @warning Only use this constructor with POD types
38  MinMax() : mMin(Limits::max()), mMax(Limits::lowest())
39  {
40  static_assert(std::numeric_limits<ValueType>::is_specialized,
41  "openvdb::math::MinMax default constructor requires a std::numeric_limits specialization");
42  }
43 
44  /// @brief Constructor
45  MinMax(const ValueType &min, const ValueType &max) : mMin(min), mMax(max)
46  {
47  }
48 
49  /// @brief Default copy constructor
50  MinMax(const MinMax &other) = default;
51 
52  /// Add a single sample.
53  inline void add(const ValueType &val, const Less &less = Less())
54  {
55  if (less(val, mMin)) mMin = val;
56  if (less(mMax, val)) mMax = val;
57  }
58 
59  /// Return the minimum value.
60  inline const ValueType& min() const { return mMin; }
61 
62  /// Return the maximum value.
63  inline const ValueType& max() const { return mMax; }
64 
65  /// Add the samples from the other Stats instance.
66  inline void add(const MinMax& other, const Less &less = Less())
67  {
68  if (less(other.mMin, mMin)) mMin = other.mMin;
69  if (less(mMax, other.mMax)) mMax = other.mMax;
70  }
71 
72  /// @brief Print MinMax to the specified output stream.
73  void print(const std::string &name= "", std::ostream &strm=std::cout, int precision=3) const
74  {
75  // Write to a temporary string stream so as not to affect the state
76  // (precision, field width, etc.) of the output stream.
77  std::ostringstream os;
78  os << std::setprecision(precision) << std::setiosflags(std::ios::fixed);
79  os << "MinMax ";
80  if (!name.empty()) os << "for \"" << name << "\" ";
81  os << " Min=" << mMin << ", Max=" << mMax << std::endl;
82  strm << os.str();
83  }
84 
85 protected:
86 
87  ValueType mMin, mMax;
88 };//end MinMax
89 
90 /// @brief This class computes the minimum and maximum values of a population
91 /// of floating-point values.
92 class Extrema
93 {
94 public:
95 
96  /// @brief Constructor
97  /// @warning The min/max values are initiated to extreme values
99  : mSize(0)
100  , mMin(std::numeric_limits<double>::max())
101  , mMax(-mMin)
102  {
103  }
104 
105  /// Add a single sample.
106  void add(double val)
107  {
108  ++mSize;
109  mMin = std::min<double>(val, mMin);
110  mMax = std::max<double>(val, mMax);
111  }
112 
113  /// Add @a n samples with constant value @a val.
114  void add(double val, uint64_t n)
115  {
116  mSize += n;
117  mMin = std::min<double>(val, mMin);
118  mMax = std::max<double>(val, mMax);
119  }
120 
121  /// Return the size of the population, i.e., the total number of samples.
122  inline uint64_t size() const { return mSize; }
123 
124  /// Return the minimum value.
125  inline double min() const { return mMin; }
126 
127  /// Return the maximum value.
128  inline double max() const { return mMax; }
129 
130  /// Return the range defined as the maximum value minus the minimum value.
131  inline double range() const { return mMax - mMin; }
132 
133  /// Add the samples from the other Stats instance.
134  void add(const Extrema& other)
135  {
136  if (other.mSize > 0) this->join(other);
137  }
138 
139  /// @brief Print extrema to the specified output stream.
140  void print(const std::string &name= "", std::ostream &strm=std::cout, int precision=3) const
141  {
142  // Write to a temporary string stream so as not to affect the state
143  // (precision, field width, etc.) of the output stream.
144  std::ostringstream os;
145  os << std::setprecision(precision) << std::setiosflags(std::ios::fixed);
146  os << "Extrema ";
147  if (!name.empty()) os << "for \"" << name << "\" ";
148  if (mSize>0) {
149  os << "with " << mSize << " samples:\n"
150  << " Min=" << mMin
151  << ", Max=" << mMax
152  << ", Range="<< this->range() << std::endl;
153  } else {
154  os << ": no samples were added." << std::endl;
155  }
156  strm << os.str();
157  }
158 
159 protected:
160 
161  inline void join(const Extrema& other)
162  {
163  assert(other.mSize > 0);
164  mSize += other.mSize;
165  mMin = std::min<double>(mMin, other.mMin);
166  mMax = std::max<double>(mMax, other.mMax);
167  }
168 
169  uint64_t mSize;
170  double mMin, mMax;
171 };//end Extrema
172 
173 
174 /// @brief This class computes statistics (minimum value, maximum
175 /// value, mean, variance and standard deviation) of a population
176 /// of floating-point values.
177 ///
178 /// @details variance = Mean[ (X-Mean[X])^2 ] = Mean[X^2] - Mean[X]^2,
179 /// standard deviation = sqrt(variance)
180 ///
181 /// @note This class employs incremental computation and double precision.
182 class Stats : public Extrema
183 {
184 public:
186  : Extrema()
187  , mAvg(0.0)
188  , mAux(0.0)
189  {
190  }
191 
192  /// Add a single sample.
193  void add(double val)
194  {
195  Extrema::add(val);
196  const double delta = val - mAvg;
197  mAvg += delta/double(mSize);
198  mAux += delta*(val - mAvg);
199  }
200 
201  /// Add @a n samples with constant value @a val.
202  void add(double val, uint64_t n)
203  {
204  const double denom = 1.0/double(mSize + n);
205  const double delta = val - mAvg;
206  mAvg += denom * delta * double(n);
207  mAux += denom * delta * delta * double(mSize) * double(n);
208  Extrema::add(val, n);
209  }
210 
211  /// Add the samples from the other Stats instance.
212  void add(const Stats& other)
213  {
214  if (other.mSize > 0) {
215  const double denom = 1.0/double(mSize + other.mSize);
216  const double delta = other.mAvg - mAvg;
217  mAvg += denom * delta * double(other.mSize);
218  mAux += other.mAux + denom * delta * delta * double(mSize) * double(other.mSize);
219  Extrema::join(other);
220  }
221  }
222 
223  //@{
224  /// Return the arithmetic mean, i.e. average, value.
225  inline double avg() const { return mAvg; }
226  inline double mean() const { return mAvg; }
227  //@}
228 
229  //@{
230  /// @brief Return the population variance.
231  /// @note The unbiased sample variance = population variance *
232  //num/(num-1)
233  inline double var() const { return mSize<2 ? 0.0 : mAux/double(mSize); }
234  inline double variance() const { return this->var(); }
235  //@}
236 
237  //@{
238  /// @brief Return the standard deviation (=Sqrt(variance)) as
239  /// defined from the (biased) population variance.
240  inline double std() const { return sqrt(this->var()); }
241  inline double stdDev() const { return this->std(); }
242  //@}
243 
244  /// @brief Print statistics to the specified output stream.
245  void print(const std::string &name= "", std::ostream &strm=std::cout, int precision=3) const
246  {
247  // Write to a temporary string stream so as not to affect the state
248  // (precision, field width, etc.) of the output stream.
249  std::ostringstream os;
250  os << std::setprecision(precision) << std::setiosflags(std::ios::fixed);
251  os << "Statistics ";
252  if (!name.empty()) os << "for \"" << name << "\" ";
253  if (mSize>0) {
254  os << "with " << mSize << " samples:\n"
255  << " Min=" << mMin
256  << ", Max=" << mMax
257  << ", Ave=" << mAvg
258  << ", Std=" << this->stdDev()
259  << ", Var=" << this->variance() << std::endl;
260  } else {
261  os << ": no samples were added." << std::endl;
262  }
263  strm << os.str();
264  }
265 
266 protected:
267  using Extrema::mSize;
268  using Extrema::mMin;
269  using Extrema::mMax;
270  double mAvg, mAux;
271 }; // end Stats
272 
273 
274 ////////////////////////////////////////
275 
276 
277 /// @brief This class computes a histogram, with a fixed interval width,
278 /// of a population of floating-point values.
280 {
281 public:
282  /// Construct with given minimum and maximum values and the given bin count.
283  Histogram(double min, double max, size_t numBins = 10)
284  : mSize(0), mMin(min), mMax(max + 1e-10),
285  mDelta(double(numBins)/(max-min)), mBins(numBins)
286  {
287  if ( mMax <= mMin ) {
288  OPENVDB_THROW(ValueError, "Histogram: expected min < max");
289  } else if ( numBins == 0 ) {
290  OPENVDB_THROW(ValueError, "Histogram: expected at least one bin");
291  }
292  for (size_t i=0; i<numBins; ++i) mBins[i]=0;
293  }
294 
295  /// @brief Construct with the given bin count and with minimum and maximum values
296  /// taken from a Stats object.
297  Histogram(const Stats& s, size_t numBins = 10):
298  mSize(0), mMin(s.min()), mMax(s.max()+1e-10),
299  mDelta(double(numBins)/(mMax-mMin)), mBins(numBins)
300  {
301  if ( mMax <= mMin ) {
302  OPENVDB_THROW(ValueError, "Histogram: expected min < max");
303  } else if ( numBins == 0 ) {
304  OPENVDB_THROW(ValueError, "Histogram: expected at least one bin");
305  }
306  for (size_t i=0; i<numBins; ++i) mBins[i]=0;
307  }
308 
309  /// @brief Add @a n samples with constant value @a val, provided that the
310  /// @a val falls within this histogram's value range.
311  /// @return @c true if the sample value falls within this histogram's value range.
312  inline bool add(double val, uint64_t n = 1)
313  {
314  if (val<mMin || val>mMax) return false;
315  mBins[size_t(mDelta*(val-mMin))] += n;
316  mSize += n;
317  return true;
318  }
319 
320  /// @brief Add all the contributions from the other histogram, provided that
321  /// it has the same configuration as this histogram.
322  bool add(const Histogram& other)
323  {
324  if (!isApproxEqual(mMin, other.mMin) || !isApproxEqual(mMax, other.mMax) ||
325  mBins.size() != other.mBins.size()) return false;
326  for (size_t i=0, e=mBins.size(); i!=e; ++i) mBins[i] += other.mBins[i];
327  mSize += other.mSize;
328  return true;
329  }
330 
331  /// Return the number of bins in this histogram.
332  inline size_t numBins() const { return mBins.size(); }
333  /// Return the lower bound of this histogram's value range.
334  inline double min() const { return mMin; }
335  /// Return the upper bound of this histogram's value range.
336  inline double max() const { return mMax; }
337  /// Return the minimum value in the <i>n</i>th bin.
338  inline double min(int n) const { return mMin+n/mDelta; }
339  /// Return the maximum value in the <i>n</i>th bin.
340  inline double max(int n) const { return mMin+(n+1)/mDelta; }
341  /// Return the number of samples in the <i>n</i>th bin.
342  inline uint64_t count(int n) const { return mBins[n]; }
343  /// Return the population size, i.e., the total number of samples.
344  inline uint64_t size() const { return mSize; }
345 
346  /// Print the histogram to the specified output stream.
347  void print(const std::string& name = "", std::ostream& strm = std::cout) const
348  {
349  // Write to a temporary string stream so as not to affect the state
350  // (precision, field width, etc.) of the output stream.
351  std::ostringstream os;
352  os << std::setprecision(6) << std::setiosflags(std::ios::fixed) << std::endl;
353  os << "Histogram ";
354  if (!name.empty()) os << "for \"" << name << "\" ";
355  if (mSize > 0) {
356  os << "with " << mSize << " samples:\n";
357  os << "==============================================================\n";
358  os << "|| # | Min | Max | Frequency | % ||\n";
359  os << "==============================================================\n";
360  for (int i = 0, e = int(mBins.size()); i != e; ++i) {
361  os << "|| " << std::setw(4) << i << " | " << std::setw(14) << this->min(i) << " | "
362  << std::setw(14) << this->max(i) << " | " << std::setw(9) << mBins[i] << " | "
363  << std::setw(3) << (100*mBins[i]/mSize) << " ||\n";
364  }
365  os << "==============================================================\n";
366  } else {
367  os << ": no samples were added." << std::endl;
368  }
369  strm << os.str();
370  }
371 
372 private:
373  uint64_t mSize;
374  double mMin, mMax, mDelta;
375  std::vector<uint64_t> mBins;
376 };// end Histogram
377 
378 } // namespace math
379 } // namespace OPENVDB_VERSION_NAME
380 } // namespace openvdb
381 
382 #endif // OPENVDB_MATH_STATS_HAS_BEEN_INCLUDED
double max() const
Return the upper bound of this histogram&#39;s value range.
Definition: Stats.h:336
uint64_t size() const
Return the population size, i.e., the total number of samples.
Definition: Stats.h:344
ValueType mMin
Definition: Stats.h:87
Histogram(double min, double max, size_t numBins=10)
Construct with given minimum and maximum values and the given bin count.
Definition: Stats.h:283
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
void add(const Stats &other)
Add the samples from the other Stats instance.
Definition: Stats.h:212
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
const ValueType & max() const
Return the maximum value.
Definition: Stats.h:63
Templated class to compute the minimum and maximum values.
Definition: Stats.h:30
double avg() const
Return the arithmetic mean, i.e. average, value.
Definition: Stats.h:225
Histogram(const Stats &s, size_t numBins=10)
Construct with the given bin count and with minimum and maximum values taken from a Stats object...
Definition: Stats.h:297
void print(const std::string &name="", std::ostream &strm=std::cout, int precision=3) const
Print extrema to the specified output stream.
Definition: Stats.h:140
uint64_t mSize
Definition: Stats.h:169
uint64_t count(int n) const
Return the number of samples in the nth bin.
Definition: Stats.h:342
Definition: Coord.h:586
double range() const
Return the range defined as the maximum value minus the minimum value.
Definition: Stats.h:131
double max() const
Return the maximum value.
Definition: Stats.h:128
double min() const
Return the lower bound of this histogram&#39;s value range.
Definition: Stats.h:334
ValueType mMax
Definition: Stats.h:87
Definition: Exceptions.h:65
Extrema()
Constructor.
Definition: Stats.h:98
bool add(const Histogram &other)
Add all the contributions from the other histogram, provided that it has the same configuration as th...
Definition: Stats.h:322
double mAvg
Definition: Stats.h:270
double std() const
Return the standard deviation (=Sqrt(variance)) as defined from the (biased) population variance...
Definition: Stats.h:240
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:107
const ValueType & min() const
Return the minimum value.
Definition: Stats.h:60
void add(double val)
Add a single sample.
Definition: Stats.h:193
void add(double val, uint64_t n)
Add n samples with constant value val.
Definition: Stats.h:114
void print(const std::string &name="", std::ostream &strm=std::cout, int precision=3) const
Print statistics to the specified output stream.
Definition: Stats.h:245
double mMax
Definition: Stats.h:170
double mMin
Definition: Stats.h:170
double var() const
Return the population variance.
Definition: Stats.h:233
double mAux
Definition: Stats.h:270
MinMax(const ValueType &min, const ValueType &max)
Constructor.
Definition: Stats.h:45
This class computes the minimum and maximum values of a population of floating-point values...
Definition: Stats.h:92
This class computes statistics (minimum value, maximum value, mean, variance and standard deviation) ...
Definition: Stats.h:182
Definition: Exceptions.h:13
void add(double val)
Add a single sample.
Definition: Stats.h:106
Stats()
Definition: Stats.h:185
void add(const ValueType &val, const Less &less=Less())
Add a single sample.
Definition: Stats.h:53
void add(double val, uint64_t n)
Add n samples with constant value val.
Definition: Stats.h:202
void add(const MinMax &other, const Less &less=Less())
Add the samples from the other Stats instance.
Definition: Stats.h:66
uint64_t size() const
Return the size of the population, i.e., the total number of samples.
Definition: Stats.h:122
bool isApproxEqual(const Type &a, const Type &b, const Type &tolerance)
Return true if a is equal to b to within the given tolerance.
Definition: Math.h:407
double max(int n) const
Return the maximum value in the nth bin.
Definition: Stats.h:340
double variance() const
Return the population variance.
Definition: Stats.h:234
MinMax()
Empty constructor.
Definition: Stats.h:38
void join(const Extrema &other)
Definition: Stats.h:161
double min() const
Return the minimum value.
Definition: Stats.h:125
double mean() const
Return the arithmetic mean, i.e. average, value.
Definition: Stats.h:226
This class computes a histogram, with a fixed interval width, of a population of floating-point value...
Definition: Stats.h:279
double min(int n) const
Return the minimum value in the nth bin.
Definition: Stats.h:338
size_t numBins() const
Return the number of bins in this histogram.
Definition: Stats.h:332
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:116
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:103
void add(const Extrema &other)
Add the samples from the other Stats instance.
Definition: Stats.h:134
void print(const std::string &name="", std::ostream &strm=std::cout, int precision=3) const
Print MinMax to the specified output stream.
Definition: Stats.h:73
void print(const std::string &name="", std::ostream &strm=std::cout) const
Print the histogram to the specified output stream.
Definition: Stats.h:347
bool add(double val, uint64_t n=1)
Add n samples with constant value val, provided that the val falls within this histogram&#39;s value rang...
Definition: Stats.h:312
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:202
double stdDev() const
Return the standard deviation (=Sqrt(variance)) as defined from the (biased) population variance...
Definition: Stats.h:241