npstat is hosted by Hepforge, IPPP Durham
NPStat  5.10.0
ScalableClassicalOrthoPoly1D.hh
Go to the documentation of this file.
1 #ifndef NPSTAT_SCALABLECLASSICALORTHOPOLY1D_HH_
2 #define NPSTAT_SCALABLECLASSICALORTHOPOLY1D_HH_
3 
4 /*!
5 // \file ScalableClassicalOrthoPoly1D.hh
6 //
7 // \brief Class for shifting and scaling classical continuous orthonormal
8 // polynomials
9 //
10 // Author: I. Volobouev
11 //
12 // October 2020
13 */
14 
16 
17 namespace npstat {
18  class ScalableOrthoPoly1DDeg;
19  class ScalableOrthoPoly1DWeight;
20 
22  {
23  public:
26 
28  long double location, long double scale);
29 
31  double location, double scale);
32 
35 
36  inline ScalableClassicalOrthoPoly1D* clone() const
37  {return new ScalableClassicalOrthoPoly1D(*this);}
38 
39  inline ~ScalableClassicalOrthoPoly1D() {delete poly_;}
40 
41  inline long double location() const {return location_;}
42  inline long double scale() const {return scale_;}
43 
44  // Note that the Jacobi matrix principal minor is returned
45  // for the unscaled OPS
46  inline Matrix<long double> jacobiMatrix(const unsigned n) const
47  {return poly_->jacobiMatrix(n);}
48 
49  inline void setLocation(const long double v) {location_ = v;}
50  inline void setScale(const long double v)
51  {
52  if (v <= 0.0) throw std::invalid_argument(
53  "In npstat::ScalableClassicalOrthoPoly1D::setScale: "
54  "scale parameter must be positive");
55  scale_ = v;
56  }
57 
58  inline long double weight(const long double x) const
59  {return poly_->weight((x - location_)/scale_)/scale_;}
60 
61  inline double xmin() const {return scale_*poly_->xmin() + location_;}
62 
63  inline double xmax() const {return scale_*poly_->xmax() + location_;}
64 
65  inline unsigned maxDegree() const {return poly_->maxDegree();}
66 
67  inline long double poly(const unsigned deg, const long double x) const
68  {return poly_->poly(deg, (x - location_)/scale_);}
69 
70  inline long double monic(const unsigned deg, const long double x) const
71  {return poly_->monic(deg, (x - location_)/scale_);}
72 
73  /**
74  // Values of two orthonormal polynomials.
75  // Faster than calling "poly" two times.
76  */
77  inline std::pair<long double,long double> twopoly(
78  const unsigned deg1, const unsigned deg2, const long double x) const
79  {return poly_->twopoly(deg1, deg2, (x - location_)/scale_);}
80 
81  /**
82  // Values of all orthonormal polynomials up to some degree.
83  // Faster than calling "poly" multiple times. The size of
84  // the "values" array should be at least maxdeg + 1.
85  */
86  inline void allpoly(const long double x,
87  long double* values, const unsigned maxdeg) const
88  {poly_->allpoly((x - location_)/scale_, values, maxdeg);}
89 
90  inline void allmonic(const long double x,
91  long double* values, const unsigned maxdeg) const
92  {poly_->allmonic((x - location_)/scale_, values, maxdeg);}
93 
94  inline double series(const double* coeffs, const unsigned maxdeg,
95  const double x) const
96  {return poly_->series(coeffs, maxdeg, (x - location_)/scale_);}
97 
98  inline double integrateSeries(const double* coeffs, const unsigned maxdeg) const
99  {return scale_*poly_->integrateSeries(coeffs, maxdeg);}
100 
101  /**
102  // Build the coefficients of the orthogonal polynomial series
103  // for the given function. The length of the array "coeffs"
104  // should be at least maxdeg + 1. Note that the coefficients
105  // are returned in the order of increasing degree (same order
106  // is used by the "series" function).
107  */
108  template <class Functor, class Quadrature>
109  void calculateCoeffs(const Functor& fcn, const Quadrature& quad,
110  double* coeffs, unsigned maxdeg) const;
111 
112  /**
113  // Build the coefficients of the orthogonal polynomial series
114  // for the given sample of points (empirical density function).
115  // The length of the array "coeffs" should be at least maxdeg + 1.
116  // Note that the coefficients are returned in the order of
117  // increasing degree (same order is used by the "series" function).
118  */
119  template <class Numeric>
120  inline void sampleCoeffs(const Numeric* coords, const unsigned long lenCoords,
121  double* coeffs, const unsigned maxdeg) const
122  {
123  const Numeric mu = static_cast<Numeric>(location_);
124  const Numeric s = static_cast<Numeric>(scale_);
125  poly_->sampleCoeffs(coords, lenCoords, mu, s, coeffs, maxdeg);
126  }
127 
128  template <class Numeric>
129  inline void sampleCoeffVars(const Numeric* coords, const unsigned long lenCoords,
130  const double* coeffs, const unsigned maxdeg,
131  double* variances) const
132  {
133  const Numeric mu = static_cast<Numeric>(location_);
134  const Numeric s = static_cast<Numeric>(scale_);
135  poly_->sampleCoeffVars(coords, lenCoords, mu, s, coeffs, maxdeg, variances);
136  }
137 
138  template <class Numeric>
140  sampleCoeffCovariance(const Numeric* coords, const unsigned long lenCoords,
141  const double* coeffs, const unsigned maxdeg) const
142  {
143  const Numeric mu = static_cast<Numeric>(location_);
144  const Numeric s = static_cast<Numeric>(scale_);
145  return poly_->sampleCoeffCovariance(coords, lenCoords, mu, s, coeffs, maxdeg);
146  }
147 
148  /**
149  // Build the coefficients of the orthogonal polynomial series for
150  // the given sample of weighted points (empirical density function).
151  // The first element of the pair will be treated as the coordinate
152  // and the second element will be treated as weight. Weights must
153  // not be negative. The length of the array "coeffs" should be
154  // at least maxdeg + 1. Note that the coefficients are returned
155  // in the order of increasing degree (same order is used by the
156  // "series" function).
157  */
158  template <class Pair>
159  inline void weightedSampleCoeffs(const Pair* points, const unsigned long numPoints,
160  double* coeffs, const unsigned maxdeg) const
161  {
162  typedef typename Pair::first_type Numeric;
163  const Numeric mu = static_cast<Numeric>(location_);
164  const Numeric s = static_cast<Numeric>(scale_);
165  return poly_->weightedSampleCoeffs(points, numPoints, mu, s, coeffs, maxdeg);
166  }
167 
168  template <class Pair>
169  inline void weightedSampleCoeffVars(const Pair* points, const unsigned long nPoints,
170  const double* coeffs, const unsigned maxdeg,
171  double* variances) const
172  {
173  typedef typename Pair::first_type Numeric;
174  const Numeric mu = static_cast<Numeric>(location_);
175  const Numeric s = static_cast<Numeric>(scale_);
176  return poly_->weightedSampleCoeffVars(points,nPoints,mu,s,coeffs,maxdeg,variances);
177  }
178 
179  template <class Pair>
181  weightedSampleCoeffCovariance(const Pair* points, const unsigned long nPoints,
182  const double* coeffs, const unsigned maxdeg) const
183  {
184  typedef typename Pair::first_type Numeric;
185  const Numeric mu = static_cast<Numeric>(location_);
186  const Numeric s = static_cast<Numeric>(scale_);
187  return poly_->weightedSampleCoeffCovariance(points, nPoints, mu, s, coeffs, maxdeg);
188  }
189 
190  /**
191  // Unweighted averages of the polynomial values for the given sample.
192  // The length of array "averages" should be at least maxdeg + 1.
193  */
194  template <class Numeric, typename Real>
195  void sampleAverages(const Numeric* coords, unsigned long lenCoords,
196  Real* averages, unsigned maxdeg) const;
197 
198  /**
199  // Averages of the polynomial values for the given sample of
200  // weighted points (not weighting by the polynomial weight function).
201  // The first element of the pair will be treated as the coordinate
202  // and the second element will be treated as weight. Weights must not
203  // be negative. The length of array "averages" should be at least
204  // maxdeg + 1.
205  */
206  template <class Pair, typename Real>
207  void weightedPointsAverages(const Pair* points, unsigned long numPoints,
208  Real* averages, unsigned maxdeg) const;
209 
210  /**
211  // Averages of the polynomial values weighted by an external
212  // weight function. The length of array "averages" should be
213  // at least maxdeg + 1.
214  */
215  template <class Functor, typename Real>
216  void extWeightAverages(const Functor& extWeight,
217  const AbsIntervalQuadrature1D& quad,
218  Real* averages, unsigned maxdeg) const;
219 
220  /**
221  // Pairwise products of the polynomial values weighted by
222  // an external weight function. The returned matrix will be
223  // symmetric and will have the dimensions (maxdeg + 1) x (maxdeg + 1).
224  */
225  template <class Functor>
226  Matrix<double> extWeightProductAverages(const Functor& extWeight,
227  const AbsIntervalQuadrature1D& quad, unsigned maxdeg) const;
228 
229  private:
231  long double location_;
232  long double scale_;
233 
234 #ifdef SWIG
235  public:
236  inline void setLocation2(const double v)
237  {setLocation(v);}
238 
239  inline void setScale2(const double v)
240  {setScale(v);}
241 
242  inline double location2() const
243  {return location();}
244 
245  inline double scale2() const
246  {return scale();}
247 
248  inline double weight2(const double x) const
249  {return weight(x);}
250 
251  inline double poly2(const unsigned deg, const double x) const
252  {return poly(deg, x);}
253 
254  inline double monic2(const unsigned deg, const double x) const
255  {return monic(deg, x);}
256 
257  inline std::pair<double,double> twopoly2(const unsigned deg1,
258  const unsigned deg2,
259  const double x) const
260  {
261  const std::pair<long double,long double>& p = twopoly(deg1, deg2, x);
262  return std::pair<double,double>(p.first, p.second);
263  }
264 
265  inline std::vector<double> allpoly2(const unsigned maxdeg, const double x) const
266  {
267  std::vector<long double> p(maxdeg+1);
268  allpoly(x, &p[0], p.size());
269  return std::vector<double>(p.begin(), p.end());
270  }
271 
272  inline std::vector<double> allmonic2(const unsigned maxdeg, const double x) const
273  {
274  std::vector<long double> p(maxdeg+1);
275  allmonic(x, &p[0], p.size());
276  return std::vector<double>(p.begin(), p.end());
277  }
278 #endif // SWIG
279  };
280 
281  /**
282  // A functor for the weight function of the given ortho poly system.
283  // The poly system is not copied, only a reference is used. It is
284  // a responsibility of the user to make sure that the lifetime of
285  // the poly system object exceeds the lifetime of the functor.
286  */
287  class ScalableOrthoPoly1DWeight : public Functor1<long double, long double>
288  {
289  public:
290  inline explicit ScalableOrthoPoly1DWeight(
291  const ScalableClassicalOrthoPoly1D& fcn,
292  const long double normfactor)
293  : fcn_(fcn), norm_(normfactor) {}
294 
295  // Separate constructor here because swig gets confused
296  // by long doubles with defaults
297  inline explicit ScalableOrthoPoly1DWeight(
298  const ScalableClassicalOrthoPoly1D& fcn)
299  : fcn_(fcn), norm_(1.0L) {}
300 
301  inline virtual ~ScalableOrthoPoly1DWeight() {}
302 
303  inline virtual long double operator()(const long double& a) const
304  {return norm_*fcn_.weight(a);}
305 
306  private:
308 
309  const ScalableClassicalOrthoPoly1D& fcn_;
310  long double norm_;
311  };
312 
313  /**
314  // A functor for a particular degree polynomial of the given ortho
315  // poly system. The poly system is not copied, only a reference is used.
316  // It is a responsibility of the user to make sure that the lifetime of
317  // the poly system object exceeds the lifetime of the functor.
318  */
319  class ScalableOrthoPoly1DDeg : public Functor1<long double, long double>
320  {
321  public:
323  const unsigned degree,
324  const long double normfactor=1.0L)
325  : fcn_(fcn), norm_(normfactor), deg_(degree)
326  {
327  if (deg_ > fcn_.maxDegree()) throw std::invalid_argument(
328  "In npstat::ScalableOrthoPoly1DDeg::constructor: "
329  "degree argument is out of range");
330  }
331 
332  inline virtual ~ScalableOrthoPoly1DDeg() {}
333 
334  inline virtual long double operator()(const long double& a) const
335  {return norm_*fcn_.poly(deg_, a);}
336 
337  private:
339 
340  const ScalableClassicalOrthoPoly1D& fcn_;
341  long double norm_;
342  unsigned deg_;
343  };
344 }
345 
346 #include "npstat/nm/ScalableClassicalOrthoPoly1D.icc"
347 
348 #endif // NPSTAT_SCALABLECLASSICALORTHOPOLY1D_HH_
Base class for classical continuous orthonormal polynomials.
Definition: AbsClassicalOrthoPoly1D.hh:32
Matrix< long double > jacobiMatrix(unsigned n) const
virtual double xmin() const =0
void allmonic(long double x, long double *values, unsigned maxdeg) const
void sampleCoeffs(const Numeric *coords, unsigned long lenCoords, double *coeffs, unsigned maxdeg) const
void weightedSampleCoeffs(const Pair *points, unsigned long numPoints, double *coeffs, unsigned maxdeg) const
Matrix< double > sampleCoeffCovariance(const Numeric *coords, unsigned long lenCoords, const double *coeffs, unsigned maxdeg) const
double integrateSeries(const double *coeffs, unsigned maxdeg) const
long double monic(unsigned deg, long double x) const
Matrix< double > weightedSampleCoeffCovariance(const Pair *points, unsigned long nPoints, const double *coeffs, unsigned maxdeg) const
void weightedSampleCoeffVars(const Pair *points, unsigned long nPoints, const double *coeffs, unsigned maxdeg, double *variances) const
void allpoly(long double x, long double *values, unsigned maxdeg) const
virtual long double weight(long double x) const =0
std::pair< long double, long double > twopoly(unsigned deg1, unsigned deg2, long double x) const
double series(const double *coeffs, unsigned maxdeg, double x) const
virtual unsigned maxDegree() const
Definition: AbsClassicalOrthoPoly1D.hh:52
long double poly(unsigned deg, long double x) const
void sampleCoeffVars(const Numeric *coords, unsigned long lenCoords, const double *coeffs, unsigned maxdeg, double *variances) const
Definition: AbsIntervalQuadrature1D.hh:19
Definition: ScalableClassicalOrthoPoly1D.hh:22
void sampleCoeffs(const Numeric *coords, const unsigned long lenCoords, double *coeffs, const unsigned maxdeg) const
Definition: ScalableClassicalOrthoPoly1D.hh:120
void sampleAverages(const Numeric *coords, unsigned long lenCoords, Real *averages, unsigned maxdeg) const
void calculateCoeffs(const Functor &fcn, const Quadrature &quad, double *coeffs, unsigned maxdeg) const
void weightedPointsAverages(const Pair *points, unsigned long numPoints, Real *averages, unsigned maxdeg) const
void allpoly(const long double x, long double *values, const unsigned maxdeg) const
Definition: ScalableClassicalOrthoPoly1D.hh:86
void extWeightAverages(const Functor &extWeight, const AbsIntervalQuadrature1D &quad, Real *averages, unsigned maxdeg) const
Matrix< double > extWeightProductAverages(const Functor &extWeight, const AbsIntervalQuadrature1D &quad, unsigned maxdeg) const
std::pair< long double, long double > twopoly(const unsigned deg1, const unsigned deg2, const long double x) const
Definition: ScalableClassicalOrthoPoly1D.hh:77
void weightedSampleCoeffs(const Pair *points, const unsigned long numPoints, double *coeffs, const unsigned maxdeg) const
Definition: ScalableClassicalOrthoPoly1D.hh:159
Definition: ScalableClassicalOrthoPoly1D.hh:320
Definition: ScalableClassicalOrthoPoly1D.hh:288
Definition: AbsArrayProjector.hh:14
Definition: SimpleFunctors.hh:58