Index: trunk/npstat/nm/AbsClassicalOrthoPoly1D.hh =================================================================== --- trunk/npstat/nm/AbsClassicalOrthoPoly1D.hh (revision 907) +++ trunk/npstat/nm/AbsClassicalOrthoPoly1D.hh (revision 908) @@ -1,630 +1,630 @@ #ifndef NPSTAT_ABSCLASSICALORTHOPOLY1D_HH_ #define NPSTAT_ABSCLASSICALORTHOPOLY1D_HH_ /*! // \file AbsClassicalOrthoPoly1D.hh // // \brief Base class for classical continuous orthonormal polynomials // // Author: I. Volobouev // // May 2017 */ #include #include #include #include #include #include "geners/CPP11_auto_ptr.hh" #include "npstat/nm/Matrix.hh" #include "npstat/nm/SimpleFunctors.hh" #include "npstat/nm/AbsIntervalQuadrature1D.hh" namespace npstat { class StorablePolySeries1D; class OrthoPoly1DDeg; class OrthoPoly1DWeight; class AbsClassicalOrthoPoly1D { public: typedef OrthoPoly1DDeg degree_functor; typedef OrthoPoly1DWeight weight_functor; inline virtual ~AbsClassicalOrthoPoly1D() {} /** Virtual copy constructor */ virtual AbsClassicalOrthoPoly1D* clone() const = 0; /** The weight function should be normalized */ virtual long double weight(long double x) const = 0; //@{ /** Support of the polynomial */ virtual double xmin() const = 0; virtual double xmax() const = 0; //@} /** Maximum polynomial degree supported */ inline virtual unsigned maxDegree() const {return UINT_MAX - 1U;} /** // Generate principal minor of order n of the Jacobi matrix. // n must not exceed the output of "maxDegree()" method. */ Matrix jacobiMatrix(unsigned n) const; /** Polynomial values */ long double poly(unsigned deg, long double x) const; /** // Values of two orthonormal polynomials. // Faster than calling "poly" two times. */ std::pair twopoly( unsigned deg1, unsigned deg2, long double x) const; /** // Values of all orthonormal polynomials up to some degree. // Faster than calling "poly" multiple times. The size of // the "values" array should be at least maxdeg + 1. */ void allpoly(long double x, long double* values, unsigned maxdeg) const; /** Polynomial series */ double series(const double* coeffs, unsigned maxdeg, double x) const; /** Integral of the series from xmin() to xmax() */ double integrateSeries(const double* coeffs, unsigned maxdeg) const; /** // Build the coefficients of the orthogonal polynomial series // for the given function. The length of the array "coeffs" // should be at least maxdeg + 1. Note that the coefficients // are returned in the order of increasing degree (same order // is used by the "series" function). */ template void calculateCoeffs(const Functor& fcn, const Quadrature& quad, double* coeffs, unsigned maxdeg) const; /** // Build the coefficients of the orthogonal polynomial series // for the given sample of points (empirical density function). // The length of the array "coeffs" should be at least maxdeg + 1. // Note that the coefficients are returned in the order of // increasing degree (same order is used by the "series" function). */ template void sampleCoeffs(const Numeric* coords, unsigned long lenCoords, double* coeffs, unsigned maxdeg) const; /** // Estimate the variances of the coefficients returned by // the "sampleCoeffs" function. The "coeffs" array should be // at least maxdeg + 1 elements long and should be filled // by a previous call to "sampleCoeffs". The "variances" array // should have at least maxdeg + 1 elements. It will contain // the respective variances upon return. */ template void sampleCoeffVars(const Numeric* coords, unsigned long lenCoords, const double* coeffs, unsigned maxdeg, double* variances) const; /** // Estimate the covariances of the coefficients returned by // the "sampleCoeffs" function. The "coeffs" array should be // at least maxdeg + 1 elements long and should be filled // by a previous call to "sampleCoeffs". The returned matrix // will be dimensioned (maxdeg + 1) x (maxdeg + 1). */ template npstat::Matrix sampleCoeffCovariance(const Numeric* coords, unsigned long lenCoords, const double* coeffs, unsigned maxdeg) const; /** // Build the coefficients of the orthogonal polynomial series // for the given sample of points (empirical density function). // The length of the array "coeffs" should be at least maxdeg + 1. // Note that the coefficients are returned in the order of // increasing degree (same order is used by the "series" function). // Before calculating the coefficients, the coordinates are shifted // and scaled according to x_new = (x_original - location)/scale. // The resulting coefficients are also divided by scale. */ template void sampleCoeffs(const Numeric* coords, unsigned long lenCoords, Numeric location, Numeric scale, double* coeffs, unsigned maxdeg) const; /** // Estimate the variances of the coefficients returned by // the "sampleCoeffs" function. The "coeffs" array should be // at least maxdeg + 1 elements long and should be filled // by a previous call to "sampleCoeffs" with the same location // and scale. The "variances" array should have at least maxdeg + 1 // elements. It will contain the respective variances upon return. */ template void sampleCoeffVars(const Numeric* coords, unsigned long lenCoords, Numeric location, Numeric scale, const double* coeffs, unsigned maxdeg, double* variances) const; /** // Estimate the covariances of the coefficients returned by // the "sampleCoeffs" function. The "coeffs" array should be // at least maxdeg + 1 elements long and should be filled // by a previous call to "sampleCoeffs" with the same location // and scale. The returned matrix will be dimensioned // (maxdeg + 1) x (maxdeg + 1). */ template npstat::Matrix sampleCoeffCovariance(const Numeric* coords, unsigned long lenCoords, Numeric location, Numeric scale, const double* coeffs, unsigned maxdeg) const; /** // Build the coefficients of the orthogonal polynomial series for // the given sample of weighted points (empirical density function). // The first element of the pair will be treated as the coordinate // and the second element will be treated as weight. Weights must // not be negative. The length of the array "coeffs" should be // at least maxdeg + 1. Note that the coefficients are returned // in the order of increasing degree (same order is used by the // "series" function). */ template void weightedSampleCoeffs(const Pair* points, unsigned long numPoints, double* coeffs, unsigned maxdeg) const; /** // Estimate the variances of the coefficients returned by the // "weightedSampleCoeffs" function. The "coeffs" array should // be at least maxdeg + 1 elements long and should be filled // by a previous call to "weightedSampleCoeffs". The "variances" // array should have at least maxdeg + 1 elements. It will contain // the respective variances upon return. This code assumes that // weights and coordinates are statistically independent from // each other. */ template void weightedSampleCoeffVars(const Pair* points, unsigned long nPoints, const double* coeffs, unsigned maxdeg, double* variances) const; /** // Estimate the covariances of the coefficients returned by the // "weightedSampleCoeffs" function. The "coeffs" array should // be at least maxdeg + 1 elements long and should be filled // by a previous call to "weightedSampleCoeffs". The returned // matrix will be dimensioned (maxdeg + 1) x (maxdeg + 1). This // code assumes that weights and coordinates are statistically // independent from each other. */ template npstat::Matrix weightedSampleCoeffCovariance(const Pair* points, unsigned long nPoints, const double* coeffs, unsigned maxdeg) const; /** // Build the coefficients of the orthogonal polynomial series for // the given sample of weighted points (empirical density function). // The first element of the pair will be treated as the coordinate // and the second element will be treated as weight. Weights must // not be negative. The length of the array "coeffs" should be // at least maxdeg + 1. Note that the coefficients are returned // in the order of increasing degree (same order is used by the // "series" function). Before calculating the coefficients, the // coordinates are shifted and scaled according to // x_new = (x_original - location)/scale. The resulting coefficients // are also divided by scale. */ template void weightedSampleCoeffs(const Pair* points, unsigned long numPoints, typename Pair::first_type location, typename Pair::first_type scale, double* coeffs, unsigned maxdeg) const; /** // Estimate the variances of the coefficients returned by the // "weightedSampleCoeffs" function. The "coeffs" array should // be at least maxdeg + 1 elements long and should be filled // by a previous call to "weightedSampleCoeffs" with the same // location and scale. The "variances" array should have at least // maxdeg + 1 elements. It will contain the respective variances // upon return. This code assumes that weights and coordinates // are statistically independent from each other. */ template void weightedSampleCoeffVars(const Pair* points, unsigned long nPoints, typename Pair::first_type location, typename Pair::first_type scale, const double* coeffs, unsigned maxdeg, double* variances) const; /** // Estimate the covariances of the coefficients returned by the // "weightedSampleCoeffs" function. The "coeffs" array should // be at least maxdeg + 1 elements long and should be filled // by a previous call to "weightedSampleCoeffs" with the same // location and scale. The returned matrix will be dimensioned // (maxdeg + 1) x (maxdeg + 1). This code assumes that weights // and coordinates are statistically independent from each other. */ template npstat::Matrix weightedSampleCoeffCovariance(const Pair* points, unsigned long nPoints, typename Pair::first_type location, typename Pair::first_type scale, const double* coeffs, unsigned maxdeg) const; /** // This method is useful for testing the numerical precision // of the orthonormalization procedure. It returns the scalar // products between various polynomials. */ template double empiricalKroneckerDelta(const Quadrature& quad, unsigned deg1, unsigned deg2) const; /** // A measure-weighted average of a product of four orthonormal // poly values */ template double jointAverage(const Quadrature& q, unsigned deg1, unsigned deg2, unsigned deg3, unsigned deg4) const; /** // A measure-weighted average of a product of multiple orthonormal // poly values. "checkedForZeros" argument should be set to "true" // if we are sure that there are no zero elements in the "degrees" // array. */ template double jointAverage(const Quadrature& q, const unsigned* degrees, unsigned nDegrees, bool checkedForZeros = false) const; /** // Direct unweighted integration of of a product of four orthonormal // poly values. The integration function should support the "integrate" // method without limits. Intended for use with GaussHermiteQuadrature // and such. */ template double directQuadrature(const Quadrature& q, unsigned deg1, unsigned deg2, unsigned deg3, unsigned deg4) const; /** // Direct unweighted integration of of a product of multiple orthonormal // poly values. The integration function should support the "integrate" // method without limits. Intended for use with GaussHermiteQuadrature // and such. "checkedForZeros" argument should be set to "true" if we are // sure that there are no zero elements in the "degrees" array. */ template double directQuadrature(const Quadrature& q, const unsigned* degrees, unsigned nDegrees, bool checkedForZeros = false) const; /** // An unweighted integral of the orthonormal polynomial with the // given degree to some power. For this method, it is assumed // that the polynomials are supported on a closed interval (without // such an assumption unweighted integrals do not make much sense) // and that Gauss-Legendre quadratures can be used. */ double integratePoly(unsigned degree, unsigned power) const; /** // An unweighted integral of a product of multiple orthonormal // polynomials. For this method, it is assumed that the polynomials // are supported on a closed interval (without such an assumption // unweighted integrals do not make much sense) and that Gauss-Legendre // quadratures can be used. */ double jointIntegral(const unsigned* degrees, unsigned nDegrees) const; /** // Unweighted averages of the polynomial values for the given sample. // The length of array "averages" should be at least maxdeg + 1. */ template void sampleAverages(const Numeric* coords, unsigned long lenCoords, double* averages, unsigned maxdeg) const; /** // Averages of the polynomial values for the given sample of // weighted points (not weighting by the polynomial weight function). // The first element of the pair will be treated as the coordinate // and the second element will be treated as weight. Weights must not // be negative. The length of array "averages" should be at least // maxdeg + 1. */ template void weightedPointsAverages(const Pair* points, unsigned long numPoints, double* averages, unsigned maxdeg) const; /** // Averages of the polynomial values weighted by an external // weight function. The length of array "averages" should be // at least maxdeg + 1. */ template void extWeightAverages(const Functor& extWeight, const AbsIntervalQuadrature1D& quad, double* averages, unsigned maxdeg) const; /** // Unweighted averages of the pairwise products of the polynomial // values for the given sample. The returned matrix will be symmetric // and will have the dimensions (maxdeg + 1) x (maxdeg + 1). */ template Matrix sampleProductAverages(const Numeric* coords, unsigned long lenCoords, unsigned maxdeg) const; /** // Pairwise products of the polynomial values weighted by // an external weight function. The returned matrix will be // symmetric and will have the dimensions (maxdeg + 1) x (maxdeg + 1). */ template Matrix extWeightProductAverages(const Functor& extWeight, const AbsIntervalQuadrature1D& quad, unsigned maxdeg) const; /** // Unweighted average of a product of polynomial values for the // given sample. "degrees" is the collection of polynomial degrees. // Polynomials of these degrees will be included in the product. */ template double jointSampleAverage(const Numeric* coords, unsigned long lenCoords, const unsigned* degrees, unsigned lenDegrees) const; // Similar to the previous method but calculates two averages // simultaneously template std::pair twoJointSampleAverages( const Numeric* coords, unsigned long lenCoords, const unsigned* degrees1, unsigned lenDegrees1, const unsigned* degrees2, unsigned lenDegrees2) const; CPP11_auto_ptr makeStorablePolySeries( unsigned maxPolyDeg, const double *coeffs=0, unsigned maxdeg=0, double shift=0.0) const; // Functions needed for compatibility with certain template codes inline long double location() const {return 0.0;} inline long double scale() const {return 1.0;} protected: inline static int kdelta(const unsigned i, const unsigned j) {return i == j ? 1 : 0;} // Recurrence relationship function should return alpha // as the first element of the pair and the square root // of beta as the second virtual std::pair recurrenceCoeffs(unsigned deg) const = 0; - private: // Helper classes class ProdFcn : public Functor1 { public: inline ProdFcn(const AbsClassicalOrthoPoly1D& p, const unsigned d1, const unsigned d2) : poly(p), deg1(d1), deg2(d2) {} inline virtual ~ProdFcn() {} inline long double operator()(const long double& x) const { const std::pair& p = poly.twopoly(deg1, deg2, x); return p.first*p.second*poly.weight(x); } private: const AbsClassicalOrthoPoly1D& poly; unsigned deg1; unsigned deg2; }; class MultiProdFcn; friend class MultiProdFcn; class MultiProdFcn : public Functor1 { public: inline MultiProdFcn(const AbsClassicalOrthoPoly1D& p, const unsigned* degrees, unsigned lenDegrees, const bool includeWeight=true) : poly(p), degs(degrees, degrees+lenDegrees), maxdeg(0), weighted(includeWeight) { if (lenDegrees) maxdeg = *std::max_element(degrees, degrees+lenDegrees); } inline virtual ~MultiProdFcn() {} inline long double operator()(const long double& x) const { long double w = 1.0L, p = 1.0L; if (weighted) w = poly.weight(x); if (maxdeg) p = poly.normpolyprod(°s[0], degs.size(), maxdeg, x); return w*p; } private: const AbsClassicalOrthoPoly1D& poly; std::vector degs; unsigned maxdeg; bool weighted; }; + private: // For calling the function below, maxdeg should be calculated as // *std::max_element(degrees, degrees+nDegrees) long double normpolyprod(const unsigned* degrees, unsigned nDegrees, unsigned maxdeg, long double x) const; #ifdef SWIG public: inline double weight2(const double x) const {return weight(x);} inline double poly2(const unsigned deg, const double x) const {return poly(deg, x);} inline std::pair twopoly2(const unsigned deg1, const unsigned deg2, const double x) const { const std::pair& p = twopoly(deg1, deg2, x); return std::pair(p.first, p.second); } inline std::vector allpoly2(const unsigned maxdeg, const double x) const { std::vector p(maxdeg+1); allpoly(x, &p[0], p.size()); return std::vector(p.begin(), p.end()); } inline StorablePolySeries1D* makeStorablePolySeries_2( unsigned maxPolyDeg, const std::vector& coeffs, double shift=0.0) const { CPP11_auto_ptr ptr; if (coeffs.empty()) ptr = this->makeStorablePolySeries(maxPolyDeg, 0, 0, shift); else ptr = this->makeStorablePolySeries(maxPolyDeg, &coeffs[0], coeffs.size() - 1, shift); return ptr.release(); } inline Matrix jacobiMatrix_2(const unsigned n) const {return jacobiMatrix(n);} inline double location2() const {return location();} inline double scale2() const {return scale();} #endif // SWIG }; /** // A functor for the weight function of the given ortho poly system. // The poly system is not copied, only a reference is used. It is // a responsibility of the user to make sure that the lifetime of // the poly system object exceeds the lifetime of the functor. */ class OrthoPoly1DWeight : public Functor1 { public: inline OrthoPoly1DWeight(const AbsClassicalOrthoPoly1D& fcn, const long double normfactor) : fcn_(fcn), norm_(normfactor) {} // Separate constructor here because swig gets confused // by long doubles with defaults inline explicit OrthoPoly1DWeight(const AbsClassicalOrthoPoly1D& fcn) : fcn_(fcn), norm_(1.0L) {} inline virtual ~OrthoPoly1DWeight() {} inline virtual long double operator()(const long double& a) const {return norm_*fcn_.weight(a);} private: OrthoPoly1DWeight(); const AbsClassicalOrthoPoly1D& fcn_; long double norm_; }; /** // A functor for a particular degree polynomial of the given ortho // poly system. The poly system is not copied, only a reference is used. // It is a responsibility of the user to make sure that the lifetime of // the poly system object exceeds the lifetime of the functor. */ class OrthoPoly1DDeg : public Functor1 { public: inline OrthoPoly1DDeg(const AbsClassicalOrthoPoly1D& fcn, const unsigned degree, const long double normfactor) : fcn_(fcn), norm_(normfactor), deg_(degree) { if (deg_ > fcn_.maxDegree()) throw std::invalid_argument( "In npstat::OrthoPoly1DDeg::constructor: " "degree argument is out of range"); } // Separate constructor here because swig gets confused // by long doubles with defaults inline OrthoPoly1DDeg(const AbsClassicalOrthoPoly1D& fcn, const unsigned degree) : fcn_(fcn), norm_(1.0L), deg_(degree) { if (deg_ > fcn_.maxDegree()) throw std::invalid_argument( "In npstat::OrthoPoly1DDeg::constructor: " "degree argument is out of range"); } inline virtual ~OrthoPoly1DDeg() {} inline virtual long double operator()(const long double& a) const {return norm_*fcn_.poly(deg_, a);} private: OrthoPoly1DDeg(); const AbsClassicalOrthoPoly1D& fcn_; long double norm_; unsigned deg_; }; class UnweightedTwoPolyProd : public Functor1 { public: inline UnweightedTwoPolyProd(const AbsClassicalOrthoPoly1D& fcn, const unsigned deg1, const unsigned deg2) : fcn_(fcn), degree1_(deg1), degree2_(deg2) {} inline virtual ~UnweightedTwoPolyProd() {} inline virtual long double operator()(const long double& a) const { std::pair p = fcn_.twopoly( degree1_, degree2_, a); return p.first * p.second; } private: const AbsClassicalOrthoPoly1D& fcn_; unsigned degree1_; unsigned degree2_; }; } #include "npstat/nm/AbsClassicalOrthoPoly1D.icc" #endif // NPSTAT_ABSCLASSICALORTHOPOLY1D_HH_ Index: trunk/npstat/nm/AbsClassicalOrthoPoly1D.icc =================================================================== --- trunk/npstat/nm/AbsClassicalOrthoPoly1D.icc (revision 907) +++ trunk/npstat/nm/AbsClassicalOrthoPoly1D.icc (revision 908) @@ -1,691 +1,691 @@ #include #include #include #include #include "npstat/nm/polyPrivateUtils.hh" namespace npstat { namespace Private { template class ClassOrthoPolyHlp : public Functor1 { public: inline ClassOrthoPolyHlp(const SomePoly1D& p, const Functor& f, const unsigned d1) : poly(p), fcn(f), deg(d1) {} inline long double operator()(const long double& x) const {return fcn(x)*poly.poly(deg, x)*poly.weight(x);} private: const SomePoly1D& poly; const Functor& fcn; unsigned deg; }; } template void AbsClassicalOrthoPoly1D::calculateCoeffs( const Functor& fcn, const Quadrature& quad, double *coeffs, const unsigned maxdeg) const { assert(coeffs); const double a = xmin(); const double b = xmax(); for (unsigned i=0; i<=maxdeg; ++i) { Private::ClassOrthoPolyHlp func(*this, fcn, i); coeffs[i] = quad.integrate(func, a, b); } } template double AbsClassicalOrthoPoly1D::empiricalKroneckerDelta( const Quadrature& quad, const unsigned deg1, const unsigned deg2) const { - ProdFcn fcn(*this, deg1, deg2); + const ProdFcn fcn(*this, deg1, deg2); return quad.integrate(fcn, xmin(), xmax()); } template double AbsClassicalOrthoPoly1D::directQuadrature( const Quadrature& quad, const unsigned deg1, const unsigned deg2, const unsigned deg3, const unsigned deg4) const { unsigned degs[4]; unsigned nDegs = 0; if (deg1) degs[nDegs++] = deg1; if (deg2) degs[nDegs++] = deg2; if (deg3) degs[nDegs++] = deg3; if (deg4) degs[nDegs++] = deg4; return directQuadrature(quad, degs, nDegs, true); } template double AbsClassicalOrthoPoly1D::directQuadrature( const Quadrature& quad, const unsigned* degrees, const unsigned nDegrees, const bool checkedForZeros) const { if (nDegrees) { assert(degrees); if (!checkedForZeros) { bool allNonZero = true; for (unsigned ideg=0; ideg one(1.0); + const ConstValue1 one(1.0); return quad.integrate(one); } } template double AbsClassicalOrthoPoly1D::jointAverage( const Quadrature& quad, const unsigned deg1, const unsigned deg2, const unsigned deg3, const unsigned deg4) const { unsigned degs[4]; unsigned nDegs = 0; if (deg1) degs[nDegs++] = deg1; if (deg2) degs[nDegs++] = deg2; if (deg3) degs[nDegs++] = deg3; if (deg4) degs[nDegs++] = deg4; return jointAverage(quad, degs, nDegs, true); } template double AbsClassicalOrthoPoly1D::jointAverage( const Quadrature& quad, const unsigned* degrees, const unsigned nDegrees, const bool checkedForZeros) const { if (nDegrees) { assert(degrees); if (nDegrees == 1U) return kdelta(degrees[0], 0U); if (nDegrees == 2U) return kdelta(degrees[0], degrees[1]); if (!checkedForZeros) { bool allNonZero = true; for (unsigned ideg=0; ideg Matrix AbsClassicalOrthoPoly1D::sampleProductAverages( const Numeric* coords, const unsigned long lenCoords, const unsigned maxdeg) const { if (!lenCoords) throw std::invalid_argument( "In npstat::AbsClassicalOrthoPoly1D::sampleProductAverages:" " empty sample"); assert(coords); const unsigned long nsums = (maxdeg + 1)*(unsigned long)(maxdeg + 2)/2; std::vector membuf(nsums + (maxdeg + 1U), 0.0L); long double* poly = &membuf[0]; long double* sums = poly + (maxdeg + 1U); for (unsigned long i=0; i mat(maxdeg + 1U, maxdeg + 1U); unsigned long isum = 0; for (unsigned k=0; k<=maxdeg; ++k) for (unsigned j=0; j<=k; ++j, ++isum) { const double v = sums[isum]/lenCoords; mat[k][j] = v; if (j != k) mat[j][k] = v; } return mat; } template void AbsClassicalOrthoPoly1D::extWeightAverages( const Functor& fcn, const AbsIntervalQuadrature1D& quad, double* averages, const unsigned maxdeg) const { Private::extWeightAverages( *this, fcn, quad, maxdeg, xmin(), xmax(), averages); } template Matrix AbsClassicalOrthoPoly1D::extWeightProductAverages( const Functor& fcn, const AbsIntervalQuadrature1D& quad, const unsigned maxdeg) const { return Private::extWeightProductAverages( *this, fcn, quad, maxdeg, xmin(), xmax()); } template void AbsClassicalOrthoPoly1D::sampleAverages( const Numeric* coords, const unsigned long lenCoords, double *averages, const unsigned maxdeg) const { if (!lenCoords) throw std::invalid_argument( "In npstat::AbsClassicalOrthoPoly1D::sampleAverages: empty sample"); assert(coords); assert(averages); std::vector membuf(2U*(maxdeg + 1U), 0.0L); long double* poly = &membuf[0]; long double* sums = poly + (maxdeg + 1U); for (unsigned long i=0; i void AbsClassicalOrthoPoly1D::sampleCoeffs( const Numeric* coords, const unsigned long lenCoords, const Numeric location, const Numeric scale, double *coeffs, const unsigned maxdeg) const { if (!lenCoords) throw std::invalid_argument( "In npstat::AbsClassicalOrthoPoly1D::sampleCoeffs: empty sample"); assert(coords); assert(coeffs); const Numeric zero = Numeric(); if (scale == zero) throw std::invalid_argument( "In npstat::AbsClassicalOrthoPoly1D::sampleCoeffs: zero scale"); std::vector membuf(2U*(maxdeg + 1U), 0.0L); long double* poly = &membuf[0]; long double* sums = poly + (maxdeg + 1U); for (unsigned long i=0; i void AbsClassicalOrthoPoly1D::sampleCoeffVars( const Numeric* coords, const unsigned long lenCoords, const Numeric location, const Numeric scale, const double *coeffs, const unsigned maxdeg, double *variances) const { if (lenCoords < 2UL) throw std::invalid_argument( "In npstat::AbsClassicalOrthoPoly1D::sampleCoeffVars: " "insufficient sample size"); assert(coords); assert(coeffs); assert(variances); const Numeric zero = Numeric(); if (scale == zero) throw std::invalid_argument( "In npstat::AbsClassicalOrthoPoly1D::sampleCoeffVars: zero scale"); std::vector membuf(2U*(maxdeg + 1U), 0.0L); long double* poly = &membuf[0]; long double* sums = poly + (maxdeg + 1U); for (unsigned long i=0; i npstat::Matrix AbsClassicalOrthoPoly1D::sampleCoeffCovariance( const Numeric* coords, const unsigned long lenCoords, const Numeric location, const Numeric scale, const double *coeffs, const unsigned maxdeg) const { if (lenCoords < 2UL) throw std::invalid_argument( "In npstat::AbsClassicalOrthoPoly1D::sampleCoeffCovariance: " "insufficient sample size"); assert(coords); assert(coeffs); const Numeric zero = Numeric(); if (scale == zero) throw std::invalid_argument( "In npstat::AbsClassicalOrthoPoly1D::sampleCoeffCovariance: " "zero scale"); std::vector membuf(maxdeg + 1U, 0.0L); long double* poly = &membuf[0]; npstat::Matrix sums(maxdeg + 1U, maxdeg + 1U, 0); for (unsigned long i=0; i void AbsClassicalOrthoPoly1D::sampleCoeffs( const Numeric* coords, const unsigned long lenCoords, double *coeffs, const unsigned maxdeg) const { const Numeric zero = Numeric(); const Numeric one = static_cast(1); sampleCoeffs(coords, lenCoords, zero, one, coeffs, maxdeg); } template void AbsClassicalOrthoPoly1D::sampleCoeffVars( const Numeric* coords, const unsigned long lenCoords, const double *coeffs, const unsigned maxdeg, double *variances) const { const Numeric zero = Numeric(); const Numeric one = static_cast(1); sampleCoeffVars(coords, lenCoords, zero, one, coeffs, maxdeg, variances); } template npstat::Matrix AbsClassicalOrthoPoly1D::sampleCoeffCovariance( const Numeric* coords, unsigned long lenCoords, const double* coeffs, unsigned maxdeg) const { const Numeric zero = Numeric(); const Numeric one = static_cast(1); return sampleCoeffCovariance(coords, lenCoords, zero, one, coeffs, maxdeg); } template void AbsClassicalOrthoPoly1D::weightedSampleCoeffs( const Pair* points, const unsigned long numPoints, const typename Pair::first_type location, const typename Pair::first_type scale, double *coeffs, const unsigned maxdeg) const { typedef typename Pair::first_type Numeric; if (!numPoints) throw std::invalid_argument( "In npstat::AbsClassicalOrthoPoly1D::weightedSampleCoeffs: " "empty sample"); assert(points); assert(coeffs); const Numeric zero = Numeric(); if (scale == zero) throw std::invalid_argument( "In npstat::AbsClassicalOrthoPoly1D::weightedSampleCoeffs: " "zero scale"); std::vector membuf(2U*(maxdeg + 1U), 0.0L); long double* poly = &membuf[0]; long double* sums = poly + (maxdeg + 1U); long double wsum = 0.0L; for (unsigned long i=0; i void AbsClassicalOrthoPoly1D::weightedPointsAverages( const Pair* points, const unsigned long numPoints, double *averages, const unsigned maxdeg) const { if (!numPoints) throw std::invalid_argument( "In npstat::AbsClassicalOrthoPoly1D::weightedPointsAverages: " "empty sample"); assert(points); assert(averages); std::vector membuf(2U*(maxdeg + 1U), 0.0L); long double* poly = &membuf[0]; long double* sums = poly + (maxdeg + 1U); long double wsum = 0.0L; for (unsigned long i=0; i void AbsClassicalOrthoPoly1D::weightedSampleCoeffVars( const Pair* points, const unsigned long numPoints, typename Pair::first_type location, typename Pair::first_type scale, const double *coeffs, const unsigned maxdeg, double *variances) const { typedef typename Pair::first_type Numeric; if (numPoints < 2UL) throw std::invalid_argument( "In npstat::AbsClassicalOrthoPoly1D::weightedSampleCoeffVars: " "insufficient sample size"); assert(points); assert(coeffs); assert(variances); const Numeric zero = Numeric(); if (scale == zero) throw std::invalid_argument( "In npstat::AbsClassicalOrthoPoly1D::weightedSampleCoeffVars: " "zero scale"); std::vector membuf(2U*(maxdeg + 1U), 0.0L); long double* poly = &membuf[0]; long double* sums = poly + (maxdeg + 1U); long double wsum = 0.0L, wsqsum = 0.0L; for (unsigned long i=0; i npstat::Matrix AbsClassicalOrthoPoly1D::weightedSampleCoeffCovariance( const Pair* points, const unsigned long numPoints, typename Pair::first_type location, typename Pair::first_type scale, const double *coeffs, const unsigned maxdeg) const { typedef typename Pair::first_type Numeric; if (numPoints < 2UL) throw std::invalid_argument( "In npstat::AbsClassicalOrthoPoly1D::weightedSampleCoeffCovariance: " "insufficient sample size"); assert(points); assert(coeffs); const Numeric zero = Numeric(); if (scale == zero) throw std::invalid_argument( "In npstat::AbsClassicalOrthoPoly1D::weightedSampleCoeffCovariance: " "zero scale"); std::vector membuf(maxdeg + 1U, 0.0L); long double* poly = &membuf[0]; npstat::Matrix sums(maxdeg + 1U, maxdeg + 1U, 0); long double wsum = 0.0L, wsqsum = 0.0L; for (unsigned long i=0; i void AbsClassicalOrthoPoly1D::weightedSampleCoeffs( const Pair* points, const unsigned long numPoints, double *coeffs, const unsigned maxdeg) const { typedef typename Pair::first_type Numeric; const Numeric zero = Numeric(); const Numeric one = static_cast(1); weightedSampleCoeffs(points, numPoints, zero, one, coeffs, maxdeg); } template void AbsClassicalOrthoPoly1D::weightedSampleCoeffVars( const Pair* points, const unsigned long nPoints, const double *coeffs, const unsigned maxdeg, double *variances) const { typedef typename Pair::first_type Numeric; const Numeric zero = Numeric(); const Numeric one = static_cast(1); weightedSampleCoeffVars(points, nPoints, zero, one, coeffs, maxdeg, variances); } template npstat::Matrix AbsClassicalOrthoPoly1D::weightedSampleCoeffCovariance( const Pair* points, unsigned long nPoints, const double* coeffs, unsigned maxdeg) const { typedef typename Pair::first_type Numeric; const Numeric zero = Numeric(); const Numeric one = static_cast(1); return weightedSampleCoeffCovariance(points, nPoints, zero, one, coeffs, maxdeg); } template double AbsClassicalOrthoPoly1D::jointSampleAverage( const Numeric* coords, const unsigned long lenCoords, const unsigned* degrees, const unsigned lenDegrees) const { if (!lenCoords) throw std::invalid_argument( "In npstat::AbsClassicalOrthoPoly1D::jointSampleAverage: " "empty sample"); assert(coords); if (lenDegrees) { assert(degrees); const unsigned maxdeg = *std::max_element(degrees, degrees+lenDegrees); std::vector membuf(maxdeg + 1U, 0.0L); long double* poly = &membuf[0]; long double sum = 0.0L; for (unsigned long i=0; i std::pair AbsClassicalOrthoPoly1D::twoJointSampleAverages( const Numeric* coords, const unsigned long lenCoords, const unsigned* degrees1, const unsigned lenDegrees1, const unsigned* degrees2, const unsigned lenDegrees2) const { if (!lenCoords) throw std::invalid_argument( "In npstat::AbsClassicalOrthoPoly1D::twoJointSampleAverages: empty sample"); assert(coords); unsigned maxdeg1 = 0, maxdeg2 = 0; if (lenDegrees1) { assert(degrees1); maxdeg1 = *std::max_element(degrees1, degrees1+lenDegrees1); } if (lenDegrees2) { assert(degrees2); maxdeg2 = *std::max_element(degrees2, degrees2+lenDegrees2); } const unsigned maxdeg = std::max(maxdeg1, maxdeg2); if (lenDegrees1 || lenDegrees2) { std::vector membuf(maxdeg + 1U, 0.0L); long double* poly = &membuf[0]; long double sum1 = 0.0L, sum2 = 0.0L; for (unsigned long i=0; i(sum1/lenCoords, sum2/lenCoords); } else return std::pair(1.0, 1.0); } }