X-Git-Url: https://www.ginac.de/ginac.git//ginac.git?p=ginac.git;a=blobdiff_plain;f=ginac%2Fintegral.cpp;h=d2d451b4b4a41258f9941a9be43f8b59c4cb12c6;hp=467cf2909a6aa02f702586d1c1db82151ec4b502;hb=c12c8ec3c5cf0c75f061f6c52d04206277bbdcca;hpb=c0ba2b239690e1b97aaecb860930b170a2bc1df2 diff --git a/ginac/integral.cpp b/ginac/integral.cpp index 467cf290..d2d451b4 100644 --- a/ginac/integral.cpp +++ b/ginac/integral.cpp @@ -3,7 +3,7 @@ * Implementation of GiNaC's symbolic integral. */ /* - * GiNaC Copyright (C) 1999-2004 Johannes Gutenberg University Mainz, Germany + * GiNaC Copyright (C) 1999-2016 Johannes Gutenberg University Mainz, Germany * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,7 +17,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "integral.h" @@ -48,8 +48,7 @@ GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(integral, basic, ////////// integral::integral() - : inherited(TINFO_integral), - x((new symbol())->setflag(status_flags::dynallocated)) + : x(dynallocate()) {} ////////// @@ -59,7 +58,7 @@ integral::integral() // public integral::integral(const ex & x_, const ex & a_, const ex & b_, const ex & f_) - : inherited(TINFO_integral), x(x_), a(a_), b(b_), f(f_) + : x(x_), a(a_), b(b_), f(f_) { if (!is_a(x)) { throw(std::invalid_argument("first argument of integral must be of type symbol")); @@ -70,8 +69,9 @@ integral::integral(const ex & x_, const ex & a_, const ex & b_, const ex & f_) // archiving ////////// -integral::integral(const archive_node & n, lst & sym_lst) : inherited(n, sym_lst) +void integral::read_archive(const archive_node& n, lst& sym_lst) { + inherited::read_archive(n, sym_lst); n.find_ex("x", x, sym_lst); n.find_ex("a", a, sym_lst); n.find_ex("b", b, sym_lst); @@ -87,8 +87,6 @@ void integral::archive(archive_node & n) const n.add_ex("f", f); } -DEFAULT_UNARCHIVE(integral) - ////////// // functions overriding virtual functions from base classes ////////// @@ -142,77 +140,74 @@ int integral::compare_same_type(const basic & other) const return f.compare(o.f); } -ex integral::eval(int level) const +ex integral::eval() const { - if ((level==1) && (flags & status_flags::evaluated)) + if (flags & status_flags::evaluated) return *this; - if (level == -max_recursion_level) - throw(std::runtime_error("max recursion level reached")); - - ex eintvar = (level==1) ? x : x.eval(level-1); - ex ea = (level==1) ? a : a.eval(level-1); - ex eb = (level==1) ? b : b.eval(level-1); - ex ef = (level==1) ? f : f.eval(level-1); - if (!ef.has(eintvar) && !haswild(ef)) - return eb*ef-ea*ef; + if (!f.has(x) && !haswild(f)) + return b*f-a*f; - if (ea==eb) + if (a==b) return _ex0; - if (are_ex_trivially_equal(eintvar,x) && are_ex_trivially_equal(ea,a) - && are_ex_trivially_equal(eb,b) && are_ex_trivially_equal(ef,f)) - return this->hold(); - return (new integral(eintvar, ea, eb, ef)) - ->setflag(status_flags::dynallocated | status_flags::evaluated); + return this->hold(); } -ex integral::evalf(int level) const +ex integral::evalf() const { - ex ea; - ex eb; - ex ef; - - if (level==1) { - ea = a; - eb = b; - ef = f; - } else if (level == -max_recursion_level) { - throw(runtime_error("max recursion level reached")); - } else { - ea = a.evalf(level-1); - eb = b.evalf(level-1); - ef = f.evalf(level-1); - } + ex ea = a.evalf(); + ex eb = b.evalf(); + ex ef = f.evalf(); // 12.34 is just an arbitrary number used to check whether a number - // results after subsituting a number for the integration variable. - if (is_exactly_a(ea) && is_exactly_a(eb) - && is_exactly_a(ef.subs(x==12.34).evalf())) { - try { + // results after substituting a number for the integration variable. + if (is_exactly_a(ea) && is_exactly_a(eb) && + is_exactly_a(ef.subs(x==12.34).evalf())) { return adaptivesimpson(x, ea, eb, ef); - } catch (runtime_error &rte) {} } - if (are_ex_trivially_equal(a, ea) && are_ex_trivially_equal(b, eb) - && are_ex_trivially_equal(f, ef)) + if (are_ex_trivially_equal(a, ea) && are_ex_trivially_equal(b, eb) && + are_ex_trivially_equal(f, ef)) return *this; else - return (new integral(x, ea, eb, ef)) - ->setflag(status_flags::dynallocated); + return dynallocate(x, ea, eb, ef); } int integral::max_integration_level = 15; -ex integral::relative_integration_error = power(10,-8).evalf(); +ex integral::relative_integration_error = 1e-8; ex subsvalue(const ex & var, const ex & value, const ex & fun) { ex result = fun.subs(var==value).evalf(); if (is_a(result)) return result; - throw logic_error("integrant does not evaluate to numeric"); + throw logic_error("integrand does not evaluate to numeric"); } +struct error_and_integral +{ + error_and_integral(const ex &err, const ex &integ) + :error(err), integral(integ){} + ex error; + ex integral; +}; + +struct error_and_integral_is_less +{ + bool operator()(const error_and_integral &e1,const error_and_integral &e2) const + { + int c = e1.integral.compare(e2.integral); + if(c < 0) + return true; + if(c > 0) + return false; + return ex_is_less()(e1.error, e2.error); + } +}; + +typedef map lookup_map; + /** Numeric integration routine based upon the "Adaptive Quadrature" one * in "Numerical Analysis" by Burden and Faires. Parameters are integration * variable, left boundary, right boundary, function to be integrated and @@ -220,13 +215,21 @@ ex subsvalue(const ex & var, const ex & value, const ex & fun) * after substituting the integration variable by a number. Another thing * to note is that this implementation is no good at integrating functions * with discontinuities. */ -ex adaptivesimpson(const ex & x, const ex & a, const ex & b, const ex & f, const ex & error) +ex adaptivesimpson(const ex & x, const ex & a_in, const ex & b_in, const ex & f, const ex & error) { - // use lookup table to be potentially much faster. - static exmap lookup; + // Check whether boundaries and error are numbers. + ex a = is_exactly_a(a_in) ? a_in : a_in.evalf(); + ex b = is_exactly_a(b_in) ? b_in : b_in.evalf(); + if(!is_exactly_a(a) || !is_exactly_a(b)) + throw std::runtime_error("For numerical integration the boundaries of the integral should evalf into numbers."); + if(!is_exactly_a(error)) + throw std::runtime_error("For numerical integration the error should be a number."); + + // Use lookup table to be potentially much faster. + static lookup_map lookup; static symbol ivar("ivar"); ex lookupex = integral(ivar,a,b,f.subs(x==ivar)); - exmap::iterator emi = lookup.find(lookupex); + lookup_map::iterator emi = lookup.find(error_and_integral(error, lookupex)); if (emi!=lookup.end()) return emi->second; @@ -248,7 +251,7 @@ ex adaptivesimpson(const ex & x, const ex & a, const ex & b, const ex & f, const fbvec[i] = subsvalue(x, b, f); svec[i] = hvec[i]*(favec[i]+4*fcvec[i]+fbvec[i])/3; lvec[i] = 1; - errorvec[i] = integral::relative_integration_error*svec[i]; + errorvec[i] = error*abs(svec[i]); while (i>0) { ex fd = subsvalue(x, avec[i]+hvec[i]/2, f); @@ -261,7 +264,7 @@ ex adaptivesimpson(const ex & x, const ex & a, const ex & b, const ex & f, const ex nu4 = fbvec[i]; ex nu5 = hvec[i]; // hopefully prevents a crash if the function is zero sometimes. - ex nu6 = max(errorvec[i], (s1+s2)*integral::relative_integration_error); + ex nu6 = max(errorvec[i], abs(s1+s2)*error); ex nu7 = svec[i]; int nu8 = lvec[i]; --i; @@ -291,7 +294,7 @@ ex adaptivesimpson(const ex & x, const ex & a, const ex & b, const ex & f, const } } - lookup[lookupex]=app; + lookup[error_and_integral(error, lookupex)]=app; return app; } @@ -319,30 +322,34 @@ ex integral::op(size_t i) const { GINAC_ASSERT(i<4); - switch(i) { - case(0): + switch (i) { + case 0: return x; - case(1): + case 1: return a; - case(2): + case 2: return b; - case(3): + case 3: return f; + default: + throw (std::out_of_range("integral::op() out of range")); } } ex & integral::let_op(size_t i) { ensure_if_modifiable(); - switch(i) { - case(0): + switch (i) { + case 0: return x; - case(1): + case 1: return a; - case(2): + case 2: return b; - case(3): + case 3: return f; + default: + throw (std::out_of_range("integral::let_op() out of range")); } } @@ -375,22 +382,22 @@ ex integral::expand(unsigned options) const return (prefactor*integral(x, newa, newb, rest)).expand(options); } - if (are_ex_trivially_equal(a, newa) && are_ex_trivially_equal(b, newb) - && are_ex_trivially_equal(f, newf)) { + if (are_ex_trivially_equal(a, newa) && are_ex_trivially_equal(b, newb) && + are_ex_trivially_equal(f, newf)) { if (options==0) this->setflag(status_flags::expanded); return *this; } - const basic & newint = (new integral(x, newa, newb, newf)) - ->setflag(status_flags::dynallocated); + const integral & newint = dynallocate(x, newa, newb, newf); if (options == 0) newint.setflag(status_flags::expanded); return newint; } ex integral::derivative(const symbol & s) const -{ if (s==x) +{ + if (s==x) throw(logic_error("differentiation with respect to dummy variable")); return b.diff(s)*f.subs(x==b)-a.diff(s)*f.subs(x==a)+integral(x, a, b, f.diff(s)); } @@ -400,7 +407,7 @@ unsigned integral::return_type() const return f.return_type(); } -unsigned integral::return_type_tinfo() const +return_type_t integral::return_type_tinfo() const { return f.return_type_tinfo(); } @@ -411,12 +418,11 @@ ex integral::conjugate() const ex conjb = b.conjugate(); ex conjf = f.conjugate().subs(x.conjugate()==x); - if (are_ex_trivially_equal(a, conja) && are_ex_trivially_equal(b, conjb) - && are_ex_trivially_equal(f, conjf)) + if (are_ex_trivially_equal(a, conja) && are_ex_trivially_equal(b, conjb) && + are_ex_trivially_equal(f, conjf)) return *this; - return (new integral(x, conja, conjb, conjf)) - ->setflag(status_flags::dynallocated); + return dynallocate(x, conja, conjb, conjf); } ex integral::eval_integ() const @@ -438,4 +444,5 @@ ex integral::eval_integ() const return *this; } +GINAC_BIND_UNARCHIVER(integral); } // namespace GiNaC