|
GiNaC
1.6.2
|
00001 00005 /* 00006 * GiNaC Copyright (C) 1999-2011 Johannes Gutenberg University Mainz, Germany 00007 * 00008 * This program 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 2 of the License, or 00011 * (at your option) any later version. 00012 * 00013 * This program 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 this program; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 */ 00022 00023 #include "integral.h" 00024 #include "numeric.h" 00025 #include "symbol.h" 00026 #include "add.h" 00027 #include "mul.h" 00028 #include "power.h" 00029 #include "inifcns.h" 00030 #include "wildcard.h" 00031 #include "archive.h" 00032 #include "registrar.h" 00033 #include "utils.h" 00034 #include "operators.h" 00035 #include "relational.h" 00036 00037 using namespace std; 00038 00039 namespace GiNaC { 00040 00041 GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(integral, basic, 00042 print_func<print_dflt>(&integral::do_print). 00043 print_func<print_latex>(&integral::do_print_latex)) 00044 00045 00046 00047 // default constructor 00049 00050 integral::integral() 00051 : 00052 x((new symbol())->setflag(status_flags::dynallocated)) 00053 {} 00054 00056 // other constructors 00058 00059 // public 00060 00061 integral::integral(const ex & x_, const ex & a_, const ex & b_, const ex & f_) 00062 : x(x_), a(a_), b(b_), f(f_) 00063 { 00064 if (!is_a<symbol>(x)) { 00065 throw(std::invalid_argument("first argument of integral must be of type symbol")); 00066 } 00067 } 00068 00070 // archiving 00072 00073 void integral::read_archive(const archive_node& n, lst& sym_lst) 00074 { 00075 inherited::read_archive(n, sym_lst); 00076 n.find_ex("x", x, sym_lst); 00077 n.find_ex("a", a, sym_lst); 00078 n.find_ex("b", b, sym_lst); 00079 n.find_ex("f", f, sym_lst); 00080 } 00081 00082 void integral::archive(archive_node & n) const 00083 { 00084 inherited::archive(n); 00085 n.add_ex("x", x); 00086 n.add_ex("a", a); 00087 n.add_ex("b", b); 00088 n.add_ex("f", f); 00089 } 00090 00092 // functions overriding virtual functions from base classes 00094 00095 void integral::do_print(const print_context & c, unsigned level) const 00096 { 00097 c.s << "integral("; 00098 x.print(c); 00099 c.s << ","; 00100 a.print(c); 00101 c.s << ","; 00102 b.print(c); 00103 c.s << ","; 00104 f.print(c); 00105 c.s << ")"; 00106 } 00107 00108 void integral::do_print_latex(const print_latex & c, unsigned level) const 00109 { 00110 string varname = ex_to<symbol>(x).get_name(); 00111 if (level > precedence()) 00112 c.s << "\\left("; 00113 c.s << "\\int_{"; 00114 a.print(c); 00115 c.s << "}^{"; 00116 b.print(c); 00117 c.s << "} d"; 00118 if (varname.size() > 1) 00119 c.s << "\\," << varname << "\\:"; 00120 else 00121 c.s << varname << "\\,"; 00122 f.print(c,precedence()); 00123 if (level > precedence()) 00124 c.s << "\\right)"; 00125 } 00126 00127 int integral::compare_same_type(const basic & other) const 00128 { 00129 GINAC_ASSERT(is_exactly_a<integral>(other)); 00130 const integral &o = static_cast<const integral &>(other); 00131 00132 int cmpval = x.compare(o.x); 00133 if (cmpval) 00134 return cmpval; 00135 cmpval = a.compare(o.a); 00136 if (cmpval) 00137 return cmpval; 00138 cmpval = b.compare(o.b); 00139 if (cmpval) 00140 return cmpval; 00141 return f.compare(o.f); 00142 } 00143 00144 ex integral::eval(int level) const 00145 { 00146 if ((level==1) && (flags & status_flags::evaluated)) 00147 return *this; 00148 if (level == -max_recursion_level) 00149 throw(std::runtime_error("max recursion level reached")); 00150 00151 ex eintvar = (level==1) ? x : x.eval(level-1); 00152 ex ea = (level==1) ? a : a.eval(level-1); 00153 ex eb = (level==1) ? b : b.eval(level-1); 00154 ex ef = (level==1) ? f : f.eval(level-1); 00155 00156 if (!ef.has(eintvar) && !haswild(ef)) 00157 return eb*ef-ea*ef; 00158 00159 if (ea==eb) 00160 return _ex0; 00161 00162 if (are_ex_trivially_equal(eintvar,x) && are_ex_trivially_equal(ea,a) 00163 && are_ex_trivially_equal(eb,b) && are_ex_trivially_equal(ef,f)) 00164 return this->hold(); 00165 return (new integral(eintvar, ea, eb, ef)) 00166 ->setflag(status_flags::dynallocated | status_flags::evaluated); 00167 } 00168 00169 ex integral::evalf(int level) const 00170 { 00171 ex ea; 00172 ex eb; 00173 ex ef; 00174 00175 if (level==1) { 00176 ea = a; 00177 eb = b; 00178 ef = f; 00179 } else if (level == -max_recursion_level) { 00180 throw(runtime_error("max recursion level reached")); 00181 } else { 00182 ea = a.evalf(level-1); 00183 eb = b.evalf(level-1); 00184 ef = f.evalf(level-1); 00185 } 00186 00187 // 12.34 is just an arbitrary number used to check whether a number 00188 // results after subsituting a number for the integration variable. 00189 if (is_exactly_a<numeric>(ea) && is_exactly_a<numeric>(eb) 00190 && is_exactly_a<numeric>(ef.subs(x==12.34).evalf())) { 00191 return adaptivesimpson(x, ea, eb, ef); 00192 } 00193 00194 if (are_ex_trivially_equal(a, ea) && are_ex_trivially_equal(b, eb) 00195 && are_ex_trivially_equal(f, ef)) 00196 return *this; 00197 else 00198 return (new integral(x, ea, eb, ef)) 00199 ->setflag(status_flags::dynallocated); 00200 } 00201 00202 int integral::max_integration_level = 15; 00203 ex integral::relative_integration_error = 1e-8; 00204 00205 ex subsvalue(const ex & var, const ex & value, const ex & fun) 00206 { 00207 ex result = fun.subs(var==value).evalf(); 00208 if (is_a<numeric>(result)) 00209 return result; 00210 throw logic_error("integrand does not evaluate to numeric"); 00211 } 00212 00213 struct error_and_integral 00214 { 00215 error_and_integral(const ex &err, const ex &integ) 00216 :error(err), integral(integ){} 00217 ex error; 00218 ex integral; 00219 }; 00220 00221 struct error_and_integral_is_less 00222 { 00223 bool operator()(const error_and_integral &e1,const error_and_integral &e2) const 00224 { 00225 int c = e1.integral.compare(e2.integral); 00226 if(c < 0) 00227 return true; 00228 if(c > 0) 00229 return false; 00230 return ex_is_less()(e1.error, e2.error); 00231 } 00232 }; 00233 00234 typedef map<error_and_integral, ex, error_and_integral_is_less> lookup_map; 00235 00243 ex adaptivesimpson(const ex & x, const ex & a_in, const ex & b_in, const ex & f, const ex & error) 00244 { 00245 // Check whether boundaries and error are numbers. 00246 ex a = is_exactly_a<numeric>(a_in) ? a_in : a_in.evalf(); 00247 ex b = is_exactly_a<numeric>(b_in) ? b_in : b_in.evalf(); 00248 if(!is_exactly_a<numeric>(a) || !is_exactly_a<numeric>(b)) 00249 throw std::runtime_error("For numerical integration the boundaries of the integral should evalf into numbers."); 00250 if(!is_exactly_a<numeric>(error)) 00251 throw std::runtime_error("For numerical integration the error should be a number."); 00252 00253 // Use lookup table to be potentially much faster. 00254 static lookup_map lookup; 00255 static symbol ivar("ivar"); 00256 ex lookupex = integral(ivar,a,b,f.subs(x==ivar)); 00257 lookup_map::iterator emi = lookup.find(error_and_integral(error, lookupex)); 00258 if (emi!=lookup.end()) 00259 return emi->second; 00260 00261 ex app = 0; 00262 int i = 1; 00263 exvector avec(integral::max_integration_level+1); 00264 exvector hvec(integral::max_integration_level+1); 00265 exvector favec(integral::max_integration_level+1); 00266 exvector fbvec(integral::max_integration_level+1); 00267 exvector fcvec(integral::max_integration_level+1); 00268 exvector svec(integral::max_integration_level+1); 00269 exvector errorvec(integral::max_integration_level+1); 00270 vector<int> lvec(integral::max_integration_level+1); 00271 00272 avec[i] = a; 00273 hvec[i] = (b-a)/2; 00274 favec[i] = subsvalue(x, a, f); 00275 fcvec[i] = subsvalue(x, a+hvec[i], f); 00276 fbvec[i] = subsvalue(x, b, f); 00277 svec[i] = hvec[i]*(favec[i]+4*fcvec[i]+fbvec[i])/3; 00278 lvec[i] = 1; 00279 errorvec[i] = error*abs(svec[i]); 00280 00281 while (i>0) { 00282 ex fd = subsvalue(x, avec[i]+hvec[i]/2, f); 00283 ex fe = subsvalue(x, avec[i]+3*hvec[i]/2, f); 00284 ex s1 = hvec[i]*(favec[i]+4*fd+fcvec[i])/6; 00285 ex s2 = hvec[i]*(fcvec[i]+4*fe+fbvec[i])/6; 00286 ex nu1 = avec[i]; 00287 ex nu2 = favec[i]; 00288 ex nu3 = fcvec[i]; 00289 ex nu4 = fbvec[i]; 00290 ex nu5 = hvec[i]; 00291 // hopefully prevents a crash if the function is zero sometimes. 00292 ex nu6 = max(errorvec[i], abs(s1+s2)*error); 00293 ex nu7 = svec[i]; 00294 int nu8 = lvec[i]; 00295 --i; 00296 if (abs(ex_to<numeric>(s1+s2-nu7)) <= nu6) 00297 app+=(s1+s2); 00298 else { 00299 if (nu8>=integral::max_integration_level) 00300 throw runtime_error("max integration level reached"); 00301 ++i; 00302 avec[i] = nu1+nu5; 00303 favec[i] = nu3; 00304 fcvec[i] = fe; 00305 fbvec[i] = nu4; 00306 hvec[i] = nu5/2; 00307 errorvec[i]=nu6/2; 00308 svec[i] = s2; 00309 lvec[i] = nu8+1; 00310 ++i; 00311 avec[i] = nu1; 00312 favec[i] = nu2; 00313 fcvec[i] = fd; 00314 fbvec[i] = nu3; 00315 hvec[i] = hvec[i-1]; 00316 errorvec[i]=errorvec[i-1]; 00317 svec[i] = s1; 00318 lvec[i] = lvec[i-1]; 00319 } 00320 } 00321 00322 lookup[error_and_integral(error, lookupex)]=app; 00323 return app; 00324 } 00325 00326 int integral::degree(const ex & s) const 00327 { 00328 return ((b-a)*f).degree(s); 00329 } 00330 00331 int integral::ldegree(const ex & s) const 00332 { 00333 return ((b-a)*f).ldegree(s); 00334 } 00335 00336 ex integral::eval_ncmul(const exvector & v) const 00337 { 00338 return f.eval_ncmul(v); 00339 } 00340 00341 size_t integral::nops() const 00342 { 00343 return 4; 00344 } 00345 00346 ex integral::op(size_t i) const 00347 { 00348 GINAC_ASSERT(i<4); 00349 00350 switch (i) { 00351 case 0: 00352 return x; 00353 case 1: 00354 return a; 00355 case 2: 00356 return b; 00357 case 3: 00358 return f; 00359 default: 00360 throw (std::out_of_range("integral::op() out of range")); 00361 } 00362 } 00363 00364 ex & integral::let_op(size_t i) 00365 { 00366 ensure_if_modifiable(); 00367 switch (i) { 00368 case 0: 00369 return x; 00370 case 1: 00371 return a; 00372 case 2: 00373 return b; 00374 case 3: 00375 return f; 00376 default: 00377 throw (std::out_of_range("integral::let_op() out of range")); 00378 } 00379 } 00380 00381 ex integral::expand(unsigned options) const 00382 { 00383 if (options==0 && (flags & status_flags::expanded)) 00384 return *this; 00385 00386 ex newa = a.expand(options); 00387 ex newb = b.expand(options); 00388 ex newf = f.expand(options); 00389 00390 if (is_a<add>(newf)) { 00391 exvector v; 00392 v.reserve(newf.nops()); 00393 for (size_t i=0; i<newf.nops(); ++i) 00394 v.push_back(integral(x, newa, newb, newf.op(i)).expand(options)); 00395 return ex(add(v)).expand(options); 00396 } 00397 00398 if (is_a<mul>(newf)) { 00399 ex prefactor = 1; 00400 ex rest = 1; 00401 for (size_t i=0; i<newf.nops(); ++i) 00402 if (newf.op(i).has(x)) 00403 rest *= newf.op(i); 00404 else 00405 prefactor *= newf.op(i); 00406 if (prefactor != 1) 00407 return (prefactor*integral(x, newa, newb, rest)).expand(options); 00408 } 00409 00410 if (are_ex_trivially_equal(a, newa) && are_ex_trivially_equal(b, newb) 00411 && are_ex_trivially_equal(f, newf)) { 00412 if (options==0) 00413 this->setflag(status_flags::expanded); 00414 return *this; 00415 } 00416 00417 const basic & newint = (new integral(x, newa, newb, newf)) 00418 ->setflag(status_flags::dynallocated); 00419 if (options == 0) 00420 newint.setflag(status_flags::expanded); 00421 return newint; 00422 } 00423 00424 ex integral::derivative(const symbol & s) const 00425 { 00426 if (s==x) 00427 throw(logic_error("differentiation with respect to dummy variable")); 00428 return b.diff(s)*f.subs(x==b)-a.diff(s)*f.subs(x==a)+integral(x, a, b, f.diff(s)); 00429 } 00430 00431 unsigned integral::return_type() const 00432 { 00433 return f.return_type(); 00434 } 00435 00436 return_type_t integral::return_type_tinfo() const 00437 { 00438 return f.return_type_tinfo(); 00439 } 00440 00441 ex integral::conjugate() const 00442 { 00443 ex conja = a.conjugate(); 00444 ex conjb = b.conjugate(); 00445 ex conjf = f.conjugate().subs(x.conjugate()==x); 00446 00447 if (are_ex_trivially_equal(a, conja) && are_ex_trivially_equal(b, conjb) 00448 && are_ex_trivially_equal(f, conjf)) 00449 return *this; 00450 00451 return (new integral(x, conja, conjb, conjf)) 00452 ->setflag(status_flags::dynallocated); 00453 } 00454 00455 ex integral::eval_integ() const 00456 { 00457 if (!(flags & status_flags::expanded)) 00458 return this->expand().eval_integ(); 00459 00460 if (f==x) 00461 return b*b/2-a*a/2; 00462 if (is_a<power>(f) && f.op(0)==x) { 00463 if (f.op(1)==-1) 00464 return log(b/a); 00465 if (!f.op(1).has(x)) { 00466 ex primit = power(x,f.op(1)+1)/(f.op(1)+1); 00467 return primit.subs(x==b)-primit.subs(x==a); 00468 } 00469 } 00470 00471 return *this; 00472 } 00473 00474 GINAC_BIND_UNARCHIVER(integral); 00475 } // namespace GiNaC