![]() |
Object-oriented Scientific Computing Library: Version 0.910
|
00001 /* 00002 ------------------------------------------------------------------- 00003 00004 Copyright (C) 2006-2012, Andrew W. Steiner 00005 00006 This file is part of O2scl. 00007 00008 O2scl is free software; you can redistribute it and/or modify 00009 it under the terms of the GNU General Public License as published by 00010 the Free Software Foundation; either version 3 of the License, or 00011 (at your option) any later version. 00012 00013 O2scl is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 GNU General Public License for more details. 00017 00018 You should have received a copy of the GNU General Public License 00019 along with O2scl. If not, see <http://www.gnu.org/licenses/>. 00020 00021 ------------------------------------------------------------------- 00022 */ 00023 /* Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007, 2009 Gerard 00024 * Jungman, Brian Gough 00025 * 00026 * This program is free software; you can redistribute it and/or modify 00027 * it under the terms of the GNU General Public License as published by 00028 * the Free Software Foundation; either version 3 of the License, or (at 00029 * your option) any later version. 00030 * 00031 * This program is distributed in the hope that it will be useful, but 00032 * WITHOUT ANY WARRANTY; without even the implied warranty of 00033 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00034 * General Public License for more details. 00035 * 00036 * You should have received a copy of the GNU General Public License 00037 * along with this program; if not, write to the Free Software 00038 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 00039 * 02110-1301, USA. 00040 * 00041 */ 00042 #ifndef O2SCL_GSL_SERIES_H 00043 #define O2SCL_GSL_SERIES_H 00044 00045 #include <iostream> 00046 #include <cmath> 00047 #include <gsl/gsl_sum.h> 00048 #include <gsl/gsl_minmax.h> 00049 #include <gsl/gsl_nan.h> 00050 #include <gsl/gsl_machine.h> 00051 #include <o2scl/err_hnd.h> 00052 00053 #ifndef DOXYGENP 00054 namespace o2scl { 00055 #endif 00056 00057 /** \brief Series acceleration by Levin u-transform (GSL) 00058 00059 Given an array of terms in a sum, this attempts to evaluate the 00060 entire sum with an estimate of the error. 00061 00062 \future Move the worspaces to classes? 00063 */ 00064 class gsl_series { 00065 00066 public: 00067 00068 /** \brief \c size is the number of terms in the series 00069 */ 00070 gsl_series(size_t size=0); 00071 00072 virtual ~gsl_series(); 00073 00074 /** \brief Return the accelerated sum of the series with 00075 a simple error estimate 00076 00077 The input vector \c x should be an array with \c n values 00078 from <tt>x[0]</tt> to <tt>x[n-1]</tt>. 00079 */ 00080 template<class vec_t> 00081 double series_accel(size_t na, vec_t &array, double &abserr_trunc) { 00082 00083 if (na!=size) set_size(na); 00084 00085 double sum_accel; 00086 size_t min_terms=0; 00087 size_t max_terms=size-1; 00088 00089 if (size == 0) { 00090 00091 sum_accel=0.0; 00092 abserr_trunc=0.0; 00093 wt->sum_plain=0.0; 00094 wt->terms_used=0; 00095 return sum_accel; 00096 00097 } else if (size == 1) { 00098 00099 sum_accel=array[0]; 00100 abserr_trunc=GSL_POSINF; 00101 wt->sum_plain=array[0]; 00102 wt->terms_used=1; 00103 return sum_accel; 00104 00105 } else { 00106 00107 const double SMALL=0.01; 00108 const size_t nmax=GSL_MAX(max_terms,size)-1; 00109 double trunc_n=0.0, trunc_nm1=0.0; 00110 double actual_trunc_n=0.0, actual_trunc_nm1=0.0; 00111 double result_n=0.0, result_nm1=0.0; 00112 size_t n; 00113 int better=0; 00114 int before=0; 00115 int converging=0; 00116 double least_trunc=GSL_DBL_MAX; 00117 double result_least_trunc; 00118 00119 /* Calculate specified minimum number of terms. No convergence 00120 tests are made, and no truncation information is stored. */ 00121 00122 for (n=0; n < min_terms; n++) { 00123 const double t=array[n]; 00124 00125 result_nm1=result_n; 00126 levin_utrunc_step(t,n,result_n); 00127 } 00128 00129 /* Assume the result after the minimum calculation is the best. */ 00130 00131 result_least_trunc=result_n; 00132 00133 /* Calculate up to maximum number of terms. Check truncation 00134 condition. */ 00135 00136 for (; n <= nmax; n++) { 00137 const double t=array[n]; 00138 00139 result_nm1=result_n; 00140 levin_utrunc_step(t,n,result_n); 00141 00142 /* Compute the truncation error directly */ 00143 00144 actual_trunc_nm1=actual_trunc_n; 00145 actual_trunc_n=fabs(result_n-result_nm1); 00146 00147 /* Average results to make a more reliable estimate of the 00148 real truncation error */ 00149 00150 trunc_nm1=trunc_n; 00151 trunc_n=0.5*(actual_trunc_n+actual_trunc_nm1); 00152 00153 /* Determine if we are in the convergence region. */ 00154 00155 better=(trunc_n < trunc_nm1 || trunc_n < SMALL*fabs(result_n)); 00156 converging=converging || (better && before); 00157 before=better; 00158 00159 if (converging) { 00160 if (trunc_n < least_trunc) { 00161 /* Found a low truncation point in the convergence 00162 region. Save it. */ 00163 00164 least_trunc=trunc_n; 00165 result_least_trunc=result_n; 00166 } 00167 00168 if (fabs(trunc_n/result_n) < 10.0*GSL_MACH_EPS) 00169 break; 00170 } 00171 } 00172 00173 if (converging) { 00174 00175 /* Stopped in the convergence region. Return result and 00176 error estimate. */ 00177 sum_accel=result_least_trunc; 00178 abserr_trunc=least_trunc; 00179 wt->terms_used=n; 00180 return sum_accel; 00181 00182 } else { 00183 00184 /* Never reached the convergence region. Use the last 00185 calculated values. */ 00186 sum_accel=result_n; 00187 abserr_trunc=trunc_n; 00188 wt->terms_used=n; 00189 return sum_accel; 00190 } 00191 } 00192 00193 00194 return sum_accel; 00195 } 00196 00197 /** \brief Return the accelerated sum of the series with 00198 an accurate error estimate 00199 00200 The input vector \c x should be an array with \c n values 00201 from <tt>x[0]</tt> to <tt>x[n-1]</tt>. 00202 */ 00203 template<class vec_t> 00204 double series_accel_err(size_t na, vec_t &array, double &abserr) { 00205 00206 if (na!=size) set_size(na); 00207 00208 double sum_accel; 00209 size_t min_terms=0; 00210 size_t max_terms=size-1; 00211 00212 /* Ignore any trailing zeros in the array */ 00213 size_t size2=size; 00214 00215 while (size2 > 0 && array[size2-1]==0) { 00216 size2--; 00217 } 00218 00219 if (size2==0) { 00220 00221 sum_accel=0.0; 00222 abserr=0.0; 00223 w->sum_plain=0.0; 00224 w->terms_used=0; 00225 return sum_accel; 00226 00227 } else if (size2==1) { 00228 00229 sum_accel=array[0]; 00230 abserr=0.0; 00231 w->sum_plain=array[0]; 00232 w->terms_used=1; 00233 return sum_accel; 00234 00235 } else { 00236 00237 const double SMALL=0.01; 00238 const size_t nmax=GSL_MAX(max_terms,size)-1; 00239 double noise_n=0.0,noise_nm1=0.0; 00240 double trunc_n=0.0, trunc_nm1=0.0; 00241 double actual_trunc_n=0.0, actual_trunc_nm1=0.0; 00242 double result_n=0.0, result_nm1=0.0; 00243 double variance=0; 00244 size_t n; 00245 unsigned int i; 00246 int better=0; 00247 int before=0; 00248 int converging=0; 00249 double least_trunc=GSL_DBL_MAX; 00250 double least_trunc_noise=GSL_DBL_MAX; 00251 double least_trunc_result; 00252 00253 /* Calculate specified minimum number of terms. No convergence 00254 tests are made, and no truncation information is stored. */ 00255 00256 for (n=0; n < min_terms; n++) { 00257 const double t=array[n]; 00258 result_nm1=result_n; 00259 levin_u_step(t,n,nmax,result_n); 00260 } 00261 00262 least_trunc_result=result_n; 00263 00264 variance=0; 00265 for (i=0; i < n; i++) { 00266 double dn=w->dsum[i]*GSL_MACH_EPS*array[i]; 00267 variance += dn*dn; 00268 } 00269 noise_n=std::sqrt(variance); 00270 00271 /* Calculate up to maximum number of terms. Check truncation 00272 condition. */ 00273 00274 for (; n <= nmax; n++) { 00275 const double t=array[n]; 00276 00277 result_nm1=result_n; 00278 levin_u_step(t,n,nmax,result_n); 00279 00280 /* Compute the truncation error directly */ 00281 00282 actual_trunc_nm1=actual_trunc_n; 00283 actual_trunc_n=fabs(result_n-result_nm1); 00284 00285 /* Average results to make a more reliable estimate of the 00286 real truncation error */ 00287 00288 trunc_nm1=trunc_n; 00289 trunc_n=0.5*(actual_trunc_n+actual_trunc_nm1); 00290 00291 noise_nm1=noise_n; 00292 variance=0; 00293 00294 for (i=0; i <= n; i++) { 00295 double dn=w->dsum[i]*GSL_MACH_EPS*array[i]; 00296 variance += dn*dn; 00297 } 00298 00299 noise_n=std::sqrt(variance); 00300 00301 /* Determine if we are in the convergence region. */ 00302 00303 better=(trunc_n < trunc_nm1 || 00304 trunc_n < SMALL*fabs(result_n)); 00305 converging=converging || (better && before); 00306 before=better; 00307 00308 if (converging) { 00309 if (trunc_n < least_trunc) { 00310 /* Found a low truncation point in the convergence 00311 region. Save it. */ 00312 00313 least_trunc_result=result_n; 00314 least_trunc=trunc_n; 00315 least_trunc_noise=noise_n; 00316 } 00317 00318 if (noise_n > trunc_n/3.0) { 00319 break; 00320 } 00321 00322 if (trunc_n < 10.0*GSL_MACH_EPS*fabs(result_n)) { 00323 break; 00324 } 00325 } 00326 00327 } 00328 00329 if (converging) { 00330 00331 /* Stopped in the convergence region. Return result and 00332 error estimate. */ 00333 sum_accel=least_trunc_result; 00334 abserr=GSL_MAX_DBL(least_trunc,least_trunc_noise); 00335 w->terms_used=n; 00336 return sum_accel; 00337 00338 } else { 00339 00340 /* Never reached the convergence region. Use the last 00341 calculated values. */ 00342 sum_accel=result_n; 00343 abserr=GSL_MAX_DBL(trunc_n,noise_n); 00344 w->terms_used=n; 00345 return sum_accel; 00346 } 00347 } 00348 00349 return sum_accel; 00350 } 00351 00352 /** \brief Set the number of terms */ 00353 void set_size(size_t new_size); 00354 00355 #ifndef DOXYGENP 00356 00357 protected: 00358 00359 /** \brief Desc 00360 */ 00361 static const size_t series_index(size_t i, size_t j, size_t nmax) { 00362 return i*(nmax+1)+j; 00363 } 00364 00365 /** \brief Perform a step 00366 */ 00367 int levin_u_step(const double term, const size_t n, 00368 const size_t nmax, double &sum_accel); 00369 00370 /** \brief Perform a step 00371 */ 00372 int levin_utrunc_step(const double term, const size_t n, 00373 double &sum_accel); 00374 00375 /// The GSL workspace 00376 gsl_sum_levin_u_workspace *w; 00377 00378 /// The GSL workspace 00379 gsl_sum_levin_utrunc_workspace *wt; 00380 00381 /// The workspace size 00382 size_t size; 00383 00384 #endif 00385 00386 }; 00387 00388 #ifndef DOXYGENP 00389 } 00390 #endif 00391 00392 #endif
Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).