GiNaC 1.8.10
integral.cpp
Go to the documentation of this file.
1
5/*
6 * GiNaC Copyright (C) 1999-2026 Johannes Gutenberg University Mainz, Germany
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22#include "integral.h"
23#include "numeric.h"
24#include "symbol.h"
25#include "add.h"
26#include "mul.h"
27#include "power.h"
28#include "inifcns.h"
29#include "wildcard.h"
30#include "archive.h"
31#include "registrar.h"
32#include "utils.h"
33#include "operators.h"
34#include "relational.h"
35
36using namespace std;
37
38namespace GiNaC {
39
42 print_func<print_python>(&integral::do_print).
43 print_func<print_latex>(&integral::do_print_latex))
44
45
46
47// default constructor
49
51 : x(dynallocate<symbol>())
52{}
53
55// other constructors
57
58// public
59
60integral::integral(const ex & x_, const ex & a_, const ex & b_, const ex & f_)
61 : x(x_), a(a_), b(b_), f(f_)
62{
63 if (!is_a<symbol>(x)) {
64 throw(std::invalid_argument("first argument of integral must be of type symbol"));
65 }
66}
67
69// archiving
71
73{
74 inherited::read_archive(n, sym_lst);
75 n.find_ex("x", x, sym_lst);
76 n.find_ex("a", a, sym_lst);
77 n.find_ex("b", b, sym_lst);
78 n.find_ex("f", f, sym_lst);
79}
80
82{
83 inherited::archive(n);
84 n.add_ex("x", x);
85 n.add_ex("a", a);
86 n.add_ex("b", b);
87 n.add_ex("f", f);
88}
89
91// functions overriding virtual functions from base classes
93
94void integral::do_print(const print_context & c, unsigned level) const
95{
96 c.s << "integral(";
97 x.print(c);
98 c.s << ",";
99 a.print(c);
100 c.s << ",";
101 b.print(c);
102 c.s << ",";
103 f.print(c);
104 c.s << ")";
105}
106
107void integral::do_print_latex(const print_latex & c, unsigned level) const
108{
109 string varname = ex_to<symbol>(x).get_name();
110 if (level > precedence())
111 c.s << "\\left(";
112 c.s << "\\int_{";
113 a.print(c);
114 c.s << "}^{";
115 b.print(c);
116 c.s << "} d";
117 if (varname.size() > 1)
118 c.s << "\\," << varname << "\\:";
119 else
120 c.s << varname << "\\,";
121 f.print(c,precedence());
122 if (level > precedence())
123 c.s << "\\right)";
124}
125
126int integral::compare_same_type(const basic & other) const
127{
128 GINAC_ASSERT(is_exactly_a<integral>(other));
129 const integral &o = static_cast<const integral &>(other);
130
131 int cmpval = x.compare(o.x);
132 if (cmpval)
133 return cmpval;
134 cmpval = a.compare(o.a);
135 if (cmpval)
136 return cmpval;
137 cmpval = b.compare(o.b);
138 if (cmpval)
139 return cmpval;
140 return f.compare(o.f);
141}
142
144{
146 return *this;
147
148 if (!f.has(x) && !haswild(f))
149 return b*f-a*f;
150
151 if (a==b)
152 return _ex0;
153
154 return this->hold();
155}
156
158{
159 ex ea = a.evalf();
160 ex eb = b.evalf();
161 ex ef = f.evalf();
162
163 // 12.34 is just an arbitrary number used to check whether a number
164 // results after substituting a number for the integration variable.
165 if (is_exactly_a<numeric>(ea) && is_exactly_a<numeric>(eb) &&
166 is_exactly_a<numeric>(ef.subs(x==12.34).evalf())) {
167 return adaptivesimpson(x, ea, eb, ef);
168 }
169
172 return *this;
173 else
174 return dynallocate<integral>(x, ea, eb, ef);
175}
176
179
180ex subsvalue(const ex & var, const ex & value, const ex & fun)
181{
182 ex result = fun.subs(var==value).evalf();
183 if (is_a<numeric>(result))
184 return result;
185 throw logic_error("integrand does not evaluate to numeric");
186}
187
189{
190 error_and_integral(const ex &err, const ex &integ)
191 :error(err), integral(integ){}
194};
195
197{
198 bool operator()(const error_and_integral &e1,const error_and_integral &e2) const
199 {
200 int c = e1.integral.compare(e2.integral);
201 if(c < 0)
202 return true;
203 if(c > 0)
204 return false;
205 return ex_is_less()(e1.error, e2.error);
206 }
207};
208
209typedef map<error_and_integral, ex, error_and_integral_is_less> lookup_map;
210
218ex adaptivesimpson(const ex & x, const ex & a_in, const ex & b_in, const ex & f, const ex & error)
219{
220 // Check whether boundaries and error are numbers.
221 ex a = is_exactly_a<numeric>(a_in) ? a_in : a_in.evalf();
222 ex b = is_exactly_a<numeric>(b_in) ? b_in : b_in.evalf();
223 if(!is_exactly_a<numeric>(a) || !is_exactly_a<numeric>(b))
224 throw std::runtime_error("For numerical integration the boundaries of the integral should evalf into numbers.");
225 if(!is_exactly_a<numeric>(error))
226 throw std::runtime_error("For numerical integration the error should be a number.");
227
228 // Use lookup table to be potentially much faster.
229 static lookup_map lookup;
230 static symbol ivar("ivar");
231 ex lookupex = integral(ivar,a,b,f.subs(x==ivar));
232 auto emi = lookup.find(error_and_integral(error, lookupex));
233 if (emi!=lookup.end())
234 return emi->second;
235
236 ex app = 0;
237 int i = 1;
245 vector<int> lvec(integral::max_integration_level+1);
246
247 avec[i] = a;
248 hvec[i] = (b-a)/2;
249 favec[i] = subsvalue(x, a, f);
250 fcvec[i] = subsvalue(x, a+hvec[i], f);
251 fbvec[i] = subsvalue(x, b, f);
252 svec[i] = hvec[i]*(favec[i]+4*fcvec[i]+fbvec[i])/3;
253 lvec[i] = 1;
254 errorvec[i] = error*abs(svec[i]);
255
256 while (i>0) {
257 ex fd = subsvalue(x, avec[i]+hvec[i]/2, f);
258 ex fe = subsvalue(x, avec[i]+3*hvec[i]/2, f);
259 ex s1 = hvec[i]*(favec[i]+4*fd+fcvec[i])/6;
260 ex s2 = hvec[i]*(fcvec[i]+4*fe+fbvec[i])/6;
261 ex nu1 = avec[i];
262 ex nu2 = favec[i];
263 ex nu3 = fcvec[i];
264 ex nu4 = fbvec[i];
265 ex nu5 = hvec[i];
266 // hopefully prevents a crash if the function is zero sometimes.
267 ex nu6 = max(errorvec[i], abs(s1+s2)*error);
268 ex nu7 = svec[i];
269 int nu8 = lvec[i];
270 --i;
271 if (abs(ex_to<numeric>(s1+s2-nu7)) <= nu6)
272 app+=(s1+s2);
273 else {
275 throw runtime_error("max integration level reached");
276 ++i;
277 avec[i] = nu1+nu5;
278 favec[i] = nu3;
279 fcvec[i] = fe;
280 fbvec[i] = nu4;
281 hvec[i] = nu5/2;
282 errorvec[i]=nu6/2;
283 svec[i] = s2;
284 lvec[i] = nu8+1;
285 ++i;
286 avec[i] = nu1;
287 favec[i] = nu2;
288 fcvec[i] = fd;
289 fbvec[i] = nu3;
290 hvec[i] = hvec[i-1];
291 errorvec[i]=errorvec[i-1];
292 svec[i] = s1;
293 lvec[i] = lvec[i-1];
294 }
295 }
296
297 lookup[error_and_integral(error, lookupex)]=app;
298 return app;
299}
300
301int integral::degree(const ex & s) const
302{
303 return ((b-a)*f).degree(s);
304}
305
306int integral::ldegree(const ex & s) const
307{
308 return ((b-a)*f).ldegree(s);
309}
310
312{
313 return f.eval_ncmul(v);
314}
315
316size_t integral::nops() const
317{
318 return 4;
319}
320
321ex integral::op(size_t i) const
322{
323 GINAC_ASSERT(i<4);
324
325 switch (i) {
326 case 0:
327 return x;
328 case 1:
329 return a;
330 case 2:
331 return b;
332 case 3:
333 return f;
334 default:
335 throw (std::out_of_range("integral::op() out of range"));
336 }
337}
338
340{
342 switch (i) {
343 case 0:
344 return x;
345 case 1:
346 return a;
347 case 2:
348 return b;
349 case 3:
350 return f;
351 default:
352 throw (std::out_of_range("integral::let_op() out of range"));
353 }
354}
355
357{
359 return *this;
360
361 ex newa = a.expand(options);
362 ex newb = b.expand(options);
363 ex newf = f.expand(options);
364
365 if (is_a<add>(newf)) {
366 exvector v;
367 v.reserve(newf.nops());
368 for (size_t i=0; i<newf.nops(); ++i)
369 v.push_back(integral(x, newa, newb, newf.op(i)).expand(options));
370 return ex(add(v)).expand(options);
371 }
372
373 if (is_a<mul>(newf)) {
374 ex prefactor = 1;
375 ex rest = 1;
376 for (size_t i=0; i<newf.nops(); ++i)
377 if (newf.op(i).has(x))
378 rest *= newf.op(i);
379 else
380 prefactor *= newf.op(i);
381 if (prefactor != 1)
382 return (prefactor*integral(x, newa, newb, rest)).expand(options);
383 }
384
385 if (are_ex_trivially_equal(a, newa) && are_ex_trivially_equal(b, newb) &&
386 are_ex_trivially_equal(f, newf)) {
387 if (options==0)
388 this->setflag(status_flags::expanded);
389 return *this;
390 }
391
392 const integral & newint = dynallocate<integral>(x, newa, newb, newf);
393 if (options == 0)
395 return newint;
396}
397
399{
400 if (s==x)
401 throw(logic_error("differentiation with respect to dummy variable"));
402 return b.diff(s)*f.subs(x==b)-a.diff(s)*f.subs(x==a)+integral(x, a, b, f.diff(s));
403}
404
405unsigned integral::return_type() const
406{
407 return f.return_type();
408}
409
414
416{
417 ex conja = a.conjugate();
418 ex conjb = b.conjugate();
419 ex conjf = f.conjugate().subs(x.conjugate()==x);
420
421 if (are_ex_trivially_equal(a, conja) && are_ex_trivially_equal(b, conjb) &&
423 return *this;
424
425 return dynallocate<integral>(x, conja, conjb, conjf);
426}
427
429{
431 return this->expand().eval_integ();
432
433 if (f==x)
434 return b*b/2-a*a/2;
435 if (is_a<power>(f) && f.op(0)==x) {
436 if (f.op(1)==-1)
437 return log(b/a);
438 if (!f.op(1).has(x)) {
439 ex primit = power(x,f.op(1)+1)/(f.op(1)+1);
440 return primit.subs(x==b)-primit.subs(x==a);
441 }
442 }
443
444 return *this;
445}
446
448} // namespace GiNaC
Interface to GiNaC's sums of expressions.
Archiving of GiNaC expressions.
#define GINAC_ASSERT(X)
Assertion macro for checking invariances.
Definition assertion.h:32
Sum of expressions.
Definition add.h:31
This class stores all properties needed to record/retrieve the state of one object of class basic (or...
Definition archive.h:48
This class is the ABC (abstract base class) of GiNaC's class hierarchy.
Definition basic.h:104
const basic & setflag(unsigned f) const
Set some status_flags.
Definition basic.h:287
void ensure_if_modifiable() const
Ensure the object may be modified without hurting others, throws if this is not the case.
Definition basic.cpp:893
friend class ex
Definition basic.h:107
unsigned flags
of type status_flags
Definition basic.h:301
const basic & hold() const
Stop further evaluation.
Definition basic.cpp:886
virtual int compare_same_type(const basic &other) const
Returns order relation between two objects of same type.
Definition basic.cpp:718
Wrapper template for making GiNaC classes out of STL containers.
Definition container.h:72
Lightweight wrapper for GiNaC's symbolic objects.
Definition ex.h:72
ex eval_integ() const
Definition ex.h:124
ex diff(const symbol &s, unsigned nth=1) const
Compute partial derivative of an expression.
Definition ex.cpp:86
ex expand(unsigned options=0) const
Expand an expression.
Definition ex.cpp:73
int degree(const ex &s) const
Definition ex.h:173
bool has(const ex &pattern, unsigned options=0) const
Definition ex.h:151
ex evalf() const
Definition ex.h:121
ex eval_ncmul(const exvector &v) const
Definition ex.h:123
ex conjugate() const
Definition ex.h:146
unsigned return_type() const
Definition ex.h:230
return_type_t return_type_tinfo() const
Definition ex.h:231
size_t nops() const
Definition ex.h:135
ex subs(const exmap &m, unsigned options=0) const
Definition ex.h:841
int compare(const ex &other) const
Definition ex.h:322
void print(const print_context &c, unsigned level=0) const
Print expression to stream.
Definition ex.cpp:54
ex op(size_t i) const
Definition ex.h:136
Symbolic integral.
Definition integral.h:33
ex evalf() const override
Evaluate object numerically.
Definition integral.cpp:157
void do_print(const print_context &c, unsigned level) const
Definition integral.cpp:94
static ex relative_integration_error
Definition integral.h:74
ex expand(unsigned options=0) const override
Expand expression, i.e.
Definition integral.cpp:356
unsigned return_type() const override
Definition integral.cpp:405
int degree(const ex &s) const override
Return degree of highest power in object s.
Definition integral.cpp:301
ex eval() const override
Perform automatic non-interruptive term rewriting rules.
Definition integral.cpp:143
size_t nops() const override
Number of operands/members.
Definition integral.cpp:316
ex conjugate() const override
Definition integral.cpp:415
unsigned precedence() const override
Return relative operator precedence (for parenthezing output).
Definition integral.h:42
ex eval_integ() const override
Evaluate integrals, if result is known.
Definition integral.cpp:428
ex eval_ncmul(const exvector &v) const override
Definition integral.cpp:311
int ldegree(const ex &s) const override
Return degree of lowest power in object s.
Definition integral.cpp:306
void do_print_latex(const print_latex &c, unsigned level) const
Definition integral.cpp:107
integral(const ex &x_, const ex &a_, const ex &b_, const ex &f_)
Definition integral.cpp:60
ex & let_op(size_t i) override
Return modifiable operand/member at position i.
Definition integral.cpp:339
void read_archive(const archive_node &n, lst &syms) override
Read (a.k.a.
Definition integral.cpp:72
ex op(size_t i) const override
Return operand/member at position i.
Definition integral.cpp:321
void archive(archive_node &n) const override
Save (a.k.a.
Definition integral.cpp:81
return_type_t return_type_tinfo() const override
Definition integral.cpp:410
static int max_integration_level
Definition integral.h:73
ex derivative(const symbol &s) const override
Default implementation of ex::diff().
Definition integral.cpp:398
This class holds a two-component object, a basis and and exponent representing exponentiation.
Definition power.h:38
Base class for print_contexts.
Definition print.h:101
Context for latex-parsable output.
Definition print.h:121
@ expanded
.expand(0) has already done its job (other expand() options ignore this flag)
Definition flags.h:203
@ evaluated
.eval() has already done its job
Definition flags.h:202
Basic CAS symbol.
Definition symbol.h:38
static const bool value
Definition factor.cpp:198
unsigned options
Definition factor.cpp:2473
size_t n
Definition factor.cpp:1431
size_t c
Definition factor.cpp:756
ex x
Definition factor.cpp:1609
Interface to GiNaC's initially known functions.
Interface to GiNaC's symbolic integral.
Interface to GiNaC's products of expressions.
Definition add.cpp:35
bool haswild(const ex &x)
Check whether x has a wildcard anywhere as a subexpression.
Definition wildcard.cpp:121
ex adaptivesimpson(const ex &x, const ex &a_in, const ex &b_in, const ex &f, const ex &error)
Numeric integration routine based upon the "Adaptive Quadrature" one in "Numerical Analysis" by Burde...
Definition integral.cpp:218
B & dynallocate(Args &&... args)
Constructs a new (class basic or derived) B object on the heap.
Definition basic.h:333
const numeric abs(const numeric &x)
Absolute value.
Definition numeric.cpp:2319
bool are_ex_trivially_equal(const ex &e1, const ex &e2)
Compare two objects of class quickly without doing a deep tree traversal.
Definition ex.h:699
print_func< print_dflt >(&diracone::do_print). print_func< print_latex >(&diracone
Definition clifford.cpp:51
ex subsvalue(const ex &var, const ex &value, const ex &fun)
Definition integral.cpp:180
const numeric log(const numeric &x)
Natural logarithm.
Definition numeric.cpp:1449
GINAC_IMPLEMENT_REGISTERED_CLASS_OPT_T(lst, basic, print_func< print_context >(&lst::do_print). print_func< print_tree >(&lst::do_print_tree)) template<> bool lst GINAC_BIND_UNARCHIVER(lst)
Specialization of container::info() for lst.
Definition lst.cpp:41
const ex _ex0
Definition utils.cpp:368
std::vector< ex > exvector
Definition basic.h:47
map< error_and_integral, ex, error_and_integral_is_less > lookup_map
Definition integral.cpp:209
Definition ex.h:987
Makes the interface to the underlying bignum package available.
Interface to GiNaC's overloaded operators.
Interface to GiNaC's symbolic exponentiation (basis^exponent).
GiNaC's class registrar (for class basic and all classes derived from it).
#define GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(classname, supername, options)
Macro for inclusion in the implementation of each registered class.
Definition registrar.h:183
Interface to relations between expressions.
bool operator()(const error_and_integral &e1, const error_and_integral &e2) const
Definition integral.cpp:198
error_and_integral(const ex &err, const ex &integ)
Definition integral.cpp:190
To distinguish between different kinds of non-commutative objects.
Definition registrar.h:42
Interface to GiNaC's symbolic objects.
Interface to several small and furry utilities needed within GiNaC but not of any interest to the use...
Interface to GiNaC's wildcard objects.

This page is part of the GiNaC developer's reference. It was generated automatically by doxygen. For an introduction, see the tutorial.