2 from sympy
.core
import Basic
, S
, C
, Symbol
, Wild
, Pow
, sympify
3 from sympy
.core
.methods
import RelMeths
, ArithMeths
5 from sympy
.integrals
.trigonometry
import trigintegrate
6 from sympy
.integrals
.risch
import heurisch
7 from sympy
.utilities
import threaded
8 from sympy
.simplify
import apart
9 from sympy
.series
import limit
10 from sympy
.polys
import Poly
11 from sympy
.solvers
import solve
13 class Integral(Basic
, RelMeths
, ArithMeths
):
14 """Represents unevaluated integral."""
16 def __new__(cls
, function
, *symbols
, **assumptions
):
17 function
= sympify(function
)
19 if function
.is_Number
:
22 elif function
is S
.Infinity
:
24 elif function
is S
.NegativeInfinity
:
25 return S
.NegativeInfinity
31 if isinstance(V
, Symbol
):
32 limits
.append((V
,None))
34 elif isinstance(V
, (tuple, list)):
36 limits
.append( (V
[0],tuple(V
[1:])) )
39 if isinstance(V
[0], Symbol
):
40 limits
.append((V
[0],None))
43 raise ValueError("Invalid integration variable or limits")
45 # no symbols provided -- let's compute full antiderivative
46 limits
= [(symb
,None) for symb
in function
.atoms(Symbol
)]
51 obj
= Basic
.__new
__(cls
, **assumptions
)
52 obj
._args
= (function
, tuple(limits
))
68 for x
,ab
in self
.limits
:
73 def transform(self
, x
, mapping
, inverse
=False):
75 Replace the integration variable x in the integrand with the
76 expression given by `mapping`, e.g. 2*x or 1/x. The integrand and
77 endpoints are rescaled to preserve the value of the original
80 In effect, this performs a variable substitution (although the
81 symbol remains unchanged; follow up with subs to obtain a
84 With inverse=True, the inverse transformation is performed.
86 The mapping must be uniquely invertible (e.g. a linear or linear
87 fractional transformation).
89 if x
not in self
.variables
:
92 function
= self
.function
93 y
= Symbol('y', dummy
=True)
94 inverse_mapping
= solve(mapping
.subs(x
,y
)-x
, y
)
95 if len(inverse_mapping
) != 1 or not inverse_mapping
[0].has(x
):
96 raise ValueError("The mapping must be uniquely invertible")
97 inverse_mapping
= inverse_mapping
[0]
99 mapping
, inverse_mapping
= inverse_mapping
, mapping
100 function
= function
.subs(x
, mapping
) * mapping
.diff(x
)
102 for sym
, limit
in limits
:
103 if sym
== x
and limit
and len(limit
) == 2:
105 a
= inverse_mapping
.subs(x
, a
)
106 b
= inverse_mapping
.subs(x
, b
)
108 raise ValueError("The mapping must transform the "
109 "endpoints into separate points")
113 newlimits
.append((sym
, a
, b
))
115 newlimits
.append((sym
, limit
))
116 return Integral(function
, *newlimits
)
118 def doit(self
, **hints
):
119 if not hints
.get('integrals', True):
122 function
= self
.function
124 for x
,ab
in self
.limits
:
125 antideriv
= self
._eval
_integral
(function
, x
)
127 if antideriv
is None:
134 A
= antideriv
.subs(x
, a
)
137 A
= limit(antideriv
, x
, a
)
141 B
= antideriv
.subs(x
, b
)
144 B
= limit(antideriv
, x
, b
)
152 def _eval_integral(self
, f
, x
):
153 """Calculate the antiderivative to the function f(x).
155 This is a powerful function that should in theory be able to integrate
156 everything that can be integrated. If you find something, that it
157 doesn't, it is easy to implement it.
159 (1) Simple heuristics (based on pattern matching and integral table):
161 - most frequently used functions (eg. polynomials)
162 - functions non-integrable by any of the following algorithms (eg.
165 (2) Integration of rational functions:
167 (a) using apart() - apart() is full partial fraction decomposition
168 procedure based on Bronstein-Salvy algorithm. It gives formal
169 decomposition with no polynomial factorization at all (so it's fast
170 and gives the most general results). However it needs much better
171 implementation of RootsOf class (if fact any implementation).
172 (b) using Trager's algorithm - possibly faster than (a) but needs
175 (3) Whichever implementation of pmInt (Mateusz, Kirill's or a
176 combination of both).
178 - this way we can handle efficiently huge class of elementary and
181 (4) Recursive Risch algorithm as described in Bronstein's integration
184 - this way we can handle those integrable functions for which (3)
187 (5) Powerful heuristics based mostly on user defined rules.
189 - handle complicated, rarely used cases
192 # if it is a poly(x) then let the polynomial integrate itself (fast)
194 # It is important to make this check first, otherwise the other code
195 # will return a sympy expression instead of a Polynomial.
197 # see Polynomial for details.
198 if isinstance(f
, Poly
):
199 return f
.integrate(x
)
201 # let's cut it short if `f` does not depend on `x`
205 # try to convert to poly(x) and then integrate if successful (fast)
209 return poly
.integrate(x
).as_basic()
211 # since Integral(f=g1+g2+...) == Integral(g1) + Integral(g2) + ...
212 # we are going to handle Add terms separately,
213 # if `f` is not Add -- we only have one term
219 if isinstance(f
, Basic
):
222 coeff
, g
= g
.as_independent(x
)
226 parts
.append(coeff
* x
)
231 if g
.is_Pow
and not g
.exp
.has(x
):
232 a
= Wild('a', exclude
=[x
])
233 b
= Wild('b', exclude
=[x
])
235 M
= g
.base
.match(a
*x
+ b
)
241 h
= g
.base
**(g
.exp
+1) / (g
.exp
+1)
243 parts
.append(coeff
* h
/ M
[a
])
250 h
= self
._eval
_integral
(apart(g
, x
), x
)
251 parts
.append(coeff
* h
)
255 h
= trigintegrate(g
, x
)
257 parts
.append(coeff
* h
)
260 # fall back to the more general algorithm
261 h
= heurisch(g
, x
, hints
=[])
264 parts
.append(coeff
* h
)
270 @threaded(use_add
=False)
271 def integrate(*args
, **kwargs
):
272 """integrate(f, var, ...)
274 Compute definite or indefinite integral of one or more variables
275 using Risch-Norman algorithm and table lookup. This procedure is
276 able to handle elementary algebraic and transcendental functions
277 and also a huge class of special functions, including Airy,
278 Bessel, Whittaker and Lambert.
282 - a symbol -- indefinite integration
283 - a tuple (symbol, a, b) -- definite integration
285 Several variables can be specified, in which case the result is multiple
288 Also, if no var is specified at all, then full-antiderivative of f is
289 returned. This is equivalent of integrating f over all it's variables.
294 >>> from sympy import *
295 >>> x, y = symbols('xy')
297 >>> integrate(x*y, x)
300 >>> integrate(log(x), x)
309 See also the doctest of Integral._eval_integral(), which explains
310 thoroughly the strategy that SymPy uses for integration.
313 integral
= Integral(*args
, **kwargs
)
315 if isinstance(integral
, Integral
):
316 return integral
.doit()