MathTL
numerics/schoenberg_splines.h
00001 // -*- c++ -*-
00002 
00003 // +--------------------------------------------------------------------+
00004 // | This file is part of MathTL - the Mathematical Template Library    |
00005 // |                                                                    |
00006 // | Copyright (c) 2002-2009                                            |
00007 // | Thorsten Raasch, Manuel Werner                                     |
00008 // +--------------------------------------------------------------------+
00009 
00010 #ifndef _MATHTL_SCHOENBERG_SPLINES_H
00011 #define _MATHTL_SCHOENBERG_SPLINES_H
00012 
00013 #include <cmath>
00014 #include <utils/function.h>
00015 #include <numerics/splines.h>
00016 #include <numerics/cardinal_splines.h>
00017 
00018 namespace MathTL
00019 {
00030   template <int d>
00031   class SchoenbergKnotSequence
00032     : public KnotSequence
00033   {
00034   public:
00035     /*
00036       index of the first knot
00037     */
00038     int k0() const { return -d+1; }
00039     
00043     double knot(const int k) const { return std::max(0,k); }
00044   };
00045   
00049   template <int d>
00050   double EvaluateSchoenbergBSpline(const int k, const double x)
00051   {
00052     double r(0);
00053 
00054     // take care of the multiple knot t_{-d+1} = ... = t_0
00055 #if 0
00056     const double diff1 = std::max(0,k+d-1) - std::max(0,k);
00057     if (diff1 > 0) r += (x - std::max(0,k)) * EvaluateSchoenbergBSpline<d-1>(k, x) / diff1;
00058 
00059     const double diff2 = std::max(0,k+d) - std::max(0,k+1);
00060     if (diff2 > 0) r += (std::max(0,k+d) - x) * EvaluateSchoenbergBSpline<d-1>(k+1, x) / diff2;
00061 #else
00062     if (k <= 0)
00063       {
00064         const double diff1 = std::max(0,k+d-1);
00065         if (diff1 > 0) r += x * EvaluateSchoenbergBSpline<d-1>(k, x) / diff1;
00066         
00067         const double diff2 = std::max(0,k+d) - std::max(0,k+1);
00068         if (diff2 > 0) r += (std::max(0,k+d) - x) * EvaluateSchoenbergBSpline<d-1>(k+1, x) / diff2;
00069       }
00070     else
00071       return ((x-k) * EvaluateSchoenbergBSpline<d-1>(k, x)
00072               +(k+d-x) * EvaluateSchoenbergBSpline<d-1>(k+1, x)) / (d - 1);
00073 #endif
00074     
00075     return r;
00076   }
00077   
00081   template <>
00082   inline
00083   double EvaluateSchoenbergBSpline<1>(const int k, const double x)
00084   {
00085 #if 0
00086     return (x >= std::max(0,k) && x < std::max(0,k+1) ? 1.0 : 0.0);
00087 #else
00088     if (k <= 0)
00089       return (x >= 0 && x < std::max(0,k+1) ? 1.0 : 0.0);
00090     else
00091       return (x >= k && x < k+1 ? 1.0 : 0.0);
00092 #endif
00093   }
00094 
00098   template <>
00099   inline
00100   double EvaluateSchoenbergBSpline<2>(const int k, const double x)
00101   {
00102     return (x < 0 ? 0 : EvaluateCardinalBSpline<2>(k, x));
00103   }
00104 
00109   template <int d>
00110   inline
00111   double EvaluateSchoenbergBSpline_td(const int j, const int k, const double x)
00112   {
00113 #if 0
00114     const double factor(1 << j);
00115     return sqrt(factor) * EvaluateSchoenbergBSpline<d>(k-(d/2), factor * x);
00116 #else
00117     return twotothejhalf(j) * EvaluateSchoenbergBSpline<d>(k-(d/2), (1<<j) * x);
00118 #endif
00119   }
00123   template <int d>
00124   inline
00125   double EvaluateSchoenbergBSpline_x(const int k, const double x)
00126   {
00127     double r(0);
00128 
00129     if (k == 1-d) {
00130       r = (1-d) * EvaluateSchoenbergBSpline<d-1>(2-d, x);
00131     } else {
00132       if (k >= 0)
00133         r = EvaluateSchoenbergBSpline<d-1>(k, x) - EvaluateSchoenbergBSpline<d-1>(k+1, x);
00134       else
00135         r = (d-1) * (EvaluateSchoenbergBSpline<d-1>(k, x) / (k+d-1)
00136                      - EvaluateSchoenbergBSpline<d-1>(k+1, x) / (k+d));
00137     }
00138 
00139     return r;
00140   }
00141   
00145   template <>
00146   inline
00147   double EvaluateSchoenbergBSpline_x<1>(const int k, const double x)
00148   {
00149     return 0.;
00150   }
00151 
00155   template <int d>
00156   inline
00157   double EvaluateSchoenbergBSpline_xx(const int k, const double x)
00158   {
00159     double r(0);
00160     
00161     if (k == 1-d) {
00162       r = (1-d) * EvaluateSchoenbergBSpline_x<d-1>(2-d, x);
00163     } else {
00164       if (k >= 0)
00165         r = EvaluateSchoenbergBSpline_x<d-1>(k, x) - EvaluateSchoenbergBSpline_x<d-1>(k+1, x);
00166       else
00167         r = (d-1) * (EvaluateSchoenbergBSpline_x<d-1>(k, x) / (k+d-1)
00168                      - EvaluateSchoenbergBSpline_x<d-1>(k+1, x) / (k+d));
00169     }
00170 
00171     return r;
00172   }
00173   
00177   template <>
00178   inline
00179   double EvaluateSchoenbergBSpline_xx<1>(const int k, const double x)
00180   {
00181     return 0.;
00182   }
00183 
00188   template <int d>
00189   inline
00190   double EvaluateSchoenbergBSpline_td_x(const int j, const int k, const double x)
00191   {
00192 #if 0
00193     const double factor(1 << j);
00194     return factor * sqrt(factor) * EvaluateSchoenbergBSpline_x<d>(k-(d/2), factor * x);
00195 #else
00196     return twotothejhalf(3*j) * EvaluateSchoenbergBSpline_x<d>(k-(d/2), (1<<j) * x);
00197 #endif
00198   }
00199 
00204   template <int d>
00205   inline
00206   double EvaluateSchoenbergBSpline_td_xx(const int j, const int k, const double x)
00207   {
00208 #if 0
00209     const double factor(1 << j);
00210     return  factor * factor * sqrt(factor) * EvaluateSchoenbergBSpline_xx<d>(k-(d/2), factor * x);
00211 #else
00212     return twotothejhalf(5*j) * EvaluateSchoenbergBSpline_xx<d>(k-(d/2), (1<<j) * x);
00213 #endif
00214   }
00215 
00216 
00217 /*
00218    expand a Schoenbergspline as a Picewise Polynomial funktion 
00219    f = 1 falls es sich um einen Generator an der rechten Intervall Grenze handelt
00220    f = 0 sonst
00221 */
00222 template <int d>
00223   Piecewise<double> ExpandSchoenbergBspline(const int j, const int k, const int f)
00224 {
00225   Piecewise<double> r(j);
00226   Polynomial<double> p, q;
00227   if (f==0){
00228     p.set_coefficient(0, floor((double) d/2.0) -k);  //floor((double) d/2.0)
00229     p.set_coefficient(1, ldexp(1.0, j)); // p(x)=2^jx-k+floor(d/2)
00230   }
00231   else{
00232     p.set_coefficient(0, floor((double) d/2.0) + ldexp(1.0, j) -k);
00233     p.set_coefficient(1, -ldexp(1.0, j));
00234   }
00235   double factor = sqrt(ldexp(1.0, j));
00236   int m, n;
00237   SparseMatrix<double> coeffs(d, d);
00238   switch(d) // precalculated entries for 1<=d<=4
00239     {
00240     case 1:
00241       {
00242         if (k>=0) {coeffs.set_entry(0, 0, 1);} // k-floor((double) d/2.0) >=0
00243         else {coeffs.set_entry(0, 0, 0);}
00244       }
00245       break;
00246     case 2:
00247       {
00248         if (k>=1) {   // k-floor((double) d/2.0) >=0
00249         coeffs.set_entry(1, 0, 1);
00250 
00251         coeffs.set_entry(0, 1, 2);
00252         coeffs.set_entry(1, 1, -1);}
00253         else if (k>= 0) {  // k-floor((double) d/2.0) >=-1
00254         coeffs.set_entry(0, 1, 2);
00255         coeffs.set_entry(1, 1, -1);}
00256       }
00257       break;
00258     case 3:
00259       {
00260         if (k>=1) { // k-floor((double) d/2.0) >=0
00261         coeffs.set_entry(2, 0, 0.5);
00262 
00263         coeffs.set_entry(0, 1, -1.5);
00264         coeffs.set_entry(1, 1, 3);
00265         coeffs.set_entry(2, 1, -1);
00266 
00267         coeffs.set_entry(0, 2, 4.5);
00268         coeffs.set_entry(1, 2, -3);
00269         coeffs.set_entry(2, 2, 0.5);
00270         }
00271         else if (k>=0){ // k-floor((double) d/2.0) >=-1
00272         coeffs.set_entry(0, 1, -3.5);
00273         coeffs.set_entry(1, 1, 5.0);
00274         coeffs.set_entry(2, 1, -1.5);
00275 
00276         coeffs.set_entry(0, 2, 4.5);
00277         coeffs.set_entry(1, 2, -3);
00278         coeffs.set_entry(2, 2, 0.5);
00279         }
00280         else if (k>=-1){ // k-floor((double) d/2.0) >=-2
00281         coeffs.set_entry(0, 2, 9);
00282         coeffs.set_entry(1, 2, -6);
00283         coeffs.set_entry(2, 2, 1);}
00284       }
00285       break;
00286     case 4:
00287       {
00288         if (k>=2) { // k-floor((double) d/2.0) >=0
00289         coeffs.set_entry(3, 0, 1.0/6.0);
00290 
00291         coeffs.set_entry(0, 1, 2.0/3.0);
00292         coeffs.set_entry(1, 1, -2);
00293         coeffs.set_entry(2, 1, 2);
00294         coeffs.set_entry(3, 1, -0.5);
00295 
00296         coeffs.set_entry(0, 2, -22.0/3.0);
00297         coeffs.set_entry(1, 2, 10);
00298         coeffs.set_entry(2, 2, -4);
00299         coeffs.set_entry(3, 2, 0.5);
00300 
00301         coeffs.set_entry(0, 3, 32.0/3.0);
00302         coeffs.set_entry(1, 3, -8);
00303         coeffs.set_entry(2, 3, 2);
00304         coeffs.set_entry(3, 3, -1.0/6.0);
00305         }
00306         else if (k>=1){ // k-floor((double) d/2.0) >=-1
00307         coeffs.set_entry(0, 1, 29.0/12.0);
00308         coeffs.set_entry(1, 1, -5.75);
00309         coeffs.set_entry(2, 1, 4.25);
00310         coeffs.set_entry(3, 1, -5.5/6.0);
00311 
00312         coeffs.set_entry(0, 2, -115.0/12.0); 
00313         coeffs.set_entry(1, 2, 12.25); 
00314         coeffs.set_entry(2, 2, -4.75);
00315         coeffs.set_entry(3, 2, 7.0/12.0);
00316 
00317         coeffs.set_entry(0, 3, 32.0/3.0);
00318         coeffs.set_entry(1, 3, -8);
00319         coeffs.set_entry(2, 3, 2);
00320         coeffs.set_entry(3, 3, -1.0/6.0);
00321         }
00322         else if (k>=0){ // k-floor((double) d/2.0) >=-2
00323         coeffs.set_entry(0, 2, -38.0); 
00324         coeffs.set_entry(1, 2, 42.0); 
00325         coeffs.set_entry(2, 2, -15.0);
00326         coeffs.set_entry(3, 2, 21.0/12.0);
00327 
00328         coeffs.set_entry(0, 3, 16.0);
00329         coeffs.set_entry(1, 3, -12.0);
00330         coeffs.set_entry(2, 3, 3.0);
00331         coeffs.set_entry(3, 3, -0.25);
00332         }
00333         else if (k>=-1){ // k-floor((double) d/2.0) >=-3
00334         coeffs.set_entry(0, 3, 64.0);
00335         coeffs.set_entry(1, 3, -48.0);
00336         coeffs.set_entry(2, 3, 12.0);
00337         coeffs.set_entry(3, 3, -1.0);
00338         }
00339       }
00340       break;
00341     default:
00342     {
00343       return r;
00344       //coeffs = localBSplineCoeffs(d);
00345     }
00346 }
00347   for (n=0; n<=d-1; n++)
00348     {
00349      // coeffs.findc(n, ind);
00350      // CoeffsType col;
00351       for (m=0; m<=d-1; m++)
00352         q.set_coefficient(m, coeffs.get_entry(m, n));
00353       if (f==0){
00354         r.set_local_expansion(n + k - floor((double) d/2.0), q.substitute_into(p));  //(int)floor((double) d/2.0)
00355       } 
00356       else {
00357         r.set_local_expansion((int)ldexp(1.0, j) - n - k + floor((double) d/2.0) -1, q.substitute_into(p));
00358       }
00359     }
00360   r *= factor;
00361 
00362   return r;
00363    
00364 }
00365 
00366 
00367 
00368 
00369 
00373   template <int d>
00374   class SchoenbergBSpline_td : public Function<1>
00375   {
00376   public:
00378     SchoenbergBSpline_td(const int j, const int k)
00379       : j_(j), k_(k) {}
00380     
00382     virtual ~SchoenbergBSpline_td() {}
00383 
00385     inline double value(const Point<1>& p,
00386                         const unsigned int component = 0) const
00387     {
00388       return EvaluateSchoenbergBSpline_td<d>(j_, k_, p[0]);
00389     }
00390   
00392     void vector_value(const Point<1> &p,
00393                       Vector<double>& values) const
00394     {
00395       values.resize(1, false);
00396       values[0] = value(p);
00397     }
00398    
00400     void set_j(const int j) { j_ = j; }
00401     
00403     void set_k(const int k) { k_ = k; }
00404     
00405   protected:
00406     int j_, k_;
00407   };
00408 
00409 }
00410 
00411 #endif
 All Classes Functions Variables Typedefs Enumerations