Page Menu
Home
HEPForge
Search
Configure Global Search
Log In
Files
F9501593
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
28 KB
Subscribers
None
View Options
Index: trunk/npstat/nm/ContOrthoPoly1D.hh
===================================================================
--- trunk/npstat/nm/ContOrthoPoly1D.hh (revision 720)
+++ trunk/npstat/nm/ContOrthoPoly1D.hh (revision 721)
@@ -1,632 +1,640 @@
#ifndef NPSTAT_CONTORTHOPOLY1D_HH_
#define NPSTAT_CONTORTHOPOLY1D_HH_
/*!
// \file ContOrthoPoly1D.hh
//
// \brief Continuous orthogonal polynomial series in one dimension
// generated for a discrete measure
//
// Author: I. Volobouev
//
// May 2017
*/
#include <vector>
#include <utility>
#include <cassert>
#include <cmath>
#include <map>
#include "geners/CPP11_auto_ptr.hh"
#include "npstat/nm/OrthoPolyMethod.hh"
#include "npstat/nm/Matrix.hh"
#include "npstat/nm/SimpleFunctors.hh"
#include "npstat/nm/PreciseType.hh"
#ifdef USE_LAPACK_QUAD
#include "npstat/nm/GaussLegendreQuadratureQ.hh"
#else
#include "npstat/nm/GaussLegendreQuadrature.hh"
#endif
namespace npstat {
class StorablePolySeries1D;
class ContOrthoPoly1D
{
public:
typedef PreciseType<double>::type precise_type;
// The first element of the pair is the coordinate and the
// second element is the weight (all weights must be non-negative)
typedef std::pair<double,double> MeasurePoint;
#ifdef USE_LAPACK_QUAD
typedef GaussLegendreQuadratureQ PreciseQuadrature;
#else
typedef GaussLegendreQuadrature PreciseQuadrature;
#endif
/**
// Main constructor, with obvious arguments. The first element
// of the measure pair is the coordinate and the second element
// is the weight (all weights must be non-negative). Internally,
// the measure will be sorted in the order of increasing weight
// and the measure coordinates will be shifted so that their
// weighted mean is at 0.
*/
template<typename Numeric1, typename Numeric2>
ContOrthoPoly1D(unsigned maxDegree,
const std::vector<std::pair<Numeric1,Numeric2> >& measure,
OrthoPolyMethod m = OPOLY_STIELTJES);
/** Constructor which assumes that all weights are 1.0 */
template<typename Numeric>
ContOrthoPoly1D(unsigned maxDegree,
const std::vector<Numeric>& coords,
OrthoPolyMethod m = OPOLY_STIELTJES);
//@{
/** A simple inspector of object properties */
inline unsigned maxDegree() const {return maxdeg_;}
inline unsigned long measureLength() const {return measure_.size();}
inline MeasurePoint measure(const unsigned index) const
{return measure_.at(index);}
inline double coordinate(const unsigned index) const
{return measure_.at(index).first;}
inline double weight(const unsigned index) const
{return measure_.at(index).second;}
inline precise_type sumOfWeights() const {return wsum_;}
inline precise_type sumOfWeightSquares() const {return wsumsq_;}
inline bool areAllWeightsEqual() const {return allWeightsEqual_;}
inline double minCoordinate() const {return minX_;}
inline double maxCoordinate() const {return maxX_;}
inline precise_type meanCoordinate() const {return meanX_;}
//@}
/** Kish's effective sample size for the measure */
double effectiveSampleSize() const;
/** Return the value of one of the normalized polynomials */
double poly(unsigned deg, double x) const;
/** Return the values of two of the normalized polynomials */
std::pair<double,double> polyPair(
unsigned deg1, unsigned deg2, double x) const;
/**
// Return the values of all orthonormal polynomials up to some
// maximum degree. Size of the "polyValues" array should be
// at least maxdeg + 1.
*/
template <typename Numeric>
inline void allPolys(const double x, const unsigned maxdeg,
Numeric* polyValues) const
{getAllPolys(x - meanX_, maxdeg, polyValues);}
/**
+ // Function added for interface compatibility with
+ // AbsClassicalOrthoPoly1D
+ */
+ inline void allpoly(const long double x, long double* values,
+ const unsigned maxdeg) const
+ {getAllPolys(x - meanX_, maxdeg, values);}
+
+ /**
// Average values of the polynomials for a sample of points.
// Size of the "averages" array should be at least maxdeg + 1.
// Note that the resulting averages are not weighted by the measure.
*/
template <typename Numeric>
void sampleAverages(const Numeric* coords, unsigned long lenCoords,
double* averages, unsigned maxdeg) const;
/**
// Average values of the pairwise polynomial products for
// a sample of points. The returned matrix will be symmetric
// and will have the dimensions (maxdeg + 1) x (maxdeg + 1).
// Note that the resulting averages are not weighted by the measure.
*/
template <typename Numeric>
Matrix<double> sampleProductAverages(const Numeric* coords,
unsigned long lenCoords,
unsigned maxdeg) const;
/** Return the value of the orthonormal polynomial series */
template <typename Numeric>
double series(const Numeric* coeffs, unsigned deg, double x) 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 <class Functor, typename Numeric>
void calculateCoeffs(const Functor& fcn,
Numeric* coeffs, unsigned maxdeg) const;
/**
// Build the coefficients of the orthogonal polynomial series
// for the given function in such a way that the integral of
// the truncated series on the [xmin, xmax] interval is constrained
// to "integralValue". 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). The construction minimizes the ISE weighted
// by the empirical density.
//
// The function returns the chi-square from the corresponding
// constrained least squares problem. This is the sum of
// (coeffs[i] - c[i])^2, 0 <= i <= maxdeg, where c[i] are
// determined by the "calculateCoeffs" method.
*/
template <class Functor>
double constrainedCoeffs(const Functor& fcn,
double *coeffs, unsigned maxdeg,
double xmin, double xmax,
double integralValue = 1.0) const;
/**
// Build the coefficients of the orthogonal polynomial series
// for the discrete weight values (that is, fcn(x_i) = w_i,
// using the terminology of the "calculateCoeffs" method). This
// can sometimes be useful for weighted measures. Of course,
// for unweighted measures this results in just delta_{deg,0}.
*/
void weightCoeffs(double *coeffs, unsigned maxdeg) const;
/**
// Integrated squared error between the given function and the
// polynomial series. Parameter "integrationRulePoints" specifies
// the parameter "npoints" for the GaussLegendreQuadrature class.
// If "integrationRulePoints" is 0, the rule will be picked
// automatically in such a way that it integrates a polynomial
// of degree maxdeg*2 exactly.
*/
template <class Functor>
double integratedSquaredError(const Functor& fcn,
const double *coeffs, unsigned maxdeg,
double xmin, double xmax,
unsigned integrationRulePoints=0U) const;
/**
// Squared error between the given function and the polynomial
// series, weighted according to the measure
*/
template <class Functor>
double weightedSquaredError(const Functor& fcn, 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.
*/
precise_type empiricalKroneckerDelta(unsigned deg1, unsigned deg2) const;
/**
// If the Kronecker deltas were calculated from a sample, they
// would be random and would have a covariance matrix. This
// is an estimate of the terms in that covariance matrix. The
// covariance is between delta_{deg1,deg2} and delta_{deg3,deg4}.
*/
double empiricalKroneckerCovariance(unsigned deg1, unsigned deg2,
unsigned deg3, unsigned deg4) const;
/**
// Examine the recurrence coefficients. The first element of
// the returned pair is alpha, and the second element is beta.
// Higher precision than double is used internally.
*/
std::pair<double,double> recurrenceCoeffs(unsigned deg) const;
/**
// Generate principal minor of order n of the Jacobi matrix.
// n must not exceed "maxDegree"
*/
Matrix<precise_type> jacobiMatrix(unsigned n) const;
/**
// Roots of the polynomial with the given degree. Naturally,
// the degree argument must not exceed "maxDegree".
*/
void calculateRoots(precise_type* roots, unsigned degree) const;
/**
// Integral of an orthonormal polynomials to some power without
// the weight (so this is not an inner product with the poly of
// degree 0).
*/
precise_type integratePoly(unsigned degree, unsigned power,
double xmin, double xmax) const;
/**
// Integral of the product of three orthonormal polynomials
// without the weight (so this is not an inner product)
*/
precise_type integrateTripleProduct(unsigned deg1, unsigned deg2,
unsigned deg3, double xmin,
double xmax) const;
/**
// Unweighted triple product integrals arranged in a matrix.
// The returned matrix will be dimensioned pairs.size() x (maxdeg+1).
*/
Matrix<precise_type> tripleProductMatrix(
const std::vector<std::pair<unsigned,unsigned> >& pairs,
unsigned maxdeg, double xmin, double xmax) const;
/**
// Integral of the product of two orthonormal polynomials
// with some external weight function (e.g., oracle density).
// "EW" in the method name stands for "externally weighted".
//
// "integrationRulePoints" argument will be passed to the
// GaussLegendreQuadrature constructor and must be supported
// by that class.
*/
template <class Functor>
double integrateEWPolyProduct(const Functor& weight,
unsigned deg1, unsigned deg2,
double xmin, double xmax,
unsigned integrationRulePoints) const;
/**
// A measure-weighted average of orthonormal poly values
// to some power
*/
double powerAverage(unsigned deg, unsigned power) const;
/**
// A measure-weighted average of the product of two orthonormal
// poly values to some powers
*/
double jointPowerAverage(unsigned deg1, unsigned power1,
unsigned deg2, unsigned power2) const;
/**
// A measure-weighted average of the product of several
// orthonormal poly values
*/
double jointAverage(const unsigned* degrees, unsigned nDegrees,
bool degreesSortedIncreasingOrder = false) const;
//@{
/**
// A measure-weighted average that will be remembered internally
// so that another call to this function with the same arguments
// will return the answer quickly
*/
double cachedJointAverage(unsigned deg1, unsigned deg2,
unsigned deg3, unsigned deg4) const;
double cachedJointAverage(unsigned deg1, unsigned deg2,
unsigned deg3, unsigned deg4,
unsigned deg5, unsigned deg6) const;
double cachedJointAverage(unsigned deg1, unsigned deg2,
unsigned deg3, unsigned deg4,
unsigned deg5, unsigned deg6,
unsigned deg7, unsigned deg8) const;
//@}
/** Covariance between v_{ab} and v_{cd} */
double cov4(unsigned a, unsigned b, unsigned c, unsigned d) const;
/** Covariance between v_{ab}*v_{cd} and v_{ef} */
double cov6(unsigned a, unsigned b, unsigned c, unsigned d,
unsigned e, unsigned f) const;
/** Covariance between v_{ab}*v_{cd} and v_{ef}*v_{gh} */
double cov8(unsigned a, unsigned b, unsigned c, unsigned d,
unsigned e, unsigned f, unsigned g, unsigned h) const;
/** Covariance between two cov4 estimates (i.e., error on the error) */
double covCov4(unsigned a, unsigned b, unsigned c, unsigned d,
unsigned e, unsigned f, unsigned g, unsigned h) const;
/**
// Alternative implementation of "cov8". It is slower than "cov8"
// but easier to program and verify. Useful mainly for testing "cov8".
*/
double slowCov8(unsigned a, unsigned b, unsigned c, unsigned d,
unsigned e, unsigned f, unsigned g, unsigned h) const;
/** Estimate of eps_{mn} expectation */
double epsExpectation(unsigned m, unsigned n, bool highOrder) const;
/**
// Estimate of covariance between eps_{ij} and eps_{mn}.
//
// The result should be identical with "empiricalKroneckerCovariance"
// in case "highOrder" argument is "false". However, this method
// caches results of various calculations of averages and should
// perform better inside cycles over indices.
*/
double epsCovariance(unsigned i, unsigned j,
unsigned m, unsigned n, bool highOrder) const;
/**
// Covariance matrix created by multiple calls to "epsCovariance"
*/
Matrix<double> epsCovarianceMatrix(
const std::vector<std::pair<unsigned,unsigned> >& pairs,
bool highOrder) const;
/** Construct a StorablePolySeries1D object out of this one */
CPP11_auto_ptr<StorablePolySeries1D> makeStorablePolySeries(
double xmin, double xmax,
const double *coeffs=0, unsigned maxdeg=0) const;
private:
static const precise_type precise_zero;
struct Recurrence
{
inline Recurrence(const precise_type a,
const precise_type b)
: alpha(a), beta(b)
{
assert(beta > 0.0);
sqrbeta = std::sqrt(beta);
}
precise_type alpha;
precise_type beta;
precise_type sqrbeta;
};
class PolyFcn;
friend class PolyFcn;
class PolyFcn : public Functor1<precise_type, precise_type>
{
public:
inline PolyFcn(const ContOrthoPoly1D& p,
const unsigned d1, const unsigned power)
: poly(p), deg1(d1), polypow(power) {}
inline precise_type operator()(const precise_type& x) const
{
precise_type p = 1.0;
if (polypow)
{
p = poly.normpoly(deg1, x);
switch (polypow)
{
case 1U:
break;
case 2U:
p *= p;
break;
default:
const precise_type myPow = polypow;
p = std::pow(p, myPow);
break;
}
}
return p;
}
private:
const ContOrthoPoly1D& poly;
unsigned deg1;
unsigned polypow;
};
class TripleProdFcn;
friend class TripleProdFcn;
class TripleProdFcn : public Functor1<precise_type, precise_type>
{
public:
inline TripleProdFcn(const ContOrthoPoly1D& p, const unsigned d1,
const unsigned d2, const unsigned d3)
: poly(p)
{
degs[0] = d1;
degs[1] = d2;
degs[2] = d3;
degmax = std::max(d1, std::max(d2, d3));
}
inline precise_type operator()(const precise_type& x) const
{return poly.normpolyprod(degs, 3, degmax, x);}
private:
const ContOrthoPoly1D& poly;
unsigned degs[3];
unsigned degmax;
};
template<class Funct> class EWPolyProductFcn;
template<class Funct> friend class EWPolyProductFcn;
template<class Funct>
class EWPolyProductFcn : public Functor1<precise_type, precise_type>
{
public:
inline EWPolyProductFcn(const ContOrthoPoly1D& p, const Funct& w,
const unsigned d1, const unsigned d2)
: poly(p), wf(w)
{
degs[0] = d1;
degs[1] = d2;
degmax = std::max(d1, d2);
}
inline precise_type operator()(const precise_type& x) const
{return poly.normpolyprod(degs,2,degmax,x-poly.meanX_)*wf(x);}
private:
const ContOrthoPoly1D& poly;
const Funct& wf;
unsigned degs[2];
unsigned degmax;
};
class MemoKey
{
public:
inline MemoKey(const unsigned d0, const unsigned d1,
const unsigned d2, const unsigned d3)
: nDegs_(4U)
{
degs_[0] = d0;
degs_[1] = d1;
degs_[2] = d2;
degs_[3] = d3;
std::sort(degs_, degs_+nDegs_);
}
inline MemoKey(const unsigned d0, const unsigned d1,
const unsigned d2, const unsigned d3,
const unsigned d4, const unsigned d5)
: nDegs_(6U)
{
degs_[0] = d0;
degs_[1] = d1;
degs_[2] = d2;
degs_[3] = d3;
degs_[4] = d4;
degs_[5] = d5;
std::sort(degs_, degs_+nDegs_);
}
inline MemoKey(const unsigned d0, const unsigned d1,
const unsigned d2, const unsigned d3,
const unsigned d4, const unsigned d5,
const unsigned d6, const unsigned d7)
: nDegs_(8U)
{
degs_[0] = d0;
degs_[1] = d1;
degs_[2] = d2;
degs_[3] = d3;
degs_[4] = d4;
degs_[5] = d5;
degs_[6] = d6;
degs_[7] = d7;
std::sort(degs_, degs_+nDegs_);
}
inline const unsigned* degrees() const {return degs_;}
inline unsigned nDegrees() const {return nDegs_;}
inline bool operator<(const MemoKey& r) const
{
if (nDegs_ < r.nDegs_)
return true;
if (r.nDegs_ < nDegs_)
return false;
for (unsigned i=0; i<nDegs_; ++i)
{
if (degs_[i] < r.degs_[i])
return true;
if (r.degs_[i] < degs_[i])
return false;
}
return false;
}
inline bool operator==(const MemoKey& r) const
{
if (nDegs_ != r.nDegs_)
return false;
for (unsigned i=0; i<nDegs_; ++i)
if (degs_[i] != r.degs_[i])
return false;
return true;
}
inline bool operator!=(const MemoKey& r) const
{return !(*this == r);}
private:
unsigned degs_[8];
unsigned nDegs_;
};
void calcMeanXandWeightSums();
void calcRecurrenceCoeffs(OrthoPolyMethod m);
void calcRecurrenceStieltjes();
void calcRecurrenceLanczos();
precise_type monicpoly(unsigned degree, precise_type x) const;
std::pair<precise_type,precise_type> monicInnerProducts(
unsigned degree) const;
precise_type normpoly(unsigned degree, precise_type x) const;
std::pair<precise_type,precise_type> twonormpoly(
unsigned deg1, unsigned deg2, precise_type x) const;
precise_type normpolyprod(const unsigned* degrees, unsigned nDeg,
unsigned degmax, precise_type x) const;
template <typename Numeric>
precise_type normseries(const Numeric* coeffs, unsigned maxdeg,
precise_type x) const;
template <typename Numeric>
void getAllPolys(double x, unsigned maxdeg, Numeric *polyValues) const;
double getCachedAverage(const MemoKey& key) const;
std::vector<MeasurePoint> measure_;
std::vector<Recurrence> rCoeffs_;
mutable std::map<MemoKey,double> cachedAverages_;
precise_type wsum_;
precise_type wsumsq_;
precise_type meanX_;
double minX_;
double maxX_;
unsigned maxdeg_;
bool allWeightsEqual_;
#ifdef SWIG
public:
inline StorablePolySeries1D* makeStorablePolySeries_2(
double xmin, double xmax, const std::vector<double>& coeffs) const
{
CPP11_auto_ptr<StorablePolySeries1D> ptr;
if (coeffs.empty())
ptr = this->makeStorablePolySeries(xmin, xmax);
else
ptr = this->makeStorablePolySeries(xmin, xmax, &coeffs[0],
coeffs.size() - 1);
return ptr.release();
}
inline double sumOfWeights_2() const
{return sumOfWeights();}
inline double sumOfWeightSquares_2() const
{return sumOfWeightSquares();}
inline double meanCoordinate_2() const
{return meanCoordinate();}
inline double empiricalKroneckerDelta_2(const unsigned deg1,
const unsigned deg2) const
{return empiricalKroneckerDelta(deg1, deg2);}
inline Matrix<double> jacobiMatrix_2(const unsigned n) const
{return jacobiMatrix(n);}
inline double integratePoly_2(const unsigned degree, const unsigned power,
const double xmin, const double xmax) const
{return integratePoly(degree, power, xmin, xmax);}
inline double integrateTripleProduct_2(const unsigned deg1, const unsigned deg2,
const unsigned deg3, const double xmin,
const double xmax) const
{return integrateTripleProduct(deg1, deg2, deg3, xmin, xmax);}
inline Matrix<double> tripleProductMatrix_2(
const std::vector<std::pair<unsigned,unsigned> >& pairs,
const unsigned maxdeg, const double xmin, const double xmax) const
{return tripleProductMatrix(pairs, maxdeg, xmin, xmax);}
#endif
};
}
#include "npstat/nm/ContOrthoPoly1D.icc"
#endif // NPSTAT_CONTORTHOPOLY1D_HH_
Index: trunk/npstat/stat/KDE1DHOSymbetaKernel.cc
===================================================================
--- trunk/npstat/stat/KDE1DHOSymbetaKernel.cc (revision 720)
+++ trunk/npstat/stat/KDE1DHOSymbetaKernel.cc (revision 721)
@@ -1,91 +1,92 @@
#include <cassert>
#include <stdexcept>
#include "npstat/nm/ClassicalOrthoPolys1D.hh"
#include "npstat/stat/KDE1DHOSymbetaKernel.hh"
#include "npstat/stat/Distributions1D.hh"
namespace npstat {
KDE1DHOSymbetaKernel::KDE1DHOSymbetaKernel(
const int i_power, const double i_filterDegree)
- : power_(i_power), filterDegree_(i_filterDegree), lastShrinkage_(1.0)
+ : power_(i_power), filterDegree_(i_filterDegree),
+ lastShrinkage_(1.0), poly_(0)
{
if (filterDegree_ < 0.0) throw std::invalid_argument(
"In npstat::KDE1DHOSymbetaKernel constructor: filterDegree"
" argument can not be negative");
if (i_power < 0)
poly_ = new HermiteProbOrthoPoly1D();
else if (i_power == 0)
poly_ = new LegendreOrthoPoly1D();
else
poly_ = new JacobiOrthoPoly1D(i_power, i_power);
maxdeg_ = floor(filterDegree_);
if (static_cast<double>(maxdeg_) != filterDegree_)
{
lastShrinkage_ = sqrt(filterDegree_ - maxdeg_);
++maxdeg_;
}
polyValues_.resize(2U*(maxdeg_ + 1U));
poly_->allpoly(0.0L, &polyValues_[0], maxdeg_);
if (i_power < 0)
{
Gauss1D g(0.0, 1.0);
xmin_ = g.quantile(0.0);
xmax_ = g.quantile(1.0);
}
else
{
xmin_ = poly_->xmin();
xmax_ = poly_->xmax();
}
}
KDE1DHOSymbetaKernel::KDE1DHOSymbetaKernel(const KDE1DHOSymbetaKernel& r)
: poly_(0)
{
copyInternals(r);
}
void KDE1DHOSymbetaKernel::copyInternals(const KDE1DHOSymbetaKernel& r)
{
assert(!poly_);
poly_ = r.poly_->clone();
power_ = r.power_;
maxdeg_ = r.maxdeg_;
filterDegree_ = r.filterDegree_;
xmin_ = r.xmin_;
xmax_ = r.xmax_;
lastShrinkage_ = r.lastShrinkage_;
polyValues_ = r.polyValues_;
}
KDE1DHOSymbetaKernel& KDE1DHOSymbetaKernel::operator=(
const KDE1DHOSymbetaKernel& r)
{
if (this != &r)
{
delete poly_;
poly_ = 0;
copyInternals(r);
}
return *this;
}
double KDE1DHOSymbetaKernel::operator()(const double x) const
{
long double sum = 1.0L;
if (filterDegree_)
{
const long double* poly0 = &polyValues_[0];
long double* polyx = &polyValues_[0] + (maxdeg_ + 1U);
poly_->allpoly(x, polyx, maxdeg_);
for (unsigned i=1U; i<maxdeg_; ++i)
sum += poly0[i]*polyx[i];
sum += poly0[maxdeg_]*polyx[maxdeg_]*lastShrinkage_;
}
return sum*poly_->weight(x);
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Feb 23, 2:46 PM (1 d, 8 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4486698
Default Alt Text
(28 KB)
Attached To
rNPSTATSVN npstatsvn
Event Timeline
Log In to Comment