Index: trunk/npstat/nm/FejerQuadrature.icc =================================================================== --- trunk/npstat/nm/FejerQuadrature.icc (revision 575) +++ trunk/npstat/nm/FejerQuadrature.icc (revision 576) @@ -1,51 +1,51 @@ #include #include namespace npstat { template inline long double FejerQuadrature::integrate( const Functor1& function, const long double left, const long double right) const { if (buf_.size() != npoints_) buf_.resize(npoints_); std::pair* results = &buf_[0]; const long double midpoint = (left + right)/2.0L; const long double unit = (right - left)/2.0L; FcnArg a; long double v; for (unsigned i=0; i(midpoint + unit*a_[i]); v = w_[i]*static_cast(function(a)); results[i].first = std::abs(v); results[i].second = v; } std::sort(buf_.begin(), buf_.end()); v = 0.0L; for (unsigned i=0; i inline std::vector > - FejerQuadrature::weightedChebyshevPoints( + FejerQuadrature::weightedIntegrationPoints( const Functor& weight, const long double left, const long double right) const { typedef std::pair DDPair; std::vector result; result.reserve(npoints_); const long double midpoint = (left + right)/2.0L; const long double unit = (right - left)/2.0L; for (unsigned i=0; i #include #include namespace npstat { template inline long double GaussLegendreQuadrature::integrate( const Functor1& function, const long double left, const long double right) const { if (buf_.size() != npoints_) buf_.resize(npoints_); std::pair* results = &buf_[0]; const unsigned halfpoints = npoints_/2; const long double midpoint = (left + right)/2.0L; const long double unit = (right - left)/2.0L; FcnArg a; long double v; for (unsigned i=0; i(midpoint + unit*a_[i]); v = w_[i]*static_cast(function(a)); results[2*i].first = std::abs(v); results[2*i].second = v; a = static_cast(midpoint - unit*a_[i]); v = w_[i]*static_cast(function(a)); results[2*i+1].first = std::abs(v); results[2*i+1].second = v; } std::sort(buf_.begin(), buf_.end()); v = 0.0L; for (unsigned i=0; i inline long double GaussLegendreQuadrature::integrate( const Functor1& function, const long double left, const long double right, const unsigned nsplit) const { if (!nsplit) throw std::invalid_argument( "In npstat::GaussLegendreQuadrature::integrate: " "number of subintervals must be positive"); const long double step = (right - left)/nsplit; long double acc = 0.0L; for (unsigned i=0; i + inline std::vector > + GaussLegendreQuadrature::weightedIntegrationPoints( + const Functor& weight, + const long double left, const long double right) const + { + typedef std::pair DDPair; + + std::vector result; + result.reserve(npoints_); + const unsigned halfpoints = npoints_/2; + const long double midpoint = (left + right)/2.0L; + const long double unit = (right - left)/2.0L; + for (unsigned i=0; i #include #include "npstat/nm/SimpleFunctors.hh" namespace npstat { /** // Fejer quadrature. Internally, operations are performed // in long double precision. */ class FejerQuadrature { public: explicit FejerQuadrature(unsigned npoints); /** Return the number of quadrature points */ inline unsigned npoints() const {return npoints_;} /** // The abscissae of the integration rule. // The buffer length should be at least npoints. */ void getAbscissae(long double* abscissae, unsigned len) const; /** // The weights of the integration rule. // The buffer length should be at least npoints. */ void getWeights(long double* weights, unsigned len) const; /** Perform the quadrature on [a, b] interval */ template long double integrate(const Functor1& fcn, long double a, long double b) const; /** - // Weighted integration points on the given interval, suitable - // for constructing orthogonal polynomials w.r.t. the given - // weight function (in particular, by ContOrthoPoly1D class). + // Weighted integration points (Chebyshev points in this case) + // on the given interval, suitable for constructing orthogonal + // polynomials w.r.t. the given weight function (in particular, + // by ContOrthoPoly1D class). Naturally, rule with "npoints" + // points must be able to calculate polynomial normalization + // integrals exactly. */ template - std::vector > weightedChebyshevPoints( + std::vector > weightedIntegrationPoints( const Functor& weight, long double a, long double b) const; /** // Minimum number of points which integrates a polynomial // with the given degree exactly */ static unsigned minimalExactRule(unsigned polyDegree); private: FejerQuadrature(); std::vector a_; std::vector w_; mutable std::vector > buf_; unsigned npoints_; #ifdef SWIG public: inline std::vector abscissae2() const { return std::vector(a_.begin(), a_.end()); } inline std::vector weights2() const { return std::vector(w_.begin(), w_.end()); } #endif }; } #include "npstat/nm/FejerQuadrature.icc" #endif // NPSTAT_FEJERQUADRATURE_HH_ Index: trunk/npstat/nm/GaussLegendreQuadrature.hh =================================================================== --- trunk/npstat/nm/GaussLegendreQuadrature.hh (revision 575) +++ trunk/npstat/nm/GaussLegendreQuadrature.hh (revision 576) @@ -1,104 +1,115 @@ #ifndef NPSTAT_GAUSSLEGENDREQUADRATURE_HH_ #define NPSTAT_GAUSSLEGENDREQUADRATURE_HH_ /*! // \file GaussLegendreQuadrature.hh // // \brief Gauss-Legendre quadratures in long double precision // // Author: I. Volobouev // // April 2010 */ #include #include #include "npstat/nm/SimpleFunctors.hh" namespace npstat { /** // Gauss-Legendre quadrature. Internally, operations are performed // in long double precision. */ class GaussLegendreQuadrature { public: /** // At the moment, the following numbers of points are supported: // 2, 4, 6, 8, 10, 12, 16, 32, 64, 100, 128, 256, 512, 1024. // // If an unsupported number of points is given in the // constructor, std::invalid_argument exception will be thrown. */ explicit GaussLegendreQuadrature(unsigned npoints); /** Return the number of quadrature points */ inline unsigned npoints() const {return npoints_;} /** // The abscissae are returned for positive points only, // so the buffer length should be at least npoints/2. */ void getAbscissae(long double* abscissae, unsigned len) const; /** // The weights are returned for positive points only, // so the buffer length should be at least npoints/2. */ void getWeights(long double* weights, unsigned len) const; - /** Perform the quadrature */ + /** Perform the quadrature on [a, b] interval */ template long double integrate(const Functor1& fcn, long double a, long double b) const; /** // This method splits the interval [a, b] into "nsplit" // subintervals of equal length, applies Gauss-Legendre // quadrature to each subinterval, and sums the results. */ template long double integrate(const Functor1& fcn, long double a, long double b, unsigned nsplit) const; + /** + // Weighted integration points on the given interval, suitable + // for constructing orthogonal polynomials w.r.t. the given + // weight function (in particular, by ContOrthoPoly1D class). + // Naturally, rule with "npoints" points must be able to calculate + // polynomial normalization integrals exactly. + */ + template + std::vector > weightedIntegrationPoints( + const Functor& weight, long double a, long double b) const; + /** Check if the rule with the given number of points is supported */ static bool isAllowed(unsigned npoints); /** The complete set of allowed rules, in the increasing order */ static std::vector allowedNPonts(); /** // Minimum number of points, among the supported rules, which // integrates a polynomial with the given degree exactly. // Returns 0 if the degree is out of range. */ static unsigned minimalExactRule(unsigned polyDegree); private: GaussLegendreQuadrature(); const long double* a_; const long double* w_; mutable std::vector > buf_; unsigned npoints_; #ifdef SWIG public: inline std::vector abscissae2() const { return std::vector(a_, a_+npoints_/2U); } inline std::vector weights2() const { return std::vector(w_, w_+npoints_/2U); } #endif }; } #include "npstat/nm/GaussLegendreQuadrature.icc" #endif // NPSTAT_GAUSSLEGENDREQUADRATURE_HH_ Index: trunk/tests/test_ContOrthoPoly1D.cc =================================================================== --- trunk/tests/test_ContOrthoPoly1D.cc (revision 575) +++ trunk/tests/test_ContOrthoPoly1D.cc (revision 576) @@ -1,206 +1,230 @@ #include "UnitTest++.h" #include "test_utils.hh" #include "npstat/nm/ContOrthoPoly1D.hh" #include "npstat/nm/ClassicalOrthoPolys1D.hh" #include "npstat/nm/FejerQuadrature.hh" #include "npstat/rng/MersenneTwister.hh" using namespace npstat; using namespace std; inline static int kdelta(const unsigned i, const unsigned j) { return i == j ? 1 : 0; } namespace { TEST(ContOrthoPoly1D_orthonormalization) { const double eps = 1.0e-15; const OrthoPolyMethod method[] = {OPOLY_STIELTJES, OPOLY_LANCZOS}; const unsigned nMethods = sizeof(method)/sizeof(method[0]); const unsigned npoints = 64; const unsigned maxdeg = 10; const unsigned ntries = 10; std::vector points(2U*npoints); std::vector measure; measure.reserve(npoints); std::vector coeffs(maxdeg + 1); MersenneTwister rng; for (unsigned imeth=0; imeth(kdelta(i, j)), d, eps); } measure.clear(); for (unsigned i=0; i(kdelta(i, 0)), coeffs[i], eps); } } TEST(ContOrthoPoly1D_weightCoeffs) { const double eps = 1.0e-7; const unsigned maxdeg = 10; const unsigned ntries = 10; const unsigned npoints = maxdeg + 1U; std::vector points(2U*npoints); std::vector measure; measure.reserve(npoints); std::vector coeffs(maxdeg + 1); MersenneTwister rng; for (unsigned itry=0; itry points(npoints); for (unsigned itry=0; itry points(npoints); for (unsigned itry=0; itry