00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #ifndef _INTEGRATION_H_
00034 #define _INTEGRATION_H_
00035
00036
00037 #include <math.h>
00038 #include <functional>
00039 #include <numeric>
00040 #include <limits>
00041 #include <stdexcept>
00042 #include "errormacros.h"
00043
00044 namespace Go {
00047
00048
00049
00055 template <typename Functor>
00056 void trapezoidal(Functor& f, double a, double b, double& s, int n)
00057 {
00058 DEBUG_ERROR_IF(n < 1, "Bad function argument to trapezoidal().");
00059 if (n == 1) {
00060 s = 0.5 * (b - a) * (f(a) + f(b));
00061 } else {
00062 int num_int_pts = 1 << (n-2);
00063
00064 double spacing = (b - a) / num_int_pts;
00065 double x = a + 0.5 * spacing;
00066 double sum = 0.0;
00067 for (int i = 0; i < num_int_pts; ++i) {
00068 sum += f(x);
00069 x += spacing;
00070 }
00071 s += (b - a) * sum / num_int_pts;
00072 s *= 0.5;
00073 }
00074 }
00075
00076
00079 template <typename Functor>
00080 double simpsons_rule(Functor& f, double a, double b,
00081 const double eps = 1.0e-6, const int max_iter = 20)
00082 {
00083 const double one_third = double(1) / double(3);
00084 double result = 0;
00085 double tz = 0;
00086 double last_tz = std::numeric_limits<double>::min();
00087 double last_result = std::numeric_limits<double>::min();
00088
00089 for (int j = 1; j <= max_iter; ++j) {
00090 trapezoidal(f, a, b, tz, j);
00091 result = (4.0 * tz - last_tz) * one_third;
00092 if ((fabs(result - last_result) < eps * fabs(last_result)) ||
00093 (fabs(result) < eps && fabs(last_result) < eps && j > 6)) {
00094 return result;
00095 }
00096 last_result = result;
00097 last_tz = tz;
00098 }
00099 MESSAGE("Too many steps in simpsons_rule.");
00100 throw std::runtime_error("Too many steps in simpsons_rule.");
00101 }
00102
00105 template <typename Functor>
00106 double gaussian_quadrature(Functor& f, double a, double b)
00107 {
00108 static double x[] = { 0.1488743389,
00109 0.4333953941,
00110 0.6794095682,
00111 0.8650633666,
00112 0.9739065285 };
00113 static double weight[] = { 0.2955242247,
00114 0.2692667193,
00115 0.2190863625,
00116 0.1494513491,
00117 0.0666713443 };
00118
00119 double midpt = 0.5 * (b + a);
00120 double half_length = 0.5 * (b - a);
00121 double scaled_result = double(0);
00122 double step = double(0);
00123 for (int i = 0; i < 5; ++i) {
00124 step = half_length * x[i];
00125 scaled_result += weight[i] * (f(midpt + step) + f(midpt - step));
00126 }
00127
00128 return scaled_result * half_length;
00129 }
00130
00131
00132
00133
00135 template <typename Functor>
00136 class Integrate2ndFunctor {
00137 public:
00138 Integrate2ndFunctor(Functor& f, double a, double b)
00139 : f_(f), a_(a), b_(b) { }
00140
00141 double operator() (double t) const
00142 {
00143 std::binder1st<Functor> fu(f_, t);
00144 return gaussian_quadrature(fu, a_, b_);
00145 }
00146
00147 private:
00148 Functor f_;
00149 double a_, b_;
00150
00151 };
00153
00156 template <typename Functor2D>
00157 double simpsons_rule2D(Functor2D& f,
00158 double ax, double bx, double ay, double by,
00159 const double eps = 1.0e-6, const int max_iter = 20)
00160 {
00161 Integrate2ndFunctor<Functor2D> fu(f, ay, by);
00162 return simpsons_rule(fu, ax, bx, eps, max_iter);
00163 }
00164
00165
00168 template <typename Functor2D>
00169 double gaussian_quadrature2D(Functor2D& f,
00170 double ax, double bx, double ay, double by)
00171 {
00172 Integrate2ndFunctor<Functor2D> fu(f, ay, by);
00173 return gaussian_quadrature(fu, ax, bx);
00174 }
00175
00176
00178 }
00179
00180
00181 #endif // _INTEGRATION_H
00182
00183