Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/externals/g4tools/include/tools/spline

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

Diff markup

Differences between /externals/g4tools/include/tools/spline (Version 11.3.0) and /externals/g4tools/include/tools/spline (Version 1.0)


  1 // Copyright (C) 2010, Guy Barrand. All rights    
  2 // See the file tools.license for terms.          
  3                                                   
  4 #ifndef tools_spline                              
  5 #define tools_spline                              
  6                                                   
  7 // From Federico Carminati code found in root-    
  8                                                   
  9 #include "mnmx"                                   
 10 #include <cstddef>                                
 11 #include <vector>                                 
 12 #include <ostream>                                
 13 #include <cmath>                                  
 14                                                   
 15 namespace tools {                                 
 16 namespace spline {                                
 17                                                   
 18 class base_poly {                                 
 19 public:                                           
 20   base_poly():fX(0),fY(0) {}                      
 21   base_poly(double x,double y):fX(x),fY(y) {}     
 22   virtual ~base_poly(){}                          
 23 public:                                           
 24   base_poly(base_poly const &a_from):fX(a_from    
 25   base_poly& operator=(base_poly const &a_from    
 26     if(this==&a_from) return *this;               
 27     fX = a_from.fX;                               
 28     fY = a_from.fY;                               
 29     return *this;                                 
 30   }                                               
 31 public:                                           
 32   const double& X() const {return fX;}            
 33   const double& Y() const {return fY;}            
 34   double &X() {return fX;}                        
 35   double &Y() {return fY;}                        
 36 protected:                                        
 37   double fX;     // abscissa                      
 38   double fY;     // constant term                 
 39 };                                                
 40                                                   
 41 class cubic_poly : public base_poly {             
 42 public:                                           
 43   cubic_poly():fB(0), fC(0), fD(0) {}             
 44   cubic_poly(double x, double y, double b, dou    
 45 public:                                           
 46   cubic_poly(cubic_poly const &a_from)            
 47   :base_poly(a_from), fB(a_from.fB), fC(a_from    
 48   cubic_poly& operator=(cubic_poly const &a_fr    
 49     if(this==&a_from) return *this;               
 50     base_poly::operator=(a_from);                 
 51     fB = a_from.fB;                               
 52     fC = a_from.fC;                               
 53     fD = a_from.fD;                               
 54     return *this;                                 
 55   }                                               
 56 public:                                           
 57   double &B() {return fB;}                        
 58   double &C() {return fC;}                        
 59   double &D() {return fD;}                        
 60   double eval(double x) const {double dx=x-fX;    
 61 protected:                                        
 62   double fB; // first order expansion coeffici    
 63   double fC; // second order expansion coeffic    
 64   double fD; // third order expansion coeffici    
 65 };                                                
 66                                                   
 67 class quintic_poly : public base_poly {           
 68 public:                                           
 69   quintic_poly():fB(0), fC(0), fD(0), fE(0), f    
 70   quintic_poly(double x, double y, double b, d    
 71   :base_poly(x,y), fB(b), fC(c), fD(d), fE(e),    
 72 public:                                           
 73   quintic_poly(quintic_poly const &a_from)        
 74   :base_poly(a_from)                              
 75   ,fB(a_from.fB),fC(a_from.fC),fD(a_from.fD),f    
 76   quintic_poly& operator=(quintic_poly const &    
 77     if(this==&a_from) return *this;               
 78     base_poly::operator=(a_from);                 
 79     fB = a_from.fB;                               
 80     fC = a_from.fC;                               
 81     fD = a_from.fD;                               
 82     fE = a_from.fE;                               
 83     fF = a_from.fF;                               
 84     return *this;                                 
 85   }                                               
 86 public:                                           
 87   double &B() {return fB;}                        
 88   double &C() {return fC;}                        
 89   double &D() {return fD;}                        
 90   double &E() {return fE;}                        
 91   double &F() {return fF;}                        
 92   double eval(double x) const {double dx=x-fX;    
 93 protected:                                        
 94   double fB; // first order expansion coeffici    
 95   double fC; // second order expansion coeffic    
 96   double fD; // third order expansion coeffici    
 97   double fE; // fourth order expansion coeffic    
 98   double fF; // fifth order expansion coeffici    
 99 };                                                
100                                                   
101 //////////////////////////////////////////////    
102 //////////////////////////////////////////////    
103 //////////////////////////////////////////////    
104 class base_spline {                               
105 protected:                                        
106   base_spline(std::ostream& a_out):m_out(a_out    
107 public:                                           
108   base_spline(std::ostream& a_out,double delta    
109   :m_out(a_out),fDelta(delta), fXmin(xmin),fXm    
110   {}                                              
111   virtual ~base_spline() {}                       
112 protected:                                        
113   base_spline(const base_spline& a_from)          
114   :m_out(a_from.m_out)                            
115   ,fDelta(a_from.fDelta),fXmin(a_from.fXmin),f    
116   base_spline& operator=(const base_spline& a_    
117     if(this==&a_from) return *this;               
118     fDelta=a_from.fDelta;                         
119     fXmin=a_from.fXmin;                           
120     fXmax=a_from.fXmax;                           
121     fNp=a_from.fNp;                               
122     fKstep=a_from.fKstep;                         
123     return *this;                                 
124   }                                               
125 protected:                                        
126   std::ostream& m_out;                            
127   double  fDelta;     // Distance between equi    
128   double  fXmin;      // Minimum value of absc    
129   double  fXmax;      // Maximum value of absc    
130   size_t  fNp;        // Number of knots          
131   bool    fKstep;     // True of equidistant k    
132 };                                                
133                                                   
134                                                   
135 //////////////////////////////////////////////    
136 //                                                
137 // cubic                                          
138 //                                                
139 // Class to create third splines to interpolat    
140 // Arbitrary conditions can be introduced for     
141 // derivatives at beginning and ending points     
142 //                                                
143 //////////////////////////////////////////////    
144                                                   
145 class cubic : public base_spline {                
146 protected:                                        
147   cubic(std::ostream& a_out) : base_spline(a_o    
148 public:                                           
149   cubic(std::ostream& a_out,size_t a_n,double     
150   :base_spline(a_out,-1,0,0,a_n,false)            
151   ,fValBeg(a_valbeg), fValEnd(a_valend), fBegC    
152   {                                               
153     if(!a_n) {                                    
154       m_out << "tools::spline::cubic : a_np is    
155       return;                                     
156     }                                             
157     fXmin = a_x[0];                               
158     fXmax = a_x[a_n-1];                           
159     fPoly.resize(a_n);                            
160     for (size_t i=0; i<a_n; ++i) {                
161        fPoly[i].X() = a_x[i];                     
162        fPoly[i].Y() = a_y[i];                     
163     }                                             
164     build_coeff(); // Build the spline coeffic    
165   }                                               
166 public:                                           
167   cubic(const cubic& a_from)                      
168   :base_spline(a_from)                            
169   ,fPoly(a_from.fPoly),fValBeg(a_from.fValBeg)    
170   {}                                              
171   cubic& operator=(const cubic& a_from) {         
172     if(this==&a_from) return *this;               
173     base_spline::operator=(a_from);               
174     fPoly = a_from.fPoly;                         
175     fValBeg=a_from.fValBeg;                       
176     fValEnd=a_from.fValEnd;                       
177     fBegCond=a_from.fBegCond;                     
178     fEndCond=a_from.fEndCond;                     
179     return *this;                                 
180   }                                               
181 public:                                           
182   double eval(double x) const {                   
183     if(!fNp) return 0;                            
184     // Eval this spline at x                      
185     size_t klow = find_x(x);                      
186     if ( (fNp > 1) && (klow >= (fNp-1))) klow     
187     return fPoly[klow].eval(x);                   
188   }                                               
189 protected:                                        
190   template<typename T>                            
191   static int TMath_Nint(T x) {                    
192     // Round to nearest integer. Rounds half i    
193     int i;                                        
194     if (x >= 0) {                                 
195       i = int(x + 0.5);                           
196       if ( i & 1 && x + 0.5 == T(i) ) i--;        
197     } else {                                      
198       i = int(x - 0.5);                           
199       if ( i & 1 && x - 0.5 == T(i) ) i++;        
200     }                                             
201     return i;                                     
202   }                                               
203   static int TMath_FloorNint(double x) { retur    
204                                                   
205   size_t find_x(double x) const {                 
206     int klow=0, khig=int(fNp-1);                  
207     //                                            
208     // If out of boundaries, extrapolate          
209     // It may be badly wrong                      
210     if(x<=fXmin) klow=0;                          
211     else if(x>=fXmax) klow=khig;                  
212     else {                                        
213       if(fKstep) { // Equidistant knots, use h    
214          klow = TMath_FloorNint((x-fXmin)/fDel    
215          // Correction for rounding errors        
216          if (x < fPoly[klow].X())                 
217            klow = mx<int>(klow-1,0);              
218          else if (klow < khig) {                  
219            if (x > fPoly[klow+1].X()) ++klow;     
220          }                                        
221       } else {                                    
222          int khalf;                               
223          //                                       
224          // Non equidistant knots, binary sear    
225          while((khig-klow)>1) {                   
226            khalf = (klow+khig)/2;                 
227            if(x>fPoly[khalf].X()) klow=khalf;     
228            else                   khig=khalf;     
229          }                                        
230          //                                       
231          // This could be removed, sanity chec    
232          if( (x<fPoly[klow].X()) || (fPoly[klo    
233             m_out << "tools::spline::cubic::fi    
234                   << " x(" << klow << ") = " <    
235                   << " < x(" << klow+1 << ") =    
236       << "." << std::endl;                        
237          }                                        
238       }                                           
239     }                                             
240     return klow;                                  
241   }                                               
242                                                   
243   void build_coeff() {                            
244     ///      subroutine cubspl ( tau, c, n, ib    
245     ///  from  * a practical guide to splines     
246     ///     ************************  input  *    
247     ///     n = number of data points. assumed    
248     ///     (tau(i), c(1,i), i=1,...,n) = absc    
249     ///        data points. tau is assumed to     
250     ///     ibcbeg, ibcend = boundary conditio    
251     ///     c(2,1), c(2,n) = boundary conditio    
252     ///        ibcbeg = 0  means no boundary c    
253     ///           in this case, the not-a-knot    
254     ///           jump in the third derivative    
255     ///           zero, thus the first and the    
256     ///           are made to coincide.)          
257     ///        ibcbeg = 1  means that the slop    
258     ///           c(2,1), supplied by input.      
259     ///        ibcbeg = 2  means that the seco    
260     ///           made to equal c(2,1), suppli    
261     ///        ibcend = 0, 1, or 2 has analogo    
262     ///           boundary condition at tau(n)    
263     ///           mation taken from c(2,n).       
264     ///     ***********************  output  *    
265     ///     c(j,i), j=1,...,4; i=1,...,l (= n-    
266     ///        of the cubic interpolating spli    
267     ///        joints) tau(2), ..., tau(n-1).     
268     ///        (tau(i), tau(i+1)), the spline     
269     ///           f(x) = c(1,i)+h*(c(2,i)+h*(c    
270     ///        where h = x - tau(i). the funct    
271     ///        used to evaluate f or its deriv    
272     ///        and k=4.                           
273                                                   
274     int j, l;                                     
275     double   divdf1,divdf3,dtau,g=0;              
276     // ***** a tridiagonal linear system for t    
277     //  f  at tau(i), i=1,...,n, is generated     
278     //  ination, with s(i) ending up in c(2,i)    
279     //     c(3,.) and c(4,.) are used initiall    
280     l = int(fNp-1);                               
281     // compute first differences of x sequence    
282     // compute first divided difference of dat    
283    {for (size_t m=1; m<fNp ; ++m) {               
284        fPoly[m].C() = fPoly[m].X() - fPoly[m-1    
285        fPoly[m].D() = (fPoly[m].Y() - fPoly[m-    
286     }}                                            
287     // construct first equation from the bound    
288     //             D[0]*s[0] + C[0]*s[1] = B[0    
289     if(fBegCond==0) {                             
290        if(fNp == 2) {                             
291          //     no condition at left end and n    
292          fPoly[0].D() = 1.;                       
293          fPoly[0].C() = 1.;                       
294          fPoly[0].B() = 2.*fPoly[1].D();          
295       } else {                                    
296          //     not-a-knot condition at left e    
297          fPoly[0].D() = fPoly[2].C();             
298          fPoly[0].C() = fPoly[1].C() + fPoly[2    
299          fPoly[0].B() = ((fPoly[1].C()+2.*fPol    
300                   fPoly[1].C()*fPoly[1].C()*fP    
301       }                                           
302     } else if (fBegCond==1) {                     
303       //     slope prescribed at left end.        
304       fPoly[0].B() = fValBeg;                     
305       fPoly[0].D() = 1.;                          
306       fPoly[0].C() = 0.;                          
307     } else if (fBegCond==2) {                     
308       //     second derivative prescribed at l    
309       fPoly[0].D() = 2.;                          
310       fPoly[0].C() = 1.;                          
311       fPoly[0].B() = 3.*fPoly[1].D() - fPoly[1    
312     }                                             
313     bool forward_gauss_elimination = true;        
314     if(fNp > 2) {                                 
315       //  if there are interior knots, generat    
316       //  ry out the forward pass of gauss eli    
317       //  equation reads    D[m]*s[m] + C[m]*s    
318      {for (int m=1; m<l; ++m) {                   
319          g = -fPoly[m+1].C()/fPoly[m-1].D();      
320          fPoly[m].B() = g*fPoly[m-1].B() + 3.*    
321          fPoly[m].D() = g*fPoly[m-1].C() + 2.*    
322       }}                                          
323       // construct last equation from the seco    
324       //           (-g*D[n-2])*s[n-2] + D[n-1]    
325       //     if slope is prescribed at right e    
326       //     substitution, since c array happe    
327       //     at this point.                       
328       if(fEndCond == 0) {                         
329          if (fNp > 3 || fBegCond != 0) {          
330             //     not-a-knot and n .ge. 3, an    
331             //     left end point.                
332             g = fPoly[fNp-2].C() + fPoly[fNp-1    
333             fPoly[fNp-1].B() = ((fPoly[fNp-1].    
334                          + fPoly[fNp-1].C()*fP    
335             g = -g/fPoly[fNp-2].D();              
336             fPoly[fNp-1].D() = fPoly[fNp-2].C(    
337          } else {                                 
338             //     either (n=3 and not-a-knot     
339             //     knot at left end point).       
340             fPoly[fNp-1].B() = 2.*fPoly[fNp-1]    
341             fPoly[fNp-1].D() = 1.;                
342             g = -1./fPoly[fNp-2].D();             
343          }                                        
344       } else if (fEndCond == 1) {                 
345          fPoly[fNp-1].B() = fValEnd;              
346          forward_gauss_elimination = false;       
347       } else if (fEndCond == 2) {                 
348          //     second derivative prescribed a    
349          fPoly[fNp-1].B() = 3.*fPoly[fNp-1].D(    
350          fPoly[fNp-1].D() = 2.;                   
351          g = -1./fPoly[fNp-2].D();                
352       }                                           
353     } else {                                      
354       if(fEndCond == 0) {                         
355          if (fBegCond > 0) {                      
356             //     either (n=3 and not-a-knot     
357             //     knot at left end point).       
358             fPoly[fNp-1].B() = 2.*fPoly[fNp-1]    
359             fPoly[fNp-1].D() = 1.;                
360             g = -1./fPoly[fNp-2].D();             
361          } else {                                 
362             //     not-a-knot at right endpoin    
363             fPoly[fNp-1].B() = fPoly[fNp-1].D(    
364             forward_gauss_elimination = false;    
365          }                                        
366       } else if(fEndCond == 1) {                  
367          fPoly[fNp-1].B() = fValEnd;              
368          forward_gauss_elimination = false;       
369       } else if(fEndCond == 2) {                  
370          //     second derivative prescribed a    
371          fPoly[fNp-1].B() = 3.*fPoly[fNp-1].D(    
372          fPoly[fNp-1].D() = 2.;                   
373          g = -1./fPoly[fNp-2].D();                
374       }                                           
375     }                                             
376     // complete forward pass of gauss eliminat    
377     if(forward_gauss_elimination) {               
378       fPoly[fNp-1].D() = g*fPoly[fNp-2].C() +     
379       fPoly[fNp-1].B() = (g*fPoly[fNp-2].B() +    
380     }                                             
381     // carry out back substitution                
382     j = l-1;                                      
383     do {                                          
384        fPoly[j].B() = (fPoly[j].B() - fPoly[j]    
385        --j;                                       
386     }  while (j>=0);                              
387     // ****** generate cubic coefficients in e    
388     //  at its left endpoint, from value and s    
389     for (size_t i=1; i<fNp; ++i) {                
390        dtau = fPoly[i].C();                       
391        divdf1 = (fPoly[i].Y() - fPoly[i-1].Y()    
392        divdf3 = fPoly[i-1].B() + fPoly[i].B()     
393        fPoly[i-1].C() = (divdf1 - fPoly[i-1].B    
394        fPoly[i-1].D() = (divdf3/dtau)/dtau;       
395     }                                             
396   }                                               
397                                                   
398 protected:                                        
399   std::vector<cubic_poly> fPoly; //[fNp] Array    
400   double        fValBeg;     // Initial value     
401   double        fValEnd;     // End value of f    
402   int           fBegCond;    // 0=no beg cond,    
403   int           fEndCond;    // 0=no end cond,    
404 };                                                
405                                                   
406 //////////////////////////////////////////////    
407 //                                                
408 // quintic                                        
409 //                                                
410 // Class to create quintic natural splines to     
411 // Arbitrary conditions can be introduced for     
412 // derivatives using double knots (see build_c    
413 // Double knots are automatically introduced a    
414 //                                                
415 //////////////////////////////////////////////    
416 class quintic : public base_spline {              
417 protected:                                        
418   quintic(std::ostream& a_out):base_spline(a_o    
419 public:                                           
420   quintic(std::ostream& a_out,size_t a_n ,doub    
421   :base_spline(a_out,-1,0,0,a_n,false) {          
422     if(!a_n) {                                    
423       m_out << "tools::spline::quintic : a_np     
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 coeffic    
434   }                                               
435 public:                                           
436   quintic(const quintic& a_from):base_spline(a    
437   quintic& operator=(const quintic& a_from) {     
438     if(this==&a_from) return *this;               
439     base_spline::operator=(a_from);               
440     fPoly = a_from.fPoly;                         
441     return *this;                                 
442   }                                               
443 public:                                           
444   double eval(double x) const {if(!fNp) return    
445                                                   
446 protected:                                        
447   size_t find_x(double x) const {                 
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=int(fNp-1);            
454     else {                                        
455       if(fKstep) { // Equidistant knots, use h    
456         klow = mn<int>(int((x-fXmin)/fDelta),i    
457       } else {                                    
458         int khig=int(fNp-1);                      
459         int khalf;                                
460         // Non equidistant knots, binary searc    
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    
470         m_out << "tools::spline::quintic::find    
471               << " x(" << klow << ") = " << fP    
472               << " < x(" << klow+1<< ") = " <<    
473         << std::endl;                             
474       }                                           
475     }                                             
476     return klow;                                  
477   }                                               
478                                                   
479   void build_coeff() {                            
480     //////////////////////////////////////////    
481     ///     algorithm 600, collected algorithm    
482     ///     algorithm appeared in acm-trans. m    
483     ///     jun., 1983, p. 258-259.               
484     ///                                           
485     ///     quintic computes the coefficients     
486     ///     s(x) with knots x(i) interpolating    
487     ///               s(x(i)) = y(i)  for i =     
488     ///     in each interval (x(i),x(i+1)) the    
489     ///     polynomial of fifth degree:           
490     ///     s(xx) = ((((f(i)*p+e(i))*p+d(i))*p    
491     ///           = ((((-f(i)*q+e(i+1))*q-d(i+    
492     ///     where  p = xx - x(i)  and  q = x(i    
493     ///     (note the first subscript in the s    
494     ///     the different polynomials are piec    
495     ///     its derivatives up to s"" are cont    
496     ///                                           
497     ///        input:                             
498     ///                                           
499     ///     n          number of data points,     
500     ///     x(1:n)     the strictly increasing    
501     ///                knots.  the spacing mus    
502     ///                of x(i+1) - x(i) can be    
503     ///                underflow of exponents.    
504     ///     y(1:n)     the prescribed function    
505     ///                                           
506     ///        output:                            
507     ///                                           
508     ///     b,c,d,e,f  the computed spline coe    
509     ///         (1:n)  specifically               
510     ///                b(i) = s'(x(i)), c(i) =    
511     ///                e(i) = s""(x(i))/24,  f    
512     ///                f(n) is neither used no    
513     ///                b,c,d,e,f must always b    
514     ///                                           
515     ///        option:                            
516     ///                                           
517     ///     it is possible to specify values f    
518     ///     derivatives of the spline function    
519     ///     this is done by relaxing the requi    
520     ///     knots be strictly increasing or de    
521     ///                                           
522     ///     if x(j) = x(j+1) then s(x(j)) = y(    
523     ///     if x(j) = x(j+1) = x(j+2) then in     
524     ///                                           
525     ///     note that s""(x) is discontinuous     
526     ///     addition, s"'(x) is discontinuous     
527     ///     subroutine assigns y(i) to y(i+1)     
528     ///     y(i+2) at a triple knot.  the repr    
529     ///     valid in each open interval (x(i),    
530     ///     x(j) = x(j+1), the output coeffici    
531     ///       y(j) = s(x(j))          = y(j+1)    
532     ///       b(j) = s'(x(j))         = b(j+1)    
533     ///       c(j) = s"(x(j))/2       = c(j+1)    
534     ///       d(j) = s"'(x(j))/6      = d(j+1)    
535     ///       e(j) = s""(x(j)-0)/24     e(j+1)    
536     ///       f(j) = s""'(x(j)-0)/120   f(j+1)    
537     ///     at a triple knot, x(j) = x(j+1) =     
538     ///     coefficients have the following va    
539     ///       y(j) = s(x(j))         = y(j+1)     
540     ///       b(j) = s'(x(j))        = b(j+1)     
541     ///       c(j) = s"(x(j))/2      = c(j+1)     
542     ///       d(j) = s"'((x(j)-0)/6    d(j+1)     
543     ///       e(j) = s""(x(j)-0)/24    e(j+1)     
544     ///       f(j) = s""'(x(j)-0)/120  f(j+1)     
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    
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+    
580                                   *(pr* 20.+q2    
581                                   ((p2+r2)*8.+    
582              fPoly[i-1].D() += q3*6./(pq*pq);     
583              fPoly[i].E() = q2*(p*qr+pq*3.*(qr    
584              fPoly[i-1].E() += q2*(r*pq+qr*3.*    
585              fPoly[i-1].F() = q3/pqqr;            
586           } else                                  
587              fPoly[i+1].D() = fPoly[i].E() = f    
588        }                                          
589     }                                             
590     if (r) fPoly[_m-1].D() += r*6.*r2/(qr*qr);    
591                                                   
592     //     First and second order divided diff    
593     //     values, stored in b from 2 to n and    
594     //     respectively. care is taken of doub    
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())/(fP    
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())/(fP    
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)    
615     if (_m > 1) {                                 
616        p=fPoly[0].C()=fPoly[_m-1].E()=fPoly[0]    
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    
625              fPoly[i].E() -= q*fPoly[i-1].F();    
626              fPoly[i].C() = fPoly[i+2].C()-fPo    
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    
637                          -fPoly[i].F()*fPoly[i    
638                                                   
639     //     Integrate the third derivative of s    
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    
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(    
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)*1    
672           fPoly[i].C() =                          
673           fPoly[i].D()*(p-q)+(fPoly[i+1].B()-f    
674                              p3-(v+fPoly[i].E(    
675           fPoly[i].B() = (p*(fPoly[i+1].B()-v*    
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[    
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   }                                               
696 protected:                                        
697   std::vector<quintic_poly> fPoly;     //[fNp]    
698 };                                                
699                                                   
700 }}                                                
701                                                   
702 #endif