npstat is hosted by Hepforge, IPPP Durham
NPStat  5.10.0
AbsDistribution1D.hh
Go to the documentation of this file.
1 #ifndef NPSTAT_ABSDISTRIBUTION1D_HH_
2 #define NPSTAT_ABSDISTRIBUTION1D_HH_
3 
4 /*!
5 // \file AbsDistribution1D.hh
6 //
7 // \brief Interface definition for 1-d continuous statistical distributions
8 //
9 // Author: I. Volobouev
10 //
11 // November 2009
12 */
13 
14 #include <cassert>
15 #include <typeinfo>
16 #include <stdexcept>
17 
18 #include "geners/ClassId.hh"
21 
22 namespace npstat {
23  /**
24  // All classes derived from this base should have copy constructors
25  // (possibly automatic).
26  //
27  // quantile(0.0) and quantile(1.0) should return the boundaries
28  // of the support interval.
29  */
31  {
32  inline virtual ~AbsDistribution1D() {}
33 
34  /** Probability density */
35  virtual double density(double x) const = 0;
36 
37  /** Cumulative distribution function */
38  virtual double cdf(double x) const = 0;
39 
40  /**
41  // 1 - cdf, known as "survival function" or "exceedance".
42  // Implementations should avoid subtractive cancellation.
43  */
44  virtual double exceedance(double x) const = 0;
45 
46  /** The quantile function (inverse cdf) */
47  virtual double quantile(double x) const = 0;
48 
49  /**
50  // Derived classes should not implement "operator==", implement
51  // "isEqual" instead
52  */
53  inline bool operator==(const AbsDistribution1D& r) const
54  {return (typeid(*this) == typeid(r)) && this->isEqual(r);}
55 
56  /** Logical negation of operator== */
57  inline bool operator!=(const AbsDistribution1D& r) const
58  {return !(*this == r);}
59 
60  /** "Virtual copy constructor" */
61  virtual AbsDistribution1D* clone() const = 0;
62 
63  /**
64  // Random number generator according to the given distribution.
65  // Should return the number of random points used up from the
66  // generator.
67  */
68  inline virtual unsigned random(AbsRandomGenerator& g,
69  double* generatedRandom) const
70  {
71  assert(generatedRandom);
72  *generatedRandom = quantile(g());
73  return 1U;
74  }
75 
76  /**
77  // Numerical moment calculation using Gauss-Legendre or
78  // Fejer quadrature. If "useFejerQuadrature" argument is
79  // set to "false", the number of integration points should
80  // be supported by the "GaussLegendreQuadrature" class.
81  //
82  // No attempt is made to determine whether the moment actually
83  // exists. If it does not, the function might return Inf or
84  // fail in some other ways. This method might also be highly
85  // inaccurate for distributions with singularities or for
86  // distributions that have a lot of weight near support boundaries.
87  //
88  // For better results, it might be useful to calculate the
89  // 0th order moment (i.e., the normalization factor for the
90  // quadrature scheme chosen) and then divide everything by it.
91  */
92  long double empiricalMoment(long double center, unsigned order,
93  unsigned nIntegrationPoints = 1024U,
94  bool useFejerQuadrature = false) const;
95 
96  /**
97  // Numerical calculation of the expectation value of some functor,
98  // using Gauss-Legendre or Fejer quadrature. If "useFejerQuadrature"
99  // argument is set to "false", the number of integration points
100  // should be supported by the "GaussLegendreQuadrature" class.
101  */
102  template <class Functor>
103  double expectation(const Functor& fcn,
104  unsigned nIntegrationPoints = 1024U,
105  bool useFejerQuadrature = false) const;
106 
107  //@{
108  /** Prototype needed for I/O */
109  virtual gs::ClassId classId() const = 0;
110  inline virtual bool write(std::ostream&) const {return false;}
111  //@}
112 
113  static inline const char* classname()
114  {return "npstat::AbsDistribution1D";}
115  static inline unsigned version() {return 1;}
116  static AbsDistribution1D* read(const gs::ClassId& id, std::istream&);
117 
118  protected:
119  /** Comparison for equality. To be implemented by derived classes. */
120  virtual bool isEqual(const AbsDistribution1D&) const = 0;
121 
122  private:
123  template <class Funct>
124  class ExpectationFunctor : public Functor1<double, double>
125  {
126  public:
127  inline ExpectationFunctor(const Funct& fcn,
128  const AbsDistribution1D& distro)
129  : fcn_(fcn), distro_(distro) {}
130 
131  inline virtual ~ExpectationFunctor() {}
132 
133  inline double operator()(const double& x) const
134  {return fcn_(x)*distro_.density(x);}
135  private:
136  const Funct& fcn_;
137  const AbsDistribution1D& distro_;
138  };
139 
140 #ifdef SWIG
141  public:
142  inline double random2(AbsRandomGenerator& g) const
143  {
144  double d;
145  this->random(g, &d);
146  return d;
147  }
148 #endif // SWIG
149  };
150 
151  class UnscaledDensityFunctor1D;
152  class UnscaledCdfFunctor1D;
153 
154  /**
155  // This base class is used to model distributions which have
156  // "trivial" behavior w.r.t. location and scale parameters. That is,
157  // if the distribution density is g(x), the density with location
158  // parameter "mu" and scale parameter "sigma" is g((x - mu)/sigma)/sigma.
159  //
160  // All distributions with infinite support on both sides fall in this
161  // category, as well as a large number of distributions with finite
162  // support.
163  */
165  {
166  public:
167  /** Location and scale parameters must be provided */
168  inline AbsScalableDistribution1D(const double location,
169  const double scale) :
170  location_(location), scale_(scale)
171  {
172  if (scale_ <= 0.0) throw std::invalid_argument(
173  "In npstat::AbsScalableDistribution1D constructor: "
174  "scale parameter must be positive");
175  }
176 
177  inline virtual ~AbsScalableDistribution1D() {}
178 
179  /** Get the location parameter */
180  inline double location() const {return location_;}
181 
182  /** Get the scale parameter */
183  inline double scale() const {return scale_;}
184 
185  /** Set the location parameter */
186  inline void setLocation(const double v) {location_ = v;}
187 
188  /** Set the scale parameter */
189  inline void setScale(const double v)
190  {
191  if (v <= 0.0) throw std::invalid_argument(
192  "In npstat::AbsScalableDistribution1D::setScale: "
193  "scale parameter must be positive");
194  scale_ = v;
195  }
196 
197  //@{
198  /** Method overriden from the AbsDistribution1D base class */
199  inline double density(const double x) const
200  {return unscaledDensity((x - location_)/scale_)/scale_;}
201 
202  inline double cdf(const double x) const
203  {return unscaledCdf((x - location_)/scale_);}
204 
205  inline double exceedance(const double x) const
206  {return unscaledExceedance((x - location_)/scale_);}
207 
208  inline double quantile(const double x) const
209  {return scale_*unscaledQuantile(x) + location_;}
210 
211  inline virtual unsigned random(AbsRandomGenerator& g,
212  double* generatedRandom) const
213  {
214  const unsigned count = unscaledRandom(g, generatedRandom);
215  *generatedRandom *= scale_;
216  *generatedRandom += location_;
217  return count;
218  }
219  //@}
220 
221  /** "Virtual copy constructor" */
222  virtual AbsScalableDistribution1D* clone() const = 0;
223 
224  //@{
225  /** Method related to "geners" I/O */
226  virtual gs::ClassId classId() const = 0;
227  virtual bool write(std::ostream& os) const;
228  //@}
229 
230  /**
231  // Pseudo-read function for I/O. Note that this class is abstract,
232  // so its instance can not be created.
233  */
234  static bool read(std::istream& is, double* location, double* scale);
235 
236  protected:
237  /**
238  // Derived classes should override the following method as long as
239  // they have at least one additional data member. Don't forget to
240  // call "isEqual" of the base class inside the derived classes.
241  */
242  virtual bool isEqual(const AbsDistribution1D& other) const
243  {
244  const AbsScalableDistribution1D& r =
245  static_cast<const AbsScalableDistribution1D&>(other);
246  return location_ == r.location_ && scale_ == r.scale_;
247  }
248 
249  private:
250  friend class UnscaledDensityFunctor1D;
251  friend class UnscaledCdfFunctor1D;
252 
254 
255  virtual double unscaledDensity(double x) const = 0;
256  virtual double unscaledCdf(double x) const = 0;
257  virtual double unscaledExceedance(double x) const = 0;
258  virtual double unscaledQuantile(double x) const = 0;
259  inline virtual unsigned unscaledRandom(AbsRandomGenerator& g,
260  double* generatedRandom) const
261  {
262  assert(generatedRandom);
263  *generatedRandom = unscaledQuantile(g());
264  return 1U;
265  }
266 
267  double location_;
268  double scale_;
269  };
270 
271  /**
272  // A functor for the density function of the given 1-d distribution.
273  // For this and subsequent functors, the distribution is not copied,
274  // only a reference is used. It is a responsibility of the user to
275  // make sure that the lifetime of the distribution object exceeds
276  // the lifetime of the functor.
277  */
278  class DensityFunctor1D : public Functor1<double, double>
279  {
280  public:
281  inline explicit DensityFunctor1D(const AbsDistribution1D& fcn,
282  const double normfactor=1.0)
283  : fcn_(fcn), norm_(normfactor) {}
284 
285  inline virtual ~DensityFunctor1D() {}
286 
287  inline virtual double operator()(const double& a) const
288  {return norm_*fcn_.density(a);}
289 
290  private:
292  const AbsDistribution1D& fcn_;
293  const double norm_;
294  };
295 
296  /** A functor for the density squared of the given 1-d distribution */
297  class DensitySquaredFunctor1D : public Functor1<double, double>
298  {
299  public:
300  inline explicit DensitySquaredFunctor1D(const AbsDistribution1D& fcn,
301  const double normfactor=1.0)
302  : fcn_(fcn), norm_(normfactor) {}
303 
304  inline virtual ~DensitySquaredFunctor1D() {}
305 
306  inline virtual double operator()(const double& a) const
307  {
308  const double d = fcn_.density(a);
309  return norm_*norm_*d*d;
310  }
311 
312  private:
314  const AbsDistribution1D& fcn_;
315  const double norm_;
316  };
317 
318  /**
319  // A functor for the cumulative distribution function of
320  // the given 1-d distribution
321  */
322  class CdfFunctor1D : public Functor1<double, double>
323  {
324  public:
325  inline explicit CdfFunctor1D(const AbsDistribution1D& fcn,
326  const double normfactor=1.0)
327  : fcn_(fcn), norm_(normfactor) {}
328 
329  inline virtual ~CdfFunctor1D() {}
330 
331  inline virtual double operator()(const double& a) const
332  {return norm_*fcn_.cdf(a);}
333 
334  private:
335  CdfFunctor1D();
336  const AbsDistribution1D& fcn_;
337  const double norm_;
338  };
339 
340  /** A functor for the exceedance function of the given 1-d distribution */
341  class ExceedanceFunctor1D : public Functor1<double, double>
342  {
343  public:
344  inline explicit ExceedanceFunctor1D(const AbsDistribution1D& fcn,
345  const double normfactor=1.0)
346  : fcn_(fcn), norm_(normfactor) {}
347 
348  inline virtual ~ExceedanceFunctor1D() {}
349 
350  inline virtual double operator()(const double& a) const
351  {return norm_*fcn_.exceedance(a);}
352 
353  private:
355  const AbsDistribution1D& fcn_;
356  const double norm_;
357  };
358 
359  /** A functor for the quantile function of the given 1-d distribution */
360  class QuantileFunctor1D : public Functor1<double, double>
361  {
362  public:
363  inline explicit QuantileFunctor1D(const AbsDistribution1D& fcn,
364  const double normfactor=1.0)
365  : fcn_(fcn), norm_(normfactor) {}
366 
367  inline virtual ~QuantileFunctor1D() {}
368 
369  inline virtual double operator()(const double& a) const
370  {return fcn_.quantile(a/norm_);}
371 
372  private:
374  const AbsDistribution1D& fcn_;
375  const double norm_;
376  };
377 
378  /** A functor for the unscaled density */
379  class UnscaledDensityFunctor1D : public Functor1<double, double>
380  {
381  public:
382  inline explicit UnscaledDensityFunctor1D(const AbsScalableDistribution1D& fcn,
383  const double normfactor=1.0)
384  : fcn_(fcn), norm_(normfactor) {}
385 
386  inline virtual ~UnscaledDensityFunctor1D() {}
387 
388  inline virtual double operator()(const double& a) const
389  {return norm_*fcn_.unscaledDensity(a);}
390 
391  private:
393  const AbsScalableDistribution1D& fcn_;
394  const double norm_;
395  };
396 
397  /** A functor for the unscaled cdf */
398  class UnscaledCdfFunctor1D : public Functor1<double, double>
399  {
400  public:
401  inline explicit UnscaledCdfFunctor1D(const AbsScalableDistribution1D& fcn,
402  const double normfactor=1.0)
403  : fcn_(fcn), norm_(normfactor) {}
404 
405  inline virtual ~UnscaledCdfFunctor1D() {}
406 
407  inline virtual double operator()(const double& a) const
408  {return norm_*fcn_.unscaledCdf(a);}
409 
410  private:
412  const AbsScalableDistribution1D& fcn_;
413  const double norm_;
414  };
415 
416  /**
417  // A functor that gives the ratio between the density and its
418  // maximum value. Can be used to sample the distributions by
419  // acceptance-rejection. Does not copy the distribution, so
420  // the functor lifetime should not exceed the lifetime of the
421  // distribution.
422  */
423  class AcceptanceFunctor1D : public Functor1<double, double>
424  {
425  public:
426  inline AcceptanceFunctor1D(const AbsDistribution1D& fcn,
427  const double maxDensityValue)
428  : fcn_(fcn), max_(maxDensityValue)
429  {
430  if (max_ <= 0.0) throw std::invalid_argument(
431  "In npstat::AcceptanceFunctor1D constructor: "
432  "maximum density value must be positive");
433  }
434 
435  inline virtual ~AcceptanceFunctor1D() {}
436 
437  inline virtual double operator()(const double& a) const
438  {
439  const double ratio = fcn_.density(a)/max_;
440  if (ratio > 1.0) throw std::runtime_error(
441  "In npstat::AcceptanceFunctor1D::operator(): "
442  "the maximum density parameter is too small");
443  return ratio;
444  }
445 
446  private:
448  const AbsDistribution1D& fcn_;
449  const double max_;
450  };
451 
452  /**
453  // A functor that gives the ratio between the minimum density
454  // value and the density itself. For use in sampling inverse
455  // densities.
456  */
457  class InverseAcceptanceFunctor1D : public Functor1<double, double>
458  {
459  public:
461  const double minDensityValue)
462  : fcn_(fcn), min_(minDensityValue)
463  {
464  if (min_ <= 0.0) throw std::invalid_argument(
465  "In npstat::AcceptanceFunctor1D constructor: "
466  "minimum density value must be positive");
467  }
468 
469  inline virtual ~InverseAcceptanceFunctor1D() {}
470 
471  inline virtual double operator()(const double& a) const
472  {
473  const double d = fcn_.density(a);
474  assert(d > 0.0);
475  const double ratio = min_/d;
476  if (ratio > 1.0) throw std::runtime_error(
477  "In npstat::InverseAcceptanceFunctor1D::operator(): "
478  "the minimum density parameter is too large");
479  return ratio;
480  }
481 
482  private:
484  const AbsDistribution1D& fcn_;
485  const double min_;
486  };
487 }
488 
489 #include "npstat/stat/AbsDistribution1D.icc"
490 
491 #endif // NPSTAT_ABSDISTRIBUTION1D_HH_
Interface definition for pseudo- and quasi-random number generators.
Interface definitions and concrete simple functors for a variety of functor-based calculations.
Definition: AbsDistribution1D.hh:165
static bool read(std::istream &is, double *location, double *scale)
double scale() const
Definition: AbsDistribution1D.hh:183
void setLocation(const double v)
Definition: AbsDistribution1D.hh:186
virtual unsigned random(AbsRandomGenerator &g, double *generatedRandom) const
Definition: AbsDistribution1D.hh:211
AbsScalableDistribution1D(const double location, const double scale)
Definition: AbsDistribution1D.hh:168
virtual bool isEqual(const AbsDistribution1D &other) const
Definition: AbsDistribution1D.hh:242
double density(const double x) const
Definition: AbsDistribution1D.hh:199
double exceedance(const double x) const
Definition: AbsDistribution1D.hh:205
void setScale(const double v)
Definition: AbsDistribution1D.hh:189
double cdf(const double x) const
Definition: AbsDistribution1D.hh:202
virtual gs::ClassId classId() const =0
double quantile(const double x) const
Definition: AbsDistribution1D.hh:208
double location() const
Definition: AbsDistribution1D.hh:180
virtual AbsScalableDistribution1D * clone() const =0
Definition: AbsDistribution1D.hh:424
Definition: AbsDistribution1D.hh:323
Definition: AbsDistribution1D.hh:279
Definition: AbsDistribution1D.hh:298
Definition: AbsDistribution1D.hh:342
Definition: AbsDistribution1D.hh:458
Definition: AbsDistribution1D.hh:361
Definition: AbsDistribution1D.hh:399
Definition: AbsDistribution1D.hh:380
Definition: AbsArrayProjector.hh:14
Definition: AbsDistribution1D.hh:31
virtual double density(double x) const =0
bool operator!=(const AbsDistribution1D &r) const
Definition: AbsDistribution1D.hh:57
virtual unsigned random(AbsRandomGenerator &g, double *generatedRandom) const
Definition: AbsDistribution1D.hh:68
bool operator==(const AbsDistribution1D &r) const
Definition: AbsDistribution1D.hh:53
virtual gs::ClassId classId() const =0
long double empiricalMoment(long double center, unsigned order, unsigned nIntegrationPoints=1024U, bool useFejerQuadrature=false) const
virtual AbsDistribution1D * clone() const =0
virtual double exceedance(double x) const =0
virtual double quantile(double x) const =0
double expectation(const Functor &fcn, unsigned nIntegrationPoints=1024U, bool useFejerQuadrature=false) const
virtual double cdf(double x) const =0
virtual bool isEqual(const AbsDistribution1D &) const =0
Definition: AbsRandomGenerator.hh:27
Definition: SimpleFunctors.hh:58