npstat is hosted by Hepforge, IPPP Durham
NPStat  5.10.0
AbsKDE1DKernel.hh
Go to the documentation of this file.
1 #ifndef NPSTAT_ABSKDE1DKERNEL_HH_
2 #define NPSTAT_ABSKDE1DKERNEL_HH_
3 
4 /*!
5 // \file AbsKDE1DKernel.hh
6 //
7 // \brief Brute-force non-discretized KDE in 1-d. No boundary correction.
8 //
9 // Author: I. Volobouev
10 //
11 // November 2018
12 */
13 
14 #include <cmath>
15 #include <stdexcept>
16 
19 
20 namespace npstat {
21  /** Base class for 1-d kernels and KDE */
23  {
24  public:
25  inline virtual ~AbsKDE1DKernel() {}
26 
27  virtual void setNormFactor(double normfactor) = 0;
28 
29  virtual double xmin() const = 0;
30  virtual double xmax() const = 0;
31  virtual double normFactor() const = 0;
32 
33  virtual double operator()(double x) const = 0;
34 
35  /** "Virtual copy constructor" */
36  virtual AbsKDE1DKernel* clone() const = 0;
37 
38  //@{
39  /**
40  // "nIntegPoints" argument in the following method is the
41  // number of points to use in the quadrature rule. If this
42  // method is not overriden, Gauss-Legendre quadrature is used.
43  */
44  virtual double momentIntegral(unsigned k, unsigned nIntegPoints) const;
45  virtual double squaredIntegral(unsigned nIntegPoints) const;
46  //@}
47 
48  /**
49  // Summing K((x - x[i])/h), as in the standard KDE definition.
50  // Setting "coordinatesSorted" flag to "true" if coordinates
51  // are sorted in the increasing order can potentially increase
52  // the speed of KDE evaluation.
53  */
54  template <typename Numeric>
55  double kde(double x, double bandwidth,
56  const Numeric* coords, unsigned long nCoords,
57  bool coordinatesSorted = false) const;
58 
59  /** Summing K((x[i] - x)/h) */
60  template <typename Numeric>
61  double reverseKde(double x, double bandwidth,
62  const Numeric* coords, unsigned long nCoords,
63  bool coordinatesSorted = false) const;
64 
65  /**
66  // Leave-one-out density estimate. The original density estimate
67  // should be obtained earlier with either "kde" or "reverseKde"
68  // method used with the same values of "bandwidth" and "nCoords"
69  // arguments.
70  */
71  double looKde(double bandwidth, unsigned long nCoords,
72  double originalDensityEstimate) const;
73 
74  /**
75  // Integrated squared error w.r.t. a known density. Parameter
76  // "nIntegPoints" is the number of integration points per interval,
77  // and it must be supported by the GaussLegendreQuadrature class.
78  // The integration interval is defined by the support of the density.
79  */
80  template <typename Numeric>
82  unsigned nIntegIntervals, unsigned nIntegPoints,
83  double bandwidth, bool useReverseKde,
84  const Numeric* coords, unsigned long nCoords,
85  bool coordinatesSorted = false) const;
86 
87  /**
88  // Integral of KDE squared. Parameter "nIntegPoints" is the number
89  // of integration points per interval, and it must be supported by
90  // the GaussLegendreQuadrature class.
91  */
92  template <typename Numeric>
94  double xmin, double xmax,
95  unsigned nIntegIntervals, unsigned nIntegPoints,
96  double bandwidth, bool useReverseKde,
97  const Numeric* coords, unsigned long nCoords,
98  bool coordinatesSorted = false) const;
99  protected:
100  class MomentFcn : public Functor1<double, double>
101  {
102  public:
103  inline MomentFcn(const AbsKDE1DKernel& ref, const unsigned power)
104  : kernel(ref), xpow(power) {}
105 
106  inline virtual ~MomentFcn() {}
107 
108  inline double operator()(const double& x) const
109  {return kernel(x)*(xpow ? pow(x, xpow) : 1.0);}
110  private:
111  const AbsKDE1DKernel& kernel;
112  unsigned xpow;
113  };
114 
115  class SquareFcn : public Functor1<double, double>
116  {
117  public:
118  inline explicit SquareFcn(const AbsKDE1DKernel& ref)
119  : kernel(ref) {}
120 
121  inline virtual ~SquareFcn() {}
122 
123  inline double operator()(const double& x) const
124  {const double k = kernel(x); return k*k;}
125  private:
126  const AbsKDE1DKernel& kernel;
127  };
128 
129 #ifdef SWIG
130  // Simplified non-template methods for the python API. Not for use in C++.
131  public:
132  inline double kde2(double x, double bandwidth,
133  const double* coords, unsigned nCoords,
134  bool coordinatesSorted = false) const
135  {
136  return kde(x, bandwidth, coords, nCoords, coordinatesSorted);
137  }
138 
139  inline double reverseKde2(double x, double bandwidth,
140  const double* coords, unsigned nCoords,
141  bool coordinatesSorted = false) const
142  {
143  return reverseKde(x, bandwidth, coords, nCoords, coordinatesSorted);
144  }
145 
146  inline double integratedSquaredError2(
147  const AbsDistribution1D& distro,
148  unsigned nIntegIntervals, unsigned nIntegPoints,
149  double bandwidth, bool useReverseKde,
150  const double* coords, unsigned nCoords,
151  bool coordinatesSorted = false) const
152  {
153  return integratedSquaredError(distro, nIntegIntervals, nIntegPoints,
154  bandwidth, useReverseKde, coords, nCoords,
155  coordinatesSorted);
156  }
157 
158  inline double integratedKdeSquared2(
159  double xmin, double xmax,
160  unsigned nIntegIntervals, unsigned nIntegPoints,
161  double bandwidth, bool useReverseKde,
162  const double* coords, unsigned nCoords,
163  bool coordinatesSorted = false) const
164  {
165  return integratedKdeSquared(xmin, xmax, nIntegIntervals, nIntegPoints,
166  bandwidth, useReverseKde, coords, nCoords,
167  coordinatesSorted);
168  }
169 #endif // SWIG
170  };
171 
172  /** Arbitrary 1-d densities used as kernel smoothers */
174  {
175  public:
176  inline explicit KDE1DDensityKernel(const AbsDistribution1D& d,
177  const double normfactor=1.0)
178  : distro_(0), norm_(0.0)
179  {
180  setNormFactor(normfactor);
181  distro_ = d.clone();
182  }
183 
184  inline KDE1DDensityKernel(const KDE1DDensityKernel& r)
185  : distro_(0), norm_(r.norm_) {distro_ = r.distro_->clone();}
186 
187  inline KDE1DDensityKernel& operator=(const KDE1DDensityKernel& r)
188  {
189  if (this != &r)
190  {
191  delete distro_;
192  distro_ = 0;
193  distro_ = r.distro_->clone();
194  norm_ = r.norm_;
195  }
196  return *this;
197  }
198 
199  inline virtual KDE1DDensityKernel* clone() const
200  {return new KDE1DDensityKernel(*this);}
201 
202  inline virtual ~KDE1DDensityKernel() {delete distro_;}
203 
204  inline virtual void setNormFactor(const double normfactor)
205  {
206  if (normfactor <= 0.0) throw std::invalid_argument(
207  "In npstat::KDE1DDensityKernel::setNormFactor: "
208  "normalization factor must be positive");
209  norm_ = normfactor;
210  }
211 
212  inline double xmin() const {return distro_->quantile(0.0);}
213  inline double xmax() const {return distro_->quantile(1.0);}
214  inline double normFactor() const {return norm_;}
215 
216  inline double operator()(const double x) const
217  {return norm_*distro_->density(x);}
218 
219  private:
220  AbsDistribution1D* distro_;
221  double norm_;
222  };
223 
224  /**
225  // A lightweight functor for getting KDE values. It will not copy
226  // the kernel and will not own the data. It is the responsibility
227  // of the user of this class to ensure that the lifetimes of the
228  // kernel and the data exceed the lifetime of the functor.
229  //
230  // Intended usage is via the "KDE1DFunctor" utility function.
231  */
232  template <typename Numeric>
233  class KDE1DFunctorHelper : public Functor1<double, double>
234  {
235  public:
236  inline KDE1DFunctorHelper(const AbsKDE1DKernel& kernel,
237  const double bandwidth,
238  const Numeric* coords,
239  const unsigned long nCoords,
240  const bool coordinatesSorted,
241  const bool useReverseKde)
242  : kernel_(kernel), bandwidth_(bandwidth),
243  coords_(coords), nCoords_(nCoords),
244  coordinatesSorted_(coordinatesSorted),
245  useReverseKde_(useReverseKde) {}
246 
247  inline virtual ~KDE1DFunctorHelper() {}
248 
249  inline double operator()(const double& x) const
250  {
251  double kde;
252  if (useReverseKde_)
253  kde = kernel_.reverseKde(x, bandwidth_, coords_, nCoords_,
254  coordinatesSorted_);
255  else
256  kde = kernel_.kde(x, bandwidth_, coords_, nCoords_,
257  coordinatesSorted_);
258  return kde;
259  }
260 
261  private:
262  const AbsKDE1DKernel& kernel_;
263  double bandwidth_;
264  const Numeric* coords_;
265  unsigned long nCoords_;
266  bool coordinatesSorted_;
267  bool useReverseKde_;
268  };
269 
270  /** A convenience function for making lightweight KDE functors */
271  template <typename Numeric>
273  const AbsKDE1DKernel& kernel, const double bandwidth,
274  const Numeric* coords, const unsigned long nCoords,
275  const bool coordinatesSorted = false, const bool useReverseKde = false)
276  {
277  return KDE1DFunctorHelper<Numeric>(kernel, bandwidth, coords, nCoords,
278  coordinatesSorted, useReverseKde);
279  }
280 
281  /** A functor of (x,y) for use with kernelSensitivityMatrix, etc */
282  class KDE1DFunctor2 : public Functor2<double, double, double>
283  {
284  public:
285  inline KDE1DFunctor2(const AbsKDE1DKernel& kernel,
286  const double bandwidth,
287  const bool useReverseKde = false)
288  : kernel_(kernel), bandwidth_(bandwidth),
289  useReverseKde_(useReverseKde)
290  {
291  if (bandwidth_ <= 0.0) throw std::invalid_argument(
292  "In npstat::KDE1DFunctor2 constructor: bandwidth must be positive");
293  }
294 
295  inline virtual ~KDE1DFunctor2() {}
296 
297  inline double operator()(const double& x, const double& y) const
298  {
299  const double delta = useReverseKde_ ? x - y : y - x;
300  return kernel_(delta/bandwidth_)/bandwidth_;
301  }
302 
303  private:
304  const AbsKDE1DKernel& kernel_;
305  double bandwidth_;
306  bool useReverseKde_;
307  };
308 }
309 
310 #include "npstat/stat/AbsKDE1DKernel.icc"
311 
312 #endif // NPSTAT_ABSKDE1DKERNEL_HH_
Interface definition for 1-d continuous statistical distributions.
Interface definitions and concrete simple functors for a variety of functor-based calculations.
Definition: AbsKDE1DKernel.hh:101
Definition: AbsKDE1DKernel.hh:116
Definition: AbsKDE1DKernel.hh:23
double reverseKde(double x, double bandwidth, const Numeric *coords, unsigned long nCoords, bool coordinatesSorted=false) const
double integratedSquaredError(const AbsDistribution1D &distro, unsigned nIntegIntervals, unsigned nIntegPoints, double bandwidth, bool useReverseKde, const Numeric *coords, unsigned long nCoords, bool coordinatesSorted=false) const
double kde(double x, double bandwidth, const Numeric *coords, unsigned long nCoords, bool coordinatesSorted=false) const
double looKde(double bandwidth, unsigned long nCoords, double originalDensityEstimate) const
double integratedKdeSquared(double xmin, double xmax, unsigned nIntegIntervals, unsigned nIntegPoints, double bandwidth, bool useReverseKde, const Numeric *coords, unsigned long nCoords, bool coordinatesSorted=false) const
virtual double momentIntegral(unsigned k, unsigned nIntegPoints) const
virtual AbsKDE1DKernel * clone() const =0
Definition: AbsKDE1DKernel.hh:174
virtual KDE1DDensityKernel * clone() const
Definition: AbsKDE1DKernel.hh:199
Definition: AbsKDE1DKernel.hh:283
Definition: AbsKDE1DKernel.hh:234
Definition: AbsArrayProjector.hh:14
KDE1DFunctorHelper< Numeric > KDE1DFunctor(const AbsKDE1DKernel &kernel, const double bandwidth, const Numeric *coords, const unsigned long nCoords, const bool coordinatesSorted=false, const bool useReverseKde=false)
Definition: AbsKDE1DKernel.hh:272
Definition: AbsDistribution1D.hh:31
virtual double density(double x) const =0
virtual AbsDistribution1D * clone() const =0
virtual double quantile(double x) const =0
Definition: SimpleFunctors.hh:58
Definition: SimpleFunctors.hh:89