Object-oriented Scientific Computing Library: Version 0.910
gsl_series.h
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
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).

Get Object-oriented Scientific Computing
Lib at SourceForge.net. Fast, secure and Free Open Source software
downloads.