MathTL
|
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