g4tools  5.4.0
Public Member Functions | Protected Member Functions | Protected Attributes | List of all members
tools::spline::quintic Class Reference
Inheritance diagram for tools::spline::quintic:
Inheritance graph
[legend]
Collaboration diagram for tools::spline::quintic:
Collaboration graph
[legend]

Public Member Functions

 quintic (std::ostream &a_out, size_t a_n, double a_x[], double a_y[])
 
 quintic (const quintic &a_from)
 
quinticoperator= (const quintic &a_from)
 
double eval (double x) const
 
- Public Member Functions inherited from tools::spline::base_spline
 base_spline (std::ostream &a_out, double delta, double xmin, double xmax, size_t np, bool step)
 
virtual ~base_spline ()
 

Protected Member Functions

 quintic (std::ostream &a_out)
 
size_t find_x (double x) const
 
void build_coeff ()
 
- Protected Member Functions inherited from tools::spline::base_spline
 base_spline (std::ostream &a_out)
 
 base_spline (const base_spline &a_from)
 
base_splineoperator= (const base_spline &a_from)
 

Protected Attributes

std::vector< quintic_polyfPoly
 
- Protected Attributes inherited from tools::spline::base_spline
std::ostream & m_out
 
double fDelta
 
double fXmin
 
double fXmax
 
size_t fNp
 
bool fKstep
 

Detailed Description

Definition at line 416 of file spline.

Constructor & Destructor Documentation

◆ quintic() [1/3]

tools::spline::quintic::quintic ( std::ostream &  a_out)
inlineprotected

Definition at line 418 of file spline.

418 :base_spline(a_out),fPoly() {}

◆ quintic() [2/3]

tools::spline::quintic::quintic ( std::ostream &  a_out,
size_t  a_n,
double  a_x[],
double  a_y[] 
)
inline

Definition at line 420 of file spline.

421  :base_spline(a_out,-1,0,0,a_n,false) {
422  if(!a_n) {
423  m_out << "tools::spline::quintic : a_np is null." << std::endl;
424  return;
425  }
426  fXmin = a_x[0];
427  fXmax = a_x[a_n-1];
428  fPoly.resize(fNp);
429  for (size_t i=0; i<a_n; ++i) {
430  fPoly[i].X() = a_x[i];
431  fPoly[i].Y() = a_y[i];
432  }
433  build_coeff(); // Build the spline coefficients.
434  }

◆ quintic() [3/3]

tools::spline::quintic::quintic ( const quintic a_from)
inline

Definition at line 436 of file spline.

436 :base_spline(a_from),fPoly(a_from.fPoly) {}

Member Function Documentation

◆ build_coeff()

void tools::spline::quintic::build_coeff ( )
inlineprotected

algorithm 600, collected algorithms from acm. algorithm appeared in acm-trans. math. software, vol.9, no. 2, jun., 1983, p. 258-259.

quintic computes the coefficients of a quintic natural quintic spli s(x) with knots x(i) interpolating there to given function values: s(x(i)) = y(i) for i = 1,2, ..., n. in each interval (x(i),x(i+1)) the spline function s(xx) is a polynomial of fifth degree: s(xx) = ((((f(i)*p+e(i))*p+d(i))*p+c(i))*p+b(i))*p+y(i) (*) = ((((-f(i)*q+e(i+1))*q-d(i+1))*q+c(i+1))*q-b(i+1))*q+y(i+1) where p = xx - x(i) and q = x(i+1) - xx. (note the first subscript in the second expression.) the different polynomials are pieced together so that s(x) and its derivatives up to s"" are continuous.

input:

n number of data points, (at least three, i.e. n > 2) x(1:n) the strictly increasing or decreasing sequence of knots. the spacing must be such that the fifth power of x(i+1) - x(i) can be formed without overflow or underflow of exponents. y(1:n) the prescribed function values at the knots.

output:

b,c,d,e,f the computed spline coefficients as in (*). (1:n) specifically b(i) = s'(x(i)), c(i) = s"(x(i))/2, d(i) = s"'(x(i))/6, e(i) = s""(x(i))/24, f(i) = s""'(x(i))/120. f(n) is neither used nor altered. the five arrays b,c,d,e,f must always be distinct.

option:

it is possible to specify values for the first and second derivatives of the spline function at arbitrarily many knots. this is done by relaxing the requirement that the sequence of knots be strictly increasing or decreasing. specifically:

if x(j) = x(j+1) then s(x(j)) = y(j) and s'(x(j)) = y(j+1), if x(j) = x(j+1) = x(j+2) then in addition s"(x(j)) = y(j+2).

note that s""(x) is discontinuous at a double knot and, in addition, s"'(x) is discontinuous at a triple knot. the subroutine assigns y(i) to y(i+1) in these cases and also to y(i+2) at a triple knot. the representation (*) remains valid in each open interval (x(i),x(i+1)). at a double knot, x(j) = x(j+1), the output coefficients have the following values: y(j) = s(x(j)) = y(j+1) b(j) = s'(x(j)) = b(j+1) c(j) = s"(x(j))/2 = c(j+1) d(j) = s"'(x(j))/6 = d(j+1) e(j) = s""(x(j)-0)/24 e(j+1) = s""(x(j)+0)/24 f(j) = s""'(x(j)-0)/120 f(j+1) = s""'(x(j)+0)/120 at a triple knot, x(j) = x(j+1) = x(j+2), the output coefficients have the following values: y(j) = s(x(j)) = y(j+1) = y(j+2) b(j) = s'(x(j)) = b(j+1) = b(j+2) c(j) = s"(x(j))/2 = c(j+1) = c(j+2) d(j) = s"'((x(j)-0)/6 d(j+1) = 0 d(j+2) = s"'(x(j)+0)/6 e(j) = s""(x(j)-0)/24 e(j+1) = 0 e(j+2) = s""(x(j)+0)/24 f(j) = s""'(x(j)-0)/120 f(j+1) = 0 f(j+2) = s""'(x(j)+0)/120

Definition at line 479 of file spline.

479  {
545 
546  size_t i, m;
547  double pqqr, p, q, r, s, t, u, v,
548  b1, p2, p3, q2, q3, r2, pq, pr, qr;
549 
550  if (fNp <= 2) return;
551 
552  // coefficients of a positive definite, pentadiagonal matrix,
553  // stored in D, E, F from 1 to n-3.
554  m = fNp-2;
555  q = fPoly[1].X()-fPoly[0].X();
556  r = fPoly[2].X()-fPoly[1].X();
557  q2 = q*q;
558  r2 = r*r;
559  qr = q+r;
560  fPoly[0].D() = fPoly[0].E() = 0;
561  if (q) fPoly[1].D() = q*6.*q2/(qr*qr);
562  else fPoly[1].D() = 0;
563 
564  if (m > 1) {
565  for (i = 1; i < m; ++i) {
566  p = q;
567  q = r;
568  r = fPoly[i+2].X()-fPoly[i+1].X();
569  p2 = q2;
570  q2 = r2;
571  r2 = r*r;
572  pq = qr;
573  qr = q+r;
574  if (q) {
575  q3 = q2*q;
576  pr = p*r;
577  pqqr = pq*qr;
578  fPoly[i+1].D() = q3*6./(qr*qr);
579  fPoly[i].D() += (q+q)*(pr*15.*pr+(p+r)*q
580  *(pr* 20.+q2*7.)+q2*
581  ((p2+r2)*8.+pr*21.+q2+q2))/(pqqr*pqqr);
582  fPoly[i-1].D() += q3*6./(pq*pq);
583  fPoly[i].E() = q2*(p*qr+pq*3.*(qr+r+r))/(pqqr*qr);
584  fPoly[i-1].E() += q2*(r*pq+qr*3.*(pq+p+p))/(pqqr*pq);
585  fPoly[i-1].F() = q3/pqqr;
586  } else
587  fPoly[i+1].D() = fPoly[i].E() = fPoly[i-1].F() = 0;
588  }
589  }
590  if (r) fPoly[m-1].D() += r*6.*r2/(qr*qr);
591 
592  // First and second order divided differences of the given function
593  // values, stored in b from 2 to n and in c from 3 to n
594  // respectively. care is taken of double and triple knots.
595  for (i = 1; i < fNp; ++i) {
596  if (fPoly[i].X() != fPoly[i-1].X()) {
597  fPoly[i].B() =
598  (fPoly[i].Y()-fPoly[i-1].Y())/(fPoly[i].X()-fPoly[i-1].X());
599  } else {
600  fPoly[i].B() = fPoly[i].Y();
601  fPoly[i].Y() = fPoly[i-1].Y();
602  }
603  }
604  for (i = 2; i < fNp; ++i) {
605  if (fPoly[i].X() != fPoly[i-2].X()) {
606  fPoly[i].C() =
607  (fPoly[i].B()-fPoly[i-1].B())/(fPoly[i].X()-fPoly[i-2].X());
608  } else {
609  fPoly[i].C() = fPoly[i].B()*.5;
610  fPoly[i].B() = fPoly[i-1].B();
611  }
612  }
613 
614  // Solve the linear system with c(i+2) - c(i+1) as right-hand side.
615  if (m > 1) {
616  p=fPoly[0].C()=fPoly[m-1].E()=fPoly[0].F()
617  =fPoly[m-2].F()=fPoly[m-1].F()=0;
618  fPoly[1].C() = fPoly[3].C()-fPoly[2].C();
619  fPoly[1].D() = 1./fPoly[1].D();
620 
621  if (m > 2) {
622  for (i = 2; i < m; ++i) {
623  q = fPoly[i-1].D()*fPoly[i-1].E();
624  fPoly[i].D() = 1./(fPoly[i].D()-p*fPoly[i-2].F()-q*fPoly[i-1].E());
625  fPoly[i].E() -= q*fPoly[i-1].F();
626  fPoly[i].C() = fPoly[i+2].C()-fPoly[i+1].C()-p*fPoly[i-2].C()
627  -q*fPoly[i-1].C();
628  p = fPoly[i-1].D()*fPoly[i-1].F();
629  }
630  }
631  }
632 
633  fPoly[fNp-2].C() = fPoly[fNp-1].C() = 0;
634  if (fNp > 3)
635  for (i=fNp-3; i > 0; --i)
636  fPoly[i].C() = (fPoly[i].C()-fPoly[i].E()*fPoly[i+1].C()
637  -fPoly[i].F()*fPoly[i+2].C())*fPoly[i].D();
638 
639  // Integrate the third derivative of s(x)
640  m = fNp-1;
641  q = fPoly[1].X()-fPoly[0].X();
642  r = fPoly[2].X()-fPoly[1].X();
643  b1 = fPoly[1].B();
644  q3 = q*q*q;
645  qr = q+r;
646  if (qr) {
647  v = fPoly[1].C()/qr;
648  t = v;
649  } else
650  v = t = 0;
651  if (q) fPoly[0].F() = v/q;
652  else fPoly[0].F() = 0;
653  for (i = 1; i < m; ++i) {
654  p = q;
655  q = r;
656  if (i != m-1) r = fPoly[i+2].X()-fPoly[i+1].X();
657  else r = 0;
658  p3 = q3;
659  q3 = q*q*q;
660  pq = qr;
661  qr = q+r;
662  s = t;
663  if (qr) t = (fPoly[i+1].C()-fPoly[i].C())/qr;
664  else t = 0;
665  u = v;
666  v = t-s;
667  if (pq) {
668  fPoly[i].F() = fPoly[i-1].F();
669  if (q) fPoly[i].F() = v/q;
670  fPoly[i].E() = s*5.;
671  fPoly[i].D() = (fPoly[i].C()-q*s)*10;
672  fPoly[i].C() =
673  fPoly[i].D()*(p-q)+(fPoly[i+1].B()-fPoly[i].B()+(u-fPoly[i].E())*
674  p3-(v+fPoly[i].E())*q3)/pq;
675  fPoly[i].B() = (p*(fPoly[i+1].B()-v*q3)+q*(fPoly[i].B()-u*p3))/pq-p
676  *q*(fPoly[i].D()+fPoly[i].E()*(q-p));
677  } else {
678  fPoly[i].C() = fPoly[i-1].C();
679  fPoly[i].D() = fPoly[i].E() = fPoly[i].F() = 0;
680  }
681  }
682 
683  // End points x(1) and x(n)
684  p = fPoly[1].X()-fPoly[0].X();
685  s = fPoly[0].F()*p*p*p;
686  fPoly[0].E() = fPoly[0].D() = 0;
687  fPoly[0].C() = fPoly[1].C()-s*10;
688  fPoly[0].B() = b1-(fPoly[0].C()+s)*p;
689 
690  q = fPoly[fNp-1].X()-fPoly[fNp-2].X();
691  t = fPoly[fNp-2].F()*q*q*q;
692  fPoly[fNp-1].E() = fPoly[fNp-1].D() = 0;
693  fPoly[fNp-1].C() = fPoly[fNp-2].C()+t*10;
694  fPoly[fNp-1].B() += (fPoly[fNp-1].C()-t)*q;
695  }

◆ eval()

double tools::spline::quintic::eval ( double  x) const
inline

Definition at line 444 of file spline.

444 {if(!fNp) return 0;size_t klow=find_x(x);return fPoly[klow].eval(x);}

◆ find_x()

size_t tools::spline::quintic::find_x ( double  x) const
inlineprotected

Definition at line 447 of file spline.

447  {
448  int klow=0;
449 
450  // If out of boundaries, extrapolate
451  // It may be badly wrong
452  if(x<=fXmin) klow=0;
453  else if(x>=fXmax) klow=fNp-1;
454  else {
455  if(fKstep) { // Equidistant knots, use histogramming :
456  klow = mn<int>(int((x-fXmin)/fDelta),fNp-1);
457  } else {
458  int khig=fNp-1;
459  int khalf;
460  // Non equidistant knots, binary search
461  while((khig-klow)>1) {
462  khalf = (klow+khig)/2;
463  if(x>fPoly[khalf].X()) klow=khalf;
464  else khig=khalf;
465  }
466  }
467 
468  // This could be removed, sanity check
469  if( (x<fPoly[klow].X()) || (fPoly[klow+1].X()<x) ) {
470  m_out << "tools::spline::quintic::find_x : Binary search failed"
471  << " x(" << klow << ") = " << fPoly[klow].X() << " < x= " << x
472  << " < x(" << klow+1<< ") = " << fPoly[klow+1].X() << "."
473  << std::endl;
474  }
475  }
476  return klow;
477  }

◆ operator=()

quintic& tools::spline::quintic::operator= ( const quintic a_from)
inline

Definition at line 437 of file spline.

437  {
438  if(this==&a_from) return *this;
439  base_spline::operator=(a_from);
440  fPoly = a_from.fPoly;
441  return *this;
442  }

Member Data Documentation

◆ fPoly

std::vector<quintic_poly> tools::spline::quintic::fPoly
protected

Definition at line 697 of file spline.


The documentation for this class was generated from the following file:
tools::spline::base_spline::fDelta
double fDelta
Definition: spline:127
tools::spline::base_spline::m_out
std::ostream & m_out
Definition: spline:126
tools::spline::base_spline::operator=
base_spline & operator=(const base_spline &a_from)
Definition: spline:116
tools::spline::base_spline::fNp
size_t fNp
Definition: spline:130
tools::spline::base_spline::base_spline
base_spline(std::ostream &a_out)
Definition: spline:106
tools::spline::base_spline::fKstep
bool fKstep
Definition: spline:131
tools::spline::base_spline::fXmin
double fXmin
Definition: spline:128
tools::spline::base_spline::fXmax
double fXmax
Definition: spline:129
tools::spline::quintic::fPoly
std::vector< quintic_poly > fPoly
Definition: spline:697
tools::spline::quintic::build_coeff
void build_coeff()
Definition: spline:479
tools::spline::quintic::find_x
size_t find_x(double x) const
Definition: spline:447