00001 // SuperMix version 1.0 C++ source file 00002 // 00003 // Copyright (c) 1999 California Institute of Technology. 00004 // All rights reserved. 00005 // 00006 // Redistribution and use in source and binary forms for noncommercial 00007 // purposes are permitted provided that the above copyright notice and 00008 // this paragraph are duplicated in all such forms and that any 00009 // documentation and other materials related to such distribution and 00010 // use acknowledge that the software was developed by California 00011 // Institute of Technology. Redistribution and/or use in source or 00012 // binary forms is not permitted for any commercial purpose. Use of 00013 // this software does not include a permitted use of the Institute's 00014 // name or trademark for any purpose. 00015 // 00016 // DISCLAIMER: 00017 // THIS SOFTWARE AND/OR RELATED MATERIALS ARE PROVIDED "AS-IS" WITHOUT 00018 // WARRANTY OF ANY KIND INCLUDING ANY WARRANTIES OF PERFORMANCE OR 00019 // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE OR PURPOSE (AS SET 00020 // FORTH IN UCC 23212-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE 00021 // LICENSED PRODUCT, HOWEVER USED. IN NO EVENT SHALL CALTECH/JPL BE 00022 // LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING BUT NOT LIMITED TO 00023 // INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, INCLUDING ECONOMIC 00024 // DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, REGARDLESS OF 00025 // WHETHER CALTECH/JPL SHALL BE ADVISED, HAVE REASON TO KNOW, OR IN 00026 // FACT SHALL KNOW OF THE POSSIBILITY. THE USER BEARS ALL RISK 00027 // RELATING TO QUALITY AND PERFORMANCE OF THE SOFTWARE AND/OR RELATED 00028 // MATERIALS. 00029 // 00030 // ******************************************************************** 00031 // integrate.h 00032 // 00033 // includes classes integrator<> and CauchyPV 00034 // 00035 // ******************************************************************** 00036 // class integrator<>: 00037 // 00038 // Performs numerical integrations of functions of one real variable (double). 00039 // The return type of the function to integrated is determined by a template 00040 // parameter in the declaration of an integrator object. The return type 00041 // can be any sort of object which is a member of a "vector space" with the 00042 // following operations defined on it (Y is the type name of the function 00043 // return type, double is the type of the independent variable): 00044 // 00045 // double x; 00046 // Y A; // construct an object of type Y, no particular value. 00047 // Y B(A); // construct an independent copy of (value of type Y) A; 00048 // A = B; // make A an independent copy of B 00049 // A *= x; // modify A by scaling by x. 00050 // A += B; // modify A by adding B to it 00051 // A -= B; // modify A by subtracting B from it 00052 // 00053 // Y type objects must be a vector space, in that (A *= 2.0) is equivalent 00054 // to (A += A), and (A *= 0.0) is equivalent to (A -= A) and gives the 00055 // additive identity of Y, etc. 00056 // 00057 // General scheme to use the integrator: 00058 // 00059 // Assume you have a complex-valued function of a real variable: 00060 // complex f(double x), that you must numerically integrate. The code could be: 00061 // 00062 // integrator<complex> F; // an integrator appropriate for f(). 00063 // 00064 // double a,b; // limits of integration 00065 // complex z = F(f,a,b); // use the default tolerances and integrate f(). 00066 // 00067 // F.abs_tolerance = 1e-6; F.rel_tolerance = 1e-4; // adjust tolerances 00068 // z = F(f,a,b); // integrate f() again, using new tolerances. 00069 // 00070 // Now assume that you need to integrate a real function: double g(double x), 00071 // which has an inverse square root singularity at the origin, and decreases 00072 // approximately like exp(-a*x), a >= 1, for x > 10. You must integrate g(x) 00073 // between -10 and +Infinity. The code would be: 00074 // 00075 // typedef integrator<double> Ig; // shorthand will be used repeatedly below. 00076 // Ig G; 00077 // 00078 // double answer = 0.0; 00079 // anwser += G.sqrtupper()(g, -10, 0); 00080 // anwser += G.sqrtlower()(g, 0, 10); 00081 // anwser += G.exp()(g,10,100); // upper limit is ignored here 00082 // 00083 // Note the concatenation of the method() and operator() calls; this works 00084 // because method returns a reference to G, which is used by operator(). 00085 // The code could have used separate statements: 00086 // 00087 // G.method(Ig::SQRTUPPER); answer += G(g, -10, 0); // etc. 00088 // 00089 // 00090 // Algorithms based on the Romberg integration methods described in 00091 // Numerical Recipes in C, 2nd Edition (Cambridge). 00092 // 00093 // F. Rice 00094 // 7/8/99 00095 // 00096 // ******************************************************************** 00097 // Cauchy_integrate(); class CauchyPV: 00098 // 00099 // Performs Cauchy principle value integrations of real functions of a 00100 // real variable (ie, like: double f(double x)) using integrator<double>. 00101 // The location of a nonintegrable, odd singularity (pole) is specified 00102 // in addition to the limits of integration. The function will not be 00103 // evaluated at the limits of integration, but it must remain finite 00104 // at them, since the integration method used is integrator<double>::OPEN. 00105 // 00106 // To calculate a Cauchy principal value integral: 00107 // 00108 // (1) using Cauchy_integrate (limits and pole are doubles, func a function): 00109 // double answer = Cauchy_integrate(func, low_limit, pole, high_limit); 00110 // 00111 // (2) using class CauchyPV: 00112 // CauchyPV I; // the integrator 00113 // double answer = I(f,a,s,b); 00114 // 00115 // Use method (2) if you want to adjust integrator controls to other than 00116 // the default values, or if you need to calculate integrals using several 00117 // different functions. 00118 // 00119 // F. Rice 00120 // 7/13/99 00121 // 00122 // ******************************************************************** 00123 00124 #ifndef INTEGRATE_H 00125 #define INTEGRATE_H 00126 00127 #include "num_utility.h" 00128 #include <math.h> 00129 #include <pair.h> 00130 #include <vector> 00131 #include "polynomial.h" 00132 00133 template <class Y> 00134 class integrator 00135 { 00136 public: 00137 00138 // The following enumeration provides choices for the integration method to use 00139 // (default is CLOSED): 00140 00141 typedef enum { 00142 00143 CLOSED, // Closed interval: function will be evaluated at the limits 00144 OPEN, // Open interval: function will not be evaluated at the limits 00145 SQRTLOWER, // Open: lower limit has an inverse square root singularity 00146 SQRTUPPER, // Open: upper limit has an inverse square root singularity 00147 INFINITE, // Open: one limit is very large; both limits must have the same sign 00148 EXP // Function must be decreasing at +infinity AT LEAST AS FAST AS 00149 // exp(-x);integrates from lower limit to +infinity 00150 // (upper limit is ignored; +infinity is assumed). 00151 00152 } type; 00153 00154 00155 // -------------------------------------------------------------------- 00156 // The constructor: 00157 explicit integrator(type t_ = CLOSED); 00158 00159 00160 // -------------------------------------------------------------------- 00161 // The following variables control or limit the integration process 00162 // (default values in parentheses) 00163 00164 unsigned order; // (4) the order of the Romberg extrapolation 00165 unsigned recursion_limit; // (20) the max allowable number of interval subdivisions 00166 00167 00168 // If either of the following accuracy limits is met, then accuracy is o.k: 00169 double abs_tolerance; // (1.0e-100) the max absolute error target in the integration 00170 double rel_tolerance; // (1.0e-6) the max relative error target in the integration 00171 00172 00173 // Select or change the integration method to use: 00174 integrator & closed() { t = CLOSED; return *this; } 00175 integrator & open() { t = OPEN; return *this; } 00176 integrator & sqrtlower() { t = SQRTLOWER; return *this; } 00177 integrator & sqrtupper() { t = SQRTUPPER; return *this; } 00178 integrator & infinite() { t = INFINITE; return *this; } 00179 integrator & exp() { t = EXP; return *this; } 00180 integrator & method(type t_) { t = t_; return *this; } 00181 00182 00183 // -------------------------------------------------------------------- 00184 // Perform the integration: must pass a function and limits, 00185 // as well as a norm function for error determination. If no norm function 00186 // is specified, the default is to use a global double norm(Y), if defined. 00187 // Warning: do not call a given integrator object recursively; if you want 00188 // to do a multiple integral, create an independent integrator object for 00189 // each level of the integration. 00190 00191 template <class F, class N> 00192 Y operator()( 00193 F f, // the function to be integrated 00194 double a, // the lower integration limit 00195 double b, // the upper integration limit 00196 N norm // function returning the "magnitude squared" of 00197 // an argument of type Y, for error estimates 00198 ); 00199 00200 template <class F> 00201 Y operator()( 00202 F f, // the function to be integrated 00203 double a, // the lower integration limit 00204 double b // the upper integration limit 00205 ) 00206 { return (*this)(f,a,b,norm); } // use the default norm 00207 00208 00209 // -------------------------------------------------------------------- 00210 private: 00211 00212 type t; // the integration method 00213 pair<Y,Y> result; // the final answer and error estimate 00214 typedef pair<double,Y> entry; 00215 vector<entry> s; // vector of partial sums for extrapolation 00216 poly_fit<Y> p; // the polynomial extrapolator 00217 00218 // the following functional provides access to the overloaded global norm(). 00219 default_norm<Y> norm ; 00220 00221 // the following function is used to swap integration limits, to ensure 00222 // lower limit <= upper limit; operator() will handle the sign correctly. 00223 int qswap(double & a, double & b) 00224 { if (a > b) { double t = a; a = b; b = t; return 1; } else return 0; } 00225 00226 // method implementations: 00227 template <class F, class N> 00228 void romberg_closed(F f, double a, double b, N n, 00229 void (integrator<Y>::*method)(F,double,double,int)); 00230 template <class F, class N> 00231 void romberg_open(F f, double a, double b, N n, 00232 void (integrator<Y>::*method)(F,double,double,int)); 00233 00234 template <class F> void cl(F f, double a, double b, int step); 00235 template <class F> void op(F f, double a, double b, int step); 00236 template <class F> void sl(F f, double a, double b, int step); 00237 template <class F> void su(F f, double a, double b, int step); 00238 template <class F> void in(F f, double a, double b, int step); 00239 template <class F> void ex(F f, double a, double b, int step); 00240 00241 // a class to perform change of variable needed by several of the methods: 00242 struct { 00243 Y r; 00244 00245 // 2*x*f(a+x*x), used by sl: 00246 template <class F> Y sql(F f, double x, double a) 00247 { r = f(a+x*x); r *= 2.0*x; return r; } 00248 00249 // 2*x*f(b-x*x), used by su: 00250 template <class F> Y squ(F f, double x, double b) 00251 { 00252 r = f(b-x*x); 00253 r *= (2.0*x); 00254 00255 // **** WORK AROUND **** a bug in "-O2" of the Redhat 7.x g++ compiler 00256 #ifdef __linux 00257 #ifdef __GNUC_MINOR__ 00258 #if __GNUC_MINOR__ == 96 00259 if(x!=x) 00260 { 00261 r *= 2.0; // These lines should never get called. 00262 r *= 0.5; // But just in case, we'll minimize the damage. 00263 } 00264 #endif 00265 #endif 00266 #endif 00267 // **** END WORK AROUND **** 00268 00269 return r; 00270 } 00271 00272 // (1/x^2)*f(1/x), used by in(): 00273 template <class F> Y inv(F f, double x) 00274 { r = f(1.0/x); r *= 1.0/(x*x); return r; } 00275 00276 // (1/x)*f(-ln(x)), used by ex(): 00277 template <class F> Y exf(F f, double x) 00278 { r = f(-log(x)); r *= 1.0/x; return r; } 00279 } Func; 00280 00281 }; // class intergrator<> 00282 00283 // ******************************************************************** 00284 // A helper class for CauchyPV calculations 00285 00286 // a class to calculate the symmetrized function value for CauchPV 00287 template <class F> 00288 class CauchyPV_calculator { 00289 public: 00290 F op; 00291 double x; 00292 CauchyPV_calculator(F f, double s) : op(f), x(s) { } 00293 double operator()(double t) const { return op(x+t) + op(x-t); } 00294 }; 00295 00296 00297 // ******************************************************************** 00298 class CauchyPV 00299 { 00300 typedef integrator<double> I; 00301 00302 public: 00303 double & abs_tolerance; // same functionality as for integrator<> 00304 double & rel_tolerance; 00305 unsigned & order; 00306 unsigned & recursion_limit; 00307 00308 CauchyPV(); // simple constructors 00309 CauchyPV(const CauchyPV &); 00310 00311 00312 // operator() performs the Cauchy Principal Value integration: 00313 00314 template <class F> 00315 double operator()( 00316 F f, // the function to integrate 00317 double a, // lower integration limit 00318 double s, // the singularity location 00319 double b // upper integration limit 00320 ); 00321 00322 private: 00323 00324 I integ; // the integrator 00325 00326 }; // class CauchyPV 00327 00328 template <class F> 00329 inline double Cauchy_integrate(F f, double a, double s, double b) 00330 { static CauchyPV I; return I(f,a,s,b); } 00331 00332 #include "numerical/num_integrate.h" 00333 00334 #endif /* INTEGRATE_H */
Please direct comments and corrections to
supermix@submm.caltech.edu
Go to the supermix home page
Generated by
1.2.7