npstat is hosted by Hepforge, IPPP Durham
NPStat  5.10.0
LocalQuadraticLeastSquaresND.hh
Go to the documentation of this file.
1 #ifndef NPSTAT_LOCALQUADRATICLEASTSQUARESND_HH_
2 #define NPSTAT_LOCALQUADRATICLEASTSQUARESND_HH_
3 
4 /*!
5 // \file LocalQuadraticLeastSquaresND.hh
6 //
7 // \brief Local least squares fit of a quadratic polynomial to a set
8 // of irregularly positioned points
9 //
10 // This code can properly take into account response uncertainties.
11 // The code is very general but it is rather slow in comparison with
12 // grid-based filters. Internal calculations are performed in double
13 // precision.
14 //
15 // Author: I. Volobouev
16 //
17 // October 2010
18 */
19 
20 #include <cassert>
21 #include <climits>
22 #include <stdexcept>
23 #include <vector>
24 
25 #include "npstat/nm/Matrix.hh"
27 
28 namespace npstat {
29  /**
30  // Local quadratic least squares fitter. Template parameter
31  // class Point must be subscriptable.
32  */
33  template<class Point, typename Numeric>
35  {
36  public:
37  /**
38  // The "polyDegree" parameter must be 0, 1, or 2.
39  //
40  // All values in the "bandwidthValues" array must be positive
41  // and their number, "nBandwidthValues", must be equal to
42  // the dimensionality of the weight function, weight.dim().
43  // The bandwidth values will be copied into an internal buffer.
44  //
45  // Make sure that the bandwidth values are sufficiently large
46  // so that the number of points for which the weight function
47  // is positive is always at least as large as the number of
48  // polynomial terms fitted. This must be true for every future
49  // "fit" call.
50  //
51  // This object will not copy or own "pointCoords", "values",
52  // or "errors" arrays. The number of elements in all of
53  // these arrays must be the same and equal to "nPoints". All
54  // errors must be positive. The "errors" array can also be NULL
55  // in which case all errors are assumed to be equal.
56  */
57 #ifndef SWIGBUG
59  unsigned polyDegree,
60  const AbsDistributionND& weight,
61  const double* bandwidthValues, unsigned nBandwidthValues,
62  const Point* pointCoords, unsigned nPoints,
63  const Numeric* values, const Numeric* errors = 0);
64 #endif // SWIGBUG
65 
67 
68  //@{
69  /** Examine object properties */
70  inline unsigned dim() const {return dim_;}
71  inline unsigned polyDegree() const {return polyDegree_;}
72  inline unsigned nPoints() const {return nPoints_;}
73  inline unsigned nTermsFitted() const {return nBasisFcns_;}
74  inline bool hasErrors() const {return errors_;}
75  inline double getBandwidth(const unsigned bwNumber) const
76  {
77  if (bwNumber >= dim_) throw std::out_of_range(
78  "In npstat::LocalQuadraticLeastSquaresND::getBandwidth: "
79  "bandwidth index out of range");
80  return bw_[bwNumber];
81  }
82  //@}
83 
84  /**
85  // The following function returns the chi-square of the fit.
86  // If the errors have not been specified, the sum of squared
87  // differences is returned (as if each error is set to 1).
88  */
89  double chiSquare() const;
90 
91  /**
92  // The following function returns the chi-square obtained
93  // by the leave-one-out least squares cross validation
94  */
95  double lscvCriterion() const;
96 
97  /**
98  // Change the point coordinates. Note that the number of new
99  // coordinates must be exactly equal to the number of points
100  // provided in the constructor. The array will not be copied.
101  */
102  inline void setPointCoords(const Point* newCoords)
103  {assert(newCoords); points_ = newCoords;}
104 
105  /**
106  // Change values for the point locations provided in the constructor.
107  // The array must have at least "nPoints()" elements.
108  */
109  inline void setValues(const Numeric* newValues)
110  {assert(newValues); values_ = newValues;}
111 
112  /**
113  // Change errors for the point locations provided in the constructor.
114  // The array must have at least "nPoints()" elements (or it can be
115  // NULL).
116  */
117  inline void setErrors(const Numeric* newErrors) {errors_ = newErrors;}
118 
119  /** Change bandwidth used for weight calculations */
120  inline void setBandwidth(const unsigned bwNum, const double newBw)
121  {
122  if (bwNum >= dim_) throw std::out_of_range(
123  "In npstat::LocalQuadraticLeastSquaresND::setBandwidth: "
124  "bandwidth index out of range");
125  if (newBw <= 0.0) throw std::invalid_argument(
126  "In npstat::LocalQuadraticLeastSquaresND::setBandwidth: "
127  "bandwidth must be positive");
128  bw_[bwNum] = newBw;
129  }
130 
131  /**
132  // Estimate of the smoother matrix. Will be nPoints x nPoints
133  // in size, so this works only for relatively small datasets.
134  // Smoother matrix plays similar role to the hat matrix.
135  */
136  Matrix<double> smootherMatrix(double stepInErrorUnits=1.0e-3) const;
137 
138  /**
139  // Perfom local quadratic polynomial fit with weight function
140  // centered at "coordinate". In additional to the fitted value,
141  // one can get the gradient and the Hessian at the fitted point,
142  // as estimated by the fit.
143  */
144  template <typename Num2>
145  double fit(const Num2* coordinate, unsigned coordinateDim,
146  double* gradient=0, unsigned lenGradient=0,
147  double* hessian=0, unsigned lenHessian=0,
148  unsigned excludedPoint=UINT_MAX) const;
149  private:
152  LocalQuadraticLeastSquaresND& operator=(
154 
155  double basisPoly(unsigned num, const double* coords) const;
156  double chisqCalc(bool looMode) const;
157 
158  const unsigned polyDegree_;
159  const unsigned nPoints_;
160  const unsigned dim_;
161  unsigned nBasisFcns_;
162  const AbsDistributionND* weight_;
163  const Point* points_;
164  const Numeric* values_;
165  const Numeric* errors_;
166  const Numeric zero_;
167 
168  std::vector<double> bwBuf_;
169  double* bw_;
170  double* delta_;
171 
172  std::vector<double> memBuf_;
173  double* A_;
174  double* b_;
175  double* singularValues_;
176 
177  mutable std::vector<double> workBuf_;
178  mutable std::vector<int> intBuf_;
179 
180 #ifdef SWIG
181  public:
182  // The vector of points below will not be copied
184  unsigned polyDegree,
185  const AbsDistributionND& weight,
186  const double* bandwidthValues, unsigned nBandwidthValues,
187  const std::vector<Point>& pointCoords,
188  const double* values, unsigned nValues,
189  const double* errors, unsigned nErrors);
190 
191  inline void setPointCoords_2(const std::vector<Point>& newCoords)
192  {
193  if (nPoints_ != newCoords.size()) throw std::invalid_argument(
194  "In npstat::LocalQuadraticLeastSquaresND::setPointCoords_2: "
195  "incompatible input length");
196  points_ = &newCoords[0];
197  }
198 
199  inline void setValues_2(const double* values, unsigned nValues)
200  {
201  if (nPoints_ != nValues) throw std::invalid_argument(
202  "In npstat::LocalQuadraticLeastSquaresND::setValues_2: "
203  "incompatible input length");
204  assert(values);
205  values_ = values;
206  }
207 
208  inline void setErrors_2(const double* errors, unsigned nErrors)
209  {
210  if (nErrors)
211  {
212  if (nPoints_ != nErrors) throw std::invalid_argument(
213  "In npstat::LocalQuadraticLeastSquaresND::setErrors_2: "
214  "incompatible input length");
215  assert(errors);
216  errors_ = errors;
217  }
218  else
219  errors_ = 0;
220  }
221 
222  inline double fit_2(
223  const double* coordinate, unsigned coordinateDim) const
224  {
225  return this->fit(coordinate, coordinateDim);
226  }
227 
228  inline double fitWithGradient(
229  const double* coordinate, unsigned coordinateDim,
230  double* gradient, unsigned lenGradient) const
231  {
232  if (lenGradient != dim_) throw std::invalid_argument(
233  "In npstat::LocalQuadraticLeastSquaresND::fitWithGradient: "
234  "incompatible dimensionality of the gradient");
235  return this->fit(coordinate, coordinateDim,
236  gradient, lenGradient);
237  }
238 
239  inline double fitWithHessian(
240  const double* coordinate, unsigned coordinateDim,
241  double* gradient, unsigned lenGradient,
242  Matrix<double>* hessian) const
243  {
244  if (lenGradient != dim_) throw std::invalid_argument(
245  "In npstat::LocalQuadraticLeastSquaresND::fitWithHessian: "
246  "incompatible dimensionality of the gradient");
247  assert(hessian);
248  hessian->resize(dim_, dim_);
249  return this->fit(coordinate, coordinateDim,
250  gradient, lenGradient,
251  hessian->data(), dim_*dim_);
252  }
253 #endif // SWIG
254  };
255 }
256 
257 #include "npstat/stat/LocalQuadraticLeastSquaresND.icc"
258 
259 #endif // NPSTAT_LOCALQUADRATICLEASTSQUARESND_HH_
Interface definition for multivariate continuous statistical distributions.
Template matrix class.
Definition: AbsDistributionND.hh:26
Definition: LocalQuadraticLeastSquaresND.hh:35
void setErrors(const Numeric *newErrors)
Definition: LocalQuadraticLeastSquaresND.hh:117
LocalQuadraticLeastSquaresND(unsigned polyDegree, const AbsDistributionND &weight, const double *bandwidthValues, unsigned nBandwidthValues, const Point *pointCoords, unsigned nPoints, const Numeric *values, const Numeric *errors=0)
void setPointCoords(const Point *newCoords)
Definition: LocalQuadraticLeastSquaresND.hh:102
unsigned dim() const
Definition: LocalQuadraticLeastSquaresND.hh:70
void setValues(const Numeric *newValues)
Definition: LocalQuadraticLeastSquaresND.hh:109
Matrix< double > smootherMatrix(double stepInErrorUnits=1.0e-3) const
double fit(const Num2 *coordinate, unsigned coordinateDim, double *gradient=0, unsigned lenGradient=0, double *hessian=0, unsigned lenHessian=0, unsigned excludedPoint=UINT_MAX) const
void setBandwidth(const unsigned bwNum, const double newBw)
Definition: LocalQuadraticLeastSquaresND.hh:120
Definition: AbsArrayProjector.hh:14