npstat is hosted by Hepforge, IPPP Durham
NPStat  5.10.0
OrthoPoly1D.hh
Go to the documentation of this file.
1 #ifndef NPSTAT_ORTHOPOLY1D_HH_
2 #define NPSTAT_ORTHOPOLY1D_HH_
3 
4 /*!
5 // \file OrthoPoly1D.hh
6 //
7 // \brief Discrete orthogonal polynomial series in one dimension
8 //
9 // These series are intended for use in local (or global) filtering.
10 //
11 // Author: I. Volobouev
12 //
13 // October 2009
14 */
15 
16 #include <cassert>
17 #include <stdexcept>
18 
19 #ifdef SWIG
20 #include "npstat/nm/Matrix.hh"
21 #endif // SWIG
22 
23 namespace npstat {
24  namespace Private {
25  class OrthoPoly1DSprodCalc;
26  }
27 
29  {
30  public:
31  OrthoPoly1D();
32  OrthoPoly1D(const OrthoPoly1D&);
33 
34  /*
35  // Main constructor. The arguments are as follows:
36  //
37  // maxDegree -- Maximum degree of the polynomials.
38  //
39  // weight -- Tabulated weight function, in equidistant
40  // steps, in the order of increasing x.
41  // All values must be non-negative.
42  //
43  // weightLen -- Length of the "weight" array. This length
44  // must be larger than "maxDegree".
45  //
46  // step -- The x distance between two points in the table
47  // of weights. A good choice of "step" helps the
48  // polynomial values to remain within the dynamic
49  // range of double precision numbers.
50  */
51  OrthoPoly1D(unsigned maxDegree,
52  const double *weight, unsigned weightLen,
53  double step);
54 
55  ~OrthoPoly1D();
56 
57  /** The assignment operator */
59 
60  //@{
61  /** A simple inspector of object properties */
62  inline unsigned length() const {return nw_;}
63  inline unsigned maxDegree() const {return maxdeg_;}
64  inline double step() const {return step_;}
65  //@}
66 
67  //@{
68  /** Compare for equality */
69  bool operator==(const OrthoPoly1D& r) const;
70  bool operator!=(const OrthoPoly1D& r) const;
71  //@}
72 
73  /** Return the weight function value for the given index */
74  double weight(unsigned index) const;
75 
76  /** Return the value of one of the polynomials for the given index */
77  double poly(unsigned deg, unsigned index) const;
78 
79  /**
80  // Product of the weight function and one of the polynomials
81  // for the given index
82  */
83  double polyTimesWeight(unsigned deg, unsigned index) const;
84 
85  /**
86  // Return the values of the orthogonal polynomial series
87  // at the point with the given index
88  */
89  double series(const double *coeffs, unsigned maxdeg,
90  unsigned index) const;
91 
92  /**
93  // Generate a linear filter for the point with the given index.
94  // "coeffs" are the taper function coefficients. The length of
95  // the result should be equal to the length of the weight given
96  // in the constructor.
97  */
98  template <typename Numeric>
99  void linearFilter(const double *coeffs, unsigned maxdeg,
100  unsigned index,
101  Numeric *result, unsigned lenResult) const;
102 
103  /**
104  // Generate a global filter (OSDE-style).
105  // "coeffs" are the taper function coefficients. The length of
106  // the "result" array should be equal to the square of the length
107  // of the weight given in the constructor. It will be assumed that
108  // "result" will later be treated as a square matrix which will
109  // be multiplied by a column of input data.
110  */
111  template <typename Numeric>
112  void globalFilter(const double *coeffs, unsigned maxdeg,
113  Numeric *result, unsigned long lenResult) const;
114 
115  /** Obtain just the main diagonal of the global filter */
116  template <typename Numeric>
117  void globalFilterDiag(const double *coeffs, unsigned maxdeg,
118  Numeric *result, unsigned lenResult) const;
119 
120  /**
121  // Build the coefficients of the orthogonal polynomial series
122  // for the given function. "dataLen" should be equal to "weightLen"
123  // provided in the constructor. The length of the array "coeffs"
124  // should be at least "maxdeg" + 1. Note that the coefficients
125  // are returned in the order of increasing degree (same order
126  // is used by the "series" function).
127  */
128  void calculateCoeffs(const double *data, unsigned dataLen,
129  double *coeffs, unsigned maxdeg) const;
130 
131  /*
132  // Estimate the expansion coefficients assuming that the function
133  // we are expanding is a probability density
134  */
135  void densityCoeffs(const double *data, unsigned dataLen,
136  double *coeffs, unsigned maxdeg) const;
137 
138  /*
139  // Estimate the variances of the expansion coefficients assuming
140  // that the function we are expanding is a probability density
141  */
142  void densityCoeffsVariance(const double *data, unsigned dataLen,
143  double *coeffs, unsigned maxdeg,
144  double effectiveSampleSize) const;
145 
146  /**
147  // This method is useful for testing the numerical precision
148  // of the orthonormalization procedure. It returns the scalar
149  // products between various polynomials.
150  */
151  double empiricalKroneckerDelta(unsigned deg1, unsigned deg2) const;
152 
153  /**
154  // Orthogonal series for the weight function itself.
155  // The length of the array "coeffs" should be at least maxdeg + 1.
156  */
157  void weightExpansionCoeffs(double *coeffs, unsigned maxdeg) const;
158 
159  /**
160  // Covariance matrix between weight expansion coefficients in the
161  // assumption that the weight function is a probability that is
162  // being sampled. The covariance is calculated for a single
163  // point sample. If the sample has N points, the covariance matrix
164  // should be divided by N (this assumes that the weight expansion
165  // coefficients are determined for a normalized EDF).
166  */
167  double weightExpansionCovariance(unsigned deg1, unsigned deg2) const;
168 
169  /** Scalar products between polynomials without the weight */
170  double unweightedPolyProduct(unsigned deg1, unsigned deg2) const;
171 
172  private:
173  long double *weight_;
174  long double *poly_; // this is an array dimensioned [maxdeg+1][nw]
175  long double step_;
176  unsigned nw_;
177  unsigned maxdeg_;
178 
179  long double unweightedProduct(const long double *x,
180  const long double *y) const;
181  long double scalarProduct(const long double *x,
182  const long double *y) const;
183  long double scalarProduct(const double *x,
184  const long double *y) const;
185  long double normScalarProduct(const double *x,
186  const long double *y) const;
187  long double normScalarProductSq(const double *x,
188  const long double *y,
189  long double ymean) const;
190  friend class Private::OrthoPoly1DSprodCalc;
191 
192 #ifdef SWIG
193  public:
194  inline Matrix<double>* globalFilter_2(const double *coeffs, unsigned maxdeg) const
195  {
196  assert(maxdeg);
197  Matrix<double>* m = new Matrix<double>(nw_, nw_);
198  this->globalFilter(coeffs, maxdeg-1U, m->data(), m->length());
199  m->tagAsDiagonal(false);
200  return m;
201  }
202 
203  inline void globalFilterDiag_2(const double *coeffs, unsigned maxdeg,
204  double *expansion, unsigned len) const
205  {
206  assert(maxdeg);
207  this->globalFilterDiag(coeffs, maxdeg-1U, expansion, len);
208  }
209 
210  inline void calculateCoeffs_2(const double *data, unsigned dataLen,
211  double *expansion, unsigned len) const
212  {
213  assert(len);
214  this->calculateCoeffs(data, dataLen, expansion, len-1U);
215  }
216 
217  inline void densityCoeffs_2(const double *data, unsigned dataLen,
218  double *expansion, unsigned len) const
219  {
220  assert(len);
221  this->densityCoeffs(data, dataLen, expansion, len-1U);
222  }
223 
224  inline void densityCoeffsVariance_2(const double *data, unsigned dataLen,
225  double *expansion, unsigned len,
226  double effectiveSampleSize) const
227  {
228  assert(len);
229  this->densityCoeffsVariance(data, dataLen, expansion,
230  len-1U, effectiveSampleSize);
231  }
232 
233  inline void allSeries(const double *coeffs, unsigned maxdeg,
234  double *expansion, unsigned len,
235  const bool makeNonNegative = false) const
236  {
237  if (len != nw_) throw std::invalid_argument(
238  "In npstat::OrthoPoly1D::allSeries: incompatible buffer size");
239  assert(expansion);
240  assert(maxdeg);
241  const unsigned dm1 = maxdeg-1U;
242  for (unsigned i=0; i<nw_; ++i)
243  {
244  expansion[i] = this->series(coeffs, dm1, i);
245  if (makeNonNegative)
246  if (expansion[i] < 0.0)
247  expansion[i] = 0.0;
248  }
249  }
250 
251  inline double series_2(const double *coeffs, unsigned maxdeg,
252  unsigned index) const
253  {
254  assert(maxdeg);
255  return this->series(coeffs, maxdeg-1U, index);
256  }
257 
258  inline void weightExpansionCoeffs_2(double *coeffs, unsigned maxdeg) const
259  {
260  assert(maxdeg);
261  this->weightExpansionCoeffs(coeffs, maxdeg-1U);
262  }
263 #endif // SWIG
264  };
265 
266  namespace Private {
268  {
269  public:
270  inline explicit OrthoPoly1DSprodCalc(const OrthoPoly1D& r)
271  : opoly(r) {}
272 
273  inline long double operator()(const long double* x, const long double* y,
274  const unsigned long len) const
275  {
276  assert(len == opoly.nw_);
277  return opoly.scalarProduct(x, y);
278  }
279 
280  private:
281  const OrthoPoly1D& opoly;
282  };
283  }
284 }
285 
286 #include "npstat/nm/OrthoPoly1D.icc"
287 
288 #endif // NPSTAT_ORTHOPOLY1D_HH_
Template matrix class.
Matrix & tagAsDiagonal(bool b=true)
Definition: OrthoPoly1D.hh:29
double weightExpansionCovariance(unsigned deg1, unsigned deg2) const
void weightExpansionCoeffs(double *coeffs, unsigned maxdeg) const
double poly(unsigned deg, unsigned index) const
unsigned length() const
Definition: OrthoPoly1D.hh:62
double polyTimesWeight(unsigned deg, unsigned index) const
OrthoPoly1D & operator=(const OrthoPoly1D &)
void globalFilterDiag(const double *coeffs, unsigned maxdeg, Numeric *result, unsigned lenResult) const
double weight(unsigned index) const
void globalFilter(const double *coeffs, unsigned maxdeg, Numeric *result, unsigned long lenResult) const
void linearFilter(const double *coeffs, unsigned maxdeg, unsigned index, Numeric *result, unsigned lenResult) const
double series(const double *coeffs, unsigned maxdeg, unsigned index) const
void calculateCoeffs(const double *data, unsigned dataLen, double *coeffs, unsigned maxdeg) const
double unweightedPolyProduct(unsigned deg1, unsigned deg2) const
double empiricalKroneckerDelta(unsigned deg1, unsigned deg2) const
bool operator==(const OrthoPoly1D &r) const
Definition: OrthoPoly1D.hh:268
Definition: AbsArrayProjector.hh:14