Index: trunk/npstat/nm/ContOrthoPoly1D.cc =================================================================== --- trunk/npstat/nm/ContOrthoPoly1D.cc (revision 909) +++ trunk/npstat/nm/ContOrthoPoly1D.cc (revision 910) @@ -1,978 +1,979 @@ #include "npstat/nm/ContOrthoPoly1D.hh" #include "npstat/nm/allocators.hh" #include "npstat/nm/StorablePolySeries1D.hh" #include "npstat/nm/Triple.hh" inline static int kdelta(const unsigned i, const unsigned j) { return i == j ? 1 : 0; } namespace npstat { const ContOrthoPoly1D::precise_type ContOrthoPoly1D::precise_zero = 0.0; void ContOrthoPoly1D::calcMeanXandWeightSums() { // Calculate wsum_, wsumsq_, and meanX_ const unsigned long mSize = measure_.size(); precise_type xsum = precise_zero; if (allWeightsEqual_) { const precise_type lw0 = measure_[0].second; wsum_ = mSize*lw0; wsumsq_ = mSize*lw0*lw0; for (unsigned long i = 0; i < mSize; ++i) { const double x = measure_[i].first; xsum += x; if (x < minX_) minX_ = x; if (x > maxX_) maxX_ = x; } meanX_ = xsum/mSize; } else { for (unsigned long i = 0; i < mSize; ++i) { const double x = measure_[i].first; const precise_type w = measure_[i].second; wsum_ += w; wsumsq_ += w*w; xsum += w*x; if (x < minX_) minX_ = x; if (x > maxX_) maxX_ = x; } assert(wsum_ > precise_zero); meanX_ = xsum/wsum_; } // Shift the measure double shift = meanX_; for (unsigned long i = 0; i < mSize; ++i) measure_[i].first -= shift; // Try to improve the mean xsum = precise_zero; precise_type dx; if (allWeightsEqual_) { for (unsigned long i = 0; i < mSize; ++i) xsum += measure_[i].first; dx = xsum/mSize; } else { for (unsigned long i = 0; i < mSize; ++i) { const precise_type w = measure_[i].second; xsum += w*measure_[i].first; } dx = xsum/wsum_; } // Shift the measure and the mean meanX_ += dx; shift = dx; for (unsigned long i = 0; i < mSize; ++i) measure_[i].first -= shift; } void ContOrthoPoly1D::calcRecurrenceCoeffs(const OrthoPolyMethod m) { rCoeffs_.clear(); rCoeffs_.reserve(maxdeg_ + 1); switch (m) { case OPOLY_STIELTJES: calcRecurrenceStieltjes(); break; case OPOLY_LANCZOS: calcRecurrenceLanczos(); break; default: throw std::runtime_error( "In npstat::ContOrthoPoly1D::calcRecurrenceCoeffs: " "incomplete switch statement. This is a bug. Please report."); } assert(rCoeffs_.size() == maxdeg_ + 1); } double ContOrthoPoly1D::effectiveSampleSize() const { if (allWeightsEqual_) return measure_.size(); else return wsum_*wsum_/wsumsq_; } ContOrthoPoly1D::precise_type ContOrthoPoly1D::monicpoly( const unsigned degree, const precise_type x) const { assert(degree <= maxdeg_); precise_type polyk = 1.0, polykm1 = precise_zero; for (unsigned k=0; k maxdeg_) throw std::invalid_argument( "In npstat::ContOrthoPoly1D::powerAverage: " "degree argument is out of range"); const unsigned long mSize = measure_.size(); precise_type sum = precise_zero; for (unsigned long i = 0; i < mSize; ++i) sum += measure_[i].second*powl(normpoly(deg, measure_[i].first), power); return sum/wsum_; } } } std::pair ContOrthoPoly1D::twonormpoly( const unsigned deg1, const unsigned deg2, const precise_type x) const { precise_type p1 = precise_zero, p2 = precise_zero, polyk = 1.0, polykm1 = precise_zero; const unsigned degmax = std::max(deg1, deg2); for (unsigned k=0; k(p1, p2); } ContOrthoPoly1D::precise_type ContOrthoPoly1D::normpolyprod( const unsigned* degrees, const unsigned nDeg, const unsigned degmax, const precise_type x) const { precise_type prod = 1.0, polyk = 1.0, polykm1 = precise_zero; for (unsigned k=0; k ContOrthoPoly1D::monicInnerProducts(const unsigned degree) const { precise_type sum = precise_zero, xsum = precise_zero; const unsigned long mSize = measure_.size(); for (unsigned long i = 0; i < mSize; ++i) { const precise_type x = measure_[i].first; const precise_type p = monicpoly(degree, x); const precise_type pprod = p*p*measure_[i].second; sum += pprod; xsum += x*pprod; } return std::pair(xsum/wsum_, sum/wsum_); } void ContOrthoPoly1D::weightCoeffs(double *coeffs, const unsigned maxdeg) const { if (maxdeg > maxdeg_) throw std::invalid_argument( "In npstat::ContOrthoPoly1D::weightsSquaredCoeffs: " "maximum degree out of range"); assert(coeffs); std::vector scalarProducts(maxdeg+1U, precise_zero); const unsigned long mSize = measure_.size(); for (unsigned long i = 0; i < mSize; ++i) { const double x = measure_[i].first; const double w = measure_[i].second; const precise_type f = w; precise_type polyk = 1.0, polykm1 = precise_zero; for (unsigned k=0; k ip = monicInnerProducts(deg); rCoeffs_.push_back(Recurrence(ip.first/ip.second, ip.second/prevSprod)); prevSprod = ip.second; } } void ContOrthoPoly1D::calcRecurrenceLanczos() { const unsigned long mSize = measure_.size(); std::vector dmem(mSize*2UL); precise_type* p0 = &dmem[0]; for (unsigned long i=0; i maxdeg_) throw std::invalid_argument( "In npstat::ContOrthoPoly1D::poly: degree argument is out of range"); return normpoly(deg, x - meanX_); } std::pair ContOrthoPoly1D::polyPair( const unsigned deg1, const unsigned deg2, const double x) const { if (deg1 > maxdeg_ || deg2 > maxdeg_) throw std::invalid_argument( "In npstat::ContOrthoPoly1D::polyPair: degree argument is out of range"); const std::pair& ld = twonormpoly(deg1, deg2, x - meanX_); return std::pair(ld.first, ld.second); } ContOrthoPoly1D::precise_type ContOrthoPoly1D::empiricalKroneckerDelta( const unsigned ideg1, const unsigned ideg2) const { if (ideg1 > maxdeg_ || ideg2 > maxdeg_) throw std::invalid_argument( "In npstat::ContOrthoPoly1D::empiricalKroneckerDelta: " "degree argument is out of range"); precise_type sum = precise_zero; const unsigned long mSize = measure_.size(); for (unsigned long i = 0; i < mSize; ++i) { const std::pair& p = twonormpoly(ideg1, ideg2, measure_[i].first); sum += measure_[i].second*p.first*p.second; } return sum/wsum_; } Matrix ContOrthoPoly1D::empiricalKroneckerMatrix(const unsigned maxdeg) const { if (maxdeg > maxdeg_) throw std::invalid_argument( "In npstat::ContOrthoPoly1D::empiricalKroneckerMatrix: " "matrix size is out of range"); Matrix kd(maxdeg+1U, maxdeg+1U, 0); std::vector polyv(maxdeg+1U); ContOrthoPoly1D::precise_type* polyBuf = &polyv[0]; const unsigned long mSize = measure_.size(); for (unsigned long ipt = 0; ipt < mSize; ++ipt) { const double weight = measure_[ipt].second; getAllPolys(measure_[ipt].first, maxdeg, polyBuf); for (unsigned i=0; i<=maxdeg; ++i) { const ContOrthoPoly1D::precise_type polyI = polyBuf[i]; ContOrthoPoly1D::precise_type* row = kd[i]; for (unsigned j=i; j<=maxdeg; ++j) row[j] += weight*polyI*polyBuf[j]; } } for (unsigned i=0; i maxdeg_ || ideg2 > maxdeg_) throw std::invalid_argument( "In npstat::ContOrthoPoly1D::jointPowerAverage: " "degree argument is out of range"); precise_type sum = precise_zero; const unsigned long mSize = measure_.size(); for (unsigned long i = 0; i < mSize; ++i) { const std::pair& p = twonormpoly(ideg1, ideg2, measure_[i].first); sum += measure_[i].second*powl(p.first,power1)*powl(p.second,power2); } return sum/wsum_; } double ContOrthoPoly1D::jointAverage( const unsigned* degrees, const unsigned nDegrees, const bool sorted) const { if (nDegrees) { assert(degrees); // See if we can avoid a direct calculation if (nDegrees == 1U) return kdelta(degrees[0], 0U); if (nDegrees == 2U) return kdelta(degrees[0], degrees[1]); // Check if we can remove leading zeros { unsigned nonZeroDegs = nDegrees; while (nonZeroDegs && !degrees[0]) { ++degrees; --nonZeroDegs; } if (nonZeroDegs < nDegrees) return jointAverage(degrees, nonZeroDegs, sorted); } // Check if we can remove any other zeros if (!sorted) { bool allNonZero = true; for (unsigned ideg=0; ideg maxdeg_) throw std::invalid_argument( "In npstat::ContOrthoPoly1D::jointAverage: " "degree argument is out of range"); precise_type sum = precise_zero; const unsigned long mSize = measure_.size(); for (unsigned long i = 0; i < mSize; ++i) sum += measure_[i].second*normpolyprod( degrees, nDegrees, degmax, measure_[i].first); return sum/wsum_; } else return 1.0; } double ContOrthoPoly1D::empiricalKroneckerCovariance( const unsigned deg1, const unsigned deg2, const unsigned deg3, const unsigned deg4) const { double cov = 0.0; if (!((deg1 == 0 && deg2 == 0) || (deg3 == 0 && deg4 == 0))) { unsigned degs[4]; degs[0] = deg1; degs[1] = deg2; degs[2] = deg3; degs[3] = deg4; cov = (jointAverage(degs, 4) - kdelta(deg1, deg2)*kdelta(deg3, deg4))/ effectiveSampleSize(); if (std::min(deg1, deg2) == std::min(deg3, deg4) && std::max(deg1, deg2) == std::max(deg3, deg4)) if (cov < 0.0) cov = 0.0; } return cov; } std::pair ContOrthoPoly1D::recurrenceCoeffs(const unsigned deg) const { if (deg > maxdeg_) throw std::invalid_argument( "In npstat::ContOrthoPoly1D::recurrenceCoeffs: " "degree argument is out of range"); const Recurrence& rc(rCoeffs_[deg]); return std::pair(rc.alpha, rc.beta); } Matrix ContOrthoPoly1D::jacobiMatrix(const unsigned n) const { if (!n) throw std::invalid_argument( "In npstat::ContOrthoPoly1D::jacobiMatrix: " "can not build matrix of zero size"); if (n > maxdeg_) throw std::invalid_argument( "In npstat::ContOrthoPoly1D::jacobiMatrix: " "matrix size is out of range"); Matrix mat(n, n, 0); unsigned ip1 = 1; for (unsigned i=0; i maxdeg_) throw std::invalid_argument( "In npstat::ContOrthoPoly1D::integratePoly: " "degree argument is out of range"); const unsigned nGood = PreciseQuadrature::minimalExactRule(deg1*power); if (!nGood) throw std::invalid_argument( "In npstat::ContOrthoPoly1D::integratePoly: " "product of poly degree and power is too large"); PreciseQuadrature glq(nGood); PolyFcn fcn(*this, deg1, power); return glq.integrate(fcn, xmin - meanX_, xmax - meanX_); } ContOrthoPoly1D::precise_type ContOrthoPoly1D::integrateTripleProduct( const unsigned deg1, const unsigned deg2, const unsigned deg3, const double xmin, const double xmax) const { const unsigned maxdex = std::max(std::max(deg1, deg2), deg3); if (maxdex > maxdeg_) throw std::invalid_argument( "In npstat::ContOrthoPoly1D::integrateTripleProduct: " "degree argument is out of range"); const unsigned sumdeg = deg1 + deg2 + deg3; const unsigned nGood = PreciseQuadrature::minimalExactRule(sumdeg); if (!nGood) throw std::invalid_argument( "In npstat::ContOrthoPoly1D::integrateTripleProduct: " "sum of the polynomial degrees is too large"); PreciseQuadrature glq(nGood); TripleProdFcn fcn(*this, deg1, deg2, deg3); return glq.integrate(fcn, xmin - meanX_, xmax - meanX_); } Matrix ContOrthoPoly1D::tripleProductMatrix( const std::vector >& pairs, const unsigned maxdeg, const double xmin, const double xmax) const { typedef npstat::Triple Key3; typedef std::map TripleProductMap; const unsigned nPairs = pairs.size(); if (!nPairs) throw std::invalid_argument( "In npstat::ContOrthoPoly1D::tripleProductMatrix: " "empty vector of degree specifications"); const unsigned nPolys = maxdeg + 1U; npstat::Matrix design0(nPairs, nPolys); TripleProductMap tmap; // Avoid calculating the same integral more than once for (unsigned ipair=0; ipair where = tmap.insert(std::make_pair(key, value)); assert(where.second); it = where.first; } design0[ipair][ipoly] = it->second; } } return design0; } double ContOrthoPoly1D::cachedJointAverage(const unsigned deg1, const unsigned deg2, const unsigned deg3, const unsigned deg4) const { MemoKey key(deg1, deg2, deg3, deg4); return getCachedAverage(key); } double ContOrthoPoly1D::cachedJointAverage(const unsigned deg1, const unsigned deg2, const unsigned deg3, const unsigned deg4, const unsigned deg5, const unsigned deg6) const { MemoKey key(deg1, deg2, deg3, deg4, deg5, deg6); return getCachedAverage(key); } double ContOrthoPoly1D::cachedJointAverage(const unsigned deg1, const unsigned deg2, const unsigned deg3, const unsigned deg4, const unsigned deg5, const unsigned deg6, const unsigned deg7, const unsigned deg8) const { MemoKey key(deg1, deg2, deg3, deg4, deg5, deg6, deg7, deg8); return getCachedAverage(key); } double ContOrthoPoly1D::getCachedAverage(const MemoKey& key) const { double value; std::map::const_iterator it = cachedAverages_.find(key); if (it == cachedAverages_.end()) { value = jointAverage(key.degrees(), key.nDegrees(), true); cachedAverages_.insert(std::pair(key, value)); } else value = it->second; return value; } double ContOrthoPoly1D::cov4(const unsigned deg1, const unsigned deg2, const unsigned deg3, const unsigned deg4) const { const bool has0 = (deg1 == 0 && deg2 == 0) || (deg3 == 0 && deg4 == 0); double cov = 0.0; if (!has0) { const double N = effectiveSampleSize(); cov = (cachedJointAverage(deg1, deg2, deg3, deg4) - kdelta(deg1, deg2)*kdelta(deg3, deg4))/N; if (std::min(deg1, deg2) == std::min(deg3, deg4) && std::max(deg1, deg2) == std::max(deg3, deg4)) if (cov < 0.0) cov = 0.0; } return cov; } double ContOrthoPoly1D::cov6(const unsigned a, const unsigned b, const unsigned c, const unsigned d, const unsigned e, const unsigned f) const { const bool has0 = (a == 0 && b == 0) || (c == 0 && d == 0) || (e == 0 && f == 0); double cov = 0.0; if (!has0) { double sum = cachedJointAverage(a, b, c, d, e, f); double add = 2.0; if (kdelta(a, b)) sum -= cachedJointAverage(c, d, e, f); else add = 0.0; if (kdelta(c, d)) sum -= cachedJointAverage(a, b, e, f); else add = 0.0; if (kdelta(e, f)) sum -= cachedJointAverage(a, b, c, d); else add = 0.0; const double N = effectiveSampleSize(); cov = (sum + add)/N/N; } return cov; } double ContOrthoPoly1D::slowCov8(const unsigned a, const unsigned b, const unsigned c, const unsigned d, const unsigned e, const unsigned f, const unsigned g, const unsigned h) const { const bool has0 = (a == 0 && b == 0) || (c == 0 && d == 0) || (e == 0 && f == 0) || (g == 0 && h == 0); double cov = 0.0; if (!has0) { const double pabcd = cachedJointAverage(a, b, c, d); const double pefgh = cachedJointAverage(e, f, g, h); const double pabef = cachedJointAverage(a, b, e, f); const double pcdgh = cachedJointAverage(c, d, g, h); const double pabgh = cachedJointAverage(a, b, g, h); const double pcdef = cachedJointAverage(c, d, e, f); const double pabcdef = cachedJointAverage(a, b, c, d, e, f); const double pabcdgh = cachedJointAverage(a, b, c, d, g, h); const double pabefgh = cachedJointAverage(a, b, e, f, g, h); const double pcdefgh = cachedJointAverage(c, d, e, f, g, h); const double pabcdefgh = cachedJointAverage(a, b, c, d, e, f, g, h); const double deltaprod = kdelta(a, b)*kdelta(c, d)*kdelta(e, f)*kdelta(g, h); const double tmp = kdelta(e,f)*kdelta(g,h)*pabcd + kdelta(c,d)*kdelta(g,h)*pabef + kdelta(c,d)*kdelta(e,f)*pabgh + kdelta(a,b)*kdelta(c,d)*pefgh + kdelta(a,b)*kdelta(e,f)*pcdgh + kdelta(a,b)*kdelta(g,h)*pcdef; const double term1 = pabcd*pefgh + pabef*pcdgh + pabgh*pcdef + 3.0*deltaprod - tmp; const double term2 = pabcdefgh - 6.0*deltaprod - kdelta(a,b)*pcdefgh - kdelta(c,d)*pabefgh - kdelta(e,f)*pabcdgh - kdelta(g,h)*pabcdef - pabcd*pefgh - pabef*pcdgh - pabgh*pcdef + 2.0*tmp; const double nPoints = effectiveSampleSize(); const double prod8 = (term1 + term2/nPoints)/nPoints/nPoints; cov = prod8 - cov4(a, b, c, d)*cov4(e, f, g, h); } return cov; } double ContOrthoPoly1D::covCov4(const unsigned a, const unsigned b, const unsigned c, const unsigned d, const unsigned e, const unsigned f, const unsigned g, const unsigned h) const { const bool has0 = (a == 0 && b == 0) || (c == 0 && d == 0) || (e == 0 && f == 0) || (g == 0 && h == 0); double cov = 0.0; if (!has0) { const double pabcdefgh = cachedJointAverage(a, b, c, d, e, f, g, h); const double pabcd = cachedJointAverage(a, b, c, d); const double pefgh = cachedJointAverage(e, f, g, h); const double N = effectiveSampleSize(); cov = (pabcdefgh - pabcd*pefgh)/N/N/N; } return cov; } double ContOrthoPoly1D::cov8(const unsigned a, const unsigned b, const unsigned c, const unsigned d, const unsigned e, const unsigned f, const unsigned g, const unsigned h) const { const bool has0 = (a == 0 && b == 0) || (c == 0 && d == 0) || (e == 0 && f == 0) || (g == 0 && h == 0); double cov = 0.0; if (!has0) { const bool includeCubicPart = true; // First, calculate the O(N^-2) part const double pabef = cachedJointAverage(a, b, e, f); const double pcdgh = cachedJointAverage(c, d, g, h); const double pabgh = cachedJointAverage(a, b, g, h); const double pcdef = cachedJointAverage(c, d, e, f); const double deltaprod = kdelta(a, b)*kdelta(c, d)*kdelta(e, f)*kdelta(g, h); const double tmp2 = kdelta(c, d)*kdelta(g, h)*pabef + kdelta(c, d)*kdelta(e, f)*pabgh + kdelta(a, b)*kdelta(e, f)*pcdgh + kdelta(a, b)*kdelta(g, h)*pcdef; const double term2 = pabef*pcdgh + pabgh*pcdef + 2.0*deltaprod - tmp2; double term3 = 0.0; if (includeCubicPart) { // Additional terms needed to calculate the O(N^-3) part const double pabcdefgh = cachedJointAverage(a, b, c, d, e, f, g, h); double sixsum = 0.0; if (kdelta(a, b)) sixsum += cachedJointAverage(c, d, e, f, g, h); if (kdelta(c, d)) sixsum += cachedJointAverage(a, b, e, f, g, h); if (kdelta(e, f)) sixsum += cachedJointAverage(a, b, c, d, g, h); if (kdelta(g, h)) sixsum += cachedJointAverage(a, b, c, d, e, f); const double pabcd = cachedJointAverage(a, b, c, d); const double pefgh = cachedJointAverage(e, f, g, h); const double tmp3 = tmp2 + kdelta(e, f)*kdelta(g, h)*pabcd + kdelta(a, b)*kdelta(c, d)*pefgh; term3 = pabcdefgh - 6.0*deltaprod - sixsum - (pabcd*pefgh + pabef*pcdgh + pabgh*pcdef) + 2.0*tmp3; } const double N = effectiveSampleSize(); cov = (term2 + term3/N)/N/N; // const bool isVariance = ?; // if (isVariance) // if (cov < 0.0) // cov = 0.0; } return cov; } double ContOrthoPoly1D::epsExpectation(const unsigned m_in, const unsigned n_in, const bool highOrder) const { if (highOrder) { precise_type sum = precise_zero; if (m_in || n_in) { const unsigned m = std::min(m_in, n_in); const unsigned n = std::max(m_in, n_in); for (unsigned k=0; k<=n; ++k) { const double f = k == n ? 1.0 : (k > m ? 1.0 : 2.0); sum += f*cachedJointAverage(k, k, m, n); } if (m == n) sum -= 1.0; else sum -= (cachedJointAverage(m, m, m, n) + cachedJointAverage(m, n, n, n))/2.0; } return sum/effectiveSampleSize(); } else return 0.0; } double ContOrthoPoly1D::epsCovariance(const unsigned m1_in, const unsigned n1_in, const unsigned m2_in, const unsigned n2_in, const bool highOrder) const { const bool has0 = (m1_in == 0 && n1_in == 0) || (m2_in == 0 && n2_in == 0); if (has0) return 0.0; if (highOrder) { const unsigned m1 = std::min(m1_in, n1_in); const unsigned n1 = std::max(m1_in, n1_in); const unsigned m2 = std::min(m2_in, n2_in); const unsigned n2 = std::max(m2_in, n2_in); precise_type sum = precise_zero; // Process the -v_{m1,n1} term (i.e., the linear one) of eps_{m1,n1} sum += cov4(m2, n2, m1, n1); sum += cov6(m2, n2, n2, n2, m1, n1)/2.0; sum += cov6(m2, n2, m2, m2, m1, n1)/2.0; for (unsigned k=0; k<=n2; ++k) { const double factor = k > m2 ? 1.0 : 2.0; sum -= factor*cov6(k, m2, k, n2, m1, n1); } // Process the term -v_{m1,n1}/2 (v_{n1,n1} + v_{m1,m1}) of eps_{m1,n1} unsigned idx[2]; idx[0] = n1; idx[1] = m1; for (unsigned ii=0; ii<2; ++ii) { const unsigned mOrN = idx[ii]; sum += cov6(m1, n1, mOrN, mOrN, m2, n2)/2.0; sum += cov8(m1, n1, mOrN, mOrN, m2, n2, n2, n2)/4.0; sum += cov8(m1, n1, mOrN, mOrN, m2, n2, m2, m2)/4.0; for (unsigned k=0; k<=n2; ++k) { const double factor = k > m2 ? 1.0 : 2.0; sum -= factor/2.0*cov8(m1, n1, mOrN, mOrN, k, m2, k, n2); } } // Process the sum in eps_{m1,n1} for (unsigned k1=0; k1<=n1; ++k1) { const double f1 = k1 > m1 ? 1.0 : 2.0; sum -= f1*cov6(k1, m1, k1, n1, m2, n2); sum -= f1*cov8(k1, m1, k1, n1, m2, n2, n2, n2)/2.0; sum -= f1*cov8(k1, m1, k1, n1, m2, n2, m2, m2)/2.0; for (unsigned k=0; k<=n2; ++k) { const double factor = k > m2 ? 1.0 : 2.0; sum += f1*factor*cov8(k1, m1, k1, n1, k, m2, k, n2); } } return sum; } else return cov4(m2_in, n2_in, m1_in, n1_in); } Matrix ContOrthoPoly1D::epsCovarianceMatrix( const std::vector >& pairs, const bool highOrder) const { if (pairs.empty()) throw std::invalid_argument( "In npstat::ContOrthoPoly1D::epsCovarianceMatrix: empty list of pairs"); const unsigned nPairs = pairs.size(); Matrix cov(nPairs, nPairs); for (unsigned ipair1=0; ipair1 ContOrthoPoly1D::makeStorablePolySeries( const double i_xmin, const double i_xmax, const double *coeffs, const unsigned maxdeg) const { const unsigned sz = rCoeffs_.size(); std::vector > rc(sz); for (unsigned i=0; i( new StorablePolySeries1D(rc, i_xmin, i_xmax, meanX_, coeffs, maxdeg)); } }