npstat is hosted by Hepforge, IPPP Durham
NPStat  5.10.0
KDEFilterND.hh
Go to the documentation of this file.
1 #ifndef NPSTAT_KDEFILTERND_HH_
2 #define NPSTAT_KDEFILTERND_HH_
3 
4 /*!
5 // \file KDEFilterND.hh
6 //
7 // \brief KDE on a regularly spaced multivariate grid with symmetric kernels
8 //
9 // If you don't expect to perform cross-validation or bandwidth scans,
10 // ConstantBandwidthSmootherND class might be a more convenient choice.
11 //
12 // Author: I. Volobouev
13 //
14 // December 2011
15 */
16 
17 #include <algorithm>
18 
20 
21 #include "npstat/nm/ArrayND.hh"
23 
24 namespace npstat {
25  /**
26  // This class performs kernel density estimation on a regularly spaced
27  // multivariate grid with arbitrary, tabulated symmetric kernels
28  */
29  template <unsigned MaxDeg>
31  {
32  public:
33  enum {deg_size = MaxDeg};
34 
35  /**
36  // Main constructor. The arguments are as follows:
37  //
38  // taper -- Damping factors for each polynomial degree
39  // (starting with the 0th order term). This can be
40  // NULL in which case it is assumed that all
41  // factors are 1.
42  //
43  // maxDegree -- Maximum degree of the polynomials. The value
44  // must not exceed the "MaxDeg" template parameter.
45  // The length of the "taper" array (if not NULL)
46  // must be equal to maxDegree + 1. Note that the same
47  // filter will be produced using an even degree N and
48  // an odd degree N+1.
49  //
50  // weight -- The array of weights. By default, this is just
51  // one hyperoctant corresponding to positive directions
52  // in all dimensions. The remaining part of the kernel
53  // is generated by reflections. If the full weight is
54  // provided instead, change the "mirrorWeight"
55  // default.
56  //
57  // engine -- The engine to use for convolutions. This object
58  // will not make its own copy of the engine. It is
59  // the responsibility of the user to ensure that
60  // the lifetime of the engine exceeds the lifetime
61  // of this object. It is assumed that the size
62  // of the arrays to filter will be two times smaller
63  // in each dimension than what is expected by the
64  // engine. Note that dimensionalities of weight
65  // array must not exceed data dimensionalities.
66  //
67  // id -- Filter slot number in the engine. Each filter
68  // used with this particular engine must be provided
69  // with a unique slot id.
70  //
71  // workBuffer -- Buffer array for various calculations. Must have
72  // the same shape as the convolution engine. Will
73  // not be copied internally. Must exist while this
74  // object operates.
75  //
76  // mirrorData -- If true, the data will be mirrored at the
77  // boundaries to reduce the edge effects.
78  //
79  // mirrorWeight -- If true, the weight will be mirrored. If false,
80  // the weight is considered to be complete. In the
81  // latter case the array size in each dimension
82  // must be odd and the weight should be centered
83  // in the array.
84  //
85  // manageSlot -- If true, the Fourier transform of this filter
86  // will be removed from the engine filter collection
87  // in the destructor of this object.
88  */
89  template <class Array>
90  KDEFilterND(const double* taper, unsigned maxDegree,
91  const Array& weight, ConvolutionEngineND& engine,
92  unsigned long id, ArrayND<double>& workBuffer,
93  bool mirrorData=true, bool mirrorWeight=true,
94  bool manageSlot=true);
95 
96  virtual ~KDEFilterND();
97 
98  //@{
99  /** Inspect object properties */
100  inline unsigned dim() const {return dataShape_.size();}
101  inline unsigned maxDegree() const {return taper_.size() - 1U;}
102  inline ArrayShape dataShape() const {return dataShape_;}
103  double taper(unsigned degree) const;
104  inline bool mirrorsData() const {return mirrorData_;}
105  inline unsigned long engineSlotId() const {return slotId_;}
106  inline double filterAtTheCenter() const {return filterAtTheCenter_;}
107  //@}
108 
109  //@{
110  /**
111  // Contribution of a single point into the density estimate
112  // at that point (not normalized). This is needed for various
113  // leaving-one-out cross validation procedures.
114  */
115  double selfContribution(const unsigned* index,
116  unsigned indexLen) const;
117  double linearSelfContribution(unsigned long index) const;
118  //@}
119 
120  /** Check if the self contribution varies from point to point */
121  inline bool selfContributionVaries() const {return selfContrib_;}
122 
123  /** Check the compatibility of an array with the filter */
124  template <class Array>
125  inline bool isCompatible(const Array& in) const
126  {return in.isCompatible(dataShape_);}
127 
128  /** The method which performs the filtering */
129  template <class ArrIn, class ArrOut>
130  void filter(const ArrIn& in, ArrOut* out) const;
131 
132  /**
133  // This method is included for compatibility with LocalPolyFilterND.
134  // For KDE, there is no difference between "convolve" and "filter".
135  */
136  template <class ArrIn, class ArrOut>
137  inline void convolve(const ArrIn& in, ArrOut* out) const
138  {this->filter(in, out);}
139 
140  static inline unsigned classMaxDegree() {return MaxDeg;}
141 
142  private:
143  KDEFilterND();
144  KDEFilterND(const KDEFilterND&);
145  KDEFilterND& operator=(const KDEFilterND&);
146 
147  template <class Array>
148  void initialize(const double* itaper, unsigned maxDegree,
149  const Array& inweight, bool mirrorWeight);
150 
151  void calculateSelfContribution(const ArrayND<double>& filter);
152 
153  ArrayShape dataShape_;
154  mutable ArrayShape idxBuffer_;
155  ConvolutionEngineND* engine_;
156  std::vector<double> taper_;
157  unsigned long slotId_;
158  ArrayND<double>* buf_;
159  double filterAtTheCenter_;
160  ArrayND<double>* selfContrib_;
161  bool mirrorData_;
162  bool manageSlot_;
163 
164 #ifdef SWIG
165  public:
166  inline KDEFilterND(const std::vector<double>& itaper,
167  const ArrayND<double>& inweight,
168  ConvolutionEngineND& engine,
169  unsigned long id, ArrayND<double>& workBuffer,
170  bool mirrorData=true, bool mirrorWeight=true,
171  bool manageSlot=true)
172  : dataShape_(halfShape(engine.shape())),
173  idxBuffer_(inweight.shape()),
174  engine_(&engine),
175  taper_(std::max(itaper.size(), static_cast<std::size_t>(1)), 1.0),
176  slotId_(id),
177  buf_(&workBuffer),
178  filterAtTheCenter_(0.0),
179  selfContrib_(0),
180  mirrorData_(mirrorData),
181  manageSlot_(manageSlot)
182  {
183  const double* tap = 0;
184  if (!itaper.empty())
185  tap = &itaper[0];
186  initialize(tap, taper_.size()-1, inweight, mirrorWeight);
187  }
188 #endif //SWIG
189  };
190 }
191 
192 #include "npstat/stat/KDEFilterND.icc"
193 
194 #endif // NPSTAT_KDEFILTERND_HH_
Interface definition for multivariate smoothers that can be cross-validated.
Arbitrary-dimensional array template.
Fast multidimensional convolutions via Fourier transforms (FFTW interface)
Definition: ConvolutionEngineND.hh:31
Definition: KDEFilterND.hh:31
unsigned dim() const
Definition: KDEFilterND.hh:100
void filter(const ArrIn &in, ArrOut *out) const
bool selfContributionVaries() const
Definition: KDEFilterND.hh:121
double selfContribution(const unsigned *index, unsigned indexLen) const
double linearSelfContribution(unsigned long index) const
ArrayShape dataShape() const
Definition: KDEFilterND.hh:102
KDEFilterND(const double *taper, unsigned maxDegree, const Array &weight, ConvolutionEngineND &engine, unsigned long id, ArrayND< double > &workBuffer, bool mirrorData=true, bool mirrorWeight=true, bool manageSlot=true)
void convolve(const ArrIn &in, ArrOut *out) const
Definition: KDEFilterND.hh:137
bool isCompatible(const Array &in) const
Definition: KDEFilterND.hh:125
Definition: AbsArrayProjector.hh:14
ArrayShape halfShape(const ArrayShape &inputShape)
std::vector< unsigned > ArrayShape
Definition: ArrayShape.hh:21
Definition: AbsPolyFilterND.hh:27