MathTL
numerics/cardinal_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_CARDINAL_SPLINES_H
00011 #define _MATHTL_CARDINAL_SPLINES_H
00012 
00013 #include <cmath>
00014 #include <utils/function.h>
00015 #include <numerics/splines.h>
00016 #include <utils/tiny_tools.h>
00017 #include <algebra/piecewise.h>
00018 #include <algebra/polynomial.h>
00019 #include <algebra/sparse_matrix.h>
00020 
00021 namespace MathTL
00022 {
00026   template <int d>
00027   class CardinalKnotSequence
00028     : public KnotSequence
00029   {
00030   public:
00031     /*
00032       index of the first knot
00033     */
00034     int k0() const { return -d+1; }
00035     
00039     double knot(const int k) const { return k; }
00040   };
00041 
00046   template <int d>
00047   inline
00048   double EvaluateCardinalBSpline(const double x)
00049   {
00050     return (x < 0 || x >= d ? 0
00051             : (x * EvaluateCardinalBSpline<d-1>(x)
00052                + (d-x) * EvaluateCardinalBSpline<d-1>(x-1)) / (d-1));
00053   }
00054 
00059   template <>
00060   double EvaluateCardinalBSpline<3>(const double x)
00061   {
00062     if (x < 0 || x >= 3)
00063       return 0;
00064     if (x < 1)
00065       return x*x/2;
00066     else
00067       return (x < 2 ? x*(3-x)-1.5 : (x*(x-6)+9)/2);
00068   }
00069   
00074   template <>
00075   inline
00076   double EvaluateCardinalBSpline<2>(const double x)
00077   {
00078     return (x < 0 || x >= 2 ? 0 : 1-abs(x-1));
00079   }
00080   
00085   template <>
00086   inline
00087   double EvaluateCardinalBSpline<1>(const double x)
00088   {
00089     return (x < 0 || x >= 1 ? 0 : 1);
00090   }
00091 
00095   template <int d>
00096   inline
00097   double EvaluateCardinalBSpline(const int k, const double x)
00098   {
00099     if (x < k || x >= k+d)
00100       return 0.;
00101     return ((x-k) * EvaluateCardinalBSpline<d-1>(k, x)
00102             + (k+d-x) * EvaluateCardinalBSpline<d-1>(k+1, x)) / (d-1);
00103   }
00104   
00108   template <>
00109   inline
00110   double EvaluateCardinalBSpline<1>(const int k, const double x)
00111   {
00112     if (x < k || x >= k+1)
00113       return 0.0;
00114     return 1.0;
00115   }
00116 
00121   template <int d>
00122   inline
00123   double EvaluateCardinalBSpline_td(const int j, const int k, const double x)
00124   {
00125 #if 0
00126     const double factor(1<<j);
00127     return sqrt(factor) * EvaluateCardinalBSpline<d>(k, factor * x + d/2);
00128 #else
00129     return twotothejhalf(j) * EvaluateCardinalBSpline<d>((1<<j) * x - k + d/2);
00130 #endif
00131   }
00132   
00137   template <int d>
00138   inline
00139   double EvaluateCardinalBSpline_x(const double x)
00140   {
00141     return (x < 0 || x >= d ? 0
00142             : EvaluateCardinalBSpline<d-1>(x) - EvaluateCardinalBSpline<d-1>(x-1));
00143   }
00144   
00149   template <>
00150   inline
00151   double EvaluateCardinalBSpline_x<2>(const double x)
00152   {
00153     if (x < 0 || x >= 2)
00154       return 0;
00155     return (x < 1 ? 1: -1);
00156   }
00157 
00161   template <>
00162   inline
00163   double EvaluateCardinalBSpline_x<1>(const double x)
00164   {
00165     return 0;
00166   }
00167 
00171   template <int d>
00172   inline
00173   double EvaluateCardinalBSpline_x(const int k, const double x)
00174   {
00175     if (x < k || x >= k+d)
00176       return 0;
00177     return EvaluateCardinalBSpline<d-1>(k, x) - EvaluateCardinalBSpline<d-1>(k+1, x);
00178   }
00179 
00183   template <int d>
00184   inline
00185   double EvaluateCardinalBSpline_x_sq(const int k, const double x)
00186   {
00187     return EvaluateCardinalBSpline_x<d-1>(k, x) - EvaluateCardinalBSpline_x<d-1>(k+1, x);
00188   }
00189 
00193   template <>
00194   inline
00195   double EvaluateCardinalBSpline_x<1>(const int k, const double x)
00196   {
00197     return 0;
00198   }
00199   
00204   template <int d>
00205   inline
00206   double EvaluateCardinalBSpline_td_x(const int j, const int k, const double x)
00207   {
00208 #if 0
00209     const double factor(1<<j);
00210     return factor * sqrt(factor) * EvaluateCardinalBSpline_x<d>(k, factor * x + d/2);
00211 #else
00212     return twotothejhalf(3*j) * EvaluateCardinalBSpline_x<d>((1<<j) * x - k + d/2);
00213 #endif
00214   }
00215 
00220   template <int d>
00221   inline
00222   double EvaluateCardinalBSpline_td_x_sq(const int j, const int k, const double x)
00223   {
00224 #if 0
00225     const double factor(1<<j);
00226     return factor * factor * sqrt(factor) * EvaluateCardinalBSpline_x_sq<d>(k, factor * x + d/2);
00227 #else
00228     return twotothejhalf(5*j) * EvaluateCardinalBSpline_x_sq<d>(k, (1<<j) * x + d/2);
00229 #endif
00230   }
00231 
00232 
00238   double EvaluateCardinalBSpline(const int d, const int k, double x)
00239   {
00240     if (x < k)
00241       return 0.;
00242     else
00243       {
00244         if (x >= k+d)
00245           return 0.;
00246         else
00247           {
00248             // we know that x\in\supp N_d(.-k) 
00249             if (d == 1)
00250               return 1.;
00251             else
00252               {
00253                 // hard-encode case d=2 
00254                 if (d == 2)
00255                   {
00256                     if (x < k+1)
00257                       return x-k;
00258                     else
00259                       return 2.-(x-k);
00260                   }
00261                 else
00262                   return ((x-k) * EvaluateCardinalBSpline(d-1, k, x)
00263                           + (k+d-x) * EvaluateCardinalBSpline(d-1, k+1, x)) / (d-1);
00264               }
00265           }
00266       }
00267   }
00268 
00269   
00274   inline double EvaluateCardinalBSpline_td(const int d, const int j, const int k, const double x)
00275   {
00276     const double factor(1<<j);
00277     return sqrt(factor) * EvaluateCardinalBSpline(d, k, factor * x + d/2);
00278   }
00279   
00283   inline double EvaluateCardinalBSpline_x(const int d, const int k, const double x)
00284   {
00285     if (d == 1)
00286       return 0.;
00287     else
00288       return EvaluateCardinalBSpline(d-1, k, x) - EvaluateCardinalBSpline(d-1, k+1, x);
00289   }
00290   
00295   inline double EvaluateCardinalBSpline_td_x(const int d, const int j, const int k, const double x)
00296   {
00297     const double factor(1<<j);
00298     return factor * sqrt(factor) * EvaluateCardinalBSpline_x(d, k, factor * x + d/2);
00299   }
00300 
00301 
00302 /*------------------------------------------------------------------*
00303  *                        n       n   n - k + 1     n       n       *
00304  *  Binomialkoeffizient (   ) = (   ) --------- , (   ) = (   ) = 1 *
00305  *                        k      k-1      k         0       n       *
00306  *                                                                  *
00307  *  Rekursive Berechnung, damit keine zu grossen Zahlen entstehen   *
00308  *------------------------------------------------------------------*/
00309 
00310 double binomd (long int n, long int k)
00311    {
00312    long int i;
00313    long int binomialkoeffizient = 1;
00314 
00315    if (n <  0 || k < 0 || k > n) return (-1);
00316 
00317    if (k == 0 || k == n) return (binomialkoeffizient);
00318 
00319    for (i = 1; i <= k; i++)
00320       binomialkoeffizient = binomialkoeffizient * (n - i + 1) / i;
00321    return (double)(binomialkoeffizient);
00322    } 
00323 
00324 
00325 // helper function for cBspline
00326 SparseMatrix<double> localBSplineCoeffs(const int d)
00327 {
00328   int k, mu, nu;
00329 
00330   SparseMatrix<double> A(d,d);
00331   if(d==1)
00332     {
00333       A.set_entry(0, 0, 1);
00334       return A;
00335     }
00336   else 
00337     {
00338       SparseMatrix<double> B = localBSplineCoeffs(d-1);
00339       // first row (nu=0)
00340 //       A.set_entry(0, 0, 0);
00341       for(k=1; k<d-1; k++)
00342         {
00343 //        A.set_entry(0, k, 0);
00344           for(mu=0; mu<=d-2; mu++)
00345             A.set_entry(0, k, A.get_entry(0, k) + (pow(k, mu+1)*(B.get_entry(mu, k-1)-B.get_entry(mu, k)) + pow(-1, mu)*B.get_entry(mu, k-1))/(mu+1));
00346         }
00347 //       A.set_entry(0, d-1, 0);
00348       for(mu=0; mu<=d-2; mu++)
00349         A.set_entry(0, d-1, (A.get_entry(0, d-1) + (pow(k, mu+1)*B.get_entry(mu, d-2) + pow(-1, mu)*B.get_entry(mu, d-2))/(mu+1)));       
00350       // second to last row (nu>0)
00351       for(nu=1; nu<d; nu++)
00352         {
00353           A.set_entry(nu, 0, B.get_entry(nu-1, 0)/nu);
00354           for(k=1; k<d-1; k++)
00355             {
00356               A.set_entry(nu, k, B.get_entry(nu-1, k)/nu);
00357               for(mu=nu; mu<=d-1; mu++)
00358                 A.set_entry(nu, k, A.get_entry(nu, k) - (pow(-1, mu-nu)*binomd(mu, nu)*B.get_entry(mu-1, k-1))/mu);
00359             }
00360 //        A.put(nu, d-1) = 0;
00361           for(mu=nu; mu<=d-1; mu++)
00362             A.set_entry(nu, d-1, A.get_entry(nu, d-1) - (pow(-1, mu-nu)*binomd(mu, nu)*B.get_entry(mu-1, d-2))/mu);
00363         }
00364 
00365       return A;
00366     }
00367 }
00368 
00369 
00370 
00375 template <int d>
00376   Piecewise<double> ExpandBspline(const int j, const int k)
00377 {
00378   Piecewise<double> r(j);
00379   Polynomial<double> p, q;
00380   p.set_coefficient(0, floor((double) d/2.0) -k);  //floor((double) d/2.0)
00381   p.set_coefficient(1, ldexp(1.0, j)); // p(x)=2^jx-k+floor(d/2)
00382   double factor = sqrt(ldexp(1.0, j));
00383   int m, n;
00384   SparseMatrix<double> coeffs(d, d);
00385   switch(d) // precalculated entries for 1<=d<=4
00386     {
00387     case 1:
00388       {
00389         coeffs.set_entry(0, 0, 1);
00390       }
00391       break;
00392     case 2:
00393       {
00394         coeffs.set_entry(1, 0, 1);
00395 
00396         coeffs.set_entry(0, 1, 2);
00397         coeffs.set_entry(1, 1, -1);
00398       }
00399       break;
00400     case 3:
00401       {
00402         coeffs.set_entry(2, 0, 0.5);
00403 
00404         coeffs.set_entry(0, 1, -1.5);
00405         coeffs.set_entry(1, 1, 3);
00406         coeffs.set_entry(2, 1, -1);
00407 
00408         coeffs.set_entry(0, 2, 4.5);
00409         coeffs.set_entry(1, 2, -3);
00410         coeffs.set_entry(2, 2, 0.5);
00411       }
00412       break;
00413     case 4:
00414       {
00415         coeffs.set_entry(3, 0, 1.0/6.0);
00416 
00417         coeffs.set_entry(0, 1, 2.0/3.0);
00418         coeffs.set_entry(1, 1, -2);
00419         coeffs.set_entry(2, 1, 2);
00420         coeffs.set_entry(3, 1, -0.5);
00421 
00422         coeffs.set_entry(0, 2, -22.0/3.0);
00423         coeffs.set_entry(1, 2, 10);
00424         coeffs.set_entry(2, 2, -4);
00425         coeffs.set_entry(3, 2, 0.5);
00426 
00427         coeffs.set_entry(0, 3, 32.0/3.0);
00428         coeffs.set_entry(1, 3, -8);
00429         coeffs.set_entry(2, 3, 2);
00430         coeffs.set_entry(3, 3, -1.0/6.0);
00431       }
00432       break;
00433     default:
00434     {
00435       //return r;
00436       coeffs = localBSplineCoeffs(d);
00437     }
00438 }
00439   for (n=0; n<=d-1; n++)
00440     {
00441      // coeffs.findc(n, ind);
00442      // CoeffsType col;
00443       for (m=0; m<=d-1; m++)
00444         q.set_coefficient(m, coeffs.get_entry(m, n));
00445 
00446       r.set_local_expansion(n + k - floor((double) d/2.0), q.substitute_into(p));  //(int)floor((double) d/2.0)
00447     }
00448   r *= factor;
00449 
00450   return r;
00451 }
00452 
00453 
00454 
00455 
00459 template <int d>
00460   class CardinalBSpline : public Function<1>
00461   {
00462   public:
00466     CardinalBSpline() : Function<1>(1) {}
00467 
00471     virtual ~CardinalBSpline() {}
00472 
00476     inline double value(const Point<1>& p,
00477                         const unsigned int component = 0) const
00478     {
00479       return EvaluateCardinalBSpline<d>(0, p(0));
00480     }
00481   
00485     void vector_value(const Point<1> &p,
00486                       Vector<double>& values) const
00487     {
00488       values.resize(1, false);
00489       values[0] = value(p);
00490     }
00491   };
00492 }
00493 
00494 #endif
 All Classes Functions Variables Typedefs Enumerations