| 1 | ;; Series acceleration. |
|---|
| 2 | ;; Liam Healy, Wed Nov 21 2007 - 18:41 |
|---|
| 3 | ;; Time-stamp: <2008-03-09 19:21:47EDT series-acceleration.lisp> |
|---|
| 4 | ;; $Id$ |
|---|
| 5 | |
|---|
| 6 | (in-package :gsl) |
|---|
| 7 | |
|---|
| 8 | ;;;;**************************************************************************** |
|---|
| 9 | ;;;; Creation and calculation of Levin series acceleration |
|---|
| 10 | ;;;;**************************************************************************** |
|---|
| 11 | |
|---|
| 12 | (cffi:defcstruct levin |
|---|
| 13 | "The definition of Levin series acceleration for GSL." |
|---|
| 14 | (size size) |
|---|
| 15 | (position-in-array size) |
|---|
| 16 | (terms-used size) |
|---|
| 17 | (sum-plain :double) |
|---|
| 18 | (q-num :pointer) |
|---|
| 19 | (q-den :pointer) |
|---|
| 20 | (dq-num :pointer) |
|---|
| 21 | (dq-den :pointer) |
|---|
| 22 | (dsum :pointer)) |
|---|
| 23 | |
|---|
| 24 | (defgo-s (levin order) allocate-levin free-levin) |
|---|
| 25 | |
|---|
| 26 | (defmfun allocate-levin (order) |
|---|
| 27 | "gsl_sum_levin_u_alloc" |
|---|
| 28 | ((order size)) |
|---|
| 29 | :c-return :pointer |
|---|
| 30 | :export nil |
|---|
| 31 | :index (letm levin) |
|---|
| 32 | :documentation ; FDL |
|---|
| 33 | "Allocate a workspace for a Levin u-transform of n |
|---|
| 34 | terms. The size of the workspace is O(2n^2 + 3n).") |
|---|
| 35 | |
|---|
| 36 | (defmfun free-levin (levin) |
|---|
| 37 | "gsl_sum_levin_u_free" |
|---|
| 38 | ((levin :pointer)) |
|---|
| 39 | :c-return :void ; Error in GSL manual, should be void? |
|---|
| 40 | :export nil |
|---|
| 41 | :index (letm levin) |
|---|
| 42 | :documentation ; FDL |
|---|
| 43 | "Free a previously allocated Levin acceleration.") |
|---|
| 44 | |
|---|
| 45 | (defmfun accelerate (array levin) |
|---|
| 46 | "gsl_sum_levin_u_accel" |
|---|
| 47 | (((gsl-array array) :pointer) ((dim0 array) size) (levin :pointer) |
|---|
| 48 | (accelerated-sum :double) (absolute-error :double)) |
|---|
| 49 | :documentation ; FDL |
|---|
| 50 | "From the terms of a series in array, compute the extrapolated |
|---|
| 51 | limit of the series using a Levin u-transform. Additional |
|---|
| 52 | working space must be provided in levin. The extrapolated sum is |
|---|
| 53 | returned with an estimate of the absolute error. The actual |
|---|
| 54 | term-by-term sum is returned in |
|---|
| 55 | w->sum_plain. The algorithm calculates the truncation error |
|---|
| 56 | (the difference between two successive extrapolations) and round-off |
|---|
| 57 | error (propagated from the individual terms) to choose an optimal |
|---|
| 58 | number of terms for the extrapolation.") |
|---|
| 59 | |
|---|
| 60 | ;;;;**************************************************************************** |
|---|
| 61 | ;;;; Acceleration with error estimation from truncation |
|---|
| 62 | ;;;;**************************************************************************** |
|---|
| 63 | |
|---|
| 64 | (defgo-s (levin-truncated order) allocate-levin-truncated free-levin-truncated) |
|---|
| 65 | |
|---|
| 66 | (defmfun allocate-levin-truncated (order) |
|---|
| 67 | "gsl_sum_levin_utrunc_alloc" |
|---|
| 68 | ((order size)) |
|---|
| 69 | :c-return :pointer |
|---|
| 70 | :export nil |
|---|
| 71 | :index (letm levin-truncated) |
|---|
| 72 | :documentation ; FDL |
|---|
| 73 | "Allocate a workspace for a Levin u-transform of n |
|---|
| 74 | terms, without error estimation. The size of the workspace is |
|---|
| 75 | O(3n).") |
|---|
| 76 | |
|---|
| 77 | (defmfun free-levin-truncated (levin) |
|---|
| 78 | "gsl_sum_levin_utrunc_free" |
|---|
| 79 | ((levin :pointer)) |
|---|
| 80 | :export nil |
|---|
| 81 | :index (letm levin-truncated) |
|---|
| 82 | :documentation ; FDL |
|---|
| 83 | "Free a previously allocated Levin acceleration.") |
|---|
| 84 | |
|---|
| 85 | (defmfun accelerate-truncated (array levin) |
|---|
| 86 | "gsl_sum_levin_utrunc_accel" |
|---|
| 87 | (((gsl-array array) :pointer) ((dim0 array) size) (levin :pointer) |
|---|
| 88 | (accelerated-sum :double) (absolute-error :double)) |
|---|
| 89 | :documentation ; FDL |
|---|
| 90 | "From the terms of a series in array, compute the extrapolated |
|---|
| 91 | limit of the series using a Levin u-transform. Additional |
|---|
| 92 | working space must be provided in levin. The extrapolated sum is |
|---|
| 93 | returned with an estimate of the absolute error. The actual |
|---|
| 94 | term-by-term sum is returned in w->sum_plain. The algorithm |
|---|
| 95 | terminates when the difference between two successive extrapolations |
|---|
| 96 | reaches a minimum or is sufficiently small. The difference between |
|---|
| 97 | these two values is used as estimate of the error and is stored in |
|---|
| 98 | abserr_trunc. To improve the reliability of the algorithm the |
|---|
| 99 | extrapolated values are replaced by moving averages when calculating |
|---|
| 100 | the truncation error, smoothing out any fluctuations.") |
|---|
| 101 | |
|---|
| 102 | ;;;;**************************************************************************** |
|---|
| 103 | ;;;; Example |
|---|
| 104 | ;;;;**************************************************************************** |
|---|
| 105 | |
|---|
| 106 | ;;; From Sec. 29.3 in the GSL manual. |
|---|
| 107 | |
|---|
| 108 | (defun acceleration-example () |
|---|
| 109 | (let ((maxterms 20) |
|---|
| 110 | (sum 0.0d0) |
|---|
| 111 | (zeta2 (/ (expt pi 2) 6))) |
|---|
| 112 | (letm ((levin (levin maxterms)) |
|---|
| 113 | (array (vector-double-float maxterms))) |
|---|
| 114 | (dotimes (n maxterms) |
|---|
| 115 | (setf (maref array n) (coerce (/ (expt (1+ n) 2)) 'double-float)) |
|---|
| 116 | (incf sum (maref array n))) |
|---|
| 117 | (multiple-value-bind (accelerated-sum error) |
|---|
| 118 | (accelerate array levin) |
|---|
| 119 | (format t "~&term-by-term sum =~f using ~d terms" sum maxterms) |
|---|
| 120 | (format t "~&term-by-term sum =~f using ~d terms" |
|---|
| 121 | (cffi:foreign-slot-value levin 'levin 'sum-plain) |
|---|
| 122 | (cffi:foreign-slot-value levin 'levin 'terms-used)) |
|---|
| 123 | (format t "~&exact value = ~f" zeta2) |
|---|
| 124 | (format t "~&accelerated sum = ~f using ~d terms" |
|---|
| 125 | accelerated-sum |
|---|
| 126 | (cffi:foreign-slot-value levin 'levin 'terms-used)) |
|---|
| 127 | (format t "~&estimated error = ~f" error) |
|---|
| 128 | (format t "~&actual error = ~f" (- accelerated-sum zeta2)))))) |
|---|
| 129 | |
|---|
| 130 | ;; term-by-term sum =1.5961632439130233 using 20 terms |
|---|
| 131 | ;; term-by-term sum =1.5759958390005426 using 13 terms |
|---|
| 132 | ;; exact value = 1.6449340668482264 |
|---|
| 133 | ;; accelerated sum = 1.6449340669228176 using 13 terms |
|---|
| 134 | ;; estimated error = 0.00000000008883604962761638 |
|---|
| 135 | ;; actual error = 0.00000000007459122208786084 |
|---|