npstat is hosted by Hepforge, IPPP Durham
NPStat  5.10.0
ModulatedDistribution1D.hh
Go to the documentation of this file.
1 #ifndef NPSTAT_MODULATEDDISTRIBUTION1D_HH_
2 #define NPSTAT_MODULATEDDISTRIBUTION1D_HH_
3 
4 /*!
5 // \file ModulatedDistribution1D.hh
6 //
7 // \brief 1-d continuous statistical distributions multiplied
8 // by an arbitrary smooth non-negative function
9 //
10 // Author: I. Volobouev
11 //
12 // June 2022
13 */
14 
15 #include <climits>
16 #include <algorithm>
17 
19 
22 
23 namespace npstat {
24  template<class Functor>
26  {
27  public:
28  /**
29  // Constructor arguments are as follows:
30  //
31  // distro -- distribution whose density we want to
32  // modulate
33  //
34  // fcn -- functor that will be multiplied by
35  // the density
36  //
37  // fcnXmin, fcnXmax -- limits for the functor support
38  //
39  // nIntegPoints -- number of points to use for various
40  // integrations. Should be supported by
41  // the GaussLegendreQuadrature class.
42  //
43  // nIntegIntervals -- number of intervals to use for various
44  // integrations. The support will be
45  // split into this number of intervals
46  // and then the quadrature with nIntegPoints
47  // points will be used on each interval.
48  */
50  const Functor& fcn,
51  const double fcnXmin = -DBL_MAX,
52  const double fcnXmax = DBL_MAX,
53  const unsigned nIntegPoints = 1024,
54  const unsigned nIntegIntervals = 1)
55  : distro_(0), fcn_(fcn), norm_(1.0),
56  nIntegPoints_(nIntegPoints), nIntegIntervals_(nIntegIntervals)
57  {
58  if (!(fcnXmin < fcnXmax)) throw std::invalid_argument(
59  "In npstat::ModulatedDistribution1D constructor: "
60  "invalid support specification for the modulating function");
61  xmin_ = std::max(distro.quantile(0.0), fcnXmin);
62  xmax_ = std::min(distro.quantile(1.0), fcnXmax);
63  if (!(xmin_ < xmax_)) throw std::invalid_argument(
64  "In npstat::ModulatedDistribution1D constructor: "
65  "supports of the density and of the modulating function "
66  "do not overlap");
67  GaussLegendreQuadrature glq(nIntegPoints);
68  if (!nIntegIntervals_) throw std::invalid_argument(
69  "In npstat::ModulatedDistribution1D constructor: "
70  "number of integration intervals must be positive");
71  distro_ = distro.clone();
72  norm_ = glq.integrate(DensityFunctor1D(*this),
73  xmin_, xmax_, nIntegIntervals_);
74  assert(norm_ > 0.0);
75  }
76 
78  : distro_(r.distro_->clone()), fcn_(r.fcn_),
79  xmin_(r.xmin_), xmax_(r.xmax_), norm_(r.norm_),
80  nIntegPoints_(r.nIntegPoints_),
81  nIntegIntervals_(r.nIntegIntervals_) {}
82 
83  inline ModulatedDistribution1D& operator=(const ModulatedDistribution1D& r)
84  {
85  if (&r != this)
86  {
87  AbsDistribution1D* p = r.distro_->clone();
88  delete distro_;
89  distro_ = p;
90  fcn_ = r.fcn_;
91  xmin_ = r.xmin_;
92  xmax_ = r.xmax_;
93  norm_ = r.norm_;
94  nIntegPoints_ = r.nIntegPoints_;
95  nIntegIntervals_ = r.nIntegIntervals_;
96  }
97  return *this;
98  }
99 
100  inline virtual ModulatedDistribution1D* clone() const
101  {return new ModulatedDistribution1D(*this);}
102 
103  inline virtual ~ModulatedDistribution1D() {delete distro_;}
104 
105  /** Distribution density */
106  inline virtual double density(const double x) const
107  {
108  if (x >= xmin_ && x <= xmax_)
109  {
110  const double d = distro_->density(x)*fcn_(x)/norm_;
111  assert(d >= 0.0);
112  return d;
113  }
114  else
115  return 0.0;
116  }
117 
118  /** Cumulative distribution function */
119  inline virtual double cdf(const double x) const
120  {
121  if (x <= xmin_)
122  return 0.0;
123  else if (x >= xmax_)
124  return 1.0;
125  else
126  {
127  GaussLegendreQuadrature glq(nIntegPoints_);
128  return glq.integrate(DensityFunctor1D(*this),
129  xmin_, x, nIntegIntervals_);
130  }
131  }
132 
133  /** 1 - cdf, avoiding subtractive cancellation */
134  inline virtual double exceedance(const double x) const
135  {
136  if (x <= xmin_)
137  return 1.0;
138  else if (x >= xmax_)
139  return 0.0;
140  else
141  {
142  GaussLegendreQuadrature glq(nIntegPoints_);
143  return glq.integrate(DensityFunctor1D(*this),
144  x, xmax_, nIntegIntervals_);
145  }
146  }
147 
148  /** The quantile function */
149  inline virtual double quantile(const double r1) const
150  {
151  if (!(r1 >= 0.0 && r1 <= 1.0)) throw std::domain_error(
152  "In npstat::ModulatedDistribution1D::quantile: "
153  "cdf argument outside of [0, 1] interval");
154  if (r1 == 0.0)
155  return xmin_;
156  else if (r1 == 1.0)
157  return xmax_;
158  else
159  {
160  const double tol = 2.0*std::numeric_limits<double>::epsilon();
161  double q;
162  const bool status = findRootUsingBisections(
163  CdfFunctor1D(*this), r1, xmin_, xmax_, tol, &q);
164  assert(status);
165  return q;
166  }
167  }
168 
169  /**
170  // Read/write functions are not implemented so that we can
171  // use this class with functors that do not support I/O
172  */
173  inline virtual gs::ClassId classId() const {return gs::ClassId(*this);}
174 
175  static inline const char* classname()
176  {return "npstat::ModulatedDistribution1D";}
177  static inline unsigned version() {return 1;}
178 
179  protected:
180  inline virtual bool isEqual(const AbsDistribution1D& other) const
181  {return false; /* Can't compare functors for equality */}
182 
183  private:
185 
186  AbsDistribution1D* distro_;
187  Functor fcn_;
188  double xmin_;
189  double xmax_;
190  double norm_;
191  unsigned nIntegPoints_;
192  unsigned nIntegIntervals_;
193  };
194 
195  /** Convenience function for creating ModulatedDistribution1D objects */
196  template<class Functor>
197  inline ModulatedDistribution1D<Functor>
199  const Functor& fcn,
200  const double fcnXmin = -DBL_MAX,
201  const double fcnXmax = DBL_MAX,
202  const unsigned nIntegPoints = 1024,
203  const unsigned nIntegIntervals = 1)
204  {
206  distro, fcn, fcnXmin, fcnXmax, nIntegPoints, nIntegIntervals);
207  }
208 }
209 
210 #endif // NPSTAT_MODULATEDDISTRIBUTION1D_HH_
Interface definition for 1-d continuous statistical distributions.
Gauss-Legendre quadratures in long double precision.
Definition: AbsDistribution1D.hh:323
Definition: AbsDistribution1D.hh:279
Definition: GaussLegendreQuadrature.hh:27
long double integrate(const Functor1< FcnResult, FcnArg > &fcn, long double a, long double b) const
Definition: ModulatedDistribution1D.hh:26
virtual double exceedance(const double x) const
Definition: ModulatedDistribution1D.hh:134
virtual gs::ClassId classId() const
Definition: ModulatedDistribution1D.hh:173
virtual double cdf(const double x) const
Definition: ModulatedDistribution1D.hh:119
virtual double density(const double x) const
Definition: ModulatedDistribution1D.hh:106
virtual bool isEqual(const AbsDistribution1D &other) const
Definition: ModulatedDistribution1D.hh:180
virtual double quantile(const double r1) const
Definition: ModulatedDistribution1D.hh:149
virtual ModulatedDistribution1D * clone() const
Definition: ModulatedDistribution1D.hh:100
ModulatedDistribution1D(const AbsDistribution1D &distro, const Functor &fcn, const double fcnXmin=-DBL_MAX, const double fcnXmax=DBL_MAX, const unsigned nIntegPoints=1024, const unsigned nIntegIntervals=1)
Definition: ModulatedDistribution1D.hh:49
Root finding with the bisection method.
Definition: AbsArrayProjector.hh:14
ModulatedDistribution1D< Functor > make_ModulatedDistribution1D(const AbsDistribution1D &distro, const Functor &fcn, const double fcnXmin=-DBL_MAX, const double fcnXmax=DBL_MAX, const unsigned nIntegPoints=1024, const unsigned nIntegIntervals=1)
Definition: ModulatedDistribution1D.hh:198
bool findRootUsingBisections(const Functor1< Result, Arg1 > &f, Result rhs, Arg1 x0, Arg1 x1, Arg1 tol, Arg1 *root)
Definition: AbsDistribution1D.hh:31
virtual double density(double x) const =0
virtual AbsDistribution1D * clone() const =0
virtual double quantile(double x) const =0