add read me
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
"""Integration functions that integrate a SymPy expression.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import integrate, sin
|
||||
>>> from sympy.abc import x
|
||||
>>> integrate(1/x,x)
|
||||
log(x)
|
||||
>>> integrate(sin(x),x)
|
||||
-cos(x)
|
||||
"""
|
||||
from .integrals import integrate, Integral, line_integrate
|
||||
from .transforms import (mellin_transform, inverse_mellin_transform,
|
||||
MellinTransform, InverseMellinTransform,
|
||||
laplace_transform, inverse_laplace_transform,
|
||||
laplace_correspondence, laplace_initial_conds,
|
||||
LaplaceTransform, InverseLaplaceTransform,
|
||||
fourier_transform, inverse_fourier_transform,
|
||||
FourierTransform, InverseFourierTransform,
|
||||
sine_transform, inverse_sine_transform,
|
||||
SineTransform, InverseSineTransform,
|
||||
cosine_transform, inverse_cosine_transform,
|
||||
CosineTransform, InverseCosineTransform,
|
||||
hankel_transform, inverse_hankel_transform,
|
||||
HankelTransform, InverseHankelTransform)
|
||||
from .singularityfunctions import singularityintegrate
|
||||
|
||||
__all__ = [
|
||||
'integrate', 'Integral', 'line_integrate',
|
||||
|
||||
'mellin_transform', 'inverse_mellin_transform', 'MellinTransform',
|
||||
'InverseMellinTransform', 'laplace_transform',
|
||||
'inverse_laplace_transform', 'LaplaceTransform',
|
||||
'laplace_correspondence', 'laplace_initial_conds',
|
||||
'InverseLaplaceTransform', 'fourier_transform',
|
||||
'inverse_fourier_transform', 'FourierTransform',
|
||||
'InverseFourierTransform', 'sine_transform', 'inverse_sine_transform',
|
||||
'SineTransform', 'InverseSineTransform', 'cosine_transform',
|
||||
'inverse_cosine_transform', 'CosineTransform', 'InverseCosineTransform',
|
||||
'hankel_transform', 'inverse_hankel_transform', 'HankelTransform',
|
||||
'InverseHankelTransform',
|
||||
|
||||
'singularityintegrate',
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,21 @@
|
||||
from sympy.core.symbol import Symbol
|
||||
from sympy.functions.elementary.trigonometric import sin
|
||||
from sympy.integrals.integrals import integrate
|
||||
|
||||
x = Symbol('x')
|
||||
|
||||
|
||||
def bench_integrate_sin():
|
||||
integrate(sin(x), x)
|
||||
|
||||
|
||||
def bench_integrate_x1sin():
|
||||
integrate(x**1*sin(x), x)
|
||||
|
||||
|
||||
def bench_integrate_x2sin():
|
||||
integrate(x**2*sin(x), x)
|
||||
|
||||
|
||||
def bench_integrate_x3sin():
|
||||
integrate(x**3*sin(x), x)
|
||||
@@ -0,0 +1,13 @@
|
||||
from sympy.core.symbol import Symbol
|
||||
from sympy.functions.elementary.trigonometric import sin
|
||||
from sympy.integrals.trigonometry import trigintegrate
|
||||
|
||||
x = Symbol('x')
|
||||
|
||||
|
||||
def timeit_trigintegrate_sin3x():
|
||||
trigintegrate(sin(x)**3, x)
|
||||
|
||||
|
||||
def timeit_trigintegrate_x2():
|
||||
trigintegrate(x**2, x) # -> None
|
||||
@@ -0,0 +1,201 @@
|
||||
from sympy.core.mul import Mul
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.sorting import default_sort_key
|
||||
from sympy.functions import DiracDelta, Heaviside
|
||||
from .integrals import Integral, integrate
|
||||
|
||||
|
||||
def change_mul(node, x):
|
||||
"""change_mul(node, x)
|
||||
|
||||
Rearranges the operands of a product, bringing to front any simple
|
||||
DiracDelta expression.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
If no simple DiracDelta expression was found, then all the DiracDelta
|
||||
expressions are simplified (using DiracDelta.expand(diracdelta=True, wrt=x)).
|
||||
|
||||
Return: (dirac, new node)
|
||||
Where:
|
||||
o dirac is either a simple DiracDelta expression or None (if no simple
|
||||
expression was found);
|
||||
o new node is either a simplified DiracDelta expressions or None (if it
|
||||
could not be simplified).
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import DiracDelta, cos
|
||||
>>> from sympy.integrals.deltafunctions import change_mul
|
||||
>>> from sympy.abc import x, y
|
||||
>>> change_mul(x*y*DiracDelta(x)*cos(x), x)
|
||||
(DiracDelta(x), x*y*cos(x))
|
||||
>>> change_mul(x*y*DiracDelta(x**2 - 1)*cos(x), x)
|
||||
(None, x*y*cos(x)*DiracDelta(x - 1)/2 + x*y*cos(x)*DiracDelta(x + 1)/2)
|
||||
>>> change_mul(x*y*DiracDelta(cos(x))*cos(x), x)
|
||||
(None, None)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
sympy.functions.special.delta_functions.DiracDelta
|
||||
deltaintegrate
|
||||
"""
|
||||
|
||||
new_args = []
|
||||
dirac = None
|
||||
|
||||
#Sorting is needed so that we consistently collapse the same delta;
|
||||
#However, we must preserve the ordering of non-commutative terms
|
||||
c, nc = node.args_cnc()
|
||||
sorted_args = sorted(c, key=default_sort_key)
|
||||
sorted_args.extend(nc)
|
||||
|
||||
for arg in sorted_args:
|
||||
if arg.is_Pow and isinstance(arg.base, DiracDelta):
|
||||
new_args.append(arg.func(arg.base, arg.exp - 1))
|
||||
arg = arg.base
|
||||
if dirac is None and (isinstance(arg, DiracDelta) and arg.is_simple(x)):
|
||||
dirac = arg
|
||||
else:
|
||||
new_args.append(arg)
|
||||
if not dirac: # there was no simple dirac
|
||||
new_args = []
|
||||
for arg in sorted_args:
|
||||
if isinstance(arg, DiracDelta):
|
||||
new_args.append(arg.expand(diracdelta=True, wrt=x))
|
||||
elif arg.is_Pow and isinstance(arg.base, DiracDelta):
|
||||
new_args.append(arg.func(arg.base.expand(diracdelta=True, wrt=x), arg.exp))
|
||||
else:
|
||||
new_args.append(arg)
|
||||
if new_args != sorted_args:
|
||||
nnode = Mul(*new_args).expand()
|
||||
else: # if the node didn't change there is nothing to do
|
||||
nnode = None
|
||||
return (None, nnode)
|
||||
return (dirac, Mul(*new_args))
|
||||
|
||||
|
||||
def deltaintegrate(f, x):
|
||||
"""
|
||||
deltaintegrate(f, x)
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The idea for integration is the following:
|
||||
|
||||
- If we are dealing with a DiracDelta expression, i.e. DiracDelta(g(x)),
|
||||
we try to simplify it.
|
||||
|
||||
If we could simplify it, then we integrate the resulting expression.
|
||||
We already know we can integrate a simplified expression, because only
|
||||
simple DiracDelta expressions are involved.
|
||||
|
||||
If we couldn't simplify it, there are two cases:
|
||||
|
||||
1) The expression is a simple expression: we return the integral,
|
||||
taking care if we are dealing with a Derivative or with a proper
|
||||
DiracDelta.
|
||||
|
||||
2) The expression is not simple (i.e. DiracDelta(cos(x))): we can do
|
||||
nothing at all.
|
||||
|
||||
- If the node is a multiplication node having a DiracDelta term:
|
||||
|
||||
First we expand it.
|
||||
|
||||
If the expansion did work, then we try to integrate the expansion.
|
||||
|
||||
If not, we try to extract a simple DiracDelta term, then we have two
|
||||
cases:
|
||||
|
||||
1) We have a simple DiracDelta term, so we return the integral.
|
||||
|
||||
2) We didn't have a simple term, but we do have an expression with
|
||||
simplified DiracDelta terms, so we integrate this expression.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.abc import x, y, z
|
||||
>>> from sympy.integrals.deltafunctions import deltaintegrate
|
||||
>>> from sympy import sin, cos, DiracDelta
|
||||
>>> deltaintegrate(x*sin(x)*cos(x)*DiracDelta(x - 1), x)
|
||||
sin(1)*cos(1)*Heaviside(x - 1)
|
||||
>>> deltaintegrate(y**2*DiracDelta(x - z)*DiracDelta(y - z), y)
|
||||
z**2*DiracDelta(x - z)*Heaviside(y - z)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
sympy.functions.special.delta_functions.DiracDelta
|
||||
sympy.integrals.integrals.Integral
|
||||
"""
|
||||
if not f.has(DiracDelta):
|
||||
return None
|
||||
|
||||
# g(x) = DiracDelta(h(x))
|
||||
if f.func == DiracDelta:
|
||||
h = f.expand(diracdelta=True, wrt=x)
|
||||
if h == f: # can't simplify the expression
|
||||
#FIXME: the second term tells whether is DeltaDirac or Derivative
|
||||
#For integrating derivatives of DiracDelta we need the chain rule
|
||||
if f.is_simple(x):
|
||||
if (len(f.args) <= 1 or f.args[1] == 0):
|
||||
return Heaviside(f.args[0])
|
||||
else:
|
||||
return (DiracDelta(f.args[0], f.args[1] - 1) /
|
||||
f.args[0].as_poly().LC())
|
||||
else: # let's try to integrate the simplified expression
|
||||
fh = integrate(h, x)
|
||||
return fh
|
||||
elif f.is_Mul or f.is_Pow: # g(x) = a*b*c*f(DiracDelta(h(x)))*d*e
|
||||
g = f.expand()
|
||||
if f != g: # the expansion worked
|
||||
fh = integrate(g, x)
|
||||
if fh is not None and not isinstance(fh, Integral):
|
||||
return fh
|
||||
else:
|
||||
# no expansion performed, try to extract a simple DiracDelta term
|
||||
deltaterm, rest_mult = change_mul(f, x)
|
||||
|
||||
if not deltaterm:
|
||||
if rest_mult:
|
||||
fh = integrate(rest_mult, x)
|
||||
return fh
|
||||
else:
|
||||
from sympy.solvers import solve
|
||||
deltaterm = deltaterm.expand(diracdelta=True, wrt=x)
|
||||
if deltaterm.is_Mul: # Take out any extracted factors
|
||||
deltaterm, rest_mult_2 = change_mul(deltaterm, x)
|
||||
rest_mult = rest_mult*rest_mult_2
|
||||
point = solve(deltaterm.args[0], x)[0]
|
||||
|
||||
# Return the largest hyperreal term left after
|
||||
# repeated integration by parts. For example,
|
||||
#
|
||||
# integrate(y*DiracDelta(x, 1),x) == y*DiracDelta(x,0), not 0
|
||||
#
|
||||
# This is so Integral(y*DiracDelta(x).diff(x),x).doit()
|
||||
# will return y*DiracDelta(x) instead of 0 or DiracDelta(x),
|
||||
# both of which are correct everywhere the value is defined
|
||||
# but give wrong answers for nested integration.
|
||||
n = (0 if len(deltaterm.args)==1 else deltaterm.args[1])
|
||||
m = 0
|
||||
while n >= 0:
|
||||
r = S.NegativeOne**n*rest_mult.diff(x, n).subs(x, point)
|
||||
if r.is_zero:
|
||||
n -= 1
|
||||
m += 1
|
||||
else:
|
||||
if m == 0:
|
||||
return r*Heaviside(x - point)
|
||||
else:
|
||||
return r*DiracDelta(x,m-1)
|
||||
# In some very weak sense, x=0 is still a singularity,
|
||||
# but we hope will not be of any practical consequence.
|
||||
return S.Zero
|
||||
return None
|
||||
781
venv/lib/python3.12/site-packages/sympy/integrals/heurisch.py
Normal file
781
venv/lib/python3.12/site-packages/sympy/integrals/heurisch.py
Normal file
@@ -0,0 +1,781 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from collections import defaultdict
|
||||
from functools import reduce
|
||||
from itertools import permutations
|
||||
|
||||
from sympy.core.add import Add
|
||||
from sympy.core.basic import Basic
|
||||
from sympy.core.mul import Mul
|
||||
from sympy.core.symbol import Wild, Dummy, Symbol
|
||||
from sympy.core.basic import sympify
|
||||
from sympy.core.numbers import Rational, pi, I
|
||||
from sympy.core.relational import Eq, Ne
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.sorting import ordered
|
||||
from sympy.core.traversal import iterfreeargs
|
||||
|
||||
from sympy.functions import exp, sin, cos, tan, cot, asin, atan
|
||||
from sympy.functions import log, sinh, cosh, tanh, coth, asinh
|
||||
from sympy.functions import sqrt, erf, erfi, li, Ei
|
||||
from sympy.functions import besselj, bessely, besseli, besselk
|
||||
from sympy.functions import hankel1, hankel2, jn, yn
|
||||
from sympy.functions.elementary.complexes import Abs, re, im, sign, arg
|
||||
from sympy.functions.elementary.exponential import LambertW
|
||||
from sympy.functions.elementary.integers import floor, ceiling
|
||||
from sympy.functions.elementary.piecewise import Piecewise
|
||||
from sympy.functions.special.delta_functions import Heaviside, DiracDelta
|
||||
|
||||
from sympy.simplify.radsimp import collect
|
||||
|
||||
from sympy.logic.boolalg import And, Or
|
||||
from sympy.utilities.iterables import uniq
|
||||
|
||||
from sympy.polys import quo, gcd, lcm, factor_list, cancel, PolynomialError
|
||||
from sympy.polys.monomials import itermonomials
|
||||
from sympy.polys.polyroots import root_factors
|
||||
|
||||
from sympy.polys.rings import PolyRing
|
||||
from sympy.polys.solvers import solve_lin_sys
|
||||
from sympy.polys.constructor import construct_domain
|
||||
|
||||
from sympy.integrals.integrals import integrate
|
||||
|
||||
|
||||
def components(f, x):
|
||||
"""
|
||||
Returns a set of all functional components of the given expression
|
||||
which includes symbols, function applications and compositions and
|
||||
non-integer powers. Fractional powers are collected with
|
||||
minimal, positive exponents.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import cos, sin
|
||||
>>> from sympy.abc import x
|
||||
>>> from sympy.integrals.heurisch import components
|
||||
|
||||
>>> components(sin(x)*cos(x)**2, x)
|
||||
{x, sin(x), cos(x)}
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
heurisch
|
||||
"""
|
||||
result = set()
|
||||
|
||||
if f.has_free(x):
|
||||
if f.is_symbol and f.is_commutative:
|
||||
result.add(f)
|
||||
elif f.is_Function or f.is_Derivative:
|
||||
for g in f.args:
|
||||
result |= components(g, x)
|
||||
|
||||
result.add(f)
|
||||
elif f.is_Pow:
|
||||
result |= components(f.base, x)
|
||||
|
||||
if not f.exp.is_Integer:
|
||||
if f.exp.is_Rational:
|
||||
result.add(f.base**Rational(1, f.exp.q))
|
||||
else:
|
||||
result |= components(f.exp, x) | {f}
|
||||
else:
|
||||
for g in f.args:
|
||||
result |= components(g, x)
|
||||
|
||||
return result
|
||||
|
||||
# name -> [] of symbols
|
||||
_symbols_cache: dict[str, list[Dummy]] = {}
|
||||
|
||||
|
||||
# NB @cacheit is not convenient here
|
||||
def _symbols(name, n):
|
||||
"""get vector of symbols local to this module"""
|
||||
try:
|
||||
lsyms = _symbols_cache[name]
|
||||
except KeyError:
|
||||
lsyms = []
|
||||
_symbols_cache[name] = lsyms
|
||||
|
||||
while len(lsyms) < n:
|
||||
lsyms.append( Dummy('%s%i' % (name, len(lsyms))) )
|
||||
|
||||
return lsyms[:n]
|
||||
|
||||
|
||||
def heurisch_wrapper(f, x, rewrite=False, hints=None, mappings=None, retries=3,
|
||||
degree_offset=0, unnecessary_permutations=None,
|
||||
_try_heurisch=None):
|
||||
"""
|
||||
A wrapper around the heurisch integration algorithm.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
This method takes the result from heurisch and checks for poles in the
|
||||
denominator. For each of these poles, the integral is reevaluated, and
|
||||
the final integration result is given in terms of a Piecewise.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import cos, symbols
|
||||
>>> from sympy.integrals.heurisch import heurisch, heurisch_wrapper
|
||||
>>> n, x = symbols('n x')
|
||||
>>> heurisch(cos(n*x), x)
|
||||
sin(n*x)/n
|
||||
>>> heurisch_wrapper(cos(n*x), x)
|
||||
Piecewise((sin(n*x)/n, Ne(n, 0)), (x, True))
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
heurisch
|
||||
"""
|
||||
from sympy.solvers.solvers import solve, denoms
|
||||
f = sympify(f)
|
||||
if not f.has_free(x):
|
||||
return f*x
|
||||
|
||||
res = heurisch(f, x, rewrite, hints, mappings, retries, degree_offset,
|
||||
unnecessary_permutations, _try_heurisch)
|
||||
if not isinstance(res, Basic):
|
||||
return res
|
||||
|
||||
# We consider each denominator in the expression, and try to find
|
||||
# cases where one or more symbolic denominator might be zero. The
|
||||
# conditions for these cases are stored in the list slns.
|
||||
#
|
||||
# Since denoms returns a set we use ordered. This is important because the
|
||||
# ordering of slns determines the order of the resulting Piecewise so we
|
||||
# need a deterministic order here to make the output deterministic.
|
||||
slns = []
|
||||
for d in ordered(denoms(res)):
|
||||
try:
|
||||
slns += solve([d], dict=True, exclude=(x,))
|
||||
except NotImplementedError:
|
||||
pass
|
||||
if not slns:
|
||||
return res
|
||||
slns = list(uniq(slns))
|
||||
# Remove the solutions corresponding to poles in the original expression.
|
||||
slns0 = []
|
||||
for d in denoms(f):
|
||||
try:
|
||||
slns0 += solve([d], dict=True, exclude=(x,))
|
||||
except NotImplementedError:
|
||||
pass
|
||||
slns = [s for s in slns if s not in slns0]
|
||||
if not slns:
|
||||
return res
|
||||
if len(slns) > 1:
|
||||
eqs = []
|
||||
for sub_dict in slns:
|
||||
eqs.extend([Eq(key, value) for key, value in sub_dict.items()])
|
||||
slns = solve(eqs, dict=True, exclude=(x,)) + slns
|
||||
# For each case listed in the list slns, we reevaluate the integral.
|
||||
pairs = []
|
||||
for sub_dict in slns:
|
||||
expr = heurisch(f.subs(sub_dict), x, rewrite, hints, mappings, retries,
|
||||
degree_offset, unnecessary_permutations,
|
||||
_try_heurisch)
|
||||
cond = And(*[Eq(key, value) for key, value in sub_dict.items()])
|
||||
generic = Or(*[Ne(key, value) for key, value in sub_dict.items()])
|
||||
if expr is None:
|
||||
expr = integrate(f.subs(sub_dict),x)
|
||||
pairs.append((expr, cond))
|
||||
# If there is one condition, put the generic case first. Otherwise,
|
||||
# doing so may lead to longer Piecewise formulas
|
||||
if len(pairs) == 1:
|
||||
pairs = [(heurisch(f, x, rewrite, hints, mappings, retries,
|
||||
degree_offset, unnecessary_permutations,
|
||||
_try_heurisch),
|
||||
generic),
|
||||
(pairs[0][0], True)]
|
||||
else:
|
||||
pairs.append((heurisch(f, x, rewrite, hints, mappings, retries,
|
||||
degree_offset, unnecessary_permutations,
|
||||
_try_heurisch),
|
||||
True))
|
||||
return Piecewise(*pairs)
|
||||
|
||||
class BesselTable:
|
||||
"""
|
||||
Derivatives of Bessel functions of orders n and n-1
|
||||
in terms of each other.
|
||||
|
||||
See the docstring of DiffCache.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.table = {}
|
||||
self.n = Dummy('n')
|
||||
self.z = Dummy('z')
|
||||
self._create_table()
|
||||
|
||||
def _create_table(t):
|
||||
table, n, z = t.table, t.n, t.z
|
||||
for f in (besselj, bessely, hankel1, hankel2):
|
||||
table[f] = (f(n-1, z) - n*f(n, z)/z,
|
||||
(n-1)*f(n-1, z)/z - f(n, z))
|
||||
|
||||
f = besseli
|
||||
table[f] = (f(n-1, z) - n*f(n, z)/z,
|
||||
(n-1)*f(n-1, z)/z + f(n, z))
|
||||
f = besselk
|
||||
table[f] = (-f(n-1, z) - n*f(n, z)/z,
|
||||
(n-1)*f(n-1, z)/z - f(n, z))
|
||||
|
||||
for f in (jn, yn):
|
||||
table[f] = (f(n-1, z) - (n+1)*f(n, z)/z,
|
||||
(n-1)*f(n-1, z)/z - f(n, z))
|
||||
|
||||
def diffs(t, f, n, z):
|
||||
if f in t.table:
|
||||
diff0, diff1 = t.table[f]
|
||||
repl = [(t.n, n), (t.z, z)]
|
||||
return (diff0.subs(repl), diff1.subs(repl))
|
||||
|
||||
def has(t, f):
|
||||
return f in t.table
|
||||
|
||||
_bessel_table = None
|
||||
|
||||
class DiffCache:
|
||||
"""
|
||||
Store for derivatives of expressions.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The standard form of the derivative of a Bessel function of order n
|
||||
contains two Bessel functions of orders n-1 and n+1, respectively.
|
||||
Such forms cannot be used in parallel Risch algorithm, because
|
||||
there is a linear recurrence relation between the three functions
|
||||
while the algorithm expects that functions and derivatives are
|
||||
represented in terms of algebraically independent transcendentals.
|
||||
|
||||
The solution is to take two of the functions, e.g., those of orders
|
||||
n and n-1, and to express the derivatives in terms of the pair.
|
||||
To guarantee that the proper form is used the two derivatives are
|
||||
cached as soon as one is encountered.
|
||||
|
||||
Derivatives of other functions are also cached at no extra cost.
|
||||
All derivatives are with respect to the same variable `x`.
|
||||
"""
|
||||
|
||||
def __init__(self, x):
|
||||
self.cache = {}
|
||||
self.x = x
|
||||
|
||||
global _bessel_table
|
||||
if not _bessel_table:
|
||||
_bessel_table = BesselTable()
|
||||
|
||||
def get_diff(self, f):
|
||||
cache = self.cache
|
||||
|
||||
if f in cache:
|
||||
pass
|
||||
elif (not hasattr(f, 'func') or
|
||||
not _bessel_table.has(f.func)):
|
||||
cache[f] = cancel(f.diff(self.x))
|
||||
else:
|
||||
n, z = f.args
|
||||
d0, d1 = _bessel_table.diffs(f.func, n, z)
|
||||
dz = self.get_diff(z)
|
||||
cache[f] = d0*dz
|
||||
cache[f.func(n-1, z)] = d1*dz
|
||||
|
||||
return cache[f]
|
||||
|
||||
def heurisch(f, x, rewrite=False, hints=None, mappings=None, retries=3,
|
||||
degree_offset=0, unnecessary_permutations=None,
|
||||
_try_heurisch=None):
|
||||
"""
|
||||
Compute indefinite integral using heuristic Risch algorithm.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
This is a heuristic approach to indefinite integration in finite
|
||||
terms using the extended heuristic (parallel) Risch algorithm, based
|
||||
on Manuel Bronstein's "Poor Man's Integrator".
|
||||
|
||||
The algorithm supports various classes of functions including
|
||||
transcendental elementary or special functions like Airy,
|
||||
Bessel, Whittaker and Lambert.
|
||||
|
||||
Note that this algorithm is not a decision procedure. If it isn't
|
||||
able to compute the antiderivative for a given function, then this is
|
||||
not a proof that such a functions does not exist. One should use
|
||||
recursive Risch algorithm in such case. It's an open question if
|
||||
this algorithm can be made a full decision procedure.
|
||||
|
||||
This is an internal integrator procedure. You should use top level
|
||||
'integrate' function in most cases, as this procedure needs some
|
||||
preprocessing steps and otherwise may fail.
|
||||
|
||||
Specification
|
||||
=============
|
||||
|
||||
heurisch(f, x, rewrite=False, hints=None)
|
||||
|
||||
where
|
||||
f : expression
|
||||
x : symbol
|
||||
|
||||
rewrite -> force rewrite 'f' in terms of 'tan' and 'tanh'
|
||||
hints -> a list of functions that may appear in anti-derivate
|
||||
|
||||
- hints = None --> no suggestions at all
|
||||
- hints = [ ] --> try to figure out
|
||||
- hints = [f1, ..., fn] --> we know better
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import tan
|
||||
>>> from sympy.integrals.heurisch import heurisch
|
||||
>>> from sympy.abc import x, y
|
||||
|
||||
>>> heurisch(y*tan(x), x)
|
||||
y*log(tan(x)**2 + 1)/2
|
||||
|
||||
See Manuel Bronstein's "Poor Man's Integrator":
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://www-sop.inria.fr/cafe/Manuel.Bronstein/pmint/index.html
|
||||
|
||||
For more information on the implemented algorithm refer to:
|
||||
|
||||
.. [2] K. Geddes, L. Stefanus, On the Risch-Norman Integration
|
||||
Method and its Implementation in Maple, Proceedings of
|
||||
ISSAC'89, ACM Press, 212-217.
|
||||
|
||||
.. [3] J. H. Davenport, On the Parallel Risch Algorithm (I),
|
||||
Proceedings of EUROCAM'82, LNCS 144, Springer, 144-157.
|
||||
|
||||
.. [4] J. H. Davenport, On the Parallel Risch Algorithm (III):
|
||||
Use of Tangents, SIGSAM Bulletin 16 (1982), 3-6.
|
||||
|
||||
.. [5] J. H. Davenport, B. M. Trager, On the Parallel Risch
|
||||
Algorithm (II), ACM Transactions on Mathematical
|
||||
Software 11 (1985), 356-362.
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
sympy.integrals.integrals.Integral.doit
|
||||
sympy.integrals.integrals.Integral
|
||||
sympy.integrals.heurisch.components
|
||||
"""
|
||||
f = sympify(f)
|
||||
|
||||
# There are some functions that Heurisch cannot currently handle,
|
||||
# so do not even try.
|
||||
# Set _try_heurisch=True to skip this check
|
||||
if _try_heurisch is not True:
|
||||
if f.has(Abs, re, im, sign, Heaviside, DiracDelta, floor, ceiling, arg):
|
||||
return
|
||||
|
||||
if not f.has_free(x):
|
||||
return f*x
|
||||
|
||||
if not f.is_Add:
|
||||
indep, f = f.as_independent(x)
|
||||
else:
|
||||
indep = S.One
|
||||
|
||||
rewritables = {
|
||||
(sin, cos, cot): tan,
|
||||
(sinh, cosh, coth): tanh,
|
||||
}
|
||||
|
||||
if rewrite:
|
||||
for candidates, rule in rewritables.items():
|
||||
f = f.rewrite(candidates, rule)
|
||||
else:
|
||||
for candidates in rewritables.keys():
|
||||
if f.has(*candidates):
|
||||
break
|
||||
else:
|
||||
rewrite = True
|
||||
|
||||
terms = components(f, x)
|
||||
dcache = DiffCache(x)
|
||||
|
||||
if hints is not None:
|
||||
if not hints:
|
||||
a = Wild('a', exclude=[x])
|
||||
b = Wild('b', exclude=[x])
|
||||
c = Wild('c', exclude=[x])
|
||||
|
||||
for g in set(terms): # using copy of terms
|
||||
if g.is_Function:
|
||||
if isinstance(g, li):
|
||||
M = g.args[0].match(a*x**b)
|
||||
|
||||
if M is not None:
|
||||
terms.add( x*(li(M[a]*x**M[b]) - (M[a]*x**M[b])**(-1/M[b])*Ei((M[b]+1)*log(M[a]*x**M[b])/M[b])) )
|
||||
#terms.add( x*(li(M[a]*x**M[b]) - (x**M[b])**(-1/M[b])*Ei((M[b]+1)*log(M[a]*x**M[b])/M[b])) )
|
||||
#terms.add( x*(li(M[a]*x**M[b]) - x*Ei((M[b]+1)*log(M[a]*x**M[b])/M[b])) )
|
||||
#terms.add( li(M[a]*x**M[b]) - Ei((M[b]+1)*log(M[a]*x**M[b])/M[b]) )
|
||||
|
||||
elif isinstance(g, exp):
|
||||
M = g.args[0].match(a*x**2)
|
||||
|
||||
if M is not None:
|
||||
if M[a].is_positive:
|
||||
terms.add(erfi(sqrt(M[a])*x))
|
||||
else: # M[a].is_negative or unknown
|
||||
terms.add(erf(sqrt(-M[a])*x))
|
||||
|
||||
M = g.args[0].match(a*x**2 + b*x + c)
|
||||
|
||||
if M is not None:
|
||||
if M[a].is_positive:
|
||||
terms.add(sqrt(pi/4*(-M[a]))*exp(M[c] - M[b]**2/(4*M[a]))*
|
||||
erfi(sqrt(M[a])*x + M[b]/(2*sqrt(M[a]))))
|
||||
elif M[a].is_negative:
|
||||
terms.add(sqrt(pi/4*(-M[a]))*exp(M[c] - M[b]**2/(4*M[a]))*
|
||||
erf(sqrt(-M[a])*x - M[b]/(2*sqrt(-M[a]))))
|
||||
|
||||
M = g.args[0].match(a*log(x)**2)
|
||||
|
||||
if M is not None:
|
||||
if M[a].is_positive:
|
||||
terms.add(erfi(sqrt(M[a])*log(x) + 1/(2*sqrt(M[a]))))
|
||||
if M[a].is_negative:
|
||||
terms.add(erf(sqrt(-M[a])*log(x) - 1/(2*sqrt(-M[a]))))
|
||||
|
||||
elif g.is_Pow:
|
||||
if g.exp.is_Rational and g.exp.q == 2:
|
||||
M = g.base.match(a*x**2 + b)
|
||||
|
||||
if M is not None and M[b].is_positive:
|
||||
if M[a].is_positive:
|
||||
terms.add(asinh(sqrt(M[a]/M[b])*x))
|
||||
elif M[a].is_negative:
|
||||
terms.add(asin(sqrt(-M[a]/M[b])*x))
|
||||
|
||||
M = g.base.match(a*x**2 - b)
|
||||
|
||||
if M is not None and M[b].is_positive:
|
||||
if M[a].is_positive:
|
||||
dF = 1/sqrt(M[a]*x**2 - M[b])
|
||||
F = log(2*sqrt(M[a])*sqrt(M[a]*x**2 - M[b]) + 2*M[a]*x)/sqrt(M[a])
|
||||
dcache.cache[F] = dF # hack: F.diff(x) doesn't automatically simplify to f
|
||||
terms.add(F)
|
||||
elif M[a].is_negative:
|
||||
terms.add(-M[b]/2*sqrt(-M[a])*
|
||||
atan(sqrt(-M[a])*x/sqrt(M[a]*x**2 - M[b])))
|
||||
|
||||
else:
|
||||
terms |= set(hints)
|
||||
|
||||
for g in set(terms): # using copy of terms
|
||||
terms |= components(dcache.get_diff(g), x)
|
||||
|
||||
# XXX: The commented line below makes heurisch more deterministic wrt
|
||||
# PYTHONHASHSEED and the iteration order of sets. There are other places
|
||||
# where sets are iterated over but this one is possibly the most important.
|
||||
# Theoretically the order here should not matter but different orderings
|
||||
# can expose potential bugs in the different code paths so potentially it
|
||||
# is better to keep the non-determinism.
|
||||
#
|
||||
# terms = list(ordered(terms))
|
||||
|
||||
# TODO: caching is significant factor for why permutations work at all. Change this.
|
||||
V = _symbols('x', len(terms))
|
||||
|
||||
|
||||
# sort mapping expressions from largest to smallest (last is always x).
|
||||
mapping = list(reversed(list(zip(*ordered( #
|
||||
[(a[0].as_independent(x)[1], a) for a in zip(terms, V)])))[1])) #
|
||||
rev_mapping = {v: k for k, v in mapping} #
|
||||
if mappings is None: #
|
||||
# optimizing the number of permutations of mapping #
|
||||
assert mapping[-1][0] == x # if not, find it and correct this comment
|
||||
unnecessary_permutations = [mapping.pop(-1)]
|
||||
# permute types of objects
|
||||
types = defaultdict(list)
|
||||
for i in mapping:
|
||||
e, _ = i
|
||||
types[type(e)].append(i)
|
||||
mapping = [types[i] for i in types]
|
||||
def _iter_mappings():
|
||||
for i in permutations(mapping):
|
||||
# make the expression of a given type be ordered
|
||||
yield [j for i in i for j in ordered(i)]
|
||||
mappings = _iter_mappings()
|
||||
else:
|
||||
unnecessary_permutations = unnecessary_permutations or []
|
||||
|
||||
def _substitute(expr):
|
||||
return expr.subs(mapping)
|
||||
|
||||
for mapping in mappings:
|
||||
mapping = list(mapping)
|
||||
mapping = mapping + unnecessary_permutations
|
||||
diffs = [ _substitute(dcache.get_diff(g)) for g in terms ]
|
||||
denoms = [ g.as_numer_denom()[1] for g in diffs ]
|
||||
if all(h.is_polynomial(*V) for h in denoms) and _substitute(f).is_rational_function(*V):
|
||||
denom = reduce(lambda p, q: lcm(p, q, *V), denoms)
|
||||
break
|
||||
else:
|
||||
if not rewrite:
|
||||
result = heurisch(f, x, rewrite=True, hints=hints,
|
||||
unnecessary_permutations=unnecessary_permutations)
|
||||
|
||||
if result is not None:
|
||||
return indep*result
|
||||
return None
|
||||
|
||||
numers = [ cancel(denom*g) for g in diffs ]
|
||||
def _derivation(h):
|
||||
return Add(*[ d * h.diff(v) for d, v in zip(numers, V) ])
|
||||
|
||||
def _deflation(p):
|
||||
for y in V:
|
||||
if not p.has(y):
|
||||
continue
|
||||
|
||||
if _derivation(p) is not S.Zero:
|
||||
c, q = p.as_poly(y).primitive()
|
||||
return _deflation(c)*gcd(q, q.diff(y)).as_expr()
|
||||
|
||||
return p
|
||||
|
||||
def _splitter(p):
|
||||
for y in V:
|
||||
if not p.has(y):
|
||||
continue
|
||||
|
||||
if _derivation(y) is not S.Zero:
|
||||
c, q = p.as_poly(y).primitive()
|
||||
|
||||
q = q.as_expr()
|
||||
|
||||
h = gcd(q, _derivation(q), y)
|
||||
s = quo(h, gcd(q, q.diff(y), y), y)
|
||||
|
||||
c_split = _splitter(c)
|
||||
|
||||
if s.as_poly(y).degree() == 0:
|
||||
return (c_split[0], q * c_split[1])
|
||||
|
||||
q_split = _splitter(cancel(q / s))
|
||||
|
||||
return (c_split[0]*q_split[0]*s, c_split[1]*q_split[1])
|
||||
|
||||
return (S.One, p)
|
||||
|
||||
special = {}
|
||||
|
||||
for term in terms:
|
||||
if term.is_Function:
|
||||
if isinstance(term, tan):
|
||||
special[1 + _substitute(term)**2] = False
|
||||
elif isinstance(term, tanh):
|
||||
special[1 + _substitute(term)] = False
|
||||
special[1 - _substitute(term)] = False
|
||||
elif isinstance(term, LambertW):
|
||||
special[_substitute(term)] = True
|
||||
|
||||
F = _substitute(f)
|
||||
|
||||
P, Q = F.as_numer_denom()
|
||||
|
||||
u_split = _splitter(denom)
|
||||
v_split = _splitter(Q)
|
||||
|
||||
polys = set(list(v_split) + [ u_split[0] ] + list(special.keys()))
|
||||
|
||||
s = u_split[0] * Mul(*[ k for k, v in special.items() if v ])
|
||||
polified = [ p.as_poly(*V) for p in [s, P, Q] ]
|
||||
|
||||
if None in polified:
|
||||
return None
|
||||
|
||||
#--- definitions for _integrate
|
||||
a, b, c = [ p.total_degree() for p in polified ]
|
||||
|
||||
poly_denom = (s * v_split[0] * _deflation(v_split[1])).as_expr()
|
||||
|
||||
def _exponent(g):
|
||||
if g.is_Pow:
|
||||
if g.exp.is_Rational and g.exp.q != 1:
|
||||
if g.exp.p > 0:
|
||||
return g.exp.p + g.exp.q - 1
|
||||
else:
|
||||
return abs(g.exp.p + g.exp.q)
|
||||
else:
|
||||
return 1
|
||||
elif not g.is_Atom and g.args:
|
||||
return max(_exponent(h) for h in g.args)
|
||||
else:
|
||||
return 1
|
||||
|
||||
A, B = _exponent(f), a + max(b, c)
|
||||
|
||||
if A > 1 and B > 1:
|
||||
monoms = tuple(ordered(itermonomials(V, A + B - 1 + degree_offset)))
|
||||
else:
|
||||
monoms = tuple(ordered(itermonomials(V, A + B + degree_offset)))
|
||||
|
||||
poly_coeffs = _symbols('A', len(monoms))
|
||||
|
||||
poly_part = Add(*[ poly_coeffs[i]*monomial
|
||||
for i, monomial in enumerate(monoms) ])
|
||||
|
||||
reducibles = set()
|
||||
|
||||
for poly in ordered(polys):
|
||||
coeff, factors = factor_list(poly, *V)
|
||||
reducibles.add(coeff)
|
||||
reducibles.update(fact for fact, mul in factors)
|
||||
|
||||
def _integrate(field=None):
|
||||
atans = set()
|
||||
pairs = set()
|
||||
|
||||
if field == 'Q':
|
||||
irreducibles = set(reducibles)
|
||||
else:
|
||||
setV = set(V)
|
||||
irreducibles = set()
|
||||
for poly in ordered(reducibles):
|
||||
zV = setV & set(iterfreeargs(poly))
|
||||
for z in ordered(zV):
|
||||
s = set(root_factors(poly, z, filter=field))
|
||||
irreducibles |= s
|
||||
break
|
||||
|
||||
log_part, atan_part = [], []
|
||||
|
||||
for poly in ordered(irreducibles):
|
||||
m = collect(poly, I, evaluate=False)
|
||||
y = m.get(I, S.Zero)
|
||||
if y:
|
||||
x = m.get(S.One, S.Zero)
|
||||
if x.has(I) or y.has(I):
|
||||
continue # nontrivial x + I*y
|
||||
pairs.add((x, y))
|
||||
irreducibles.remove(poly)
|
||||
|
||||
while pairs:
|
||||
x, y = pairs.pop()
|
||||
if (x, -y) in pairs:
|
||||
pairs.remove((x, -y))
|
||||
# Choosing b with no minus sign
|
||||
if y.could_extract_minus_sign():
|
||||
y = -y
|
||||
irreducibles.add(x*x + y*y)
|
||||
atans.add(atan(x/y))
|
||||
else:
|
||||
irreducibles.add(x + I*y)
|
||||
|
||||
|
||||
B = _symbols('B', len(irreducibles))
|
||||
C = _symbols('C', len(atans))
|
||||
|
||||
# Note: the ordering matters here
|
||||
for poly, b in reversed(list(zip(ordered(irreducibles), B))):
|
||||
if poly.has(*V):
|
||||
poly_coeffs.append(b)
|
||||
log_part.append(b * log(poly))
|
||||
|
||||
for poly, c in reversed(list(zip(ordered(atans), C))):
|
||||
if poly.has(*V):
|
||||
poly_coeffs.append(c)
|
||||
atan_part.append(c * poly)
|
||||
|
||||
# TODO: Currently it's better to use symbolic expressions here instead
|
||||
# of rational functions, because it's simpler and FracElement doesn't
|
||||
# give big speed improvement yet. This is because cancellation is slow
|
||||
# due to slow polynomial GCD algorithms. If this gets improved then
|
||||
# revise this code.
|
||||
candidate = poly_part/poly_denom + Add(*log_part) + Add(*atan_part)
|
||||
h = F - _derivation(candidate) / denom
|
||||
raw_numer = h.as_numer_denom()[0]
|
||||
|
||||
# Rewrite raw_numer as a polynomial in K[coeffs][V] where K is a field
|
||||
# that we have to determine. We can't use simply atoms() because log(3),
|
||||
# sqrt(y) and similar expressions can appear, leading to non-trivial
|
||||
# domains.
|
||||
syms = set(poly_coeffs) | set(V)
|
||||
non_syms = set()
|
||||
|
||||
def find_non_syms(expr):
|
||||
if expr.is_Integer or expr.is_Rational:
|
||||
pass # ignore trivial numbers
|
||||
elif expr in syms:
|
||||
pass # ignore variables
|
||||
elif not expr.has_free(*syms):
|
||||
non_syms.add(expr)
|
||||
elif expr.is_Add or expr.is_Mul or expr.is_Pow:
|
||||
list(map(find_non_syms, expr.args))
|
||||
else:
|
||||
# TODO: Non-polynomial expression. This should have been
|
||||
# filtered out at an earlier stage.
|
||||
raise PolynomialError
|
||||
|
||||
try:
|
||||
find_non_syms(raw_numer)
|
||||
except PolynomialError:
|
||||
return None
|
||||
else:
|
||||
ground, _ = construct_domain(non_syms, field=True)
|
||||
|
||||
coeff_ring = PolyRing(poly_coeffs, ground)
|
||||
ring = PolyRing(V, coeff_ring)
|
||||
try:
|
||||
numer = ring.from_expr(raw_numer)
|
||||
except ValueError:
|
||||
raise PolynomialError
|
||||
solution = solve_lin_sys(numer.coeffs(), coeff_ring, _raw=False)
|
||||
|
||||
if solution is None:
|
||||
return None
|
||||
else:
|
||||
return candidate.xreplace(solution).xreplace(
|
||||
dict(zip(poly_coeffs, [S.Zero]*len(poly_coeffs))))
|
||||
|
||||
if all(isinstance(_, Symbol) for _ in V):
|
||||
more_free = F.free_symbols - set(V)
|
||||
else:
|
||||
Fd = F.as_dummy()
|
||||
more_free = Fd.xreplace(dict(zip(V, (Dummy() for _ in V)))
|
||||
).free_symbols & Fd.free_symbols
|
||||
if not more_free:
|
||||
# all free generators are identified in V
|
||||
solution = _integrate('Q')
|
||||
|
||||
if solution is None:
|
||||
solution = _integrate()
|
||||
else:
|
||||
solution = _integrate()
|
||||
|
||||
if solution is not None:
|
||||
antideriv = solution.subs(rev_mapping)
|
||||
antideriv = cancel(antideriv).expand()
|
||||
|
||||
if antideriv.is_Add:
|
||||
antideriv = antideriv.as_independent(x)[1]
|
||||
|
||||
return indep*antideriv
|
||||
else:
|
||||
if retries >= 0:
|
||||
result = heurisch(f, x, mappings=mappings, rewrite=rewrite, hints=hints, retries=retries - 1, unnecessary_permutations=unnecessary_permutations)
|
||||
|
||||
if result is not None:
|
||||
return indep*result
|
||||
|
||||
return None
|
||||
1640
venv/lib/python3.12/site-packages/sympy/integrals/integrals.py
Normal file
1640
venv/lib/python3.12/site-packages/sympy/integrals/integrals.py
Normal file
File diff suppressed because it is too large
Load Diff
1302
venv/lib/python3.12/site-packages/sympy/integrals/intpoly.py
Normal file
1302
venv/lib/python3.12/site-packages/sympy/integrals/intpoly.py
Normal file
File diff suppressed because it is too large
Load Diff
2377
venv/lib/python3.12/site-packages/sympy/integrals/laplace.py
Normal file
2377
venv/lib/python3.12/site-packages/sympy/integrals/laplace.py
Normal file
File diff suppressed because it is too large
Load Diff
2174
venv/lib/python3.12/site-packages/sympy/integrals/manualintegrate.py
Normal file
2174
venv/lib/python3.12/site-packages/sympy/integrals/manualintegrate.py
Normal file
File diff suppressed because it is too large
Load Diff
2191
venv/lib/python3.12/site-packages/sympy/integrals/meijerint.py
Normal file
2191
venv/lib/python3.12/site-packages/sympy/integrals/meijerint.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,38 @@
|
||||
""" This module cooks up a docstring when imported. Its only purpose is to
|
||||
be displayed in the sphinx documentation. """
|
||||
|
||||
from __future__ import annotations
|
||||
from typing import Any
|
||||
|
||||
from sympy.integrals.meijerint import _create_lookup_table
|
||||
from sympy.core.add import Add
|
||||
from sympy.core.basic import Basic
|
||||
from sympy.core.expr import Expr
|
||||
from sympy.core.relational import Eq
|
||||
from sympy.core.symbol import Symbol
|
||||
from sympy.printing.latex import latex
|
||||
|
||||
t: dict[tuple[type[Basic], ...], list[Any]] = {}
|
||||
_create_lookup_table(t)
|
||||
|
||||
|
||||
doc = ""
|
||||
for about, category in t.items():
|
||||
if about == ():
|
||||
doc += 'Elementary functions:\n\n'
|
||||
else:
|
||||
doc += 'Functions involving ' + ', '.join('`%s`' % latex(
|
||||
list(category[0][0].atoms(func))[0]) for func in about) + ':\n\n'
|
||||
for formula, gs, cond, hint in category:
|
||||
if not isinstance(gs, list):
|
||||
g: Expr = Symbol('\\text{generated}')
|
||||
else:
|
||||
g = Add(*[fac*f for (fac, f) in gs])
|
||||
obj = Eq(formula, g)
|
||||
if cond is True:
|
||||
cond = ""
|
||||
else:
|
||||
cond = ',\\text{ if } %s' % latex(cond)
|
||||
doc += ".. math::\n %s%s\n\n" % (latex(obj), cond)
|
||||
|
||||
__doc__ = doc
|
||||
1333
venv/lib/python3.12/site-packages/sympy/integrals/prde.py
Normal file
1333
venv/lib/python3.12/site-packages/sympy/integrals/prde.py
Normal file
File diff suppressed because it is too large
Load Diff
617
venv/lib/python3.12/site-packages/sympy/integrals/quadrature.py
Normal file
617
venv/lib/python3.12/site-packages/sympy/integrals/quadrature.py
Normal file
@@ -0,0 +1,617 @@
|
||||
from sympy.core import S, Dummy, pi
|
||||
from sympy.functions.combinatorial.factorials import factorial
|
||||
from sympy.functions.elementary.trigonometric import sin, cos
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.special.gamma_functions import gamma
|
||||
from sympy.polys.orthopolys import (legendre_poly, laguerre_poly,
|
||||
hermite_poly, jacobi_poly)
|
||||
from sympy.polys.rootoftools import RootOf
|
||||
|
||||
|
||||
def gauss_legendre(n, n_digits):
|
||||
r"""
|
||||
Computes the Gauss-Legendre quadrature [1]_ points and weights.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The Gauss-Legendre quadrature approximates the integral:
|
||||
|
||||
.. math::
|
||||
\int_{-1}^1 f(x)\,dx \approx \sum_{i=1}^n w_i f(x_i)
|
||||
|
||||
The nodes `x_i` of an order `n` quadrature rule are the roots of `P_n`
|
||||
and the weights `w_i` are given by:
|
||||
|
||||
.. math::
|
||||
w_i = \frac{2}{\left(1-x_i^2\right) \left(P'_n(x_i)\right)^2}
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
n :
|
||||
The order of quadrature.
|
||||
n_digits :
|
||||
Number of significant digits of the points and weights to return.
|
||||
|
||||
Returns
|
||||
=======
|
||||
|
||||
(x, w) : the ``x`` and ``w`` are lists of points and weights as Floats.
|
||||
The points `x_i` and weights `w_i` are returned as ``(x, w)``
|
||||
tuple of lists.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.integrals.quadrature import gauss_legendre
|
||||
>>> x, w = gauss_legendre(3, 5)
|
||||
>>> x
|
||||
[-0.7746, 0, 0.7746]
|
||||
>>> w
|
||||
[0.55556, 0.88889, 0.55556]
|
||||
>>> x, w = gauss_legendre(4, 5)
|
||||
>>> x
|
||||
[-0.86114, -0.33998, 0.33998, 0.86114]
|
||||
>>> w
|
||||
[0.34785, 0.65215, 0.65215, 0.34785]
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
gauss_laguerre, gauss_gen_laguerre, gauss_hermite, gauss_chebyshev_t, gauss_chebyshev_u, gauss_jacobi, gauss_lobatto
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Gaussian_quadrature
|
||||
.. [2] https://people.sc.fsu.edu/~jburkardt/cpp_src/legendre_rule/legendre_rule.html
|
||||
"""
|
||||
x = Dummy("x")
|
||||
p = legendre_poly(n, x, polys=True)
|
||||
pd = p.diff(x)
|
||||
xi = []
|
||||
w = []
|
||||
for r in p.real_roots():
|
||||
if isinstance(r, RootOf):
|
||||
r = r.eval_rational(S.One/10**(n_digits+2))
|
||||
xi.append(r.n(n_digits))
|
||||
w.append((2/((1-r**2) * pd.subs(x, r)**2)).n(n_digits))
|
||||
return xi, w
|
||||
|
||||
|
||||
def gauss_laguerre(n, n_digits):
|
||||
r"""
|
||||
Computes the Gauss-Laguerre quadrature [1]_ points and weights.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The Gauss-Laguerre quadrature approximates the integral:
|
||||
|
||||
.. math::
|
||||
\int_0^{\infty} e^{-x} f(x)\,dx \approx \sum_{i=1}^n w_i f(x_i)
|
||||
|
||||
|
||||
The nodes `x_i` of an order `n` quadrature rule are the roots of `L_n`
|
||||
and the weights `w_i` are given by:
|
||||
|
||||
.. math::
|
||||
w_i = \frac{x_i}{(n+1)^2 \left(L_{n+1}(x_i)\right)^2}
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
n :
|
||||
The order of quadrature.
|
||||
n_digits :
|
||||
Number of significant digits of the points and weights to return.
|
||||
|
||||
Returns
|
||||
=======
|
||||
|
||||
(x, w) : The ``x`` and ``w`` are lists of points and weights as Floats.
|
||||
The points `x_i` and weights `w_i` are returned as ``(x, w)``
|
||||
tuple of lists.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.integrals.quadrature import gauss_laguerre
|
||||
>>> x, w = gauss_laguerre(3, 5)
|
||||
>>> x
|
||||
[0.41577, 2.2943, 6.2899]
|
||||
>>> w
|
||||
[0.71109, 0.27852, 0.010389]
|
||||
>>> x, w = gauss_laguerre(6, 5)
|
||||
>>> x
|
||||
[0.22285, 1.1889, 2.9927, 5.7751, 9.8375, 15.983]
|
||||
>>> w
|
||||
[0.45896, 0.417, 0.11337, 0.010399, 0.00026102, 8.9855e-7]
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
gauss_legendre, gauss_gen_laguerre, gauss_hermite, gauss_chebyshev_t, gauss_chebyshev_u, gauss_jacobi, gauss_lobatto
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Gauss%E2%80%93Laguerre_quadrature
|
||||
.. [2] https://people.sc.fsu.edu/~jburkardt/cpp_src/laguerre_rule/laguerre_rule.html
|
||||
"""
|
||||
x = Dummy("x")
|
||||
p = laguerre_poly(n, x, polys=True)
|
||||
p1 = laguerre_poly(n+1, x, polys=True)
|
||||
xi = []
|
||||
w = []
|
||||
for r in p.real_roots():
|
||||
if isinstance(r, RootOf):
|
||||
r = r.eval_rational(S.One/10**(n_digits+2))
|
||||
xi.append(r.n(n_digits))
|
||||
w.append((r/((n+1)**2 * p1.subs(x, r)**2)).n(n_digits))
|
||||
return xi, w
|
||||
|
||||
|
||||
def gauss_hermite(n, n_digits):
|
||||
r"""
|
||||
Computes the Gauss-Hermite quadrature [1]_ points and weights.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The Gauss-Hermite quadrature approximates the integral:
|
||||
|
||||
.. math::
|
||||
\int_{-\infty}^{\infty} e^{-x^2} f(x)\,dx \approx
|
||||
\sum_{i=1}^n w_i f(x_i)
|
||||
|
||||
The nodes `x_i` of an order `n` quadrature rule are the roots of `H_n`
|
||||
and the weights `w_i` are given by:
|
||||
|
||||
.. math::
|
||||
w_i = \frac{2^{n-1} n! \sqrt{\pi}}{n^2 \left(H_{n-1}(x_i)\right)^2}
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
n :
|
||||
The order of quadrature.
|
||||
n_digits :
|
||||
Number of significant digits of the points and weights to return.
|
||||
|
||||
Returns
|
||||
=======
|
||||
|
||||
(x, w) : The ``x`` and ``w`` are lists of points and weights as Floats.
|
||||
The points `x_i` and weights `w_i` are returned as ``(x, w)``
|
||||
tuple of lists.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.integrals.quadrature import gauss_hermite
|
||||
>>> x, w = gauss_hermite(3, 5)
|
||||
>>> x
|
||||
[-1.2247, 0, 1.2247]
|
||||
>>> w
|
||||
[0.29541, 1.1816, 0.29541]
|
||||
|
||||
>>> x, w = gauss_hermite(6, 5)
|
||||
>>> x
|
||||
[-2.3506, -1.3358, -0.43608, 0.43608, 1.3358, 2.3506]
|
||||
>>> w
|
||||
[0.00453, 0.15707, 0.72463, 0.72463, 0.15707, 0.00453]
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
gauss_legendre, gauss_laguerre, gauss_gen_laguerre, gauss_chebyshev_t, gauss_chebyshev_u, gauss_jacobi, gauss_lobatto
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Gauss-Hermite_Quadrature
|
||||
.. [2] https://people.sc.fsu.edu/~jburkardt/cpp_src/hermite_rule/hermite_rule.html
|
||||
.. [3] https://people.sc.fsu.edu/~jburkardt/cpp_src/gen_hermite_rule/gen_hermite_rule.html
|
||||
"""
|
||||
x = Dummy("x")
|
||||
p = hermite_poly(n, x, polys=True)
|
||||
p1 = hermite_poly(n-1, x, polys=True)
|
||||
xi = []
|
||||
w = []
|
||||
for r in p.real_roots():
|
||||
if isinstance(r, RootOf):
|
||||
r = r.eval_rational(S.One/10**(n_digits+2))
|
||||
xi.append(r.n(n_digits))
|
||||
w.append(((2**(n-1) * factorial(n) * sqrt(pi)) /
|
||||
(n**2 * p1.subs(x, r)**2)).n(n_digits))
|
||||
return xi, w
|
||||
|
||||
|
||||
def gauss_gen_laguerre(n, alpha, n_digits):
|
||||
r"""
|
||||
Computes the generalized Gauss-Laguerre quadrature [1]_ points and weights.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The generalized Gauss-Laguerre quadrature approximates the integral:
|
||||
|
||||
.. math::
|
||||
\int_{0}^\infty x^{\alpha} e^{-x} f(x)\,dx \approx
|
||||
\sum_{i=1}^n w_i f(x_i)
|
||||
|
||||
The nodes `x_i` of an order `n` quadrature rule are the roots of
|
||||
`L^{\alpha}_n` and the weights `w_i` are given by:
|
||||
|
||||
.. math::
|
||||
w_i = \frac{\Gamma(\alpha+n)}
|
||||
{n \Gamma(n) L^{\alpha}_{n-1}(x_i) L^{\alpha+1}_{n-1}(x_i)}
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
n :
|
||||
The order of quadrature.
|
||||
|
||||
alpha :
|
||||
The exponent of the singularity, `\alpha > -1`.
|
||||
|
||||
n_digits :
|
||||
Number of significant digits of the points and weights to return.
|
||||
|
||||
Returns
|
||||
=======
|
||||
|
||||
(x, w) : the ``x`` and ``w`` are lists of points and weights as Floats.
|
||||
The points `x_i` and weights `w_i` are returned as ``(x, w)``
|
||||
tuple of lists.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import S
|
||||
>>> from sympy.integrals.quadrature import gauss_gen_laguerre
|
||||
>>> x, w = gauss_gen_laguerre(3, -S.Half, 5)
|
||||
>>> x
|
||||
[0.19016, 1.7845, 5.5253]
|
||||
>>> w
|
||||
[1.4493, 0.31413, 0.00906]
|
||||
|
||||
>>> x, w = gauss_gen_laguerre(4, 3*S.Half, 5)
|
||||
>>> x
|
||||
[0.97851, 2.9904, 6.3193, 11.712]
|
||||
>>> w
|
||||
[0.53087, 0.67721, 0.11895, 0.0023152]
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
gauss_legendre, gauss_laguerre, gauss_hermite, gauss_chebyshev_t, gauss_chebyshev_u, gauss_jacobi, gauss_lobatto
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Gauss%E2%80%93Laguerre_quadrature
|
||||
.. [2] https://people.sc.fsu.edu/~jburkardt/cpp_src/gen_laguerre_rule/gen_laguerre_rule.html
|
||||
"""
|
||||
x = Dummy("x")
|
||||
p = laguerre_poly(n, x, alpha=alpha, polys=True)
|
||||
p1 = laguerre_poly(n-1, x, alpha=alpha, polys=True)
|
||||
p2 = laguerre_poly(n-1, x, alpha=alpha+1, polys=True)
|
||||
xi = []
|
||||
w = []
|
||||
for r in p.real_roots():
|
||||
if isinstance(r, RootOf):
|
||||
r = r.eval_rational(S.One/10**(n_digits+2))
|
||||
xi.append(r.n(n_digits))
|
||||
w.append((gamma(alpha+n) /
|
||||
(n*gamma(n)*p1.subs(x, r)*p2.subs(x, r))).n(n_digits))
|
||||
return xi, w
|
||||
|
||||
|
||||
def gauss_chebyshev_t(n, n_digits):
|
||||
r"""
|
||||
Computes the Gauss-Chebyshev quadrature [1]_ points and weights of
|
||||
the first kind.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The Gauss-Chebyshev quadrature of the first kind approximates the integral:
|
||||
|
||||
.. math::
|
||||
\int_{-1}^{1} \frac{1}{\sqrt{1-x^2}} f(x)\,dx \approx
|
||||
\sum_{i=1}^n w_i f(x_i)
|
||||
|
||||
The nodes `x_i` of an order `n` quadrature rule are the roots of `T_n`
|
||||
and the weights `w_i` are given by:
|
||||
|
||||
.. math::
|
||||
w_i = \frac{\pi}{n}
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
n :
|
||||
The order of quadrature.
|
||||
|
||||
n_digits :
|
||||
Number of significant digits of the points and weights to return.
|
||||
|
||||
Returns
|
||||
=======
|
||||
|
||||
(x, w) : the ``x`` and ``w`` are lists of points and weights as Floats.
|
||||
The points `x_i` and weights `w_i` are returned as ``(x, w)``
|
||||
tuple of lists.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.integrals.quadrature import gauss_chebyshev_t
|
||||
>>> x, w = gauss_chebyshev_t(3, 5)
|
||||
>>> x
|
||||
[0.86602, 0, -0.86602]
|
||||
>>> w
|
||||
[1.0472, 1.0472, 1.0472]
|
||||
|
||||
>>> x, w = gauss_chebyshev_t(6, 5)
|
||||
>>> x
|
||||
[0.96593, 0.70711, 0.25882, -0.25882, -0.70711, -0.96593]
|
||||
>>> w
|
||||
[0.5236, 0.5236, 0.5236, 0.5236, 0.5236, 0.5236]
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
gauss_legendre, gauss_laguerre, gauss_hermite, gauss_gen_laguerre, gauss_chebyshev_u, gauss_jacobi, gauss_lobatto
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Chebyshev%E2%80%93Gauss_quadrature
|
||||
.. [2] https://people.sc.fsu.edu/~jburkardt/cpp_src/chebyshev1_rule/chebyshev1_rule.html
|
||||
"""
|
||||
xi = []
|
||||
w = []
|
||||
for i in range(1, n+1):
|
||||
xi.append((cos((2*i-S.One)/(2*n)*S.Pi)).n(n_digits))
|
||||
w.append((S.Pi/n).n(n_digits))
|
||||
return xi, w
|
||||
|
||||
|
||||
def gauss_chebyshev_u(n, n_digits):
|
||||
r"""
|
||||
Computes the Gauss-Chebyshev quadrature [1]_ points and weights of
|
||||
the second kind.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The Gauss-Chebyshev quadrature of the second kind approximates the
|
||||
integral:
|
||||
|
||||
.. math::
|
||||
\int_{-1}^{1} \sqrt{1-x^2} f(x)\,dx \approx \sum_{i=1}^n w_i f(x_i)
|
||||
|
||||
The nodes `x_i` of an order `n` quadrature rule are the roots of `U_n`
|
||||
and the weights `w_i` are given by:
|
||||
|
||||
.. math::
|
||||
w_i = \frac{\pi}{n+1} \sin^2 \left(\frac{i}{n+1}\pi\right)
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
n : the order of quadrature
|
||||
|
||||
n_digits : number of significant digits of the points and weights to return
|
||||
|
||||
Returns
|
||||
=======
|
||||
|
||||
(x, w) : the ``x`` and ``w`` are lists of points and weights as Floats.
|
||||
The points `x_i` and weights `w_i` are returned as ``(x, w)``
|
||||
tuple of lists.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.integrals.quadrature import gauss_chebyshev_u
|
||||
>>> x, w = gauss_chebyshev_u(3, 5)
|
||||
>>> x
|
||||
[0.70711, 0, -0.70711]
|
||||
>>> w
|
||||
[0.3927, 0.7854, 0.3927]
|
||||
|
||||
>>> x, w = gauss_chebyshev_u(6, 5)
|
||||
>>> x
|
||||
[0.90097, 0.62349, 0.22252, -0.22252, -0.62349, -0.90097]
|
||||
>>> w
|
||||
[0.084489, 0.27433, 0.42658, 0.42658, 0.27433, 0.084489]
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
gauss_legendre, gauss_laguerre, gauss_hermite, gauss_gen_laguerre, gauss_chebyshev_t, gauss_jacobi, gauss_lobatto
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Chebyshev%E2%80%93Gauss_quadrature
|
||||
.. [2] https://people.sc.fsu.edu/~jburkardt/cpp_src/chebyshev2_rule/chebyshev2_rule.html
|
||||
"""
|
||||
xi = []
|
||||
w = []
|
||||
for i in range(1, n+1):
|
||||
xi.append((cos(i/(n+S.One)*S.Pi)).n(n_digits))
|
||||
w.append((S.Pi/(n+S.One)*sin(i*S.Pi/(n+S.One))**2).n(n_digits))
|
||||
return xi, w
|
||||
|
||||
|
||||
def gauss_jacobi(n, alpha, beta, n_digits):
|
||||
r"""
|
||||
Computes the Gauss-Jacobi quadrature [1]_ points and weights.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The Gauss-Jacobi quadrature of the first kind approximates the integral:
|
||||
|
||||
.. math::
|
||||
\int_{-1}^1 (1-x)^\alpha (1+x)^\beta f(x)\,dx \approx
|
||||
\sum_{i=1}^n w_i f(x_i)
|
||||
|
||||
The nodes `x_i` of an order `n` quadrature rule are the roots of
|
||||
`P^{(\alpha,\beta)}_n` and the weights `w_i` are given by:
|
||||
|
||||
.. math::
|
||||
w_i = -\frac{2n+\alpha+\beta+2}{n+\alpha+\beta+1}
|
||||
\frac{\Gamma(n+\alpha+1)\Gamma(n+\beta+1)}
|
||||
{\Gamma(n+\alpha+\beta+1)(n+1)!}
|
||||
\frac{2^{\alpha+\beta}}{P'_n(x_i)
|
||||
P^{(\alpha,\beta)}_{n+1}(x_i)}
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
n : the order of quadrature
|
||||
|
||||
alpha : the first parameter of the Jacobi Polynomial, `\alpha > -1`
|
||||
|
||||
beta : the second parameter of the Jacobi Polynomial, `\beta > -1`
|
||||
|
||||
n_digits : number of significant digits of the points and weights to return
|
||||
|
||||
Returns
|
||||
=======
|
||||
|
||||
(x, w) : the ``x`` and ``w`` are lists of points and weights as Floats.
|
||||
The points `x_i` and weights `w_i` are returned as ``(x, w)``
|
||||
tuple of lists.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import S
|
||||
>>> from sympy.integrals.quadrature import gauss_jacobi
|
||||
>>> x, w = gauss_jacobi(3, S.Half, -S.Half, 5)
|
||||
>>> x
|
||||
[-0.90097, -0.22252, 0.62349]
|
||||
>>> w
|
||||
[1.7063, 1.0973, 0.33795]
|
||||
|
||||
>>> x, w = gauss_jacobi(6, 1, 1, 5)
|
||||
>>> x
|
||||
[-0.87174, -0.5917, -0.2093, 0.2093, 0.5917, 0.87174]
|
||||
>>> w
|
||||
[0.050584, 0.22169, 0.39439, 0.39439, 0.22169, 0.050584]
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
gauss_legendre, gauss_laguerre, gauss_hermite, gauss_gen_laguerre,
|
||||
gauss_chebyshev_t, gauss_chebyshev_u, gauss_lobatto
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Gauss%E2%80%93Jacobi_quadrature
|
||||
.. [2] https://people.sc.fsu.edu/~jburkardt/cpp_src/jacobi_rule/jacobi_rule.html
|
||||
.. [3] https://people.sc.fsu.edu/~jburkardt/cpp_src/gegenbauer_rule/gegenbauer_rule.html
|
||||
"""
|
||||
x = Dummy("x")
|
||||
p = jacobi_poly(n, alpha, beta, x, polys=True)
|
||||
pd = p.diff(x)
|
||||
pn = jacobi_poly(n+1, alpha, beta, x, polys=True)
|
||||
xi = []
|
||||
w = []
|
||||
for r in p.real_roots():
|
||||
if isinstance(r, RootOf):
|
||||
r = r.eval_rational(S.One/10**(n_digits+2))
|
||||
xi.append(r.n(n_digits))
|
||||
w.append((
|
||||
- (2*n+alpha+beta+2) / (n+alpha+beta+S.One) *
|
||||
(gamma(n+alpha+1)*gamma(n+beta+1)) /
|
||||
(gamma(n+alpha+beta+S.One)*gamma(n+2)) *
|
||||
2**(alpha+beta) / (pd.subs(x, r) * pn.subs(x, r))).n(n_digits))
|
||||
return xi, w
|
||||
|
||||
|
||||
def gauss_lobatto(n, n_digits):
|
||||
r"""
|
||||
Computes the Gauss-Lobatto quadrature [1]_ points and weights.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The Gauss-Lobatto quadrature approximates the integral:
|
||||
|
||||
.. math::
|
||||
\int_{-1}^1 f(x)\,dx \approx \sum_{i=1}^n w_i f(x_i)
|
||||
|
||||
The nodes `x_i` of an order `n` quadrature rule are the roots of `P'_(n-1)`
|
||||
and the weights `w_i` are given by:
|
||||
|
||||
.. math::
|
||||
&w_i = \frac{2}{n(n-1) \left[P_{n-1}(x_i)\right]^2},\quad x\neq\pm 1\\
|
||||
&w_i = \frac{2}{n(n-1)},\quad x=\pm 1
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
n : the order of quadrature
|
||||
|
||||
n_digits : number of significant digits of the points and weights to return
|
||||
|
||||
Returns
|
||||
=======
|
||||
|
||||
(x, w) : the ``x`` and ``w`` are lists of points and weights as Floats.
|
||||
The points `x_i` and weights `w_i` are returned as ``(x, w)``
|
||||
tuple of lists.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.integrals.quadrature import gauss_lobatto
|
||||
>>> x, w = gauss_lobatto(3, 5)
|
||||
>>> x
|
||||
[-1, 0, 1]
|
||||
>>> w
|
||||
[0.33333, 1.3333, 0.33333]
|
||||
>>> x, w = gauss_lobatto(4, 5)
|
||||
>>> x
|
||||
[-1, -0.44721, 0.44721, 1]
|
||||
>>> w
|
||||
[0.16667, 0.83333, 0.83333, 0.16667]
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
gauss_legendre,gauss_laguerre, gauss_gen_laguerre, gauss_hermite, gauss_chebyshev_t, gauss_chebyshev_u, gauss_jacobi
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikipedia.org/wiki/Gaussian_quadrature#Gauss.E2.80.93Lobatto_rules
|
||||
.. [2] https://web.archive.org/web/20200118141346/http://people.math.sfu.ca/~cbm/aands/page_888.htm
|
||||
"""
|
||||
x = Dummy("x")
|
||||
p = legendre_poly(n-1, x, polys=True)
|
||||
pd = p.diff(x)
|
||||
xi = []
|
||||
w = []
|
||||
for r in pd.real_roots():
|
||||
if isinstance(r, RootOf):
|
||||
r = r.eval_rational(S.One/10**(n_digits+2))
|
||||
xi.append(r.n(n_digits))
|
||||
w.append((2/(n*(n-1) * p.subs(x, r)**2)).n(n_digits))
|
||||
|
||||
xi.insert(0, -1)
|
||||
xi.append(1)
|
||||
w.insert(0, (S(2)/(n*(n-1))).n(n_digits))
|
||||
w.append((S(2)/(n*(n-1))).n(n_digits))
|
||||
return xi, w
|
||||
@@ -0,0 +1,445 @@
|
||||
"""This module implements tools for integrating rational functions. """
|
||||
|
||||
from sympy.core.function import Lambda
|
||||
from sympy.core.numbers import I
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import (Dummy, Symbol, symbols)
|
||||
from sympy.functions.elementary.exponential import log
|
||||
from sympy.functions.elementary.trigonometric import atan
|
||||
from sympy.polys.polyerrors import DomainError
|
||||
from sympy.polys.polyroots import roots
|
||||
from sympy.polys.polytools import cancel
|
||||
from sympy.polys.rootoftools import RootSum
|
||||
from sympy.polys import Poly, resultant, ZZ
|
||||
|
||||
|
||||
def ratint(f, x, **flags):
|
||||
"""
|
||||
Performs indefinite integration of rational functions.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
Given a field :math:`K` and a rational function :math:`f = p/q`,
|
||||
where :math:`p` and :math:`q` are polynomials in :math:`K[x]`,
|
||||
returns a function :math:`g` such that :math:`f = g'`.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.integrals.rationaltools import ratint
|
||||
>>> from sympy.abc import x
|
||||
|
||||
>>> ratint(36/(x**5 - 2*x**4 - 2*x**3 + 4*x**2 + x - 2), x)
|
||||
(12*x + 6)/(x**2 - 1) + 4*log(x - 2) - 4*log(x + 1)
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] M. Bronstein, Symbolic Integration I: Transcendental
|
||||
Functions, Second Edition, Springer-Verlag, 2005, pp. 35-70
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
sympy.integrals.integrals.Integral.doit
|
||||
sympy.integrals.rationaltools.ratint_logpart
|
||||
sympy.integrals.rationaltools.ratint_ratpart
|
||||
|
||||
"""
|
||||
if isinstance(f, tuple):
|
||||
p, q = f
|
||||
else:
|
||||
p, q = f.as_numer_denom()
|
||||
|
||||
p, q = Poly(p, x, composite=False, field=True), Poly(q, x, composite=False, field=True)
|
||||
|
||||
coeff, p, q = p.cancel(q)
|
||||
poly, p = p.div(q)
|
||||
|
||||
result = poly.integrate(x).as_expr()
|
||||
|
||||
if p.is_zero:
|
||||
return coeff*result
|
||||
|
||||
g, h = ratint_ratpart(p, q, x)
|
||||
|
||||
P, Q = h.as_numer_denom()
|
||||
|
||||
P = Poly(P, x)
|
||||
Q = Poly(Q, x)
|
||||
|
||||
q, r = P.div(Q)
|
||||
|
||||
result += g + q.integrate(x).as_expr()
|
||||
|
||||
if not r.is_zero:
|
||||
symbol = flags.get('symbol', 't')
|
||||
|
||||
if not isinstance(symbol, Symbol):
|
||||
t = Dummy(symbol)
|
||||
else:
|
||||
t = symbol.as_dummy()
|
||||
|
||||
L = ratint_logpart(r, Q, x, t)
|
||||
|
||||
real = flags.get('real')
|
||||
|
||||
if real is None:
|
||||
if isinstance(f, tuple):
|
||||
p, q = f
|
||||
atoms = p.atoms() | q.atoms()
|
||||
else:
|
||||
atoms = f.atoms()
|
||||
|
||||
for elt in atoms - {x}:
|
||||
if not elt.is_extended_real:
|
||||
real = False
|
||||
break
|
||||
else:
|
||||
real = True
|
||||
|
||||
eps = S.Zero
|
||||
|
||||
if not real:
|
||||
for h, q in L:
|
||||
_, h = h.primitive()
|
||||
eps += RootSum(
|
||||
q, Lambda(t, t*log(h.as_expr())), quadratic=True)
|
||||
else:
|
||||
for h, q in L:
|
||||
_, h = h.primitive()
|
||||
R = log_to_real(h, q, x, t)
|
||||
|
||||
if R is not None:
|
||||
eps += R
|
||||
else:
|
||||
eps += RootSum(
|
||||
q, Lambda(t, t*log(h.as_expr())), quadratic=True)
|
||||
|
||||
result += eps
|
||||
|
||||
return coeff*result
|
||||
|
||||
|
||||
def ratint_ratpart(f, g, x):
|
||||
"""
|
||||
Horowitz-Ostrogradsky algorithm.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
Given a field K and polynomials f and g in K[x], such that f and g
|
||||
are coprime and deg(f) < deg(g), returns fractions A and B in K(x),
|
||||
such that f/g = A' + B and B has square-free denominator.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.integrals.rationaltools import ratint_ratpart
|
||||
>>> from sympy.abc import x, y
|
||||
>>> from sympy import Poly
|
||||
>>> ratint_ratpart(Poly(1, x, domain='ZZ'),
|
||||
... Poly(x + 1, x, domain='ZZ'), x)
|
||||
(0, 1/(x + 1))
|
||||
>>> ratint_ratpart(Poly(1, x, domain='EX'),
|
||||
... Poly(x**2 + y**2, x, domain='EX'), x)
|
||||
(0, 1/(x**2 + y**2))
|
||||
>>> ratint_ratpart(Poly(36, x, domain='ZZ'),
|
||||
... Poly(x**5 - 2*x**4 - 2*x**3 + 4*x**2 + x - 2, x, domain='ZZ'), x)
|
||||
((12*x + 6)/(x**2 - 1), 12/(x**2 - x - 2))
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
ratint, ratint_logpart
|
||||
"""
|
||||
from sympy.solvers.solvers import solve
|
||||
|
||||
f = Poly(f, x)
|
||||
g = Poly(g, x)
|
||||
|
||||
u, v, _ = g.cofactors(g.diff())
|
||||
|
||||
n = u.degree()
|
||||
m = v.degree()
|
||||
|
||||
A_coeffs = [ Dummy('a' + str(n - i)) for i in range(0, n) ]
|
||||
B_coeffs = [ Dummy('b' + str(m - i)) for i in range(0, m) ]
|
||||
|
||||
C_coeffs = A_coeffs + B_coeffs
|
||||
|
||||
A = Poly(A_coeffs, x, domain=ZZ[C_coeffs])
|
||||
B = Poly(B_coeffs, x, domain=ZZ[C_coeffs])
|
||||
|
||||
H = f - A.diff()*v + A*(u.diff()*v).quo(u) - B*u
|
||||
|
||||
result = solve(H.coeffs(), C_coeffs)
|
||||
|
||||
A = A.as_expr().subs(result)
|
||||
B = B.as_expr().subs(result)
|
||||
|
||||
rat_part = cancel(A/u.as_expr(), x)
|
||||
log_part = cancel(B/v.as_expr(), x)
|
||||
|
||||
return rat_part, log_part
|
||||
|
||||
|
||||
def ratint_logpart(f, g, x, t=None):
|
||||
r"""
|
||||
Lazard-Rioboo-Trager algorithm.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
Given a field K and polynomials f and g in K[x], such that f and g
|
||||
are coprime, deg(f) < deg(g) and g is square-free, returns a list
|
||||
of tuples (s_i, q_i) of polynomials, for i = 1..n, such that s_i
|
||||
in K[t, x] and q_i in K[t], and::
|
||||
|
||||
___ ___
|
||||
d f d \ ` \ `
|
||||
-- - = -- ) ) a log(s_i(a, x))
|
||||
dx g dx /__, /__,
|
||||
i=1..n a | q_i(a) = 0
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.integrals.rationaltools import ratint_logpart
|
||||
>>> from sympy.abc import x
|
||||
>>> from sympy import Poly
|
||||
>>> ratint_logpart(Poly(1, x, domain='ZZ'),
|
||||
... Poly(x**2 + x + 1, x, domain='ZZ'), x)
|
||||
[(Poly(x + 3*_t/2 + 1/2, x, domain='QQ[_t]'),
|
||||
...Poly(3*_t**2 + 1, _t, domain='ZZ'))]
|
||||
>>> ratint_logpart(Poly(12, x, domain='ZZ'),
|
||||
... Poly(x**2 - x - 2, x, domain='ZZ'), x)
|
||||
[(Poly(x - 3*_t/8 - 1/2, x, domain='QQ[_t]'),
|
||||
...Poly(-_t**2 + 16, _t, domain='ZZ'))]
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
ratint, ratint_ratpart
|
||||
"""
|
||||
f, g = Poly(f, x), Poly(g, x)
|
||||
|
||||
t = t or Dummy('t')
|
||||
a, b = g, f - g.diff()*Poly(t, x)
|
||||
|
||||
res, R = resultant(a, b, includePRS=True)
|
||||
res = Poly(res, t, composite=False)
|
||||
|
||||
assert res, "BUG: resultant(%s, %s) cannot be zero" % (a, b)
|
||||
|
||||
R_map, H = {}, []
|
||||
|
||||
for r in R:
|
||||
R_map[r.degree()] = r
|
||||
|
||||
def _include_sign(c, sqf):
|
||||
if c.is_extended_real and (c < 0) == True:
|
||||
h, k = sqf[0]
|
||||
c_poly = c.as_poly(h.gens)
|
||||
sqf[0] = h*c_poly, k
|
||||
|
||||
C, res_sqf = res.sqf_list()
|
||||
_include_sign(C, res_sqf)
|
||||
|
||||
for q, i in res_sqf:
|
||||
_, q = q.primitive()
|
||||
|
||||
if g.degree() == i:
|
||||
H.append((g, q))
|
||||
else:
|
||||
h = R_map[i]
|
||||
h_lc = Poly(h.LC(), t, field=True)
|
||||
|
||||
c, h_lc_sqf = h_lc.sqf_list(all=True)
|
||||
_include_sign(c, h_lc_sqf)
|
||||
|
||||
for a, j in h_lc_sqf:
|
||||
h = h.quo(Poly(a.gcd(q)**j, x))
|
||||
|
||||
inv, coeffs = h_lc.invert(q), [S.One]
|
||||
|
||||
for coeff in h.coeffs()[1:]:
|
||||
coeff = coeff.as_poly(inv.gens)
|
||||
T = (inv*coeff).rem(q)
|
||||
coeffs.append(T.as_expr())
|
||||
|
||||
h = Poly(dict(list(zip(h.monoms(), coeffs))), x)
|
||||
|
||||
H.append((h, q))
|
||||
|
||||
return H
|
||||
|
||||
|
||||
def log_to_atan(f, g):
|
||||
"""
|
||||
Convert complex logarithms to real arctangents.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
Given a real field K and polynomials f and g in K[x], with g != 0,
|
||||
returns a sum h of arctangents of polynomials in K[x], such that:
|
||||
|
||||
dh d f + I g
|
||||
-- = -- I log( ------- )
|
||||
dx dx f - I g
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.integrals.rationaltools import log_to_atan
|
||||
>>> from sympy.abc import x
|
||||
>>> from sympy import Poly, sqrt, S
|
||||
>>> log_to_atan(Poly(x, x, domain='ZZ'), Poly(1, x, domain='ZZ'))
|
||||
2*atan(x)
|
||||
>>> log_to_atan(Poly(x + S(1)/2, x, domain='QQ'),
|
||||
... Poly(sqrt(3)/2, x, domain='EX'))
|
||||
2*atan(2*sqrt(3)*x/3 + sqrt(3)/3)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
log_to_real
|
||||
"""
|
||||
if f.degree() < g.degree():
|
||||
f, g = -g, f
|
||||
|
||||
f = f.to_field()
|
||||
g = g.to_field()
|
||||
|
||||
p, q = f.div(g)
|
||||
|
||||
if q.is_zero:
|
||||
return 2*atan(p.as_expr())
|
||||
else:
|
||||
s, t, h = g.gcdex(-f)
|
||||
u = (f*s + g*t).quo(h)
|
||||
A = 2*atan(u.as_expr())
|
||||
|
||||
return A + log_to_atan(s, t)
|
||||
|
||||
|
||||
def _get_real_roots(f, x):
|
||||
"""get real roots of f if possible"""
|
||||
rs = roots(f, filter='R')
|
||||
|
||||
try:
|
||||
num_roots = f.count_roots()
|
||||
except DomainError:
|
||||
return rs
|
||||
else:
|
||||
if len(rs) == num_roots:
|
||||
return rs
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def log_to_real(h, q, x, t):
|
||||
r"""
|
||||
Convert complex logarithms to real functions.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
Given real field K and polynomials h in K[t,x] and q in K[t],
|
||||
returns real function f such that:
|
||||
___
|
||||
df d \ `
|
||||
-- = -- ) a log(h(a, x))
|
||||
dx dx /__,
|
||||
a | q(a) = 0
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.integrals.rationaltools import log_to_real
|
||||
>>> from sympy.abc import x, y
|
||||
>>> from sympy import Poly, S
|
||||
>>> log_to_real(Poly(x + 3*y/2 + S(1)/2, x, domain='QQ[y]'),
|
||||
... Poly(3*y**2 + 1, y, domain='ZZ'), x, y)
|
||||
2*sqrt(3)*atan(2*sqrt(3)*x/3 + sqrt(3)/3)/3
|
||||
>>> log_to_real(Poly(x**2 - 1, x, domain='ZZ'),
|
||||
... Poly(-2*y + 1, y, domain='ZZ'), x, y)
|
||||
log(x**2 - 1)/2
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
log_to_atan
|
||||
"""
|
||||
from sympy.simplify.radsimp import collect
|
||||
u, v = symbols('u,v', cls=Dummy)
|
||||
|
||||
H = h.as_expr().xreplace({t: u + I*v}).expand()
|
||||
Q = q.as_expr().xreplace({t: u + I*v}).expand()
|
||||
|
||||
H_map = collect(H, I, evaluate=False)
|
||||
Q_map = collect(Q, I, evaluate=False)
|
||||
|
||||
a, b = H_map.get(S.One, S.Zero), H_map.get(I, S.Zero)
|
||||
c, d = Q_map.get(S.One, S.Zero), Q_map.get(I, S.Zero)
|
||||
|
||||
R = Poly(resultant(c, d, v), u)
|
||||
|
||||
R_u = _get_real_roots(R, u)
|
||||
|
||||
if R_u is None:
|
||||
return None
|
||||
|
||||
result = S.Zero
|
||||
|
||||
for r_u in R_u.keys():
|
||||
C = Poly(c.xreplace({u: r_u}), v)
|
||||
if not C:
|
||||
# t was split into real and imaginary parts
|
||||
# and denom Q(u, v) = c + I*d. We just found
|
||||
# that c(r_u) is 0 so the roots are in d
|
||||
C = Poly(d.xreplace({u: r_u}), v)
|
||||
# we were going to reject roots from C that
|
||||
# did not set d to zero, but since we are now
|
||||
# using C = d and c is already 0, there is
|
||||
# nothing to check
|
||||
d = S.Zero
|
||||
|
||||
R_v = _get_real_roots(C, v)
|
||||
|
||||
if R_v is None:
|
||||
return None
|
||||
|
||||
R_v_paired = [] # take one from each pair of conjugate roots
|
||||
for r_v in R_v:
|
||||
if r_v not in R_v_paired and -r_v not in R_v_paired:
|
||||
if r_v.is_negative or r_v.could_extract_minus_sign():
|
||||
R_v_paired.append(-r_v)
|
||||
elif not r_v.is_zero:
|
||||
R_v_paired.append(r_v)
|
||||
|
||||
for r_v in R_v_paired:
|
||||
|
||||
D = d.xreplace({u: r_u, v: r_v})
|
||||
|
||||
if D.evalf(chop=True) != 0:
|
||||
continue
|
||||
|
||||
A = Poly(a.xreplace({u: r_u, v: r_v}), x)
|
||||
B = Poly(b.xreplace({u: r_u, v: r_v}), x)
|
||||
|
||||
AB = (A**2 + B**2).as_expr()
|
||||
|
||||
result += r_u*log(AB) + r_v*log_to_atan(A, B)
|
||||
|
||||
R_q = _get_real_roots(q, t)
|
||||
|
||||
if R_q is None:
|
||||
return None
|
||||
|
||||
for r in R_q.keys():
|
||||
result += r*log(h.as_expr().subs(t, r))
|
||||
|
||||
return result
|
||||
800
venv/lib/python3.12/site-packages/sympy/integrals/rde.py
Normal file
800
venv/lib/python3.12/site-packages/sympy/integrals/rde.py
Normal file
@@ -0,0 +1,800 @@
|
||||
"""
|
||||
Algorithms for solving the Risch differential equation.
|
||||
|
||||
Given a differential field K of characteristic 0 that is a simple
|
||||
monomial extension of a base field k and f, g in K, the Risch
|
||||
Differential Equation problem is to decide if there exist y in K such
|
||||
that Dy + f*y == g and to find one if there are some. If t is a
|
||||
monomial over k and the coefficients of f and g are in k(t), then y is
|
||||
in k(t), and the outline of the algorithm here is given as:
|
||||
|
||||
1. Compute the normal part n of the denominator of y. The problem is
|
||||
then reduced to finding y' in k<t>, where y == y'/n.
|
||||
2. Compute the special part s of the denominator of y. The problem is
|
||||
then reduced to finding y'' in k[t], where y == y''/(n*s)
|
||||
3. Bound the degree of y''.
|
||||
4. Reduce the equation Dy + f*y == g to a similar equation with f, g in
|
||||
k[t].
|
||||
5. Find the solutions in k[t] of bounded degree of the reduced equation.
|
||||
|
||||
See Chapter 6 of "Symbolic Integration I: Transcendental Functions" by
|
||||
Manuel Bronstein. See also the docstring of risch.py.
|
||||
"""
|
||||
|
||||
from operator import mul
|
||||
from functools import reduce
|
||||
|
||||
from sympy.core import oo
|
||||
from sympy.core.symbol import Dummy
|
||||
|
||||
from sympy.polys import Poly, gcd, ZZ, cancel
|
||||
|
||||
from sympy.functions.elementary.complexes import (im, re)
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
|
||||
from sympy.integrals.risch import (gcdex_diophantine, frac_in, derivation,
|
||||
splitfactor, NonElementaryIntegralException, DecrementLevel, recognize_log_derivative)
|
||||
|
||||
# TODO: Add messages to NonElementaryIntegralException errors
|
||||
|
||||
|
||||
def order_at(a, p, t):
|
||||
"""
|
||||
Computes the order of a at p, with respect to t.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
For a, p in k[t], the order of a at p is defined as nu_p(a) = max({n
|
||||
in Z+ such that p**n|a}), where a != 0. If a == 0, nu_p(a) = +oo.
|
||||
|
||||
To compute the order at a rational function, a/b, use the fact that
|
||||
nu_p(a/b) == nu_p(a) - nu_p(b).
|
||||
"""
|
||||
if a.is_zero:
|
||||
return oo
|
||||
if p == Poly(t, t):
|
||||
return a.as_poly(t).ET()[0][0]
|
||||
|
||||
# Uses binary search for calculating the power. power_list collects the tuples
|
||||
# (p^k,k) where each k is some power of 2. After deciding the largest k
|
||||
# such that k is power of 2 and p^k|a the loop iteratively calculates
|
||||
# the actual power.
|
||||
power_list = []
|
||||
p1 = p
|
||||
r = a.rem(p1)
|
||||
tracks_power = 1
|
||||
while r.is_zero:
|
||||
power_list.append((p1,tracks_power))
|
||||
p1 = p1*p1
|
||||
tracks_power *= 2
|
||||
r = a.rem(p1)
|
||||
n = 0
|
||||
product = Poly(1, t)
|
||||
while len(power_list) != 0:
|
||||
final = power_list.pop()
|
||||
productf = product*final[0]
|
||||
r = a.rem(productf)
|
||||
if r.is_zero:
|
||||
n += final[1]
|
||||
product = productf
|
||||
return n
|
||||
|
||||
|
||||
def order_at_oo(a, d, t):
|
||||
"""
|
||||
Computes the order of a/d at oo (infinity), with respect to t.
|
||||
|
||||
For f in k(t), the order or f at oo is defined as deg(d) - deg(a), where
|
||||
f == a/d.
|
||||
"""
|
||||
if a.is_zero:
|
||||
return oo
|
||||
return d.degree(t) - a.degree(t)
|
||||
|
||||
|
||||
def weak_normalizer(a, d, DE, z=None):
|
||||
"""
|
||||
Weak normalization.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
Given a derivation D on k[t] and f == a/d in k(t), return q in k[t]
|
||||
such that f - Dq/q is weakly normalized with respect to t.
|
||||
|
||||
f in k(t) is said to be "weakly normalized" with respect to t if
|
||||
residue_p(f) is not a positive integer for any normal irreducible p
|
||||
in k[t] such that f is in R_p (Definition 6.1.1). If f has an
|
||||
elementary integral, this is equivalent to no logarithm of
|
||||
integral(f) whose argument depends on t has a positive integer
|
||||
coefficient, where the arguments of the logarithms not in k(t) are
|
||||
in k[t].
|
||||
|
||||
Returns (q, f - Dq/q)
|
||||
"""
|
||||
z = z or Dummy('z')
|
||||
dn, ds = splitfactor(d, DE)
|
||||
|
||||
# Compute d1, where dn == d1*d2**2*...*dn**n is a square-free
|
||||
# factorization of d.
|
||||
g = gcd(dn, dn.diff(DE.t))
|
||||
d_sqf_part = dn.quo(g)
|
||||
d1 = d_sqf_part.quo(gcd(d_sqf_part, g))
|
||||
|
||||
a1, b = gcdex_diophantine(d.quo(d1).as_poly(DE.t), d1.as_poly(DE.t),
|
||||
a.as_poly(DE.t))
|
||||
r = (a - Poly(z, DE.t)*derivation(d1, DE)).as_poly(DE.t).resultant(
|
||||
d1.as_poly(DE.t))
|
||||
r = Poly(r, z)
|
||||
|
||||
if not r.expr.has(z):
|
||||
return (Poly(1, DE.t), (a, d))
|
||||
|
||||
N = [i for i in r.real_roots() if i in ZZ and i > 0]
|
||||
|
||||
q = reduce(mul, [gcd(a - Poly(n, DE.t)*derivation(d1, DE), d1) for n in N],
|
||||
Poly(1, DE.t))
|
||||
|
||||
dq = derivation(q, DE)
|
||||
sn = q*a - d*dq
|
||||
sd = q*d
|
||||
sn, sd = sn.cancel(sd, include=True)
|
||||
|
||||
return (q, (sn, sd))
|
||||
|
||||
|
||||
def normal_denom(fa, fd, ga, gd, DE):
|
||||
"""
|
||||
Normal part of the denominator.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
Given a derivation D on k[t] and f, g in k(t) with f weakly
|
||||
normalized with respect to t, either raise NonElementaryIntegralException,
|
||||
in which case the equation Dy + f*y == g has no solution in k(t), or the
|
||||
quadruplet (a, b, c, h) such that a, h in k[t], b, c in k<t>, and for any
|
||||
solution y in k(t) of Dy + f*y == g, q = y*h in k<t> satisfies
|
||||
a*Dq + b*q == c.
|
||||
|
||||
This constitutes step 1 in the outline given in the rde.py docstring.
|
||||
"""
|
||||
dn, ds = splitfactor(fd, DE)
|
||||
en, es = splitfactor(gd, DE)
|
||||
|
||||
p = dn.gcd(en)
|
||||
h = en.gcd(en.diff(DE.t)).quo(p.gcd(p.diff(DE.t)))
|
||||
|
||||
a = dn*h
|
||||
c = a*h
|
||||
if c.div(en)[1]:
|
||||
# en does not divide dn*h**2
|
||||
raise NonElementaryIntegralException
|
||||
ca = c*ga
|
||||
ca, cd = ca.cancel(gd, include=True)
|
||||
|
||||
ba = a*fa - dn*derivation(h, DE)*fd
|
||||
ba, bd = ba.cancel(fd, include=True)
|
||||
|
||||
# (dn*h, dn*h*f - dn*Dh, dn*h**2*g, h)
|
||||
return (a, (ba, bd), (ca, cd), h)
|
||||
|
||||
|
||||
def special_denom(a, ba, bd, ca, cd, DE, case='auto'):
|
||||
"""
|
||||
Special part of the denominator.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
case is one of {'exp', 'tan', 'primitive'} for the hyperexponential,
|
||||
hypertangent, and primitive cases, respectively. For the
|
||||
hyperexponential (resp. hypertangent) case, given a derivation D on
|
||||
k[t] and a in k[t], b, c, in k<t> with Dt/t in k (resp. Dt/(t**2 + 1) in
|
||||
k, sqrt(-1) not in k), a != 0, and gcd(a, t) == 1 (resp.
|
||||
gcd(a, t**2 + 1) == 1), return the quadruplet (A, B, C, 1/h) such that
|
||||
A, B, C, h in k[t] and for any solution q in k<t> of a*Dq + b*q == c,
|
||||
r = qh in k[t] satisfies A*Dr + B*r == C.
|
||||
|
||||
For ``case == 'primitive'``, k<t> == k[t], so it returns (a, b, c, 1) in
|
||||
this case.
|
||||
|
||||
This constitutes step 2 of the outline given in the rde.py docstring.
|
||||
"""
|
||||
# TODO: finish writing this and write tests
|
||||
|
||||
if case == 'auto':
|
||||
case = DE.case
|
||||
|
||||
if case == 'exp':
|
||||
p = Poly(DE.t, DE.t)
|
||||
elif case == 'tan':
|
||||
p = Poly(DE.t**2 + 1, DE.t)
|
||||
elif case in ('primitive', 'base'):
|
||||
B = ba.to_field().quo(bd)
|
||||
C = ca.to_field().quo(cd)
|
||||
return (a, B, C, Poly(1, DE.t))
|
||||
else:
|
||||
raise ValueError("case must be one of {'exp', 'tan', 'primitive', "
|
||||
"'base'}, not %s." % case)
|
||||
|
||||
nb = order_at(ba, p, DE.t) - order_at(bd, p, DE.t)
|
||||
nc = order_at(ca, p, DE.t) - order_at(cd, p, DE.t)
|
||||
|
||||
n = min(0, nc - min(0, nb))
|
||||
if not nb:
|
||||
# Possible cancellation.
|
||||
from .prde import parametric_log_deriv
|
||||
if case == 'exp':
|
||||
dcoeff = DE.d.quo(Poly(DE.t, DE.t))
|
||||
with DecrementLevel(DE): # We are guaranteed to not have problems,
|
||||
# because case != 'base'.
|
||||
alphaa, alphad = frac_in(-ba.eval(0)/bd.eval(0)/a.eval(0), DE.t)
|
||||
etaa, etad = frac_in(dcoeff, DE.t)
|
||||
A = parametric_log_deriv(alphaa, alphad, etaa, etad, DE)
|
||||
if A is not None:
|
||||
Q, m, z = A
|
||||
if Q == 1:
|
||||
n = min(n, m)
|
||||
|
||||
elif case == 'tan':
|
||||
dcoeff = DE.d.quo(Poly(DE.t**2+1, DE.t))
|
||||
with DecrementLevel(DE): # We are guaranteed to not have problems,
|
||||
# because case != 'base'.
|
||||
alphaa, alphad = frac_in(im(-ba.eval(sqrt(-1))/bd.eval(sqrt(-1))/a.eval(sqrt(-1))), DE.t)
|
||||
betaa, betad = frac_in(re(-ba.eval(sqrt(-1))/bd.eval(sqrt(-1))/a.eval(sqrt(-1))), DE.t)
|
||||
etaa, etad = frac_in(dcoeff, DE.t)
|
||||
|
||||
if recognize_log_derivative(Poly(2, DE.t)*betaa, betad, DE):
|
||||
A = parametric_log_deriv(alphaa*Poly(sqrt(-1), DE.t)*betad+alphad*betaa, alphad*betad, etaa, etad, DE)
|
||||
if A is not None:
|
||||
Q, m, z = A
|
||||
if Q == 1:
|
||||
n = min(n, m)
|
||||
N = max(0, -nb, n - nc)
|
||||
pN = p**N
|
||||
pn = p**-n
|
||||
|
||||
A = a*pN
|
||||
B = ba*pN.quo(bd) + Poly(n, DE.t)*a*derivation(p, DE).quo(p)*pN
|
||||
C = (ca*pN*pn).quo(cd)
|
||||
h = pn
|
||||
|
||||
# (a*p**N, (b + n*a*Dp/p)*p**N, c*p**(N - n), p**-n)
|
||||
return (A, B, C, h)
|
||||
|
||||
|
||||
def bound_degree(a, b, cQ, DE, case='auto', parametric=False):
|
||||
"""
|
||||
Bound on polynomial solutions.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
Given a derivation D on k[t] and ``a``, ``b``, ``c`` in k[t] with ``a != 0``, return
|
||||
n in ZZ such that deg(q) <= n for any solution q in k[t] of
|
||||
a*Dq + b*q == c, when parametric=False, or deg(q) <= n for any solution
|
||||
c1, ..., cm in Const(k) and q in k[t] of a*Dq + b*q == Sum(ci*gi, (i, 1, m))
|
||||
when parametric=True.
|
||||
|
||||
For ``parametric=False``, ``cQ`` is ``c``, a ``Poly``; for ``parametric=True``, ``cQ`` is Q ==
|
||||
[q1, ..., qm], a list of Polys.
|
||||
|
||||
This constitutes step 3 of the outline given in the rde.py docstring.
|
||||
"""
|
||||
# TODO: finish writing this and write tests
|
||||
|
||||
if case == 'auto':
|
||||
case = DE.case
|
||||
|
||||
da = a.degree(DE.t)
|
||||
db = b.degree(DE.t)
|
||||
|
||||
# The parametric and regular cases are identical, except for this part
|
||||
if parametric:
|
||||
dc = max(i.degree(DE.t) for i in cQ)
|
||||
else:
|
||||
dc = cQ.degree(DE.t)
|
||||
|
||||
alpha = cancel(-b.as_poly(DE.t).LC().as_expr()/
|
||||
a.as_poly(DE.t).LC().as_expr())
|
||||
|
||||
if case == 'base':
|
||||
n = max(0, dc - max(db, da - 1))
|
||||
if db == da - 1 and alpha.is_Integer:
|
||||
n = max(0, alpha, dc - db)
|
||||
|
||||
elif case == 'primitive':
|
||||
if db > da:
|
||||
n = max(0, dc - db)
|
||||
else:
|
||||
n = max(0, dc - da + 1)
|
||||
|
||||
etaa, etad = frac_in(DE.d, DE.T[DE.level - 1])
|
||||
|
||||
t1 = DE.t
|
||||
with DecrementLevel(DE):
|
||||
alphaa, alphad = frac_in(alpha, DE.t)
|
||||
if db == da - 1:
|
||||
from .prde import limited_integrate
|
||||
# if alpha == m*Dt + Dz for z in k and m in ZZ:
|
||||
try:
|
||||
(za, zd), m = limited_integrate(alphaa, alphad, [(etaa, etad)],
|
||||
DE)
|
||||
except NonElementaryIntegralException:
|
||||
pass
|
||||
else:
|
||||
if len(m) != 1:
|
||||
raise ValueError("Length of m should be 1")
|
||||
n = max(n, m[0])
|
||||
|
||||
elif db == da:
|
||||
# if alpha == Dz/z for z in k*:
|
||||
# beta = -lc(a*Dz + b*z)/(z*lc(a))
|
||||
# if beta == m*Dt + Dw for w in k and m in ZZ:
|
||||
# n = max(n, m)
|
||||
from .prde import is_log_deriv_k_t_radical_in_field
|
||||
A = is_log_deriv_k_t_radical_in_field(alphaa, alphad, DE)
|
||||
if A is not None:
|
||||
aa, z = A
|
||||
if aa == 1:
|
||||
beta = -(a*derivation(z, DE).as_poly(t1) +
|
||||
b*z.as_poly(t1)).LC()/(z.as_expr()*a.LC())
|
||||
betaa, betad = frac_in(beta, DE.t)
|
||||
from .prde import limited_integrate
|
||||
try:
|
||||
(za, zd), m = limited_integrate(betaa, betad,
|
||||
[(etaa, etad)], DE)
|
||||
except NonElementaryIntegralException:
|
||||
pass
|
||||
else:
|
||||
if len(m) != 1:
|
||||
raise ValueError("Length of m should be 1")
|
||||
n = max(n, m[0].as_expr())
|
||||
|
||||
elif case == 'exp':
|
||||
from .prde import parametric_log_deriv
|
||||
|
||||
n = max(0, dc - max(db, da))
|
||||
if da == db:
|
||||
etaa, etad = frac_in(DE.d.quo(Poly(DE.t, DE.t)), DE.T[DE.level - 1])
|
||||
with DecrementLevel(DE):
|
||||
alphaa, alphad = frac_in(alpha, DE.t)
|
||||
A = parametric_log_deriv(alphaa, alphad, etaa, etad, DE)
|
||||
if A is not None:
|
||||
# if alpha == m*Dt/t + Dz/z for z in k* and m in ZZ:
|
||||
# n = max(n, m)
|
||||
a, m, z = A
|
||||
if a == 1:
|
||||
n = max(n, m)
|
||||
|
||||
elif case in ('tan', 'other_nonlinear'):
|
||||
delta = DE.d.degree(DE.t)
|
||||
lam = DE.d.LC()
|
||||
alpha = cancel(alpha/lam)
|
||||
n = max(0, dc - max(da + delta - 1, db))
|
||||
if db == da + delta - 1 and alpha.is_Integer:
|
||||
n = max(0, alpha, dc - db)
|
||||
|
||||
else:
|
||||
raise ValueError("case must be one of {'exp', 'tan', 'primitive', "
|
||||
"'other_nonlinear', 'base'}, not %s." % case)
|
||||
|
||||
return n
|
||||
|
||||
|
||||
def spde(a, b, c, n, DE):
|
||||
"""
|
||||
Rothstein's Special Polynomial Differential Equation algorithm.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
Given a derivation D on k[t], an integer n and ``a``,``b``,``c`` in k[t] with
|
||||
``a != 0``, either raise NonElementaryIntegralException, in which case the
|
||||
equation a*Dq + b*q == c has no solution of degree at most ``n`` in
|
||||
k[t], or return the tuple (B, C, m, alpha, beta) such that B, C,
|
||||
alpha, beta in k[t], m in ZZ, and any solution q in k[t] of degree
|
||||
at most n of a*Dq + b*q == c must be of the form
|
||||
q == alpha*h + beta, where h in k[t], deg(h) <= m, and Dh + B*h == C.
|
||||
|
||||
This constitutes step 4 of the outline given in the rde.py docstring.
|
||||
"""
|
||||
zero = Poly(0, DE.t)
|
||||
|
||||
alpha = Poly(1, DE.t)
|
||||
beta = Poly(0, DE.t)
|
||||
|
||||
while True:
|
||||
if c.is_zero:
|
||||
return (zero, zero, 0, zero, beta) # -1 is more to the point
|
||||
if (n < 0) is True:
|
||||
raise NonElementaryIntegralException
|
||||
|
||||
g = a.gcd(b)
|
||||
if not c.rem(g).is_zero: # g does not divide c
|
||||
raise NonElementaryIntegralException
|
||||
|
||||
a, b, c = a.quo(g), b.quo(g), c.quo(g)
|
||||
|
||||
if a.degree(DE.t) == 0:
|
||||
b = b.to_field().quo(a)
|
||||
c = c.to_field().quo(a)
|
||||
return (b, c, n, alpha, beta)
|
||||
|
||||
r, z = gcdex_diophantine(b, a, c)
|
||||
b += derivation(a, DE)
|
||||
c = z - derivation(r, DE)
|
||||
n -= a.degree(DE.t)
|
||||
|
||||
beta += alpha * r
|
||||
alpha *= a
|
||||
|
||||
def no_cancel_b_large(b, c, n, DE):
|
||||
"""
|
||||
Poly Risch Differential Equation - No cancellation: deg(b) large enough.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
Given a derivation D on k[t], ``n`` either an integer or +oo, and ``b``,``c``
|
||||
in k[t] with ``b != 0`` and either D == d/dt or
|
||||
deg(b) > max(0, deg(D) - 1), either raise NonElementaryIntegralException, in
|
||||
which case the equation ``Dq + b*q == c`` has no solution of degree at
|
||||
most n in k[t], or a solution q in k[t] of this equation with
|
||||
``deg(q) < n``.
|
||||
"""
|
||||
q = Poly(0, DE.t)
|
||||
|
||||
while not c.is_zero:
|
||||
m = c.degree(DE.t) - b.degree(DE.t)
|
||||
if not 0 <= m <= n: # n < 0 or m < 0 or m > n
|
||||
raise NonElementaryIntegralException
|
||||
|
||||
p = Poly(c.as_poly(DE.t).LC()/b.as_poly(DE.t).LC()*DE.t**m, DE.t,
|
||||
expand=False)
|
||||
q = q + p
|
||||
n = m - 1
|
||||
c = c - derivation(p, DE) - b*p
|
||||
|
||||
return q
|
||||
|
||||
|
||||
def no_cancel_b_small(b, c, n, DE):
|
||||
"""
|
||||
Poly Risch Differential Equation - No cancellation: deg(b) small enough.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
Given a derivation D on k[t], ``n`` either an integer or +oo, and ``b``,``c``
|
||||
in k[t] with deg(b) < deg(D) - 1 and either D == d/dt or
|
||||
deg(D) >= 2, either raise NonElementaryIntegralException, in which case the
|
||||
equation Dq + b*q == c has no solution of degree at most n in k[t],
|
||||
or a solution q in k[t] of this equation with deg(q) <= n, or the
|
||||
tuple (h, b0, c0) such that h in k[t], b0, c0, in k, and for any
|
||||
solution q in k[t] of degree at most n of Dq + bq == c, y == q - h
|
||||
is a solution in k of Dy + b0*y == c0.
|
||||
"""
|
||||
q = Poly(0, DE.t)
|
||||
|
||||
while not c.is_zero:
|
||||
if n == 0:
|
||||
m = 0
|
||||
else:
|
||||
m = c.degree(DE.t) - DE.d.degree(DE.t) + 1
|
||||
|
||||
if not 0 <= m <= n: # n < 0 or m < 0 or m > n
|
||||
raise NonElementaryIntegralException
|
||||
|
||||
if m > 0:
|
||||
p = Poly(c.as_poly(DE.t).LC()/(m*DE.d.as_poly(DE.t).LC())*DE.t**m,
|
||||
DE.t, expand=False)
|
||||
else:
|
||||
if b.degree(DE.t) != c.degree(DE.t):
|
||||
raise NonElementaryIntegralException
|
||||
if b.degree(DE.t) == 0:
|
||||
return (q, b.as_poly(DE.T[DE.level - 1]),
|
||||
c.as_poly(DE.T[DE.level - 1]))
|
||||
p = Poly(c.as_poly(DE.t).LC()/b.as_poly(DE.t).LC(), DE.t,
|
||||
expand=False)
|
||||
|
||||
q = q + p
|
||||
n = m - 1
|
||||
c = c - derivation(p, DE) - b*p
|
||||
|
||||
return q
|
||||
|
||||
|
||||
# TODO: better name for this function
|
||||
def no_cancel_equal(b, c, n, DE):
|
||||
"""
|
||||
Poly Risch Differential Equation - No cancellation: deg(b) == deg(D) - 1
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
Given a derivation D on k[t] with deg(D) >= 2, n either an integer
|
||||
or +oo, and b, c in k[t] with deg(b) == deg(D) - 1, either raise
|
||||
NonElementaryIntegralException, in which case the equation Dq + b*q == c has
|
||||
no solution of degree at most n in k[t], or a solution q in k[t] of
|
||||
this equation with deg(q) <= n, or the tuple (h, m, C) such that h
|
||||
in k[t], m in ZZ, and C in k[t], and for any solution q in k[t] of
|
||||
degree at most n of Dq + b*q == c, y == q - h is a solution in k[t]
|
||||
of degree at most m of Dy + b*y == C.
|
||||
"""
|
||||
q = Poly(0, DE.t)
|
||||
lc = cancel(-b.as_poly(DE.t).LC()/DE.d.as_poly(DE.t).LC())
|
||||
if lc.is_Integer and lc.is_positive:
|
||||
M = lc
|
||||
else:
|
||||
M = -1
|
||||
|
||||
while not c.is_zero:
|
||||
m = max(M, c.degree(DE.t) - DE.d.degree(DE.t) + 1)
|
||||
|
||||
if not 0 <= m <= n: # n < 0 or m < 0 or m > n
|
||||
raise NonElementaryIntegralException
|
||||
|
||||
u = cancel(m*DE.d.as_poly(DE.t).LC() + b.as_poly(DE.t).LC())
|
||||
if u.is_zero:
|
||||
return (q, m, c)
|
||||
if m > 0:
|
||||
p = Poly(c.as_poly(DE.t).LC()/u*DE.t**m, DE.t, expand=False)
|
||||
else:
|
||||
if c.degree(DE.t) != DE.d.degree(DE.t) - 1:
|
||||
raise NonElementaryIntegralException
|
||||
else:
|
||||
p = c.as_poly(DE.t).LC()/b.as_poly(DE.t).LC()
|
||||
|
||||
q = q + p
|
||||
n = m - 1
|
||||
c = c - derivation(p, DE) - b*p
|
||||
|
||||
return q
|
||||
|
||||
|
||||
def cancel_primitive(b, c, n, DE):
|
||||
"""
|
||||
Poly Risch Differential Equation - Cancellation: Primitive case.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
Given a derivation D on k[t], n either an integer or +oo, ``b`` in k, and
|
||||
``c`` in k[t] with Dt in k and ``b != 0``, either raise
|
||||
NonElementaryIntegralException, in which case the equation Dq + b*q == c
|
||||
has no solution of degree at most n in k[t], or a solution q in k[t] of
|
||||
this equation with deg(q) <= n.
|
||||
"""
|
||||
# Delayed imports
|
||||
from .prde import is_log_deriv_k_t_radical_in_field
|
||||
with DecrementLevel(DE):
|
||||
ba, bd = frac_in(b, DE.t)
|
||||
A = is_log_deriv_k_t_radical_in_field(ba, bd, DE)
|
||||
if A is not None:
|
||||
n, z = A
|
||||
if n == 1: # b == Dz/z
|
||||
raise NotImplementedError("is_deriv_in_field() is required to "
|
||||
" solve this problem.")
|
||||
# if z*c == Dp for p in k[t] and deg(p) <= n:
|
||||
# return p/z
|
||||
# else:
|
||||
# raise NonElementaryIntegralException
|
||||
|
||||
if c.is_zero:
|
||||
return c # return 0
|
||||
|
||||
if n < c.degree(DE.t):
|
||||
raise NonElementaryIntegralException
|
||||
|
||||
q = Poly(0, DE.t)
|
||||
while not c.is_zero:
|
||||
m = c.degree(DE.t)
|
||||
if n < m:
|
||||
raise NonElementaryIntegralException
|
||||
with DecrementLevel(DE):
|
||||
a2a, a2d = frac_in(c.LC(), DE.t)
|
||||
sa, sd = rischDE(ba, bd, a2a, a2d, DE)
|
||||
stm = Poly(sa.as_expr()/sd.as_expr()*DE.t**m, DE.t, expand=False)
|
||||
q += stm
|
||||
n = m - 1
|
||||
c -= b*stm + derivation(stm, DE)
|
||||
|
||||
return q
|
||||
|
||||
|
||||
def cancel_exp(b, c, n, DE):
|
||||
"""
|
||||
Poly Risch Differential Equation - Cancellation: Hyperexponential case.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
Given a derivation D on k[t], n either an integer or +oo, ``b`` in k, and
|
||||
``c`` in k[t] with Dt/t in k and ``b != 0``, either raise
|
||||
NonElementaryIntegralException, in which case the equation Dq + b*q == c
|
||||
has no solution of degree at most n in k[t], or a solution q in k[t] of
|
||||
this equation with deg(q) <= n.
|
||||
"""
|
||||
from .prde import parametric_log_deriv
|
||||
eta = DE.d.quo(Poly(DE.t, DE.t)).as_expr()
|
||||
|
||||
with DecrementLevel(DE):
|
||||
etaa, etad = frac_in(eta, DE.t)
|
||||
ba, bd = frac_in(b, DE.t)
|
||||
A = parametric_log_deriv(ba, bd, etaa, etad, DE)
|
||||
if A is not None:
|
||||
a, m, z = A
|
||||
if a == 1:
|
||||
raise NotImplementedError("is_deriv_in_field() is required to "
|
||||
"solve this problem.")
|
||||
# if c*z*t**m == Dp for p in k<t> and q = p/(z*t**m) in k[t] and
|
||||
# deg(q) <= n:
|
||||
# return q
|
||||
# else:
|
||||
# raise NonElementaryIntegralException
|
||||
|
||||
if c.is_zero:
|
||||
return c # return 0
|
||||
|
||||
if n < c.degree(DE.t):
|
||||
raise NonElementaryIntegralException
|
||||
|
||||
q = Poly(0, DE.t)
|
||||
while not c.is_zero:
|
||||
m = c.degree(DE.t)
|
||||
if n < m:
|
||||
raise NonElementaryIntegralException
|
||||
# a1 = b + m*Dt/t
|
||||
a1 = b.as_expr()
|
||||
with DecrementLevel(DE):
|
||||
# TODO: Write a dummy function that does this idiom
|
||||
a1a, a1d = frac_in(a1, DE.t)
|
||||
a1a = a1a*etad + etaa*a1d*Poly(m, DE.t)
|
||||
a1d = a1d*etad
|
||||
|
||||
a2a, a2d = frac_in(c.LC(), DE.t)
|
||||
|
||||
sa, sd = rischDE(a1a, a1d, a2a, a2d, DE)
|
||||
stm = Poly(sa.as_expr()/sd.as_expr()*DE.t**m, DE.t, expand=False)
|
||||
q += stm
|
||||
n = m - 1
|
||||
c -= b*stm + derivation(stm, DE) # deg(c) becomes smaller
|
||||
return q
|
||||
|
||||
|
||||
def solve_poly_rde(b, cQ, n, DE, parametric=False):
|
||||
"""
|
||||
Solve a Polynomial Risch Differential Equation with degree bound ``n``.
|
||||
|
||||
This constitutes step 4 of the outline given in the rde.py docstring.
|
||||
|
||||
For parametric=False, cQ is c, a Poly; for parametric=True, cQ is Q ==
|
||||
[q1, ..., qm], a list of Polys.
|
||||
"""
|
||||
# No cancellation
|
||||
if not b.is_zero and (DE.case == 'base' or
|
||||
b.degree(DE.t) > max(0, DE.d.degree(DE.t) - 1)):
|
||||
|
||||
if parametric:
|
||||
# Delayed imports
|
||||
from .prde import prde_no_cancel_b_large
|
||||
return prde_no_cancel_b_large(b, cQ, n, DE)
|
||||
return no_cancel_b_large(b, cQ, n, DE)
|
||||
|
||||
elif (b.is_zero or b.degree(DE.t) < DE.d.degree(DE.t) - 1) and \
|
||||
(DE.case == 'base' or DE.d.degree(DE.t) >= 2):
|
||||
|
||||
if parametric:
|
||||
from .prde import prde_no_cancel_b_small
|
||||
return prde_no_cancel_b_small(b, cQ, n, DE)
|
||||
|
||||
R = no_cancel_b_small(b, cQ, n, DE)
|
||||
|
||||
if isinstance(R, Poly):
|
||||
return R
|
||||
else:
|
||||
# XXX: Might k be a field? (pg. 209)
|
||||
h, b0, c0 = R
|
||||
with DecrementLevel(DE):
|
||||
b0, c0 = b0.as_poly(DE.t), c0.as_poly(DE.t)
|
||||
if b0 is None: # See above comment
|
||||
raise ValueError("b0 should be a non-Null value")
|
||||
if c0 is None:
|
||||
raise ValueError("c0 should be a non-Null value")
|
||||
y = solve_poly_rde(b0, c0, n, DE).as_poly(DE.t)
|
||||
return h + y
|
||||
|
||||
elif DE.d.degree(DE.t) >= 2 and b.degree(DE.t) == DE.d.degree(DE.t) - 1 and \
|
||||
n > -b.as_poly(DE.t).LC()/DE.d.as_poly(DE.t).LC():
|
||||
|
||||
# TODO: Is this check necessary, and if so, what should it do if it fails?
|
||||
# b comes from the first element returned from spde()
|
||||
if not b.as_poly(DE.t).LC().is_number:
|
||||
raise TypeError("Result should be a number")
|
||||
|
||||
if parametric:
|
||||
raise NotImplementedError("prde_no_cancel_b_equal() is not yet "
|
||||
"implemented.")
|
||||
|
||||
R = no_cancel_equal(b, cQ, n, DE)
|
||||
|
||||
if isinstance(R, Poly):
|
||||
return R
|
||||
else:
|
||||
h, m, C = R
|
||||
# XXX: Or should it be rischDE()?
|
||||
y = solve_poly_rde(b, C, m, DE)
|
||||
return h + y
|
||||
|
||||
else:
|
||||
# Cancellation
|
||||
if b.is_zero:
|
||||
raise NotImplementedError("Remaining cases for Poly (P)RDE are "
|
||||
"not yet implemented (is_deriv_in_field() required).")
|
||||
else:
|
||||
if DE.case == 'exp':
|
||||
if parametric:
|
||||
raise NotImplementedError("Parametric RDE cancellation "
|
||||
"hyperexponential case is not yet implemented.")
|
||||
return cancel_exp(b, cQ, n, DE)
|
||||
|
||||
elif DE.case == 'primitive':
|
||||
if parametric:
|
||||
raise NotImplementedError("Parametric RDE cancellation "
|
||||
"primitive case is not yet implemented.")
|
||||
return cancel_primitive(b, cQ, n, DE)
|
||||
|
||||
else:
|
||||
raise NotImplementedError("Other Poly (P)RDE cancellation "
|
||||
"cases are not yet implemented (%s)." % DE.case)
|
||||
|
||||
if parametric:
|
||||
raise NotImplementedError("Remaining cases for Poly PRDE not yet "
|
||||
"implemented.")
|
||||
raise NotImplementedError("Remaining cases for Poly RDE not yet "
|
||||
"implemented.")
|
||||
|
||||
|
||||
def rischDE(fa, fd, ga, gd, DE):
|
||||
"""
|
||||
Solve a Risch Differential Equation: Dy + f*y == g.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
See the outline in the docstring of rde.py for more information
|
||||
about the procedure used. Either raise NonElementaryIntegralException, in
|
||||
which case there is no solution y in the given differential field,
|
||||
or return y in k(t) satisfying Dy + f*y == g, or raise
|
||||
NotImplementedError, in which case, the algorithms necessary to
|
||||
solve the given Risch Differential Equation have not yet been
|
||||
implemented.
|
||||
"""
|
||||
_, (fa, fd) = weak_normalizer(fa, fd, DE)
|
||||
a, (ba, bd), (ca, cd), hn = normal_denom(fa, fd, ga, gd, DE)
|
||||
A, B, C, hs = special_denom(a, ba, bd, ca, cd, DE)
|
||||
try:
|
||||
# Until this is fully implemented, use oo. Note that this will almost
|
||||
# certainly cause non-termination in spde() (unless A == 1), and
|
||||
# *might* lead to non-termination in the next step for a nonelementary
|
||||
# integral (I don't know for certain yet). Fortunately, spde() is
|
||||
# currently written recursively, so this will just give
|
||||
# RuntimeError: maximum recursion depth exceeded.
|
||||
n = bound_degree(A, B, C, DE)
|
||||
except NotImplementedError:
|
||||
# Useful for debugging:
|
||||
# import warnings
|
||||
# warnings.warn("rischDE: Proceeding with n = oo; may cause "
|
||||
# "non-termination.")
|
||||
n = oo
|
||||
|
||||
B, C, m, alpha, beta = spde(A, B, C, n, DE)
|
||||
if C.is_zero:
|
||||
y = C
|
||||
else:
|
||||
y = solve_poly_rde(B, C, m, DE)
|
||||
|
||||
return (alpha*y + beta, hn*hs)
|
||||
1851
venv/lib/python3.12/site-packages/sympy/integrals/risch.py
Normal file
1851
venv/lib/python3.12/site-packages/sympy/integrals/risch.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,63 @@
|
||||
from sympy.functions import SingularityFunction, DiracDelta
|
||||
from sympy.integrals import integrate
|
||||
|
||||
|
||||
def singularityintegrate(f, x):
|
||||
"""
|
||||
This function handles the indefinite integrations of Singularity functions.
|
||||
The ``integrate`` function calls this function internally whenever an
|
||||
instance of SingularityFunction is passed as argument.
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
The idea for integration is the following:
|
||||
|
||||
- If we are dealing with a SingularityFunction expression,
|
||||
i.e. ``SingularityFunction(x, a, n)``, we just return
|
||||
``SingularityFunction(x, a, n + 1)/(n + 1)`` if ``n >= 0`` and
|
||||
``SingularityFunction(x, a, n + 1)`` if ``n < 0``.
|
||||
|
||||
- If the node is a multiplication or power node having a
|
||||
SingularityFunction term we rewrite the whole expression in terms of
|
||||
Heaviside and DiracDelta and then integrate the output. Lastly, we
|
||||
rewrite the output of integration back in terms of SingularityFunction.
|
||||
|
||||
- If none of the above case arises, we return None.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.integrals.singularityfunctions import singularityintegrate
|
||||
>>> from sympy import SingularityFunction, symbols, Function
|
||||
>>> x, a, n, y = symbols('x a n y')
|
||||
>>> f = Function('f')
|
||||
>>> singularityintegrate(SingularityFunction(x, a, 3), x)
|
||||
SingularityFunction(x, a, 4)/4
|
||||
>>> singularityintegrate(5*SingularityFunction(x, 5, -2), x)
|
||||
5*SingularityFunction(x, 5, -1)
|
||||
>>> singularityintegrate(6*SingularityFunction(x, 5, -1), x)
|
||||
6*SingularityFunction(x, 5, 0)
|
||||
>>> singularityintegrate(x*SingularityFunction(x, 0, -1), x)
|
||||
0
|
||||
>>> singularityintegrate(SingularityFunction(x, 1, -1) * f(x), x)
|
||||
f(1)*SingularityFunction(x, 1, 0)
|
||||
|
||||
"""
|
||||
|
||||
if not f.has(SingularityFunction):
|
||||
return None
|
||||
|
||||
if isinstance(f, SingularityFunction):
|
||||
x, a, n = f.args
|
||||
if n.is_positive or n.is_zero:
|
||||
return SingularityFunction(x, a, n + 1)/(n + 1)
|
||||
elif n in (-1, -2, -3, -4):
|
||||
return SingularityFunction(x, a, n + 1)
|
||||
|
||||
if f.is_Mul or f.is_Pow:
|
||||
|
||||
expr = f.rewrite(DiracDelta)
|
||||
expr = integrate(expr, x)
|
||||
return expr.rewrite(SingularityFunction)
|
||||
return None
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,79 @@
|
||||
from sympy.core.function import Function
|
||||
from sympy.core.numbers import (Rational, pi)
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import symbols
|
||||
from sympy.functions.elementary.trigonometric import (cos, sin)
|
||||
from sympy.functions.special.delta_functions import (DiracDelta, Heaviside)
|
||||
from sympy.integrals.deltafunctions import change_mul, deltaintegrate
|
||||
|
||||
f = Function("f")
|
||||
x_1, x_2, x, y, z = symbols("x_1 x_2 x y z")
|
||||
|
||||
|
||||
def test_change_mul():
|
||||
assert change_mul(x, x) == (None, None)
|
||||
assert change_mul(x*y, x) == (None, None)
|
||||
assert change_mul(x*y*DiracDelta(x), x) == (DiracDelta(x), x*y)
|
||||
assert change_mul(x*y*DiracDelta(x)*DiracDelta(y), x) == \
|
||||
(DiracDelta(x), x*y*DiracDelta(y))
|
||||
assert change_mul(DiracDelta(x)**2, x) == \
|
||||
(DiracDelta(x), DiracDelta(x))
|
||||
assert change_mul(y*DiracDelta(x)**2, x) == \
|
||||
(DiracDelta(x), y*DiracDelta(x))
|
||||
|
||||
|
||||
def test_deltaintegrate():
|
||||
assert deltaintegrate(x, x) is None
|
||||
assert deltaintegrate(x + DiracDelta(x), x) is None
|
||||
assert deltaintegrate(DiracDelta(x, 0), x) == Heaviside(x)
|
||||
for n in range(10):
|
||||
assert deltaintegrate(DiracDelta(x, n + 1), x) == DiracDelta(x, n)
|
||||
assert deltaintegrate(DiracDelta(x), x) == Heaviside(x)
|
||||
assert deltaintegrate(DiracDelta(-x), x) == Heaviside(x)
|
||||
assert deltaintegrate(DiracDelta(x - y), x) == Heaviside(x - y)
|
||||
assert deltaintegrate(DiracDelta(y - x), x) == Heaviside(x - y)
|
||||
|
||||
assert deltaintegrate(x*DiracDelta(x), x) == 0
|
||||
assert deltaintegrate((x - y)*DiracDelta(x - y), x) == 0
|
||||
|
||||
assert deltaintegrate(DiracDelta(x)**2, x) == DiracDelta(0)*Heaviside(x)
|
||||
assert deltaintegrate(y*DiracDelta(x)**2, x) == \
|
||||
y*DiracDelta(0)*Heaviside(x)
|
||||
assert deltaintegrate(DiracDelta(x, 1), x) == DiracDelta(x, 0)
|
||||
assert deltaintegrate(y*DiracDelta(x, 1), x) == y*DiracDelta(x, 0)
|
||||
assert deltaintegrate(DiracDelta(x, 1)**2, x) == -DiracDelta(0, 2)*Heaviside(x)
|
||||
assert deltaintegrate(y*DiracDelta(x, 1)**2, x) == -y*DiracDelta(0, 2)*Heaviside(x)
|
||||
|
||||
|
||||
assert deltaintegrate(DiracDelta(x) * f(x), x) == f(0) * Heaviside(x)
|
||||
assert deltaintegrate(DiracDelta(-x) * f(x), x) == f(0) * Heaviside(x)
|
||||
assert deltaintegrate(DiracDelta(x - 1) * f(x), x) == f(1) * Heaviside(x - 1)
|
||||
assert deltaintegrate(DiracDelta(1 - x) * f(x), x) == f(1) * Heaviside(x - 1)
|
||||
assert deltaintegrate(DiracDelta(x**2 + x - 2), x) == \
|
||||
Heaviside(x - 1)/3 + Heaviside(x + 2)/3
|
||||
|
||||
p = cos(x)*(DiracDelta(x) + DiracDelta(x**2 - 1))*sin(x)*(x - pi)
|
||||
assert deltaintegrate(p, x) - (-pi*(cos(1)*Heaviside(-1 + x)*sin(1)/2 - \
|
||||
cos(1)*Heaviside(1 + x)*sin(1)/2) + \
|
||||
cos(1)*Heaviside(1 + x)*sin(1)/2 + \
|
||||
cos(1)*Heaviside(-1 + x)*sin(1)/2) == 0
|
||||
|
||||
p = x_2*DiracDelta(x - x_2)*DiracDelta(x_2 - x_1)
|
||||
assert deltaintegrate(p, x_2) == x*DiracDelta(x - x_1)*Heaviside(x_2 - x)
|
||||
|
||||
p = x*y**2*z*DiracDelta(y - x)*DiracDelta(y - z)*DiracDelta(x - z)
|
||||
assert deltaintegrate(p, y) == x**3*z*DiracDelta(x - z)**2*Heaviside(y - x)
|
||||
assert deltaintegrate((x + 1)*DiracDelta(2*x), x) == S.Half * Heaviside(x)
|
||||
assert deltaintegrate((x + 1)*DiracDelta(x*Rational(2, 3) + Rational(4, 9)), x) == \
|
||||
S.Half * Heaviside(x + Rational(2, 3))
|
||||
|
||||
a, b, c = symbols('a b c', commutative=False)
|
||||
assert deltaintegrate(DiracDelta(x - y)*f(x - b)*f(x - a), x) == \
|
||||
f(y - b)*f(y - a)*Heaviside(x - y)
|
||||
|
||||
p = f(x - a)*DiracDelta(x - y)*f(x - c)*f(x - b)
|
||||
assert deltaintegrate(p, x) == f(y - a)*f(y - c)*f(y - b)*Heaviside(x - y)
|
||||
|
||||
p = DiracDelta(x - z)*f(x - b)*f(x - a)*DiracDelta(x - y)
|
||||
assert deltaintegrate(p, x) == DiracDelta(y - z)*f(y - b)*f(y - a) * \
|
||||
Heaviside(x - y)
|
||||
@@ -0,0 +1,277 @@
|
||||
# A collection of failing integrals from the issues.
|
||||
|
||||
from sympy.core.numbers import (I, Rational, oo, pi)
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import symbols
|
||||
from sympy.functions.elementary.complexes import sign
|
||||
from sympy.functions.elementary.exponential import (exp, log)
|
||||
from sympy.functions.elementary.hyperbolic import (sech, sinh)
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.piecewise import Piecewise
|
||||
from sympy.functions.elementary.trigonometric import (acos, atan, cos, sin, tan)
|
||||
from sympy.functions.special.delta_functions import DiracDelta
|
||||
from sympy.functions.special.gamma_functions import gamma
|
||||
from sympy.integrals.integrals import (Integral, integrate)
|
||||
from sympy.simplify.fu import fu
|
||||
|
||||
|
||||
from sympy.testing.pytest import XFAIL, slow, tooslow
|
||||
|
||||
from sympy.abc import x, k, c, y, b, h, a, m, z, n, t
|
||||
|
||||
|
||||
@tooslow
|
||||
@XFAIL
|
||||
def test_issue_3880():
|
||||
# integrate_hyperexponential(Poly(t*2*(1 - t0**2)*t0*(x**3 + x**2), t), Poly((1 + t0**2)**2*2*(x**2 + x + 1), t), [Poly(1, x), Poly(1 + t0**2, t0), Poly(t, t)], [x, t0, t], [exp, tan])
|
||||
assert not integrate(exp(x)*cos(2*x)*sin(2*x) * (x**3 + x**2)/(2*(x**2 + x + 1)), x).has(Integral)
|
||||
|
||||
|
||||
def test_issue_4212_real():
|
||||
xr = symbols('xr', real=True)
|
||||
negabsx = Piecewise((-xr, xr < 0), (xr, True))
|
||||
assert integrate(sign(xr), xr) == negabsx
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_issue_4212():
|
||||
# XXX: Maybe this should be expected to fail without real assumptions on x.
|
||||
# As a complex function sign(x) is not analytic and so there is no complex
|
||||
# function whose complex derivative is sign(x). With real assumptions this
|
||||
# works (see test_issue_4212_real above).
|
||||
assert not integrate(sign(x), x).has(Integral)
|
||||
|
||||
|
||||
def test_issue_4511():
|
||||
# This works, but gives a slightly over-complicated answer.
|
||||
f = integrate(cos(x)**2 / (1 - sin(x)), x)
|
||||
assert fu(f) == x - cos(x) - 1
|
||||
assert f == ((x*tan(x/2)**2 + x - 2)/(tan(x/2)**2 + 1)).expand()
|
||||
|
||||
|
||||
def test_integrate_DiracDelta_no_meijerg():
|
||||
assert integrate(integrate(integrate(
|
||||
DiracDelta(x - y - z), (z, 0, oo)), (y, 0, 1), meijerg=False), (x, 0, 1)) == S.Half
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_integrate_DiracDelta_fails():
|
||||
# issue 6427
|
||||
# works without meijerg. See test_integrate_DiracDelta_no_meijerg above.
|
||||
assert integrate(integrate(integrate(
|
||||
DiracDelta(x - y - z), (z, 0, oo)), (y, 0, 1)), (x, 0, 1)) == S.Half
|
||||
|
||||
|
||||
@XFAIL
|
||||
@slow
|
||||
def test_issue_4525():
|
||||
# Warning: takes a long time
|
||||
assert not integrate((x**m * (1 - x)**n * (a + b*x + c*x**2))/(1 + x**2), (x, 0, 1)).has(Integral)
|
||||
|
||||
|
||||
@XFAIL
|
||||
@tooslow
|
||||
def test_issue_4540():
|
||||
# Note, this integral is probably nonelementary
|
||||
assert not integrate(
|
||||
(sin(1/x) - x*exp(x)) /
|
||||
((-sin(1/x) + x*exp(x))*x + x*sin(1/x)), x).has(Integral)
|
||||
|
||||
|
||||
@XFAIL
|
||||
@slow
|
||||
def test_issue_4891():
|
||||
# Requires the hypergeometric function.
|
||||
assert not integrate(cos(x)**y, x).has(Integral)
|
||||
|
||||
|
||||
@XFAIL
|
||||
@slow
|
||||
def test_issue_1796a():
|
||||
assert not integrate(exp(2*b*x)*exp(-a*x**2), x).has(Integral)
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_issue_4895b():
|
||||
assert not integrate(exp(2*b*x)*exp(-a*x**2), (x, -oo, 0)).has(Integral)
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_issue_4895c():
|
||||
assert not integrate(exp(2*b*x)*exp(-a*x**2), (x, -oo, oo)).has(Integral)
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_issue_4895d():
|
||||
assert not integrate(exp(2*b*x)*exp(-a*x**2), (x, 0, oo)).has(Integral)
|
||||
|
||||
|
||||
@XFAIL
|
||||
@slow
|
||||
def test_issue_4941():
|
||||
assert not integrate(sqrt(1 + sinh(x/20)**2), (x, -25, 25)).has(Integral)
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_issue_4992():
|
||||
# Nonelementary integral. Requires hypergeometric/Meijer-G handling.
|
||||
assert not integrate(log(x) * x**(k - 1) * exp(-x) / gamma(k), (x, 0, oo)).has(Integral)
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_issue_16396a():
|
||||
i = integrate(1/(1+sqrt(tan(x))), (x, pi/3, pi/6))
|
||||
assert not i.has(Integral)
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_issue_16396b():
|
||||
i = integrate(x*sin(x)/(1+cos(x)**2), (x, 0, pi))
|
||||
assert not i.has(Integral)
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_issue_16046():
|
||||
assert integrate(exp(exp(I*x)), [x, 0, 2*pi]) == 2*pi
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_issue_15925a():
|
||||
assert not integrate(sqrt((1+sin(x))**2+(cos(x))**2), (x, -pi/2, pi/2)).has(Integral)
|
||||
|
||||
|
||||
def test_issue_15925b():
|
||||
f = sqrt((-12*cos(x)**2*sin(x))**2+(12*cos(x)*sin(x)**2)**2)
|
||||
assert integrate(f, (x, 0, pi/6)) == Rational(3, 2)
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_issue_15925b_manual():
|
||||
assert not integrate(sqrt((-12*cos(x)**2*sin(x))**2+(12*cos(x)*sin(x)**2)**2),
|
||||
(x, 0, pi/6), manual=True).has(Integral)
|
||||
|
||||
|
||||
@XFAIL
|
||||
@tooslow
|
||||
def test_issue_15227():
|
||||
i = integrate(log(1-x)*log((1+x)**2)/x, (x, 0, 1))
|
||||
assert not i.has(Integral)
|
||||
# assert i == -5*zeta(3)/4
|
||||
|
||||
|
||||
@XFAIL
|
||||
@slow
|
||||
def test_issue_14716():
|
||||
i = integrate(log(x + 5)*cos(pi*x),(x, S.Half, 1))
|
||||
assert not i.has(Integral)
|
||||
# Mathematica can not solve it either, but
|
||||
# integrate(log(x + 5)*cos(pi*x),(x, S.Half, 1)).transform(x, y - 5).doit()
|
||||
# works
|
||||
# assert i == -log(Rational(11, 2))/pi - Si(pi*Rational(11, 2))/pi + Si(6*pi)/pi
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_issue_14709a():
|
||||
i = integrate(x*acos(1 - 2*x/h), (x, 0, h))
|
||||
assert not i.has(Integral)
|
||||
# assert i == 5*h**2*pi/16
|
||||
|
||||
|
||||
@slow
|
||||
@XFAIL
|
||||
def test_issue_14398():
|
||||
assert not integrate(exp(x**2)*cos(x), x).has(Integral)
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_issue_14074():
|
||||
i = integrate(log(sin(x)), (x, 0, pi/2))
|
||||
assert not i.has(Integral)
|
||||
# assert i == -pi*log(2)/2
|
||||
|
||||
|
||||
@XFAIL
|
||||
@slow
|
||||
def test_issue_14078b():
|
||||
i = integrate((atan(4*x)-atan(2*x))/x, (x, 0, oo))
|
||||
assert not i.has(Integral)
|
||||
# assert i == pi*log(2)/2
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_issue_13792():
|
||||
i = integrate(log(1/x) / (1 - x), (x, 0, 1))
|
||||
assert not i.has(Integral)
|
||||
# assert i in [polylog(2, -exp_polar(I*pi)), pi**2/6]
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_issue_11845a():
|
||||
assert not integrate(exp(y - x**3), (x, 0, 1)).has(Integral)
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_issue_11845b():
|
||||
assert not integrate(exp(-y - x**3), (x, 0, 1)).has(Integral)
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_issue_11813():
|
||||
assert not integrate((a - x)**Rational(-1, 2)*x, (x, 0, a)).has(Integral)
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_issue_11254c():
|
||||
assert not integrate(sech(x)**2, (x, 0, 1)).has(Integral)
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_issue_10584():
|
||||
assert not integrate(sqrt(x**2 + 1/x**2), x).has(Integral)
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_issue_9101():
|
||||
assert not integrate(log(x + sqrt(x**2 + y**2 + z**2)), z).has(Integral)
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_issue_7147():
|
||||
assert not integrate(x/sqrt(a*x**2 + b*x + c)**3, x).has(Integral)
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_issue_7109():
|
||||
assert not integrate(sqrt(a**2/(a**2 - x**2)), x).has(Integral)
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_integrate_Piecewise_rational_over_reals():
|
||||
f = Piecewise(
|
||||
(0, t - 478.515625*pi < 0),
|
||||
(13.2075145209219*pi/(0.000871222*t + 0.995)**2, t - 478.515625*pi >= 0))
|
||||
|
||||
assert abs((integrate(f, (t, 0, oo)) - 15235.9375*pi).evalf()) <= 1e-7
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_issue_4311_slow():
|
||||
# Not slow when bypassing heurish
|
||||
assert not integrate(x*abs(9-x**2), x).has(Integral)
|
||||
|
||||
@XFAIL
|
||||
def test_issue_20370():
|
||||
a = symbols('a', positive=True)
|
||||
assert integrate((1 + a * cos(x))**-1, (x, 0, 2 * pi)) == (2 * pi / sqrt(1 - a**2))
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_polylog():
|
||||
# log(1/x)*log(x+1)-polylog(2, -x)
|
||||
assert not integrate(log(1/x)/(x + 1), x).has(Integral)
|
||||
|
||||
|
||||
@XFAIL
|
||||
def test_polylog_manual():
|
||||
# Make sure _parts_rule does not go into an infinite loop here
|
||||
assert not integrate(log(1/x)/(x + 1), x, manual=True).has(Integral)
|
||||
@@ -0,0 +1,417 @@
|
||||
from sympy.concrete.summations import Sum
|
||||
from sympy.core.add import Add
|
||||
from sympy.core.function import (Derivative, Function, diff)
|
||||
from sympy.core.numbers import (I, Rational, pi)
|
||||
from sympy.core.relational import Eq, Ne
|
||||
from sympy.core.symbol import (Symbol, symbols)
|
||||
from sympy.functions.elementary.exponential import (LambertW, exp, log)
|
||||
from sympy.functions.elementary.hyperbolic import (asinh, cosh, sinh, tanh)
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.piecewise import Piecewise
|
||||
from sympy.functions.elementary.trigonometric import (acos, asin, atan, cos, sin, tan)
|
||||
from sympy.functions.special.bessel import (besselj, besselk, bessely, jn)
|
||||
from sympy.functions.special.error_functions import erf
|
||||
from sympy.integrals.integrals import Integral
|
||||
from sympy.logic.boolalg import And
|
||||
from sympy.matrices import Matrix
|
||||
from sympy.simplify.ratsimp import ratsimp
|
||||
from sympy.simplify.simplify import simplify
|
||||
from sympy.integrals.heurisch import components, heurisch, heurisch_wrapper
|
||||
from sympy.testing.pytest import XFAIL, slow
|
||||
from sympy.integrals.integrals import integrate
|
||||
from sympy import S
|
||||
|
||||
x, y, z, nu = symbols('x,y,z,nu')
|
||||
f = Function('f')
|
||||
|
||||
|
||||
def test_components():
|
||||
assert components(x*y, x) == {x}
|
||||
assert components(1/(x + y), x) == {x}
|
||||
assert components(sin(x), x) == {sin(x), x}
|
||||
assert components(sin(x)*sqrt(log(x)), x) == \
|
||||
{log(x), sin(x), sqrt(log(x)), x}
|
||||
assert components(x*sin(exp(x)*y), x) == \
|
||||
{sin(y*exp(x)), x, exp(x)}
|
||||
assert components(x**Rational(17, 54)/sqrt(sin(x)), x) == \
|
||||
{sin(x), x**Rational(1, 54), sqrt(sin(x)), x}
|
||||
|
||||
assert components(f(x), x) == \
|
||||
{x, f(x)}
|
||||
assert components(Derivative(f(x), x), x) == \
|
||||
{x, f(x), Derivative(f(x), x)}
|
||||
assert components(f(x)*diff(f(x), x), x) == \
|
||||
{x, f(x), Derivative(f(x), x), Derivative(f(x), x)}
|
||||
|
||||
|
||||
def test_issue_10680():
|
||||
assert isinstance(integrate(x**log(x**log(x**log(x))),x), Integral)
|
||||
|
||||
|
||||
def test_issue_21166():
|
||||
assert integrate(sin(x/sqrt(abs(x))), (x, -1, 1)) == 0
|
||||
|
||||
|
||||
def test_heurisch_polynomials():
|
||||
assert heurisch(1, x) == x
|
||||
assert heurisch(x, x) == x**2/2
|
||||
assert heurisch(x**17, x) == x**18/18
|
||||
# For coverage
|
||||
assert heurisch_wrapper(y, x) == y*x
|
||||
|
||||
|
||||
def test_heurisch_fractions():
|
||||
assert heurisch(1/x, x) == log(x)
|
||||
assert heurisch(1/(2 + x), x) == log(x + 2)
|
||||
assert heurisch(1/(x + sin(y)), x) == log(x + sin(y))
|
||||
|
||||
# Up to a constant, where C = pi*I*Rational(5, 12), Mathematica gives identical
|
||||
# result in the first case. The difference is because SymPy changes
|
||||
# signs of expressions without any care.
|
||||
# XXX ^ ^ ^ is this still correct?
|
||||
assert heurisch(5*x**5/(
|
||||
2*x**6 - 5), x) in [5*log(2*x**6 - 5) / 12, 5*log(-2*x**6 + 5) / 12]
|
||||
assert heurisch(5*x**5/(2*x**6 + 5), x) == 5*log(2*x**6 + 5) / 12
|
||||
|
||||
assert heurisch(1/x**2, x) == -1/x
|
||||
assert heurisch(-1/x**5, x) == 1/(4*x**4)
|
||||
|
||||
|
||||
def test_heurisch_log():
|
||||
assert heurisch(log(x), x) == x*log(x) - x
|
||||
assert heurisch(log(3*x), x) == -x + x*log(3) + x*log(x)
|
||||
assert heurisch(log(x**2), x) in [x*log(x**2) - 2*x, 2*x*log(x) - 2*x]
|
||||
|
||||
|
||||
def test_heurisch_exp():
|
||||
assert heurisch(exp(x), x) == exp(x)
|
||||
assert heurisch(exp(-x), x) == -exp(-x)
|
||||
assert heurisch(exp(17*x), x) == exp(17*x) / 17
|
||||
assert heurisch(x*exp(x), x) == x*exp(x) - exp(x)
|
||||
assert heurisch(x*exp(x**2), x) == exp(x**2) / 2
|
||||
|
||||
assert heurisch(exp(-x**2), x) is None
|
||||
|
||||
assert heurisch(2**x, x) == 2**x/log(2)
|
||||
assert heurisch(x*2**x, x) == x*2**x/log(2) - 2**x*log(2)**(-2)
|
||||
|
||||
assert heurisch(Integral(x**z*y, (y, 1, 2), (z, 2, 3)).function, x) == (x*x**z*y)/(z+1)
|
||||
assert heurisch(Sum(x**z, (z, 1, 2)).function, z) == x**z/log(x)
|
||||
|
||||
# https://github.com/sympy/sympy/issues/23707
|
||||
anti = -exp(z)/(sqrt(x - y)*exp(z*sqrt(x - y)) - exp(z*sqrt(x - y)))
|
||||
assert heurisch(exp(z)*exp(-z*sqrt(x - y)), z) == anti
|
||||
|
||||
|
||||
def test_heurisch_trigonometric():
|
||||
assert heurisch(sin(x), x) == -cos(x)
|
||||
assert heurisch(pi*sin(x) + 1, x) == x - pi*cos(x)
|
||||
|
||||
assert heurisch(cos(x), x) == sin(x)
|
||||
assert heurisch(tan(x), x) in [
|
||||
log(1 + tan(x)**2)/2,
|
||||
log(tan(x) + I) + I*x,
|
||||
log(tan(x) - I) - I*x,
|
||||
]
|
||||
|
||||
assert heurisch(sin(x)*sin(y), x) == -cos(x)*sin(y)
|
||||
assert heurisch(sin(x)*sin(y), y) == -cos(y)*sin(x)
|
||||
|
||||
# gives sin(x) in answer when run via setup.py and cos(x) when run via py.test
|
||||
assert heurisch(sin(x)*cos(x), x) in [sin(x)**2 / 2, -cos(x)**2 / 2]
|
||||
assert heurisch(cos(x)/sin(x), x) == log(sin(x))
|
||||
|
||||
assert heurisch(x*sin(7*x), x) == sin(7*x) / 49 - x*cos(7*x) / 7
|
||||
assert heurisch(1/pi/4 * x**2*cos(x), x) == 1/pi/4*(x**2*sin(x) -
|
||||
2*sin(x) + 2*x*cos(x))
|
||||
|
||||
assert heurisch(acos(x/4) * asin(x/4), x) == 2*x - (sqrt(16 - x**2))*asin(x/4) \
|
||||
+ (sqrt(16 - x**2))*acos(x/4) + x*asin(x/4)*acos(x/4)
|
||||
|
||||
assert heurisch(sin(x)/(cos(x)**2+1), x) == -atan(cos(x)) #fixes issue 13723
|
||||
assert heurisch(1/(cos(x)+2), x) == 2*sqrt(3)*atan(sqrt(3)*tan(x/2)/3)/3
|
||||
assert heurisch(2*sin(x)*cos(x)/(sin(x)**4 + 1), x) == atan(sqrt(2)*sin(x)
|
||||
- 1) - atan(sqrt(2)*sin(x) + 1)
|
||||
|
||||
assert heurisch(1/cosh(x), x) == 2*atan(tanh(x/2))
|
||||
|
||||
|
||||
def test_heurisch_hyperbolic():
|
||||
assert heurisch(sinh(x), x) == cosh(x)
|
||||
assert heurisch(cosh(x), x) == sinh(x)
|
||||
|
||||
assert heurisch(x*sinh(x), x) == x*cosh(x) - sinh(x)
|
||||
assert heurisch(x*cosh(x), x) == x*sinh(x) - cosh(x)
|
||||
|
||||
assert heurisch(
|
||||
x*asinh(x/2), x) == x**2*asinh(x/2)/2 + asinh(x/2) - x*sqrt(4 + x**2)/4
|
||||
|
||||
|
||||
def test_heurisch_mixed():
|
||||
assert heurisch(sin(x)*exp(x), x) == exp(x)*sin(x)/2 - exp(x)*cos(x)/2
|
||||
assert heurisch(sin(x/sqrt(-x)), x) == 2*x*cos(x/sqrt(-x))/sqrt(-x) - 2*sin(x/sqrt(-x))
|
||||
|
||||
|
||||
def test_heurisch_radicals():
|
||||
assert heurisch(1/sqrt(x), x) == 2*sqrt(x)
|
||||
assert heurisch(1/sqrt(x)**3, x) == -2/sqrt(x)
|
||||
assert heurisch(sqrt(x)**3, x) == 2*sqrt(x)**5/5
|
||||
|
||||
assert heurisch(sin(x)*sqrt(cos(x)), x) == -2*sqrt(cos(x))**3/3
|
||||
y = Symbol('y')
|
||||
assert heurisch(sin(y*sqrt(x)), x) == 2/y**2*sin(y*sqrt(x)) - \
|
||||
2*sqrt(x)*cos(y*sqrt(x))/y
|
||||
assert heurisch_wrapper(sin(y*sqrt(x)), x) == Piecewise(
|
||||
(-2*sqrt(x)*cos(sqrt(x)*y)/y + 2*sin(sqrt(x)*y)/y**2, Ne(y, 0)),
|
||||
(0, True))
|
||||
y = Symbol('y', positive=True)
|
||||
assert heurisch_wrapper(sin(y*sqrt(x)), x) == 2/y**2*sin(y*sqrt(x)) - \
|
||||
2*sqrt(x)*cos(y*sqrt(x))/y
|
||||
|
||||
|
||||
def test_heurisch_special():
|
||||
assert heurisch(erf(x), x) == x*erf(x) + exp(-x**2)/sqrt(pi)
|
||||
assert heurisch(exp(-x**2)*erf(x), x) == sqrt(pi)*erf(x)**2 / 4
|
||||
|
||||
|
||||
def test_heurisch_symbolic_coeffs():
|
||||
assert heurisch(1/(x + y), x) == log(x + y)
|
||||
assert heurisch(1/(x + sqrt(2)), x) == log(x + sqrt(2))
|
||||
assert simplify(diff(heurisch(log(x + y + z), y), y)) == log(x + y + z)
|
||||
|
||||
|
||||
def test_heurisch_symbolic_coeffs_1130():
|
||||
y = Symbol('y')
|
||||
assert heurisch_wrapper(1/(x**2 + y), x) == Piecewise(
|
||||
(log(x - sqrt(-y))/(2*sqrt(-y)) - log(x + sqrt(-y))/(2*sqrt(-y)),
|
||||
Ne(y, 0)), (-1/x, True))
|
||||
y = Symbol('y', positive=True)
|
||||
assert heurisch_wrapper(1/(x**2 + y), x) == (atan(x/sqrt(y))/sqrt(y))
|
||||
|
||||
|
||||
def test_heurisch_hacking():
|
||||
assert heurisch(sqrt(1 + 7*x**2), x, hints=[]) == \
|
||||
x*sqrt(1 + 7*x**2)/2 + sqrt(7)*asinh(sqrt(7)*x)/14
|
||||
assert heurisch(sqrt(1 - 7*x**2), x, hints=[]) == \
|
||||
x*sqrt(1 - 7*x**2)/2 + sqrt(7)*asin(sqrt(7)*x)/14
|
||||
|
||||
assert heurisch(1/sqrt(1 + 7*x**2), x, hints=[]) == \
|
||||
sqrt(7)*asinh(sqrt(7)*x)/7
|
||||
assert heurisch(1/sqrt(1 - 7*x**2), x, hints=[]) == \
|
||||
sqrt(7)*asin(sqrt(7)*x)/7
|
||||
|
||||
assert heurisch(exp(-7*x**2), x, hints=[]) == \
|
||||
sqrt(7*pi)*erf(sqrt(7)*x)/14
|
||||
|
||||
assert heurisch(1/sqrt(9 - 4*x**2), x, hints=[]) == \
|
||||
asin(x*Rational(2, 3))/2
|
||||
|
||||
assert heurisch(1/sqrt(9 + 4*x**2), x, hints=[]) == \
|
||||
asinh(x*Rational(2, 3))/2
|
||||
|
||||
assert heurisch(1/sqrt(3*x**2-4), x, hints=[]) == \
|
||||
sqrt(3)*log(3*x + sqrt(3)*sqrt(3*x**2 - 4))/3
|
||||
|
||||
|
||||
def test_heurisch_function():
|
||||
assert heurisch(f(x), x) is None
|
||||
|
||||
@XFAIL
|
||||
def test_heurisch_function_derivative():
|
||||
# TODO: it looks like this used to work just by coincindence and
|
||||
# thanks to sloppy implementation. Investigate why this used to
|
||||
# work at all and if support for this can be restored.
|
||||
|
||||
df = diff(f(x), x)
|
||||
|
||||
assert heurisch(f(x)*df, x) == f(x)**2/2
|
||||
assert heurisch(f(x)**2*df, x) == f(x)**3/3
|
||||
assert heurisch(df/f(x), x) == log(f(x))
|
||||
|
||||
|
||||
def test_heurisch_wrapper():
|
||||
f = 1/(y + x)
|
||||
assert heurisch_wrapper(f, x) == log(x + y)
|
||||
f = 1/(y - x)
|
||||
assert heurisch_wrapper(f, x) == -log(x - y)
|
||||
f = 1/((y - x)*(y + x))
|
||||
assert heurisch_wrapper(f, x) == Piecewise(
|
||||
(-log(x - y)/(2*y) + log(x + y)/(2*y), Ne(y, 0)), (1/x, True))
|
||||
# issue 6926
|
||||
f = sqrt(x**2/((y - x)*(y + x)))
|
||||
assert heurisch_wrapper(f, x) == x*sqrt(-x**2/(x**2 - y**2)) \
|
||||
- y**2*sqrt(-x**2/(x**2 - y**2))/x
|
||||
|
||||
|
||||
def test_issue_3609():
|
||||
assert heurisch(1/(x * (1 + log(x)**2)), x) == atan(log(x))
|
||||
|
||||
### These are examples from the Poor Man's Integrator
|
||||
### http://www-sop.inria.fr/cafe/Manuel.Bronstein/pmint/examples/
|
||||
|
||||
|
||||
def test_pmint_rat():
|
||||
# TODO: heurisch() is off by a constant: -3/4. Possibly different permutation
|
||||
# would give the optimal result?
|
||||
|
||||
def drop_const(expr, x):
|
||||
if expr.is_Add:
|
||||
return Add(*[ arg for arg in expr.args if arg.has(x) ])
|
||||
else:
|
||||
return expr
|
||||
|
||||
f = (x**7 - 24*x**4 - 4*x**2 + 8*x - 8)/(x**8 + 6*x**6 + 12*x**4 + 8*x**2)
|
||||
g = (4 + 8*x**2 + 6*x + 3*x**3)/(x**5 + 4*x**3 + 4*x) + log(x)
|
||||
|
||||
assert drop_const(ratsimp(heurisch(f, x)), x) == g
|
||||
|
||||
|
||||
def test_pmint_trig():
|
||||
f = (x - tan(x)) / tan(x)**2 + tan(x)
|
||||
g = -x**2/2 - x/tan(x) + log(tan(x)**2 + 1)/2
|
||||
|
||||
assert heurisch(f, x) == g
|
||||
|
||||
|
||||
def test_pmint_logexp():
|
||||
f = (1 + x + x*exp(x))*(x + log(x) + exp(x) - 1)/(x + log(x) + exp(x))**2/x
|
||||
g = log(x + exp(x) + log(x)) + 1/(x + exp(x) + log(x))
|
||||
|
||||
assert ratsimp(heurisch(f, x)) == g
|
||||
|
||||
|
||||
def test_pmint_erf():
|
||||
f = exp(-x**2)*erf(x)/(erf(x)**3 - erf(x)**2 - erf(x) + 1)
|
||||
g = sqrt(pi)*log(erf(x) - 1)/8 - sqrt(pi)*log(erf(x) + 1)/8 - sqrt(pi)/(4*erf(x) - 4)
|
||||
|
||||
assert ratsimp(heurisch(f, x)) == g
|
||||
|
||||
|
||||
def test_pmint_LambertW():
|
||||
f = LambertW(x)
|
||||
g = x*LambertW(x) - x + x/LambertW(x)
|
||||
|
||||
assert heurisch(f, x) == g
|
||||
|
||||
|
||||
def test_pmint_besselj():
|
||||
f = besselj(nu + 1, x)/besselj(nu, x)
|
||||
g = nu*log(x) - log(besselj(nu, x))
|
||||
|
||||
assert heurisch(f, x) == g
|
||||
|
||||
f = (nu*besselj(nu, x) - x*besselj(nu + 1, x))/x
|
||||
g = besselj(nu, x)
|
||||
|
||||
assert heurisch(f, x) == g
|
||||
|
||||
f = jn(nu + 1, x)/jn(nu, x)
|
||||
g = nu*log(x) - log(jn(nu, x))
|
||||
|
||||
assert heurisch(f, x) == g
|
||||
|
||||
|
||||
@slow
|
||||
def test_pmint_bessel_products():
|
||||
f = x*besselj(nu, x)*bessely(nu, 2*x)
|
||||
g = -2*x*besselj(nu, x)*bessely(nu - 1, 2*x)/3 + x*besselj(nu - 1, x)*bessely(nu, 2*x)/3
|
||||
|
||||
assert heurisch(f, x) == g
|
||||
|
||||
f = x*besselj(nu, x)*besselk(nu, 2*x)
|
||||
g = -2*x*besselj(nu, x)*besselk(nu - 1, 2*x)/5 - x*besselj(nu - 1, x)*besselk(nu, 2*x)/5
|
||||
|
||||
assert heurisch(f, x) == g
|
||||
|
||||
|
||||
def test_pmint_WrightOmega():
|
||||
def omega(x):
|
||||
return LambertW(exp(x))
|
||||
|
||||
f = (1 + omega(x) * (2 + cos(omega(x)) * (x + omega(x))))/(1 + omega(x))/(x + omega(x))
|
||||
g = log(x + LambertW(exp(x))) + sin(LambertW(exp(x)))
|
||||
|
||||
assert heurisch(f, x) == g
|
||||
|
||||
|
||||
def test_RR():
|
||||
# Make sure the algorithm does the right thing if the ring is RR. See
|
||||
# issue 8685.
|
||||
assert heurisch(sqrt(1 + 0.25*x**2), x, hints=[]) == \
|
||||
0.5*x*sqrt(0.25*x**2 + 1) + 1.0*asinh(0.5*x)
|
||||
|
||||
# TODO: convert the rest of PMINT tests:
|
||||
# Airy functions
|
||||
# f = (x - AiryAi(x)*AiryAi(1, x)) / (x**2 - AiryAi(x)**2)
|
||||
# g = Rational(1,2)*ln(x + AiryAi(x)) + Rational(1,2)*ln(x - AiryAi(x))
|
||||
# f = x**2 * AiryAi(x)
|
||||
# g = -AiryAi(x) + AiryAi(1, x)*x
|
||||
# Whittaker functions
|
||||
# f = WhittakerW(mu + 1, nu, x) / (WhittakerW(mu, nu, x) * x)
|
||||
# g = x/2 - mu*ln(x) - ln(WhittakerW(mu, nu, x))
|
||||
|
||||
|
||||
def test_issue_22527():
|
||||
t, R = symbols(r't R')
|
||||
z = Function('z')(t)
|
||||
def f(x):
|
||||
return x/sqrt(R**2 - x**2)
|
||||
Uz = integrate(f(z), z)
|
||||
Ut = integrate(f(t), t)
|
||||
assert Ut == Uz.subs(z, t)
|
||||
|
||||
|
||||
def test_heurisch_complex_erf_issue_26338():
|
||||
r = symbols('r', real=True)
|
||||
a = sqrt(pi)*erf((1 + I)/2)/2
|
||||
assert integrate(exp(-I*r**2/2), (r, 0, 1)) == a - I*a
|
||||
|
||||
a = exp(-x**2/(2*(2 - I)**2))
|
||||
assert heurisch(a, x, hints=[]) is None # None, not a wrong soln
|
||||
a = exp(-r**2/(2*(2 - I)**2))
|
||||
assert heurisch(a, r, hints=[]) is None
|
||||
a = sqrt(pi)*erf((1 + I)/2)/2
|
||||
assert integrate(exp(-I*x**2/2), (x, 0, 1)) == a - I*a
|
||||
|
||||
|
||||
def test_issue_15498():
|
||||
Z0 = Function('Z0')
|
||||
k01, k10, t, s= symbols('k01 k10 t s', real=True, positive=True)
|
||||
m = Matrix([[exp(-k10*t)]])
|
||||
_83 = Rational(83, 100) # 0.83 works, too
|
||||
[a, b, c, d, e, f, g] = [100, 0.5, _83, 50, 0.6, 2, 120]
|
||||
AIF_btf = a*(d*e*(1 - exp(-(t - b)/e)) + f*g*(1 - exp(-(t - b)/g)))
|
||||
AIF_atf = a*(d*e*exp(-(t - b)/e)*(exp((c - b)/e) - 1
|
||||
) + f*g*exp(-(t - b)/g)*(exp((c - b)/g) - 1))
|
||||
AIF_sym = Piecewise((0, t < b), (AIF_btf, And(b <= t, t < c)), (AIF_atf, c <= t))
|
||||
aif_eq = Eq(Z0(t), AIF_sym)
|
||||
f_vec = Matrix([[k01*Z0(t)]])
|
||||
integrand = m*m.subs(t, s)**-1*f_vec.subs(aif_eq.lhs, aif_eq.rhs).subs(t, s)
|
||||
solution = integrate(integrand[0], (s, 0, t))
|
||||
assert solution is not None # does not hang and takes less than 10 s
|
||||
|
||||
|
||||
@slow
|
||||
def test_heurisch_issue_26930():
|
||||
integrand = x**Rational(4, 3)*log(x)
|
||||
anti = 3*x**(S(7)/3)*log(x)/7 - 9*x**(S(7)/3)/49
|
||||
assert heurisch(integrand, x) == anti
|
||||
assert integrate(integrand, x) == anti
|
||||
assert integrate(integrand, (x, 0, 1)) == -S(9)/49
|
||||
|
||||
|
||||
def test_heurisch_issue_26922():
|
||||
|
||||
a, b, x = symbols("a, b, x", real=True, positive=True)
|
||||
C = symbols("C", real=True)
|
||||
i1 = -C*x*exp(-a*x**2 - sqrt(b)*x)
|
||||
i2 = C*x*exp(-a*x**2 + sqrt(b)*x)
|
||||
i = Integral(i1, x) + Integral(i2, x)
|
||||
res = (
|
||||
-C*exp(-a*x**2)*exp(sqrt(b)*x)/(2*a)
|
||||
+ C*exp(-a*x**2)*exp(-sqrt(b)*x)/(2*a)
|
||||
+ sqrt(pi)*C*sqrt(b)*exp(b/(4*a))*erf(sqrt(a)*x - sqrt(b)/(2*sqrt(a)))/(4*a**(S(3)/2))
|
||||
+ sqrt(pi)*C*sqrt(b)*exp(b/(4*a))*erf(sqrt(a)*x + sqrt(b)/(2*sqrt(a)))/(4*a**(S(3)/2))
|
||||
)
|
||||
|
||||
assert i.doit(heurisch=False).expand() == res
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,627 @@
|
||||
from sympy.functions.elementary.complexes import Abs
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
|
||||
from sympy.core import S, Rational
|
||||
|
||||
from sympy.integrals.intpoly import (decompose, best_origin, distance_to_side,
|
||||
polytope_integrate, point_sort,
|
||||
hyperplane_parameters, main_integrate3d,
|
||||
main_integrate, polygon_integrate,
|
||||
lineseg_integrate, integration_reduction,
|
||||
integration_reduction_dynamic, is_vertex)
|
||||
|
||||
from sympy.geometry.line import Segment2D
|
||||
from sympy.geometry.polygon import Polygon
|
||||
from sympy.geometry.point import Point, Point2D
|
||||
from sympy.abc import x, y, z
|
||||
|
||||
from sympy.testing.pytest import slow
|
||||
|
||||
|
||||
def test_decompose():
|
||||
assert decompose(x) == {1: x}
|
||||
assert decompose(x**2) == {2: x**2}
|
||||
assert decompose(x*y) == {2: x*y}
|
||||
assert decompose(x + y) == {1: x + y}
|
||||
assert decompose(x**2 + y) == {1: y, 2: x**2}
|
||||
assert decompose(8*x**2 + 4*y + 7) == {0: 7, 1: 4*y, 2: 8*x**2}
|
||||
assert decompose(x**2 + 3*y*x) == {2: x**2 + 3*x*y}
|
||||
assert decompose(9*x**2 + y + 4*x + x**3 + y**2*x + 3) ==\
|
||||
{0: 3, 1: 4*x + y, 2: 9*x**2, 3: x**3 + x*y**2}
|
||||
|
||||
assert decompose(x, True) == {x}
|
||||
assert decompose(x ** 2, True) == {x**2}
|
||||
assert decompose(x * y, True) == {x * y}
|
||||
assert decompose(x + y, True) == {x, y}
|
||||
assert decompose(x ** 2 + y, True) == {y, x ** 2}
|
||||
assert decompose(8 * x ** 2 + 4 * y + 7, True) == {7, 4*y, 8*x**2}
|
||||
assert decompose(x ** 2 + 3 * y * x, True) == {x ** 2, 3 * x * y}
|
||||
assert decompose(9 * x ** 2 + y + 4 * x + x ** 3 + y ** 2 * x + 3, True) == \
|
||||
{3, y, 4*x, 9*x**2, x*y**2, x**3}
|
||||
|
||||
|
||||
def test_best_origin():
|
||||
expr1 = y ** 2 * x ** 5 + y ** 5 * x ** 7 + 7 * x + x ** 12 + y ** 7 * x
|
||||
|
||||
l1 = Segment2D(Point(0, 3), Point(1, 1))
|
||||
l2 = Segment2D(Point(S(3) / 2, 0), Point(S(3) / 2, 3))
|
||||
l3 = Segment2D(Point(0, S(3) / 2), Point(3, S(3) / 2))
|
||||
l4 = Segment2D(Point(0, 2), Point(2, 0))
|
||||
l5 = Segment2D(Point(0, 2), Point(1, 1))
|
||||
l6 = Segment2D(Point(2, 0), Point(1, 1))
|
||||
|
||||
assert best_origin((2, 1), 3, l1, expr1) == (0, 3)
|
||||
# XXX: Should these return exact Rational output? Maybe best_origin should
|
||||
# sympify its arguments...
|
||||
assert best_origin((2, 0), 3, l2, x ** 7) == (1.5, 0)
|
||||
assert best_origin((0, 2), 3, l3, x ** 7) == (0, 1.5)
|
||||
assert best_origin((1, 1), 2, l4, x ** 7 * y ** 3) == (0, 2)
|
||||
assert best_origin((1, 1), 2, l4, x ** 3 * y ** 7) == (2, 0)
|
||||
assert best_origin((1, 1), 2, l5, x ** 2 * y ** 9) == (0, 2)
|
||||
assert best_origin((1, 1), 2, l6, x ** 9 * y ** 2) == (2, 0)
|
||||
|
||||
|
||||
@slow
|
||||
def test_polytope_integrate():
|
||||
# Convex 2-Polytopes
|
||||
# Vertex representation
|
||||
assert polytope_integrate(Polygon(Point(0, 0), Point(0, 2),
|
||||
Point(4, 0)), 1) == 4
|
||||
assert polytope_integrate(Polygon(Point(0, 0), Point(0, 1),
|
||||
Point(1, 1), Point(1, 0)), x * y) ==\
|
||||
Rational(1, 4)
|
||||
assert polytope_integrate(Polygon(Point(0, 3), Point(5, 3), Point(1, 1)),
|
||||
6*x**2 - 40*y) == Rational(-935, 3)
|
||||
|
||||
assert polytope_integrate(Polygon(Point(0, 0), Point(0, sqrt(3)),
|
||||
Point(sqrt(3), sqrt(3)),
|
||||
Point(sqrt(3), 0)), 1) == 3
|
||||
|
||||
hexagon = Polygon(Point(0, 0), Point(-sqrt(3) / 2, S.Half),
|
||||
Point(-sqrt(3) / 2, S(3) / 2), Point(0, 2),
|
||||
Point(sqrt(3) / 2, S(3) / 2), Point(sqrt(3) / 2, S.Half))
|
||||
|
||||
assert polytope_integrate(hexagon, 1) == S(3*sqrt(3)) / 2
|
||||
|
||||
# Hyperplane representation
|
||||
assert polytope_integrate([((-1, 0), 0), ((1, 2), 4),
|
||||
((0, -1), 0)], 1) == 4
|
||||
assert polytope_integrate([((-1, 0), 0), ((0, 1), 1),
|
||||
((1, 0), 1), ((0, -1), 0)], x * y) == Rational(1, 4)
|
||||
assert polytope_integrate([((0, 1), 3), ((1, -2), -1),
|
||||
((-2, -1), -3)], 6*x**2 - 40*y) == Rational(-935, 3)
|
||||
assert polytope_integrate([((-1, 0), 0), ((0, sqrt(3)), 3),
|
||||
((sqrt(3), 0), 3), ((0, -1), 0)], 1) == 3
|
||||
|
||||
hexagon = [((Rational(-1, 2), -sqrt(3) / 2), 0),
|
||||
((-1, 0), sqrt(3) / 2),
|
||||
((Rational(-1, 2), sqrt(3) / 2), sqrt(3)),
|
||||
((S.Half, sqrt(3) / 2), sqrt(3)),
|
||||
((1, 0), sqrt(3) / 2),
|
||||
((S.Half, -sqrt(3) / 2), 0)]
|
||||
assert polytope_integrate(hexagon, 1) == S(3*sqrt(3)) / 2
|
||||
|
||||
# Non-convex polytopes
|
||||
# Vertex representation
|
||||
assert polytope_integrate(Polygon(Point(-1, -1), Point(-1, 1),
|
||||
Point(1, 1), Point(0, 0),
|
||||
Point(1, -1)), 1) == 3
|
||||
assert polytope_integrate(Polygon(Point(-1, -1), Point(-1, 1),
|
||||
Point(0, 0), Point(1, 1),
|
||||
Point(1, -1), Point(0, 0)), 1) == 2
|
||||
# Hyperplane representation
|
||||
assert polytope_integrate([((-1, 0), 1), ((0, 1), 1), ((1, -1), 0),
|
||||
((1, 1), 0), ((0, -1), 1)], 1) == 3
|
||||
assert polytope_integrate([((-1, 0), 1), ((1, 1), 0), ((-1, 1), 0),
|
||||
((1, 0), 1), ((-1, -1), 0),
|
||||
((1, -1), 0)], 1) == 2
|
||||
|
||||
# Tests for 2D polytopes mentioned in Chin et al(Page 10):
|
||||
# http://dilbert.engr.ucdavis.edu/~suku/quadrature/cls-integration.pdf
|
||||
fig1 = Polygon(Point(1.220, -0.827), Point(-1.490, -4.503),
|
||||
Point(-3.766, -1.622), Point(-4.240, -0.091),
|
||||
Point(-3.160, 4), Point(-0.981, 4.447),
|
||||
Point(0.132, 4.027))
|
||||
assert polytope_integrate(fig1, x**2 + x*y + y**2) ==\
|
||||
S(2031627344735367)/(8*10**12)
|
||||
|
||||
fig2 = Polygon(Point(4.561, 2.317), Point(1.491, -1.315),
|
||||
Point(-3.310, -3.164), Point(-4.845, -3.110),
|
||||
Point(-4.569, 1.867))
|
||||
assert polytope_integrate(fig2, x**2 + x*y + y**2) ==\
|
||||
S(517091313866043)/(16*10**11)
|
||||
|
||||
fig3 = Polygon(Point(-2.740, -1.888), Point(-3.292, 4.233),
|
||||
Point(-2.723, -0.697), Point(-0.643, -3.151))
|
||||
assert polytope_integrate(fig3, x**2 + x*y + y**2) ==\
|
||||
S(147449361647041)/(8*10**12)
|
||||
|
||||
fig4 = Polygon(Point(0.211, -4.622), Point(-2.684, 3.851),
|
||||
Point(0.468, 4.879), Point(4.630, -1.325),
|
||||
Point(-0.411, -1.044))
|
||||
assert polytope_integrate(fig4, x**2 + x*y + y**2) ==\
|
||||
S(180742845225803)/(10**12)
|
||||
|
||||
# Tests for many polynomials with maximum degree given(2D case).
|
||||
tri = Polygon(Point(0, 3), Point(5, 3), Point(1, 1))
|
||||
polys = []
|
||||
expr1 = x**9*y + x**7*y**3 + 2*x**2*y**8
|
||||
expr2 = x**6*y**4 + x**5*y**5 + 2*y**10
|
||||
expr3 = x**10 + x**9*y + x**8*y**2 + x**5*y**5
|
||||
polys.extend((expr1, expr2, expr3))
|
||||
result_dict = polytope_integrate(tri, polys, max_degree=10)
|
||||
assert result_dict[expr1] == Rational(615780107, 594)
|
||||
assert result_dict[expr2] == Rational(13062161, 27)
|
||||
assert result_dict[expr3] == Rational(1946257153, 924)
|
||||
|
||||
tri = Polygon(Point(0, 3), Point(5, 3), Point(1, 1))
|
||||
expr1 = x**7*y**1 + 2*x**2*y**6
|
||||
expr2 = x**6*y**4 + x**5*y**5 + 2*y**10
|
||||
expr3 = x**10 + x**9*y + x**8*y**2 + x**5*y**5
|
||||
polys.extend((expr1, expr2, expr3))
|
||||
assert polytope_integrate(tri, polys, max_degree=9) == \
|
||||
{x**7*y + 2*x**2*y**6: Rational(489262, 9)}
|
||||
|
||||
# Tests when all integral of all monomials up to a max_degree is to be
|
||||
# calculated.
|
||||
assert polytope_integrate(Polygon(Point(0, 0), Point(0, 1),
|
||||
Point(1, 1), Point(1, 0)),
|
||||
max_degree=4) == {0: 0, 1: 1, x: S.Half,
|
||||
x ** 2 * y ** 2: S.One / 9,
|
||||
x ** 4: S.One / 5,
|
||||
y ** 4: S.One / 5,
|
||||
y: S.Half,
|
||||
x * y ** 2: S.One / 6,
|
||||
y ** 2: S.One / 3,
|
||||
x ** 3: S.One / 4,
|
||||
x ** 2 * y: S.One / 6,
|
||||
x ** 3 * y: S.One / 8,
|
||||
x * y: S.One / 4,
|
||||
y ** 3: S.One / 4,
|
||||
x ** 2: S.One / 3,
|
||||
x * y ** 3: S.One / 8}
|
||||
|
||||
# Tests for 3D polytopes
|
||||
cube1 = [[(0, 0, 0), (0, 6, 6), (6, 6, 6), (3, 6, 0),
|
||||
(0, 6, 0), (6, 0, 6), (3, 0, 0), (0, 0, 6)],
|
||||
[1, 2, 3, 4], [3, 2, 5, 6], [1, 7, 5, 2], [0, 6, 5, 7],
|
||||
[1, 4, 0, 7], [0, 4, 3, 6]]
|
||||
assert polytope_integrate(cube1, 1) == S(162)
|
||||
|
||||
# 3D Test cases in Chin et al(2015)
|
||||
cube2 = [[(0, 0, 0), (0, 0, 5), (0, 5, 0), (0, 5, 5), (5, 0, 0),
|
||||
(5, 0, 5), (5, 5, 0), (5, 5, 5)],
|
||||
[3, 7, 6, 2], [1, 5, 7, 3], [5, 4, 6, 7], [0, 4, 5, 1],
|
||||
[2, 0, 1, 3], [2, 6, 4, 0]]
|
||||
|
||||
cube3 = [[(0, 0, 0), (5, 0, 0), (5, 4, 0), (3, 2, 0), (3, 5, 0),
|
||||
(0, 5, 0), (0, 0, 5), (5, 0, 5), (5, 4, 5), (3, 2, 5),
|
||||
(3, 5, 5), (0, 5, 5)],
|
||||
[6, 11, 5, 0], [1, 7, 6, 0], [5, 4, 3, 2, 1, 0], [11, 10, 4, 5],
|
||||
[10, 9, 3, 4], [9, 8, 2, 3], [8, 7, 1, 2], [7, 8, 9, 10, 11, 6]]
|
||||
|
||||
cube4 = [[(0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1),
|
||||
(S.One / 4, S.One / 4, S.One / 4)],
|
||||
[0, 2, 1], [1, 3, 0], [4, 2, 3], [4, 3, 1],
|
||||
[0, 1, 2], [2, 4, 1], [0, 3, 2]]
|
||||
|
||||
assert polytope_integrate(cube2, x ** 2 + y ** 2 + x * y + z ** 2) ==\
|
||||
Rational(15625, 4)
|
||||
assert polytope_integrate(cube3, x ** 2 + y ** 2 + x * y + z ** 2) ==\
|
||||
S(33835) / 12
|
||||
assert polytope_integrate(cube4, x ** 2 + y ** 2 + x * y + z ** 2) ==\
|
||||
S(37) / 960
|
||||
|
||||
# Test cases from Mathematica's PolyhedronData library
|
||||
octahedron = [[(S.NegativeOne / sqrt(2), 0, 0), (0, S.One / sqrt(2), 0),
|
||||
(0, 0, S.NegativeOne / sqrt(2)), (0, 0, S.One / sqrt(2)),
|
||||
(0, S.NegativeOne / sqrt(2), 0), (S.One / sqrt(2), 0, 0)],
|
||||
[3, 4, 5], [3, 5, 1], [3, 1, 0], [3, 0, 4], [4, 0, 2],
|
||||
[4, 2, 5], [2, 0, 1], [5, 2, 1]]
|
||||
|
||||
assert polytope_integrate(octahedron, 1) == sqrt(2) / 3
|
||||
|
||||
great_stellated_dodecahedron =\
|
||||
[[(-0.32491969623290634095, 0, 0.42532540417601993887),
|
||||
(0.32491969623290634095, 0, -0.42532540417601993887),
|
||||
(-0.52573111211913359231, 0, 0.10040570794311363956),
|
||||
(0.52573111211913359231, 0, -0.10040570794311363956),
|
||||
(-0.10040570794311363956, -0.3090169943749474241, 0.42532540417601993887),
|
||||
(-0.10040570794311363956, 0.30901699437494742410, 0.42532540417601993887),
|
||||
(0.10040570794311363956, -0.3090169943749474241, -0.42532540417601993887),
|
||||
(0.10040570794311363956, 0.30901699437494742410, -0.42532540417601993887),
|
||||
(-0.16245984811645317047, -0.5, 0.10040570794311363956),
|
||||
(-0.16245984811645317047, 0.5, 0.10040570794311363956),
|
||||
(0.16245984811645317047, -0.5, -0.10040570794311363956),
|
||||
(0.16245984811645317047, 0.5, -0.10040570794311363956),
|
||||
(-0.42532540417601993887, -0.3090169943749474241, -0.10040570794311363956),
|
||||
(-0.42532540417601993887, 0.30901699437494742410, -0.10040570794311363956),
|
||||
(-0.26286555605956679615, 0.1909830056250525759, -0.42532540417601993887),
|
||||
(-0.26286555605956679615, -0.1909830056250525759, -0.42532540417601993887),
|
||||
(0.26286555605956679615, 0.1909830056250525759, 0.42532540417601993887),
|
||||
(0.26286555605956679615, -0.1909830056250525759, 0.42532540417601993887),
|
||||
(0.42532540417601993887, -0.3090169943749474241, 0.10040570794311363956),
|
||||
(0.42532540417601993887, 0.30901699437494742410, 0.10040570794311363956)],
|
||||
[12, 3, 0, 6, 16], [17, 7, 0, 3, 13],
|
||||
[9, 6, 0, 7, 8], [18, 2, 1, 4, 14],
|
||||
[15, 5, 1, 2, 19], [11, 4, 1, 5, 10],
|
||||
[8, 19, 2, 18, 9], [10, 13, 3, 12, 11],
|
||||
[16, 14, 4, 11, 12], [13, 10, 5, 15, 17],
|
||||
[14, 16, 6, 9, 18], [19, 8, 7, 17, 15]]
|
||||
# Actual volume is : 0.163118960624632
|
||||
assert Abs(polytope_integrate(great_stellated_dodecahedron, 1) -\
|
||||
0.163118960624632) < 1e-12
|
||||
|
||||
expr = x **2 + y ** 2 + z ** 2
|
||||
octahedron_five_compound = [[(0, -0.7071067811865475244, 0),
|
||||
(0, 0.70710678118654752440, 0),
|
||||
(0.1148764602736805918,
|
||||
-0.35355339059327376220, -0.60150095500754567366),
|
||||
(0.1148764602736805918, 0.35355339059327376220,
|
||||
-0.60150095500754567366),
|
||||
(0.18587401723009224507,
|
||||
-0.57206140281768429760, 0.37174803446018449013),
|
||||
(0.18587401723009224507, 0.57206140281768429760,
|
||||
0.37174803446018449013),
|
||||
(0.30075047750377283683, -0.21850801222441053540,
|
||||
0.60150095500754567366),
|
||||
(0.30075047750377283683, 0.21850801222441053540,
|
||||
0.60150095500754567366),
|
||||
(0.48662449473386508189, -0.35355339059327376220,
|
||||
-0.37174803446018449013),
|
||||
(0.48662449473386508189, 0.35355339059327376220,
|
||||
-0.37174803446018449013),
|
||||
(-0.60150095500754567366, 0, -0.37174803446018449013),
|
||||
(-0.30075047750377283683, -0.21850801222441053540,
|
||||
-0.60150095500754567366),
|
||||
(-0.30075047750377283683, 0.21850801222441053540,
|
||||
-0.60150095500754567366),
|
||||
(0.60150095500754567366, 0, 0.37174803446018449013),
|
||||
(0.4156269377774534286, -0.57206140281768429760, 0),
|
||||
(0.4156269377774534286, 0.57206140281768429760, 0),
|
||||
(0.37174803446018449013, 0, -0.60150095500754567366),
|
||||
(-0.4156269377774534286, -0.57206140281768429760, 0),
|
||||
(-0.4156269377774534286, 0.57206140281768429760, 0),
|
||||
(-0.67249851196395732696, -0.21850801222441053540, 0),
|
||||
(-0.67249851196395732696, 0.21850801222441053540, 0),
|
||||
(0.67249851196395732696, -0.21850801222441053540, 0),
|
||||
(0.67249851196395732696, 0.21850801222441053540, 0),
|
||||
(-0.37174803446018449013, 0, 0.60150095500754567366),
|
||||
(-0.48662449473386508189, -0.35355339059327376220,
|
||||
0.37174803446018449013),
|
||||
(-0.48662449473386508189, 0.35355339059327376220,
|
||||
0.37174803446018449013),
|
||||
(-0.18587401723009224507, -0.57206140281768429760,
|
||||
-0.37174803446018449013),
|
||||
(-0.18587401723009224507, 0.57206140281768429760,
|
||||
-0.37174803446018449013),
|
||||
(-0.11487646027368059176, -0.35355339059327376220,
|
||||
0.60150095500754567366),
|
||||
(-0.11487646027368059176, 0.35355339059327376220,
|
||||
0.60150095500754567366)],
|
||||
[0, 10, 16], [23, 10, 0], [16, 13, 0],
|
||||
[0, 13, 23], [16, 10, 1], [1, 10, 23],
|
||||
[1, 13, 16], [23, 13, 1], [2, 4, 19],
|
||||
[22, 4, 2], [2, 19, 27], [27, 22, 2],
|
||||
[20, 5, 3], [3, 5, 21], [26, 20, 3],
|
||||
[3, 21, 26], [29, 19, 4], [4, 22, 29],
|
||||
[5, 20, 28], [28, 21, 5], [6, 8, 15],
|
||||
[17, 8, 6], [6, 15, 25], [25, 17, 6],
|
||||
[14, 9, 7], [7, 9, 18], [24, 14, 7],
|
||||
[7, 18, 24], [8, 12, 15], [17, 12, 8],
|
||||
[14, 11, 9], [9, 11, 18], [11, 14, 24],
|
||||
[24, 18, 11], [25, 15, 12], [12, 17, 25],
|
||||
[29, 27, 19], [20, 26, 28], [28, 26, 21],
|
||||
[22, 27, 29]]
|
||||
assert Abs(polytope_integrate(octahedron_five_compound, expr)) - 0.353553\
|
||||
< 1e-6
|
||||
|
||||
cube_five_compound = [[(-0.1624598481164531631, -0.5, -0.6881909602355867691),
|
||||
(-0.1624598481164531631, 0.5, -0.6881909602355867691),
|
||||
(0.1624598481164531631, -0.5, 0.68819096023558676910),
|
||||
(0.1624598481164531631, 0.5, 0.68819096023558676910),
|
||||
(-0.52573111211913359231, 0, -0.6881909602355867691),
|
||||
(0.52573111211913359231, 0, 0.68819096023558676910),
|
||||
(-0.26286555605956679615, -0.8090169943749474241,
|
||||
-0.1624598481164531631),
|
||||
(-0.26286555605956679615, 0.8090169943749474241,
|
||||
-0.1624598481164531631),
|
||||
(0.26286555605956680301, -0.8090169943749474241,
|
||||
0.1624598481164531631),
|
||||
(0.26286555605956680301, 0.8090169943749474241,
|
||||
0.1624598481164531631),
|
||||
(-0.42532540417601993887, -0.3090169943749474241,
|
||||
0.68819096023558676910),
|
||||
(-0.42532540417601993887, 0.30901699437494742410,
|
||||
0.68819096023558676910),
|
||||
(0.42532540417601996609, -0.3090169943749474241,
|
||||
-0.6881909602355867691),
|
||||
(0.42532540417601996609, 0.30901699437494742410,
|
||||
-0.6881909602355867691),
|
||||
(-0.6881909602355867691, -0.5, 0.1624598481164531631),
|
||||
(-0.6881909602355867691, 0.5, 0.1624598481164531631),
|
||||
(0.68819096023558676910, -0.5, -0.1624598481164531631),
|
||||
(0.68819096023558676910, 0.5, -0.1624598481164531631),
|
||||
(-0.85065080835203998877, 0, -0.1624598481164531631),
|
||||
(0.85065080835203993218, 0, 0.1624598481164531631)],
|
||||
[18, 10, 3, 7], [13, 19, 8, 0], [18, 0, 8, 10],
|
||||
[3, 19, 13, 7], [18, 7, 13, 0], [8, 19, 3, 10],
|
||||
[6, 2, 11, 18], [1, 9, 19, 12], [11, 9, 1, 18],
|
||||
[6, 12, 19, 2], [1, 12, 6, 18], [11, 2, 19, 9],
|
||||
[4, 14, 11, 7], [17, 5, 8, 12], [4, 12, 8, 14],
|
||||
[11, 5, 17, 7], [4, 7, 17, 12], [8, 5, 11, 14],
|
||||
[6, 10, 15, 4], [13, 9, 5, 16], [15, 9, 13, 4],
|
||||
[6, 16, 5, 10], [13, 16, 6, 4], [15, 10, 5, 9],
|
||||
[14, 15, 1, 0], [16, 17, 3, 2], [14, 2, 3, 15],
|
||||
[1, 17, 16, 0], [14, 0, 16, 2], [3, 17, 1, 15]]
|
||||
assert Abs(polytope_integrate(cube_five_compound, expr) - 1.25) < 1e-12
|
||||
|
||||
echidnahedron = [[(0, 0, -2.4898982848827801995),
|
||||
(0, 0, 2.4898982848827802734),
|
||||
(0, -4.2360679774997896964, -2.4898982848827801995),
|
||||
(0, -4.2360679774997896964, 2.4898982848827802734),
|
||||
(0, 4.2360679774997896964, -2.4898982848827801995),
|
||||
(0, 4.2360679774997896964, 2.4898982848827802734),
|
||||
(-4.0287400534704067567, -1.3090169943749474241, -2.4898982848827801995),
|
||||
(-4.0287400534704067567, -1.3090169943749474241, 2.4898982848827802734),
|
||||
(-4.0287400534704067567, 1.3090169943749474241, -2.4898982848827801995),
|
||||
(-4.0287400534704067567, 1.3090169943749474241, 2.4898982848827802734),
|
||||
(4.0287400534704069747, -1.3090169943749474241, -2.4898982848827801995),
|
||||
(4.0287400534704069747, -1.3090169943749474241, 2.4898982848827802734),
|
||||
(4.0287400534704069747, 1.3090169943749474241, -2.4898982848827801995),
|
||||
(4.0287400534704069747, 1.3090169943749474241, 2.4898982848827802734),
|
||||
(-2.4898982848827801995, -3.4270509831248422723, -2.4898982848827801995),
|
||||
(-2.4898982848827801995, -3.4270509831248422723, 2.4898982848827802734),
|
||||
(-2.4898982848827801995, 3.4270509831248422723, -2.4898982848827801995),
|
||||
(-2.4898982848827801995, 3.4270509831248422723, 2.4898982848827802734),
|
||||
(2.4898982848827802734, -3.4270509831248422723, -2.4898982848827801995),
|
||||
(2.4898982848827802734, -3.4270509831248422723, 2.4898982848827802734),
|
||||
(2.4898982848827802734, 3.4270509831248422723, -2.4898982848827801995),
|
||||
(2.4898982848827802734, 3.4270509831248422723, 2.4898982848827802734),
|
||||
(-4.7169310137059934362, -0.8090169943749474241, -1.1135163644116066184),
|
||||
(-4.7169310137059934362, 0.8090169943749474241, -1.1135163644116066184),
|
||||
(4.7169310137059937438, -0.8090169943749474241, 1.11351636441160673519),
|
||||
(4.7169310137059937438, 0.8090169943749474241, 1.11351636441160673519),
|
||||
(-4.2916056095299737777, -2.1180339887498948482, 1.11351636441160673519),
|
||||
(-4.2916056095299737777, 2.1180339887498948482, 1.11351636441160673519),
|
||||
(4.2916056095299737777, -2.1180339887498948482, -1.1135163644116066184),
|
||||
(4.2916056095299737777, 2.1180339887498948482, -1.1135163644116066184),
|
||||
(-3.6034146492943870399, 0, -3.3405490932348205213),
|
||||
(3.6034146492943870399, 0, 3.3405490932348202056),
|
||||
(-3.3405490932348205213, -3.4270509831248422723, 1.11351636441160673519),
|
||||
(-3.3405490932348205213, 3.4270509831248422723, 1.11351636441160673519),
|
||||
(3.3405490932348202056, -3.4270509831248422723, -1.1135163644116066184),
|
||||
(3.3405490932348202056, 3.4270509831248422723, -1.1135163644116066184),
|
||||
(-2.9152236890588002395, -2.1180339887498948482, 3.3405490932348202056),
|
||||
(-2.9152236890588002395, 2.1180339887498948482, 3.3405490932348202056),
|
||||
(2.9152236890588002395, -2.1180339887498948482, -3.3405490932348205213),
|
||||
(2.9152236890588002395, 2.1180339887498948482, -3.3405490932348205213),
|
||||
(-2.2270327288232132368, 0, -1.1135163644116066184),
|
||||
(-2.2270327288232132368, -4.2360679774997896964, -1.1135163644116066184),
|
||||
(-2.2270327288232132368, 4.2360679774997896964, -1.1135163644116066184),
|
||||
(2.2270327288232134704, 0, 1.11351636441160673519),
|
||||
(2.2270327288232134704, -4.2360679774997896964, 1.11351636441160673519),
|
||||
(2.2270327288232134704, 4.2360679774997896964, 1.11351636441160673519),
|
||||
(-1.8017073246471935200, -1.3090169943749474241, 1.11351636441160673519),
|
||||
(-1.8017073246471935200, 1.3090169943749474241, 1.11351636441160673519),
|
||||
(1.8017073246471935043, -1.3090169943749474241, -1.1135163644116066184),
|
||||
(1.8017073246471935043, 1.3090169943749474241, -1.1135163644116066184),
|
||||
(-1.3763819204711735382, 0, -4.7169310137059934362),
|
||||
(-1.3763819204711735382, 0, 0.26286555605956679615),
|
||||
(1.37638192047117353821, 0, 4.7169310137059937438),
|
||||
(1.37638192047117353821, 0, -0.26286555605956679615),
|
||||
(-1.1135163644116066184, -3.4270509831248422723, -3.3405490932348205213),
|
||||
(-1.1135163644116066184, -0.8090169943749474241, 4.7169310137059937438),
|
||||
(-1.1135163644116066184, -0.8090169943749474241, -0.26286555605956679615),
|
||||
(-1.1135163644116066184, 0.8090169943749474241, 4.7169310137059937438),
|
||||
(-1.1135163644116066184, 0.8090169943749474241, -0.26286555605956679615),
|
||||
(-1.1135163644116066184, 3.4270509831248422723, -3.3405490932348205213),
|
||||
(1.11351636441160673519, -3.4270509831248422723, 3.3405490932348202056),
|
||||
(1.11351636441160673519, -0.8090169943749474241, -4.7169310137059934362),
|
||||
(1.11351636441160673519, -0.8090169943749474241, 0.26286555605956679615),
|
||||
(1.11351636441160673519, 0.8090169943749474241, -4.7169310137059934362),
|
||||
(1.11351636441160673519, 0.8090169943749474241, 0.26286555605956679615),
|
||||
(1.11351636441160673519, 3.4270509831248422723, 3.3405490932348202056),
|
||||
(-0.85065080835203998877, 0, 1.11351636441160673519),
|
||||
(0.85065080835203993218, 0, -1.1135163644116066184),
|
||||
(-0.6881909602355867691, -0.5, -1.1135163644116066184),
|
||||
(-0.6881909602355867691, 0.5, -1.1135163644116066184),
|
||||
(-0.6881909602355867691, -4.7360679774997896964, -1.1135163644116066184),
|
||||
(-0.6881909602355867691, -2.1180339887498948482, -1.1135163644116066184),
|
||||
(-0.6881909602355867691, 2.1180339887498948482, -1.1135163644116066184),
|
||||
(-0.6881909602355867691, 4.7360679774997896964, -1.1135163644116066184),
|
||||
(0.68819096023558676910, -0.5, 1.11351636441160673519),
|
||||
(0.68819096023558676910, 0.5, 1.11351636441160673519),
|
||||
(0.68819096023558676910, -4.7360679774997896964, 1.11351636441160673519),
|
||||
(0.68819096023558676910, -2.1180339887498948482, 1.11351636441160673519),
|
||||
(0.68819096023558676910, 2.1180339887498948482, 1.11351636441160673519),
|
||||
(0.68819096023558676910, 4.7360679774997896964, 1.11351636441160673519),
|
||||
(-0.42532540417601993887, -1.3090169943749474241, -4.7169310137059934362),
|
||||
(-0.42532540417601993887, -1.3090169943749474241, 0.26286555605956679615),
|
||||
(-0.42532540417601993887, 1.3090169943749474241, -4.7169310137059934362),
|
||||
(-0.42532540417601993887, 1.3090169943749474241, 0.26286555605956679615),
|
||||
(-0.26286555605956679615, -0.8090169943749474241, 1.11351636441160673519),
|
||||
(-0.26286555605956679615, 0.8090169943749474241, 1.11351636441160673519),
|
||||
(0.26286555605956679615, -0.8090169943749474241, -1.1135163644116066184),
|
||||
(0.26286555605956679615, 0.8090169943749474241, -1.1135163644116066184),
|
||||
(0.42532540417601996609, -1.3090169943749474241, 4.7169310137059937438),
|
||||
(0.42532540417601996609, -1.3090169943749474241, -0.26286555605956679615),
|
||||
(0.42532540417601996609, 1.3090169943749474241, 4.7169310137059937438),
|
||||
(0.42532540417601996609, 1.3090169943749474241, -0.26286555605956679615)],
|
||||
[9, 66, 47], [44, 62, 77], [20, 91, 49], [33, 47, 83],
|
||||
[3, 77, 84], [12, 49, 53], [36, 84, 66], [28, 53, 62],
|
||||
[73, 83, 91], [15, 84, 46], [25, 64, 43], [16, 58, 72],
|
||||
[26, 46, 51], [11, 43, 74], [4, 72, 91], [60, 74, 84],
|
||||
[35, 91, 64], [23, 51, 58], [19, 74, 77], [79, 83, 78],
|
||||
[6, 56, 40], [76, 77, 81], [21, 78, 75], [8, 40, 58],
|
||||
[31, 75, 74], [42, 58, 83], [41, 81, 56], [13, 75, 43],
|
||||
[27, 51, 47], [2, 89, 71], [24, 43, 62], [17, 47, 85],
|
||||
[14, 71, 56], [65, 85, 75], [22, 56, 51], [34, 62, 89],
|
||||
[5, 85, 78], [32, 81, 46], [10, 53, 48], [45, 78, 64],
|
||||
[7, 46, 66], [18, 48, 89], [37, 66, 85], [70, 89, 81],
|
||||
[29, 64, 53], [88, 74, 1], [38, 67, 48], [42, 83, 72],
|
||||
[57, 1, 85], [34, 48, 62], [59, 72, 87], [19, 62, 74],
|
||||
[63, 87, 67], [17, 85, 83], [52, 75, 1], [39, 87, 49],
|
||||
[22, 51, 40], [55, 1, 66], [29, 49, 64], [30, 40, 69],
|
||||
[13, 64, 75], [82, 69, 87], [7, 66, 51], [90, 85, 1],
|
||||
[59, 69, 72], [70, 81, 71], [88, 1, 84], [73, 72, 83],
|
||||
[54, 71, 68], [5, 83, 85], [50, 68, 69], [3, 84, 81],
|
||||
[57, 66, 1], [30, 68, 40], [28, 62, 48], [52, 1, 74],
|
||||
[23, 40, 51], [38, 48, 86], [9, 51, 66], [80, 86, 68],
|
||||
[11, 74, 62], [55, 84, 1], [54, 86, 71], [35, 64, 49],
|
||||
[90, 1, 75], [41, 71, 81], [39, 49, 67], [15, 81, 84],
|
||||
[61, 67, 86], [21, 75, 64], [24, 53, 43], [50, 69, 0],
|
||||
[37, 85, 47], [31, 43, 75], [61, 0, 67], [27, 47, 58],
|
||||
[10, 67, 53], [8, 58, 69], [90, 75, 85], [45, 91, 78],
|
||||
[80, 68, 0], [36, 66, 46], [65, 78, 85], [63, 0, 87],
|
||||
[32, 46, 56], [20, 87, 91], [14, 56, 68], [57, 85, 66],
|
||||
[33, 58, 47], [61, 86, 0], [60, 84, 77], [37, 47, 66],
|
||||
[82, 0, 69], [44, 77, 89], [16, 69, 58], [18, 89, 86],
|
||||
[55, 66, 84], [26, 56, 46], [63, 67, 0], [31, 74, 43],
|
||||
[36, 46, 84], [50, 0, 68], [25, 43, 53], [6, 68, 56],
|
||||
[12, 53, 67], [88, 84, 74], [76, 89, 77], [82, 87, 0],
|
||||
[65, 75, 78], [60, 77, 74], [80, 0, 86], [79, 78, 91],
|
||||
[2, 86, 89], [4, 91, 87], [52, 74, 75], [21, 64, 78],
|
||||
[18, 86, 48], [23, 58, 40], [5, 78, 83], [28, 48, 53],
|
||||
[6, 40, 68], [25, 53, 64], [54, 68, 86], [33, 83, 58],
|
||||
[17, 83, 47], [12, 67, 49], [41, 56, 71], [9, 47, 51],
|
||||
[35, 49, 91], [2, 71, 86], [79, 91, 83], [38, 86, 67],
|
||||
[26, 51, 56], [7, 51, 46], [4, 87, 72], [34, 89, 48],
|
||||
[15, 46, 81], [42, 72, 58], [10, 48, 67], [27, 58, 51],
|
||||
[39, 67, 87], [76, 81, 89], [3, 81, 77], [8, 69, 40],
|
||||
[29, 53, 49], [19, 77, 62], [22, 40, 56], [20, 49, 87],
|
||||
[32, 56, 81], [59, 87, 69], [24, 62, 53], [11, 62, 43],
|
||||
[14, 68, 71], [73, 91, 72], [13, 43, 64], [70, 71, 89],
|
||||
[16, 72, 69], [44, 89, 62], [30, 69, 68], [45, 64, 91]]
|
||||
# Actual volume is : 51.405764746872634
|
||||
assert Abs(polytope_integrate(echidnahedron, 1) - 51.4057647468726) < 1e-12
|
||||
assert Abs(polytope_integrate(echidnahedron, expr) - 253.569603474519) <\
|
||||
1e-12
|
||||
|
||||
# Tests for many polynomials with maximum degree given(2D case).
|
||||
assert polytope_integrate(cube2, [x**2, y*z], max_degree=2) == \
|
||||
{y * z: 3125 / S(4), x ** 2: 3125 / S(3)}
|
||||
|
||||
assert polytope_integrate(cube2, max_degree=2) == \
|
||||
{1: 125, x: 625 / S(2), x * z: 3125 / S(4), y: 625 / S(2),
|
||||
y * z: 3125 / S(4), z ** 2: 3125 / S(3), y ** 2: 3125 / S(3),
|
||||
z: 625 / S(2), x * y: 3125 / S(4), x ** 2: 3125 / S(3)}
|
||||
|
||||
def test_point_sort():
|
||||
assert point_sort([Point(0, 0), Point(1, 0), Point(1, 1)]) == \
|
||||
[Point2D(1, 1), Point2D(1, 0), Point2D(0, 0)]
|
||||
|
||||
fig6 = Polygon((0, 0), (1, 0), (1, 1))
|
||||
assert polytope_integrate(fig6, x*y) == Rational(-1, 8)
|
||||
assert polytope_integrate(fig6, x*y, clockwise = True) == Rational(1, 8)
|
||||
|
||||
|
||||
def test_polytopes_intersecting_sides():
|
||||
fig5 = Polygon(Point(-4.165, -0.832), Point(-3.668, 1.568),
|
||||
Point(-3.266, 1.279), Point(-1.090, -2.080),
|
||||
Point(3.313, -0.683), Point(3.033, -4.845),
|
||||
Point(-4.395, 4.840), Point(-1.007, -3.328))
|
||||
assert polytope_integrate(fig5, x**2 + x*y + y**2) ==\
|
||||
S(1633405224899363)/(24*10**12)
|
||||
|
||||
fig6 = Polygon(Point(-3.018, -4.473), Point(-0.103, 2.378),
|
||||
Point(-1.605, -2.308), Point(4.516, -0.771),
|
||||
Point(4.203, 0.478))
|
||||
assert polytope_integrate(fig6, x**2 + x*y + y**2) ==\
|
||||
S(88161333955921)/(3*10**12)
|
||||
|
||||
|
||||
def test_max_degree():
|
||||
polygon = Polygon((0, 0), (0, 1), (1, 1), (1, 0))
|
||||
polys = [1, x, y, x*y, x**2*y, x*y**2]
|
||||
assert polytope_integrate(polygon, polys, max_degree=3) == \
|
||||
{1: 1, x: S.Half, y: S.Half, x*y: Rational(1, 4), x**2*y: Rational(1, 6), x*y**2: Rational(1, 6)}
|
||||
assert polytope_integrate(polygon, polys, max_degree=2) == \
|
||||
{1: 1, x: S.Half, y: S.Half, x*y: Rational(1, 4)}
|
||||
assert polytope_integrate(polygon, polys, max_degree=1) == \
|
||||
{1: 1, x: S.Half, y: S.Half}
|
||||
|
||||
|
||||
def test_main_integrate3d():
|
||||
cube = [[(0, 0, 0), (0, 0, 5), (0, 5, 0), (0, 5, 5), (5, 0, 0),\
|
||||
(5, 0, 5), (5, 5, 0), (5, 5, 5)],\
|
||||
[2, 6, 7, 3], [3, 7, 5, 1], [7, 6, 4, 5], [1, 5, 4, 0],\
|
||||
[3, 1, 0, 2], [0, 4, 6, 2]]
|
||||
vertices = cube[0]
|
||||
faces = cube[1:]
|
||||
hp_params = hyperplane_parameters(faces, vertices)
|
||||
assert main_integrate3d(1, faces, vertices, hp_params) == -125
|
||||
assert main_integrate3d(1, faces, vertices, hp_params, max_degree=1) == \
|
||||
{1: -125, y: Rational(-625, 2), z: Rational(-625, 2), x: Rational(-625, 2)}
|
||||
|
||||
|
||||
def test_main_integrate():
|
||||
triangle = Polygon((0, 3), (5, 3), (1, 1))
|
||||
facets = triangle.sides
|
||||
hp_params = hyperplane_parameters(triangle)
|
||||
assert main_integrate(x**2 + y**2, facets, hp_params) == Rational(325, 6)
|
||||
assert main_integrate(x**2 + y**2, facets, hp_params, max_degree=1) == \
|
||||
{0: 0, 1: 5, y: Rational(35, 3), x: 10}
|
||||
|
||||
|
||||
def test_polygon_integrate():
|
||||
cube = [[(0, 0, 0), (0, 0, 5), (0, 5, 0), (0, 5, 5), (5, 0, 0),\
|
||||
(5, 0, 5), (5, 5, 0), (5, 5, 5)],\
|
||||
[2, 6, 7, 3], [3, 7, 5, 1], [7, 6, 4, 5], [1, 5, 4, 0],\
|
||||
[3, 1, 0, 2], [0, 4, 6, 2]]
|
||||
facet = cube[1]
|
||||
facets = cube[1:]
|
||||
vertices = cube[0]
|
||||
assert polygon_integrate(facet, [(0, 1, 0), 5], 0, facets, vertices, 1, 0) == -25
|
||||
|
||||
|
||||
def test_distance_to_side():
|
||||
point = (0, 0, 0)
|
||||
assert distance_to_side(point, [(0, 0, 1), (0, 1, 0)], (1, 0, 0)) == -sqrt(2)/2
|
||||
|
||||
|
||||
def test_lineseg_integrate():
|
||||
polygon = [(0, 5, 0), (5, 5, 0), (5, 5, 5), (0, 5, 5)]
|
||||
line_seg = [(0, 5, 0), (5, 5, 0)]
|
||||
assert lineseg_integrate(polygon, 0, line_seg, 1, 0) == 5
|
||||
assert lineseg_integrate(polygon, 0, line_seg, 0, 0) == 0
|
||||
|
||||
|
||||
def test_integration_reduction():
|
||||
triangle = Polygon(Point(0, 3), Point(5, 3), Point(1, 1))
|
||||
facets = triangle.sides
|
||||
a, b = hyperplane_parameters(triangle)[0]
|
||||
assert integration_reduction(facets, 0, a, b, 1, (x, y), 0) == 5
|
||||
assert integration_reduction(facets, 0, a, b, 0, (x, y), 0) == 0
|
||||
|
||||
|
||||
def test_integration_reduction_dynamic():
|
||||
triangle = Polygon(Point(0, 3), Point(5, 3), Point(1, 1))
|
||||
facets = triangle.sides
|
||||
a, b = hyperplane_parameters(triangle)[0]
|
||||
x0 = facets[0].points[0]
|
||||
monomial_values = [[0, 0, 0, 0], [1, 0, 0, 5],\
|
||||
[y, 0, 1, 15], [x, 1, 0, None]]
|
||||
|
||||
assert integration_reduction_dynamic(facets, 0, a, b, x, 1, (x, y), 1,\
|
||||
0, 1, x0, monomial_values, 3) == Rational(25, 2)
|
||||
assert integration_reduction_dynamic(facets, 0, a, b, 0, 1, (x, y), 1,\
|
||||
0, 1, x0, monomial_values, 3) == 0
|
||||
|
||||
|
||||
def test_is_vertex():
|
||||
assert is_vertex(2) is False
|
||||
assert is_vertex((2, 3)) is True
|
||||
assert is_vertex(Point(2, 3)) is True
|
||||
assert is_vertex((2, 3, 4)) is True
|
||||
assert is_vertex((2, 3, 4, 5)) is False
|
||||
|
||||
|
||||
def test_issue_19234():
|
||||
polygon = Polygon(Point(0, 0), Point(0, 1), Point(1, 1), Point(1, 0))
|
||||
polys = [ 1, x, y, x*y, x**2*y, x*y**2]
|
||||
assert polytope_integrate(polygon, polys) == \
|
||||
{1: 1, x: S.Half, y: S.Half, x*y: Rational(1, 4), x**2*y: Rational(1, 6), x*y**2: Rational(1, 6)}
|
||||
polys = [ 1, x, y, x*y, 3 + x**2*y, x + x*y**2]
|
||||
assert polytope_integrate(polygon, polys) == \
|
||||
{1: 1, x: S.Half, y: S.Half, x*y: Rational(1, 4), x**2*y + 3: Rational(19, 6), x*y**2 + x: Rational(2, 3)}
|
||||
@@ -0,0 +1,774 @@
|
||||
from sympy.integrals.laplace import (
|
||||
laplace_transform, inverse_laplace_transform,
|
||||
LaplaceTransform, InverseLaplaceTransform,
|
||||
_laplace_deep_collect, laplace_correspondence,
|
||||
laplace_initial_conds)
|
||||
from sympy.core.function import Function, expand_mul
|
||||
from sympy.core import EulerGamma, Subs, Derivative, diff
|
||||
from sympy.core.exprtools import factor_terms
|
||||
from sympy.core.numbers import I, oo, pi
|
||||
from sympy.core.relational import Eq
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import Symbol, symbols
|
||||
from sympy.simplify.simplify import simplify
|
||||
from sympy.functions.elementary.complexes import Abs, re
|
||||
from sympy.functions.elementary.exponential import exp, log, exp_polar
|
||||
from sympy.functions.elementary.hyperbolic import cosh, sinh, coth, asinh
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.piecewise import Piecewise
|
||||
from sympy.functions.elementary.trigonometric import atan, cos, sin
|
||||
from sympy.logic.boolalg import And
|
||||
from sympy.functions.special.gamma_functions import (
|
||||
lowergamma, gamma, uppergamma)
|
||||
from sympy.functions.special.delta_functions import DiracDelta, Heaviside
|
||||
from sympy.functions.special.singularity_functions import SingularityFunction
|
||||
from sympy.functions.special.zeta_functions import lerchphi
|
||||
from sympy.functions.special.error_functions import (
|
||||
fresnelc, fresnels, erf, erfc, Ei, Ci, expint, E1)
|
||||
from sympy.functions.special.bessel import besseli, besselj, besselk, bessely
|
||||
from sympy.testing.pytest import slow, warns_deprecated_sympy
|
||||
from sympy.matrices import Matrix, eye
|
||||
from sympy.abc import s
|
||||
|
||||
|
||||
@slow
|
||||
def test_laplace_transform():
|
||||
LT = laplace_transform
|
||||
ILT = inverse_laplace_transform
|
||||
a, b, c = symbols('a, b, c', positive=True)
|
||||
np = symbols('np', integer=True, positive=True)
|
||||
t, w, x = symbols('t, w, x')
|
||||
f = Function('f')
|
||||
F = Function('F')
|
||||
g = Function('g')
|
||||
y = Function('y')
|
||||
Y = Function('Y')
|
||||
|
||||
# Test helper functions
|
||||
assert (
|
||||
_laplace_deep_collect(exp((t+a)*(t+b)) +
|
||||
besselj(2, exp((t+a)*(t+b)-t**2)), t) ==
|
||||
exp(a*b + t**2 + t*(a + b)) + besselj(2, exp(a*b + t*(a + b))))
|
||||
L = laplace_transform(diff(y(t), t, 3), t, s, noconds=True)
|
||||
L = laplace_correspondence(L, {y: Y})
|
||||
L = laplace_initial_conds(L, t, {y: [2, 4, 8, 16, 32]})
|
||||
assert L == s**3*Y(s) - 2*s**2 - 4*s - 8
|
||||
# Test whether `noconds=True` in `doit`:
|
||||
assert (2*LaplaceTransform(exp(t), t, s) - 1).doit() == -1 + 2/(s - 1)
|
||||
assert (LT(a*t+t**2+t**(S(5)/2), t, s) ==
|
||||
(a/s**2 + 2/s**3 + 15*sqrt(pi)/(8*s**(S(7)/2)), 0, True))
|
||||
assert LT(b/(t+a), t, s) == (-b*exp(-a*s)*Ei(-a*s), 0, True)
|
||||
assert (LT(1/sqrt(t+a), t, s) ==
|
||||
(sqrt(pi)*sqrt(1/s)*exp(a*s)*erfc(sqrt(a)*sqrt(s)), 0, True))
|
||||
assert (LT(sqrt(t)/(t+a), t, s) ==
|
||||
(-pi*sqrt(a)*exp(a*s)*erfc(sqrt(a)*sqrt(s)) + sqrt(pi)*sqrt(1/s),
|
||||
0, True))
|
||||
assert (LT((t+a)**(-S(3)/2), t, s) ==
|
||||
(-2*sqrt(pi)*sqrt(s)*exp(a*s)*erfc(sqrt(a)*sqrt(s)) + 2/sqrt(a),
|
||||
0, True))
|
||||
assert (LT(t**(S(1)/2)*(t+a)**(-1), t, s) ==
|
||||
(-pi*sqrt(a)*exp(a*s)*erfc(sqrt(a)*sqrt(s)) + sqrt(pi)*sqrt(1/s),
|
||||
0, True))
|
||||
assert (LT(1/(a*sqrt(t) + t**(3/2)), t, s) ==
|
||||
(pi*sqrt(a)*exp(a*s)*erfc(sqrt(a)*sqrt(s)), 0, True))
|
||||
assert (LT((t+a)**b, t, s) ==
|
||||
(s**(-b - 1)*exp(-a*s)*uppergamma(b + 1, a*s), 0, True))
|
||||
assert LT(t**5/(t+a), t, s) == (120*a**5*uppergamma(-5, a*s), 0, True)
|
||||
assert LT(exp(t), t, s) == (1/(s - 1), 1, True)
|
||||
assert LT(exp(2*t), t, s) == (1/(s - 2), 2, True)
|
||||
assert LT(exp(a*t), t, s) == (1/(s - a), a, True)
|
||||
assert LT(exp(a*(t-b)), t, s) == (exp(-a*b)/(-a + s), a, True)
|
||||
assert LT(t*exp(-a*(t)), t, s) == ((a + s)**(-2), -a, True)
|
||||
assert LT(t*exp(-a*(t-b)), t, s) == (exp(a*b)/(a + s)**2, -a, True)
|
||||
assert LT(b*t*exp(-a*t), t, s) == (b/(a + s)**2, -a, True)
|
||||
assert LT(exp(-a*exp(-t)), t, s) == (lowergamma(s, a)/a**s, 0, True)
|
||||
assert LT(exp(-a*exp(t)), t, s) == (a**s*uppergamma(-s, a), 0, True)
|
||||
assert (LT(t**(S(7)/4)*exp(-8*t)/gamma(S(11)/4), t, s) ==
|
||||
((s + 8)**(-S(11)/4), -8, True))
|
||||
assert (LT(t**(S(3)/2)*exp(-8*t), t, s) ==
|
||||
(3*sqrt(pi)/(4*(s + 8)**(S(5)/2)), -8, True))
|
||||
assert LT(t**a*exp(-a*t), t, s) == ((a+s)**(-a-1)*gamma(a+1), -a, True)
|
||||
assert (LT(b*exp(-a*t**2), t, s) ==
|
||||
(sqrt(pi)*b*exp(s**2/(4*a))*erfc(s/(2*sqrt(a)))/(2*sqrt(a)),
|
||||
0, True))
|
||||
assert (LT(exp(-2*t**2), t, s) ==
|
||||
(sqrt(2)*sqrt(pi)*exp(s**2/8)*erfc(sqrt(2)*s/4)/4, 0, True))
|
||||
assert (LT(b*exp(2*t**2), t, s) ==
|
||||
(b*LaplaceTransform(exp(2*t**2), t, s), -oo, True))
|
||||
assert (LT(t*exp(-a*t**2), t, s) ==
|
||||
(1/(2*a) - s*erfc(s/(2*sqrt(a)))/(4*sqrt(pi)*a**(S(3)/2)),
|
||||
0, True))
|
||||
assert (LT(exp(-a/t), t, s) ==
|
||||
(2*sqrt(a)*sqrt(1/s)*besselk(1, 2*sqrt(a)*sqrt(s)), 0, True))
|
||||
assert LT(sqrt(t)*exp(-a/t), t, s, simplify=True) == (
|
||||
sqrt(pi)*(sqrt(a)*sqrt(s) + 1/S(2))*sqrt(s**(-3)) *
|
||||
exp(-2*sqrt(a)*sqrt(s)), 0, True)
|
||||
assert (LT(exp(-a/t)/sqrt(t), t, s) ==
|
||||
(sqrt(pi)*sqrt(1/s)*exp(-2*sqrt(a)*sqrt(s)), 0, True))
|
||||
assert (LT(exp(-a/t)/(t*sqrt(t)), t, s) ==
|
||||
(sqrt(pi)*sqrt(1/a)*exp(-2*sqrt(a)*sqrt(s)), 0, True))
|
||||
# TODO: rules with sqrt(a*t) and sqrt(a/t) have stopped working after
|
||||
# changes to as_base_exp
|
||||
# assert (
|
||||
# LT(exp(-2*sqrt(a*t)), t, s) ==
|
||||
# (1/s - sqrt(pi)*sqrt(a) * exp(a/s)*erfc(sqrt(a)*sqrt(1/s)) /
|
||||
# s**(S(3)/2), 0, True))
|
||||
# assert LT(exp(-2*sqrt(a*t))/sqrt(t), t, s) == (
|
||||
# exp(a/s)*erfc(sqrt(a) * sqrt(1/s))*(sqrt(pi)*sqrt(1/s)), 0, True)
|
||||
assert (LT(t**4*exp(-2/t), t, s) ==
|
||||
(8*sqrt(2)*(1/s)**(S(5)/2)*besselk(5, 2*sqrt(2)*sqrt(s)),
|
||||
0, True))
|
||||
assert LT(sinh(a*t), t, s) == (a/(-a**2 + s**2), a, True)
|
||||
assert (LT(b*sinh(a*t)**2, t, s) ==
|
||||
(2*a**2*b/(-4*a**2*s + s**3), 2*a, True))
|
||||
assert (LT(b*sinh(a*t)**2, t, s, simplify=True) ==
|
||||
(2*a**2*b/(s*(-4*a**2 + s**2)), 2*a, True))
|
||||
# The following line confirms that issue #21202 is solved
|
||||
assert LT(cosh(2*t), t, s) == (s/(-4 + s**2), 2, True)
|
||||
assert LT(cosh(a*t), t, s) == (s/(-a**2 + s**2), a, True)
|
||||
assert (LT(cosh(a*t)**2, t, s, simplify=True) ==
|
||||
((2*a**2 - s**2)/(s*(4*a**2 - s**2)), 2*a, True))
|
||||
assert (LT(sinh(x+3), x, s, simplify=True) ==
|
||||
((s*sinh(3) + cosh(3))/(s**2 - 1), 1, True))
|
||||
L, _, _ = LT(42*sin(w*t+x)**2, t, s)
|
||||
assert (
|
||||
L -
|
||||
21*(s**2 + s*(-s*cos(2*x) + 2*w*sin(2*x)) +
|
||||
4*w**2)/(s*(s**2 + 4*w**2))).simplify() == 0
|
||||
# The following line replaces the old test test_issue_7173()
|
||||
assert LT(sinh(a*t)*cosh(a*t), t, s, simplify=True) == (a/(-4*a**2 + s**2),
|
||||
2*a, True)
|
||||
assert LT(sinh(a*t)/t, t, s) == (log((a + s)/(-a + s))/2, a, True)
|
||||
assert (LT(t**(-S(3)/2)*sinh(a*t), t, s) ==
|
||||
(-sqrt(pi)*(sqrt(-a + s) - sqrt(a + s)), a, True))
|
||||
# assert (LT(sinh(2*sqrt(a*t)), t, s) ==
|
||||
# (sqrt(pi)*sqrt(a)*exp(a/s)/s**(S(3)/2), 0, True))
|
||||
# assert (LT(sqrt(t)*sinh(2*sqrt(a*t)), t, s, simplify=True) ==
|
||||
# ((-sqrt(a)*s**(S(5)/2) + sqrt(pi)*s**2*(2*a + s)*exp(a/s) *
|
||||
# erf(sqrt(a)*sqrt(1/s))/2)/s**(S(9)/2), 0, True))
|
||||
# assert (LT(sinh(2*sqrt(a*t))/sqrt(t), t, s) ==
|
||||
# (sqrt(pi)*exp(a/s)*erf(sqrt(a)*sqrt(1/s))/sqrt(s), 0, True))
|
||||
# assert (LT(sinh(sqrt(a*t))**2/sqrt(t), t, s) ==
|
||||
# (sqrt(pi)*(exp(a/s) - 1)/(2*sqrt(s)), 0, True))
|
||||
assert (LT(t**(S(3)/7)*cosh(a*t), t, s) ==
|
||||
(((a + s)**(-S(10)/7) + (-a+s)**(-S(10)/7))*gamma(S(10)/7)/2,
|
||||
a, True))
|
||||
# assert (LT(cosh(2*sqrt(a*t)), t, s) ==
|
||||
# (sqrt(pi)*sqrt(a)*exp(a/s)*erf(sqrt(a)*sqrt(1/s))/s**(S(3)/2) +
|
||||
# 1/s, 0, True))
|
||||
# assert (LT(sqrt(t)*cosh(2*sqrt(a*t)), t, s) ==
|
||||
# (sqrt(pi)*(a + s/2)*exp(a/s)/s**(S(5)/2), 0, True))
|
||||
# assert (LT(cosh(2*sqrt(a*t))/sqrt(t), t, s) ==
|
||||
# (sqrt(pi)*exp(a/s)/sqrt(s), 0, True))
|
||||
# assert (LT(cosh(sqrt(a*t))**2/sqrt(t), t, s) ==
|
||||
# (sqrt(pi)*(exp(a/s) + 1)/(2*sqrt(s)), 0, True))
|
||||
assert LT(log(t), t, s, simplify=True) == (
|
||||
(-log(s) - EulerGamma)/s, 0, True)
|
||||
assert (LT(-log(t/a), t, s, simplify=True) ==
|
||||
((log(a) + log(s) + EulerGamma)/s, 0, True))
|
||||
assert LT(log(1+a*t), t, s) == (-exp(s/a)*Ei(-s/a)/s, 0, True)
|
||||
assert (LT(log(t+a), t, s, simplify=True) ==
|
||||
((s*log(a) - exp(s/a)*Ei(-s/a))/s**2, 0, True))
|
||||
assert (LT(log(t)/sqrt(t), t, s, simplify=True) ==
|
||||
(sqrt(pi)*(-log(s) - log(4) - EulerGamma)/sqrt(s), 0, True))
|
||||
assert (LT(t**(S(5)/2)*log(t), t, s, simplify=True) ==
|
||||
(sqrt(pi)*(-15*log(s) - log(1073741824) - 15*EulerGamma + 46) /
|
||||
(8*s**(S(7)/2)), 0, True))
|
||||
assert (LT(t**3*log(t), t, s, noconds=True, simplify=True) -
|
||||
6*(-log(s) - S.EulerGamma + S(11)/6)/s**4).simplify() == S.Zero
|
||||
assert (LT(log(t)**2, t, s, simplify=True) ==
|
||||
(((log(s) + EulerGamma)**2 + pi**2/6)/s, 0, True))
|
||||
assert (LT(exp(-a*t)*log(t), t, s, simplify=True) ==
|
||||
((-log(a + s) - EulerGamma)/(a + s), -a, True))
|
||||
assert LT(sin(a*t), t, s) == (a/(a**2 + s**2), 0, True)
|
||||
assert (LT(Abs(sin(a*t)), t, s) ==
|
||||
(a*coth(pi*s/(2*a))/(a**2 + s**2), 0, True))
|
||||
assert LT(sin(a*t)/t, t, s) == (atan(a/s), 0, True)
|
||||
assert LT(sin(a*t)**2/t, t, s) == (log(4*a**2/s**2 + 1)/4, 0, True)
|
||||
assert (LT(sin(a*t)**2/t**2, t, s) ==
|
||||
(a*atan(2*a/s) - s*log(4*a**2/s**2 + 1)/4, 0, True))
|
||||
# assert (LT(sin(2*sqrt(a*t)), t, s) ==
|
||||
# (sqrt(pi)*sqrt(a)*exp(-a/s)/s**(S(3)/2), 0, True))
|
||||
# assert LT(sin(2*sqrt(a*t))/t, t, s) == (pi*erf(sqrt(a)*sqrt(1/s)), 0, True)
|
||||
assert LT(cos(a*t), t, s) == (s/(a**2 + s**2), 0, True)
|
||||
assert (LT(cos(a*t)**2, t, s) ==
|
||||
((2*a**2 + s**2)/(s*(4*a**2 + s**2)), 0, True))
|
||||
# assert (LT(sqrt(t)*cos(2*sqrt(a*t)), t, s, simplify=True) ==
|
||||
# (sqrt(pi)*(-a + s/2)*exp(-a/s)/s**(S(5)/2), 0, True))
|
||||
# assert (LT(cos(2*sqrt(a*t))/sqrt(t), t, s) ==
|
||||
# (sqrt(pi)*sqrt(1/s)*exp(-a/s), 0, True))
|
||||
assert (LT(sin(a*t)*sin(b*t), t, s) ==
|
||||
(2*a*b*s/((s**2 + (a - b)**2)*(s**2 + (a + b)**2)), 0, True))
|
||||
assert (LT(cos(a*t)*sin(b*t), t, s) ==
|
||||
(b*(-a**2 + b**2 + s**2)/((s**2 + (a - b)**2)*(s**2 + (a + b)**2)),
|
||||
0, True))
|
||||
assert (LT(cos(a*t)*cos(b*t), t, s) ==
|
||||
(s*(a**2 + b**2 + s**2)/((s**2 + (a - b)**2)*(s**2 + (a + b)**2)),
|
||||
0, True))
|
||||
assert (LT(-a*t*cos(a*t) + sin(a*t), t, s, simplify=True) ==
|
||||
(2*a**3/(a**4 + 2*a**2*s**2 + s**4), 0, True))
|
||||
assert LT(c*exp(-b*t)*sin(a*t), t, s) == (a *
|
||||
c/(a**2 + (b + s)**2), -b, True)
|
||||
assert LT(c*exp(-b*t)*cos(a*t), t, s) == (c*(b + s)/(a**2 + (b + s)**2),
|
||||
-b, True)
|
||||
L, plane, cond = LT(cos(x + 3), x, s, simplify=True)
|
||||
assert plane == 0
|
||||
assert L - (s*cos(3) - sin(3))/(s**2 + 1) == 0
|
||||
# Error functions (laplace7.pdf)
|
||||
assert LT(erf(a*t), t, s) == (exp(s**2/(4*a**2))*erfc(s/(2*a))/s, 0, True)
|
||||
# assert LT(erf(sqrt(a*t)), t, s) == (sqrt(a)/(s*sqrt(a + s)), 0, True)
|
||||
# assert (LT(exp(a*t)*erf(sqrt(a*t)), t, s, simplify=True) ==
|
||||
# (-sqrt(a)/(sqrt(s)*(a - s)), a, True))
|
||||
# assert (LT(erf(sqrt(a/t)/2), t, s, simplify=True) ==
|
||||
# (1/s - exp(-sqrt(a)*sqrt(s))/s, 0, True))
|
||||
# assert (LT(erfc(sqrt(a*t)), t, s, simplify=True) ==
|
||||
# (-sqrt(a)/(s*sqrt(a + s)) + 1/s, -a, True))
|
||||
# assert (LT(exp(a*t)*erfc(sqrt(a*t)), t, s) ==
|
||||
# (1/(sqrt(a)*sqrt(s) + s), 0, True))
|
||||
# assert LT(erfc(sqrt(a/t)/2), t, s) == (exp(-sqrt(a)*sqrt(s))/s, 0, True)
|
||||
# Bessel functions (laplace8.pdf)
|
||||
assert LT(besselj(0, a*t), t, s) == (1/sqrt(a**2 + s**2), 0, True)
|
||||
assert (LT(besselj(1, a*t), t, s, simplify=True) ==
|
||||
(a/(a**2 + s**2 + s*sqrt(a**2 + s**2)), 0, True))
|
||||
assert (LT(besselj(2, a*t), t, s, simplify=True) ==
|
||||
(a**2/(sqrt(a**2 + s**2)*(s + sqrt(a**2 + s**2))**2), 0, True))
|
||||
assert (LT(t*besselj(0, a*t), t, s) ==
|
||||
(s/(a**2 + s**2)**(S(3)/2), 0, True))
|
||||
assert (LT(t*besselj(1, a*t), t, s) ==
|
||||
(a/(a**2 + s**2)**(S(3)/2), 0, True))
|
||||
assert (LT(t**2*besselj(2, a*t), t, s) ==
|
||||
(3*a**2/(a**2 + s**2)**(S(5)/2), 0, True))
|
||||
# assert LT(besselj(0, 2*sqrt(a*t)), t, s) == (exp(-a/s)/s, 0, True)
|
||||
# assert (LT(t**(S(3)/2)*besselj(3, 2*sqrt(a*t)), t, s) ==
|
||||
# (a**(S(3)/2)*exp(-a/s)/s**4, 0, True))
|
||||
assert (LT(besselj(0, a*sqrt(t**2+b*t)), t, s, simplify=True) ==
|
||||
(exp(b*(s - sqrt(a**2 + s**2)))/sqrt(a**2 + s**2), 0, True))
|
||||
assert LT(besseli(0, a*t), t, s) == (1/sqrt(-a**2 + s**2), a, True)
|
||||
assert (LT(besseli(1, a*t), t, s, simplify=True) ==
|
||||
(a/(-a**2 + s**2 + s*sqrt(-a**2 + s**2)), a, True))
|
||||
assert (LT(besseli(2, a*t), t, s, simplify=True) ==
|
||||
(a**2/(sqrt(-a**2 + s**2)*(s + sqrt(-a**2 + s**2))**2), a, True))
|
||||
assert LT(t*besseli(0, a*t), t, s) == (s/(-a**2 + s**2)**(S(3)/2), a, True)
|
||||
assert LT(t*besseli(1, a*t), t, s) == (a/(-a**2 + s**2)**(S(3)/2), a, True)
|
||||
assert (LT(t**2*besseli(2, a*t), t, s) ==
|
||||
(3*a**2/(-a**2 + s**2)**(S(5)/2), a, True))
|
||||
# assert (LT(t**(S(3)/2)*besseli(3, 2*sqrt(a*t)), t, s) ==
|
||||
# (a**(S(3)/2)*exp(a/s)/s**4, 0, True))
|
||||
assert (LT(bessely(0, a*t), t, s) ==
|
||||
(-2*asinh(s/a)/(pi*sqrt(a**2 + s**2)), 0, True))
|
||||
assert (LT(besselk(0, a*t), t, s) ==
|
||||
(log((s + sqrt(-a**2 + s**2))/a)/sqrt(-a**2 + s**2), -a, True))
|
||||
assert (LT(sin(a*t)**4, t, s, simplify=True) ==
|
||||
(24*a**4/(s*(64*a**4 + 20*a**2*s**2 + s**4)), 0, True))
|
||||
# Test general rules and unevaluated forms
|
||||
# These all also test whether issue #7219 is solved.
|
||||
assert LT(Heaviside(t-1)*cos(t-1), t, s) == (s*exp(-s)/(s**2 + 1), 0, True)
|
||||
assert LT(a*f(t), t, w) == (a*LaplaceTransform(f(t), t, w), -oo, True)
|
||||
assert (LT(a*Heaviside(t+1)*f(t+1), t, s) ==
|
||||
(a*LaplaceTransform(f(t + 1), t, s), -oo, True))
|
||||
assert (LT(a*Heaviside(t-1)*f(t-1), t, s) ==
|
||||
(a*LaplaceTransform(f(t), t, s)*exp(-s), -oo, True))
|
||||
assert (LT(b*f(t/a), t, s) ==
|
||||
(a*b*LaplaceTransform(f(t), t, a*s), -oo, True))
|
||||
assert LT(exp(-f(x)*t), t, s) == (1/(s + f(x)), -re(f(x)), True)
|
||||
assert (LT(exp(-a*t)*f(t), t, s) ==
|
||||
(LaplaceTransform(f(t), t, a + s), -oo, True))
|
||||
# assert (LT(exp(-a*t)*erfc(sqrt(b/t)/2), t, s) ==
|
||||
# (exp(-sqrt(b)*sqrt(a + s))/(a + s), -a, True))
|
||||
assert (LT(sinh(a*t)*f(t), t, s) ==
|
||||
(LaplaceTransform(f(t), t, -a + s)/2 -
|
||||
LaplaceTransform(f(t), t, a + s)/2, -oo, True))
|
||||
assert (LT(sinh(a*t)*t, t, s, simplify=True) ==
|
||||
(2*a*s/(a**4 - 2*a**2*s**2 + s**4), a, True))
|
||||
assert (LT(cosh(a*t)*f(t), t, s) ==
|
||||
(LaplaceTransform(f(t), t, -a + s)/2 +
|
||||
LaplaceTransform(f(t), t, a + s)/2, -oo, True))
|
||||
assert (LT(cosh(a*t)*t, t, s, simplify=True) ==
|
||||
(1/(2*(a + s)**2) + 1/(2*(a - s)**2), a, True))
|
||||
assert (LT(sin(a*t)*f(t), t, s, simplify=True) ==
|
||||
(I*(-LaplaceTransform(f(t), t, -I*a + s) +
|
||||
LaplaceTransform(f(t), t, I*a + s))/2, -oo, True))
|
||||
assert (LT(sin(f(t)), t, s) ==
|
||||
(LaplaceTransform(sin(f(t)), t, s), -oo, True))
|
||||
assert (LT(sin(a*t)*t, t, s, simplify=True) ==
|
||||
(2*a*s/(a**4 + 2*a**2*s**2 + s**4), 0, True))
|
||||
assert (LT(cos(a*t)*f(t), t, s) ==
|
||||
(LaplaceTransform(f(t), t, -I*a + s)/2 +
|
||||
LaplaceTransform(f(t), t, I*a + s)/2, -oo, True))
|
||||
assert (LT(cos(a*t)*t, t, s, simplify=True) ==
|
||||
((-a**2 + s**2)/(a**4 + 2*a**2*s**2 + s**4), 0, True))
|
||||
L, plane, _ = LT(sin(a*t+b)**2*f(t), t, s)
|
||||
assert plane == -oo
|
||||
assert (
|
||||
-L + (
|
||||
LaplaceTransform(f(t), t, s)/2 -
|
||||
LaplaceTransform(f(t), t, -2*I*a + s)*exp(2*I*b)/4 -
|
||||
LaplaceTransform(f(t), t, 2*I*a + s)*exp(-2*I*b)/4)) == 0
|
||||
L = LT(sin(a*t+b)**2*f(t), t, s, noconds=True)
|
||||
assert (
|
||||
laplace_correspondence(L, {f: F}) ==
|
||||
F(s)/2 - F(-2*I*a + s)*exp(2*I*b)/4 -
|
||||
F(2*I*a + s)*exp(-2*I*b)/4)
|
||||
L, plane, _ = LT(sin(a*t)**3*cosh(b*t), t, s)
|
||||
assert plane == b
|
||||
assert (
|
||||
-L - 3*a/(8*(9*a**2 + b**2 + 2*b*s + s**2)) -
|
||||
3*a/(8*(9*a**2 + b**2 - 2*b*s + s**2)) +
|
||||
3*a/(8*(a**2 + b**2 + 2*b*s + s**2)) +
|
||||
3*a/(8*(a**2 + b**2 - 2*b*s + s**2))).simplify() == 0
|
||||
assert (LT(t**2*exp(-t**2), t, s) ==
|
||||
(sqrt(pi)*s**2*exp(s**2/4)*erfc(s/2)/8 - s/4 +
|
||||
sqrt(pi)*exp(s**2/4)*erfc(s/2)/4, 0, True))
|
||||
assert (LT((a*t**2 + b*t + c)*f(t), t, s) ==
|
||||
(a*Derivative(LaplaceTransform(f(t), t, s), (s, 2)) -
|
||||
b*Derivative(LaplaceTransform(f(t), t, s), s) +
|
||||
c*LaplaceTransform(f(t), t, s), -oo, True))
|
||||
assert (LT(t**np*g(t), t, s) ==
|
||||
((-1)**np*Derivative(LaplaceTransform(g(t), t, s), (s, np)),
|
||||
-oo, True))
|
||||
# The following tests check whether _piecewise_to_heaviside works:
|
||||
x1 = Piecewise((0, t <= 0), (1, t <= 1), (0, True))
|
||||
X1 = LT(x1, t, s)[0]
|
||||
assert X1 == 1/s - exp(-s)/s
|
||||
y1 = ILT(X1, s, t)
|
||||
assert y1 == Heaviside(t) - Heaviside(t - 1)
|
||||
x1 = Piecewise((0, t <= 0), (t, t <= 1), (2-t, t <= 2), (0, True))
|
||||
X1 = LT(x1, t, s)[0].simplify()
|
||||
assert X1 == (exp(2*s) - 2*exp(s) + 1)*exp(-2*s)/s**2
|
||||
y1 = ILT(X1, s, t)
|
||||
assert (
|
||||
-y1 + t*Heaviside(t) + (t - 2)*Heaviside(t - 2) -
|
||||
2*(t - 1)*Heaviside(t - 1)).simplify() == 0
|
||||
x1 = Piecewise((exp(t), t <= 0), (1, t <= 1), (exp(-(t)), True))
|
||||
X1 = LT(x1, t, s)[0]
|
||||
assert X1 == exp(-1)*exp(-s)/(s + 1) + 1/s - exp(-s)/s
|
||||
y1 = ILT(X1, s, t)
|
||||
assert y1 == (
|
||||
exp(-1)*exp(1 - t)*Heaviside(t - 1) + Heaviside(t) - Heaviside(t - 1))
|
||||
x1 = Piecewise((0, x <= 0), (1, x <= 1), (0, True))
|
||||
X1 = LT(x1, t, s)[0]
|
||||
assert X1 == Piecewise((0, x <= 0), (1, x <= 1), (0, True))/s
|
||||
x1 = [
|
||||
a*Piecewise((1, And(t > 1, t <= 3)), (2, True)),
|
||||
a*Piecewise((1, And(t >= 1, t <= 3)), (2, True)),
|
||||
a*Piecewise((1, And(t >= 1, t < 3)), (2, True)),
|
||||
a*Piecewise((1, And(t > 1, t < 3)), (2, True))]
|
||||
for x2 in x1:
|
||||
assert LT(x2, t, s)[0].expand() == 2*a/s - a*exp(-s)/s + a*exp(-3*s)/s
|
||||
assert (
|
||||
LT(Piecewise((1, Eq(t, 1)), (2, True)), t, s)[0] ==
|
||||
LaplaceTransform(Piecewise((1, Eq(t, 1)), (2, True)), t, s))
|
||||
# The following lines test whether _laplace_transform successfully
|
||||
# removes Heaviside(1) before processing espressions. It fails if
|
||||
# Heaviside(t) remains because then meijerg functions will appear.
|
||||
X1 = 1/sqrt(a*s**2-b)
|
||||
x1 = ILT(X1, s, t)
|
||||
Y1 = LT(x1, t, s)[0]
|
||||
Z1 = (Y1**2/X1**2).simplify()
|
||||
assert Z1 == 1
|
||||
# The following two lines test whether issues #5813 and #7176 are solved.
|
||||
assert (LT(diff(f(t), (t, 1)), t, s, noconds=True) ==
|
||||
s*LaplaceTransform(f(t), t, s) - f(0))
|
||||
assert (LT(diff(f(t), (t, 3)), t, s, noconds=True) ==
|
||||
s**3*LaplaceTransform(f(t), t, s) - s**2*f(0) -
|
||||
s*Subs(Derivative(f(t), t), t, 0) -
|
||||
Subs(Derivative(f(t), (t, 2)), t, 0))
|
||||
# Issue #7219
|
||||
assert (LT(diff(f(x, t, w), t, 2), t, s) ==
|
||||
(s**2*LaplaceTransform(f(x, t, w), t, s) - s*f(x, 0, w) -
|
||||
Subs(Derivative(f(x, t, w), t), t, 0), -oo, True))
|
||||
# Issue #23307
|
||||
assert (LT(10*diff(f(t), (t, 1)), t, s, noconds=True) ==
|
||||
10*s*LaplaceTransform(f(t), t, s) - 10*f(0))
|
||||
assert (LT(a*f(b*t)+g(c*t), t, s, noconds=True) ==
|
||||
a*LaplaceTransform(f(t), t, s/b)/b +
|
||||
LaplaceTransform(g(t), t, s/c)/c)
|
||||
assert inverse_laplace_transform(
|
||||
f(w), w, t, plane=0) == InverseLaplaceTransform(f(w), w, t, 0)
|
||||
assert (LT(f(t)*g(t), t, s, noconds=True) ==
|
||||
LaplaceTransform(f(t)*g(t), t, s))
|
||||
# Issue #24294
|
||||
assert (LT(b*f(a*t), t, s, noconds=True) ==
|
||||
b*LaplaceTransform(f(t), t, s/a)/a)
|
||||
assert LT(3*exp(t)*Heaviside(t), t, s) == (3/(s - 1), 1, True)
|
||||
assert (LT(2*sin(t)*Heaviside(t), t, s, simplify=True) ==
|
||||
(2/(s**2 + 1), 0, True))
|
||||
# Issue #25293
|
||||
assert (
|
||||
LT((1/(t-1))*sin(4*pi*(t-1))*DiracDelta(t-1) *
|
||||
(Heaviside(t-1/4) - Heaviside(t-2)), t, s)[0] == 4*pi*exp(-s))
|
||||
# additional basic tests from wikipedia
|
||||
assert (LT((t - a)**b*exp(-c*(t - a))*Heaviside(t - a), t, s) ==
|
||||
((c + s)**(-b - 1)*exp(-a*s)*gamma(b + 1), -c, True))
|
||||
assert (
|
||||
LT((exp(2*t)-1)*exp(-b-t)*Heaviside(t)/2, t, s, noconds=True,
|
||||
simplify=True) ==
|
||||
exp(-b)/(s**2 - 1))
|
||||
# DiracDelta function: standard cases
|
||||
assert LT(DiracDelta(t), t, s) == (1, -oo, True)
|
||||
assert LT(DiracDelta(a*t), t, s) == (1/a, -oo, True)
|
||||
assert LT(DiracDelta(t/42), t, s) == (42, -oo, True)
|
||||
assert LT(DiracDelta(t+42), t, s) == (0, -oo, True)
|
||||
assert (LT(DiracDelta(t)+DiracDelta(t-42), t, s) ==
|
||||
(1 + exp(-42*s), -oo, True))
|
||||
assert (LT(DiracDelta(t)-a*exp(-a*t), t, s, simplify=True) ==
|
||||
(s/(a + s), -a, True))
|
||||
assert (
|
||||
LT(exp(-t)*(DiracDelta(t)+DiracDelta(t-42)), t, s, simplify=True) ==
|
||||
(exp(-42*s - 42) + 1, -oo, True))
|
||||
assert LT(f(t)*DiracDelta(t-42), t, s) == (f(42)*exp(-42*s), -oo, True)
|
||||
assert LT(f(t)*DiracDelta(b*t-a), t, s) == (f(a/b)*exp(-a*s/b)/b,
|
||||
-oo, True)
|
||||
assert LT(f(t)*DiracDelta(b*t+a), t, s) == (0, -oo, True)
|
||||
# SingularityFunction
|
||||
assert LT(SingularityFunction(t, a, -1), t, s)[0] == exp(-a*s)
|
||||
assert LT(SingularityFunction(t, a, 1), t, s)[0] == exp(-a*s)/s**2
|
||||
assert LT(SingularityFunction(t, a, x), t, s)[0] == (
|
||||
LaplaceTransform(SingularityFunction(t, a, x), t, s))
|
||||
# Collection of cases that cannot be fully evaluated and/or would catch
|
||||
# some common implementation errors
|
||||
assert (LT(DiracDelta(t**2), t, s, noconds=True) ==
|
||||
LaplaceTransform(DiracDelta(t**2), t, s))
|
||||
assert LT(DiracDelta(t**2 - 1), t, s) == (exp(-s)/2, -oo, True)
|
||||
assert LT(DiracDelta(t*(1 - t)), t, s) == (1 - exp(-s), -oo, True)
|
||||
assert (LT((DiracDelta(t) + 1)*(DiracDelta(t - 1) + 1), t, s) ==
|
||||
(LaplaceTransform(DiracDelta(t)*DiracDelta(t - 1), t, s) +
|
||||
1 + exp(-s) + 1/s, 0, True))
|
||||
assert LT(DiracDelta(2*t-2*exp(a)), t, s) == (exp(-s*exp(a))/2, -oo, True)
|
||||
assert LT(DiracDelta(-2*t+2*exp(a)), t, s) == (exp(-s*exp(a))/2, -oo, True)
|
||||
# Heaviside tests
|
||||
assert LT(Heaviside(t), t, s) == (1/s, 0, True)
|
||||
assert LT(Heaviside(t - a), t, s) == (exp(-a*s)/s, 0, True)
|
||||
assert LT(Heaviside(t-1), t, s) == (exp(-s)/s, 0, True)
|
||||
assert LT(Heaviside(2*t-4), t, s) == (exp(-2*s)/s, 0, True)
|
||||
assert LT(Heaviside(2*t+4), t, s) == (1/s, 0, True)
|
||||
assert (LT(Heaviside(-2*t+4), t, s, simplify=True) ==
|
||||
(1/s - exp(-2*s)/s, 0, True))
|
||||
assert (LT(g(t)*Heaviside(t - w), t, s) ==
|
||||
(LaplaceTransform(g(t)*Heaviside(t - w), t, s), -oo, True))
|
||||
assert (
|
||||
LT(Heaviside(t-a)*g(t), t, s) ==
|
||||
(LaplaceTransform(g(a + t), t, s)*exp(-a*s), -oo, True))
|
||||
assert (
|
||||
LT(Heaviside(t+a)*g(t), t, s) ==
|
||||
(LaplaceTransform(g(t), t, s), -oo, True))
|
||||
assert (
|
||||
LT(Heaviside(-t+a)*g(t), t, s) ==
|
||||
(LaplaceTransform(g(t), t, s) -
|
||||
LaplaceTransform(g(a + t), t, s)*exp(-a*s), -oo, True))
|
||||
assert (
|
||||
LT(Heaviside(-t-a)*g(t), t, s) == (0, 0, True))
|
||||
# Fresnel functions
|
||||
assert (laplace_transform(fresnels(t), t, s, simplify=True) ==
|
||||
((-sin(s**2/(2*pi))*fresnels(s/pi) +
|
||||
sqrt(2)*sin(s**2/(2*pi) + pi/4)/2 -
|
||||
cos(s**2/(2*pi))*fresnelc(s/pi))/s, 0, True))
|
||||
assert (laplace_transform(fresnelc(t), t, s, simplify=True) ==
|
||||
((sin(s**2/(2*pi))*fresnelc(s/pi) -
|
||||
cos(s**2/(2*pi))*fresnels(s/pi) +
|
||||
sqrt(2)*cos(s**2/(2*pi) + pi/4)/2)/s, 0, True))
|
||||
# Matrix tests
|
||||
Mt = Matrix([[exp(t), t*exp(-t)], [t*exp(-t), exp(t)]])
|
||||
Ms = Matrix([[1/(s - 1), (s + 1)**(-2)],
|
||||
[(s + 1)**(-2), 1/(s - 1)]])
|
||||
# The default behaviour for Laplace transform of a Matrix returns a Matrix
|
||||
# of Tuples and is deprecated:
|
||||
with warns_deprecated_sympy():
|
||||
Ms_conds = Matrix(
|
||||
[[(1/(s - 1), 1, True), ((s + 1)**(-2), -1, True)],
|
||||
[((s + 1)**(-2), -1, True), (1/(s - 1), 1, True)]])
|
||||
with warns_deprecated_sympy():
|
||||
assert LT(Mt, t, s) == Ms_conds
|
||||
# The new behavior is to return a tuple of a Matrix and the convergence
|
||||
# conditions for the matrix as a whole:
|
||||
assert LT(Mt, t, s, legacy_matrix=False) == (Ms, 1, True)
|
||||
# With noconds=True the transformed matrix is returned without conditions
|
||||
# either way:
|
||||
assert LT(Mt, t, s, noconds=True) == Ms
|
||||
assert LT(Mt, t, s, legacy_matrix=False, noconds=True) == Ms
|
||||
|
||||
|
||||
@slow
|
||||
def test_inverse_laplace_transform():
|
||||
s = symbols('s')
|
||||
k, n, t = symbols('k, n, t', real=True)
|
||||
a, b, c, d = symbols('a, b, c, d', positive=True)
|
||||
f = Function('f')
|
||||
F = Function('F')
|
||||
|
||||
def ILT(g):
|
||||
return inverse_laplace_transform(g, s, t)
|
||||
|
||||
def ILTS(g):
|
||||
return inverse_laplace_transform(g, s, t, simplify=True)
|
||||
|
||||
def ILTF(g):
|
||||
return laplace_correspondence(
|
||||
inverse_laplace_transform(g, s, t), {f: F})
|
||||
|
||||
# Tests for the rules in Bateman54.
|
||||
|
||||
# Section 4.1: Some of the Laplace transform rules can also be used well
|
||||
# in the inverse transform.
|
||||
assert ILTF(exp(-a*s)*F(s)) == f(-a + t)
|
||||
assert ILTF(k*F(s-a)) == k*f(t)*exp(-a*t)
|
||||
assert ILTF(diff(F(s), s, 3)) == -t**3*f(t)
|
||||
assert ILTF(diff(F(s), s, 4)) == t**4*f(t)
|
||||
|
||||
# Section 5.1: Most rules are impractical for a computer algebra system.
|
||||
|
||||
# Section 5.2: Rational functions
|
||||
assert ILT(2) == 2*DiracDelta(t)
|
||||
assert ILT(1/s) == Heaviside(t)
|
||||
assert ILT(1/s**2) == t*Heaviside(t)
|
||||
assert ILT(1/s**5) == t**4*Heaviside(t)/24
|
||||
assert ILT(1/s**n) == t**(n - 1)*Heaviside(t)/gamma(n)
|
||||
assert ILT(a/(a + s)) == a*exp(-a*t)*Heaviside(t)
|
||||
assert ILT(s/(a + s)) == -a*exp(-a*t)*Heaviside(t) + DiracDelta(t)
|
||||
assert (ILT(b*s/(s+a)**2) ==
|
||||
b*(-a*t*exp(-a*t)*Heaviside(t) + exp(-a*t)*Heaviside(t)))
|
||||
assert (ILTS(c/((s+a)*(s+b))) ==
|
||||
c*(exp(a*t) - exp(b*t))*exp(-t*(a + b))*Heaviside(t)/(a - b))
|
||||
assert (ILTS(c*s/((s+a)*(s+b))) ==
|
||||
c*(a*exp(b*t) - b*exp(a*t))*exp(-t*(a + b))*Heaviside(t)/(a - b))
|
||||
assert ILTS(s/(a + s)**3) == t*(-a*t + 2)*exp(-a*t)*Heaviside(t)/2
|
||||
assert ILTS(1/(s*(a + s)**3)) == (
|
||||
-a**2*t**2 - 2*a*t + 2*exp(a*t) - 2)*exp(-a*t)*Heaviside(t)/(2*a**3)
|
||||
assert ILT(1/(s*(a + s)**n)) == (
|
||||
Heaviside(t)*lowergamma(n, a*t)/(a**n*gamma(n)))
|
||||
assert ILT((s-a)**(-b)) == t**(b - 1)*exp(a*t)*Heaviside(t)/gamma(b)
|
||||
assert ILT((a + s)**(-2)) == t*exp(-a*t)*Heaviside(t)
|
||||
assert ILT((a + s)**(-5)) == t**4*exp(-a*t)*Heaviside(t)/24
|
||||
assert ILT(s**2/(s**2 + 1)) == -sin(t)*Heaviside(t) + DiracDelta(t)
|
||||
assert ILT(1 - 1/(s**2 + 1)) == -sin(t)*Heaviside(t) + DiracDelta(t)
|
||||
assert ILT(a/(a**2 + s**2)) == sin(a*t)*Heaviside(t)
|
||||
assert ILT(s/(s**2 + a**2)) == cos(a*t)*Heaviside(t)
|
||||
assert ILT(b/(b**2 + (a + s)**2)) == exp(-a*t)*sin(b*t)*Heaviside(t)
|
||||
assert (ILT(b*s/(b**2 + (a + s)**2)) ==
|
||||
b*(-a*exp(-a*t)*sin(b*t)/b + exp(-a*t)*cos(b*t))*Heaviside(t))
|
||||
assert ILT(1/(s**2*(s**2 + 1))) == t*Heaviside(t) - sin(t)*Heaviside(t)
|
||||
assert (ILTS(c*s/(d**2*(s+a)**2+b**2)) ==
|
||||
c*(-a*d*sin(b*t/d) + b*cos(b*t/d))*exp(-a*t)*Heaviside(t)/(b*d**2))
|
||||
assert ILTS((b*s**2 + d)/(a**2 + s**2)**2) == (
|
||||
2*a**2*b*sin(a*t) + (a**2*b - d)*(a*t*cos(a*t) -
|
||||
sin(a*t)))*Heaviside(t)/(2*a**3)
|
||||
assert ILTS(b/(s**2-a**2)) == b*sinh(a*t)*Heaviside(t)/a
|
||||
assert (ILT(b/(s**2-a**2)) ==
|
||||
b*(exp(a*t)*Heaviside(t)/(2*a) - exp(-a*t)*Heaviside(t)/(2*a)))
|
||||
assert ILTS(b*s/(s**2-a**2)) == b*cosh(a*t)*Heaviside(t)
|
||||
assert (ILT(b/(s*(s+a))) ==
|
||||
b*(Heaviside(t)/a - exp(-a*t)*Heaviside(t)/a))
|
||||
# Issue #24424
|
||||
assert (ILTS((s + 8)/((s + 2)*(s**2 + 2*s + 10))) ==
|
||||
((8*sin(3*t) - 9*cos(3*t))*exp(t) + 9)*exp(-2*t)*Heaviside(t)/15)
|
||||
# Issue #8514; this is not important anymore, since this function
|
||||
# is not solved by integration anymore
|
||||
assert (ILT(1/(a*s**2+b*s+c)) ==
|
||||
2*exp(-b*t/(2*a))*sin(t*sqrt(4*a*c - b**2)/(2*a)) *
|
||||
Heaviside(t)/sqrt(4*a*c - b**2))
|
||||
|
||||
# Section 5.3: Irrational algebraic functions
|
||||
assert ( # (1)
|
||||
ILT(1/sqrt(s)/(b*s-a)) ==
|
||||
exp(a*t/b)*Heaviside(t)*erf(sqrt(a)*sqrt(t)/sqrt(b))/(sqrt(a)*sqrt(b)))
|
||||
assert ( # (2)
|
||||
ILT(1/sqrt(k*s)/(c*s-a)/s) ==
|
||||
(-2*c*sqrt(t)/(sqrt(pi)*a) +
|
||||
c**(S(3)/2)*exp(a*t/c)*erf(sqrt(a)*sqrt(t)/sqrt(c))/a**(S(3)/2)) *
|
||||
Heaviside(t)/(c*sqrt(k)))
|
||||
assert ( # (4)
|
||||
ILT(1/(sqrt(c*s)+a)) == (-a*exp(a**2*t/c)*erfc(a*sqrt(t)/sqrt(c))/c +
|
||||
1/(sqrt(pi)*sqrt(c)*sqrt(t)))*Heaviside(t))
|
||||
assert ( # (5)
|
||||
ILT(a/s/(b*sqrt(s)+a)) ==
|
||||
(-exp(a**2*t/b**2)*erfc(a*sqrt(t)/b) + 1)*Heaviside(t))
|
||||
assert ( # (6)
|
||||
ILT((a-b)*sqrt(s)/(sqrt(s)+sqrt(a))/(s-b)) ==
|
||||
(sqrt(a)*sqrt(b)*exp(b*t)*erfc(sqrt(b)*sqrt(t)) +
|
||||
a*exp(a*t)*erfc(sqrt(a)*sqrt(t)) - b*exp(b*t))*Heaviside(t))
|
||||
assert ( # (7)
|
||||
ILT(1/sqrt(s)/(sqrt(b*s)+a)) ==
|
||||
exp(a**2*t/b)*Heaviside(t)*erfc(a*sqrt(t)/sqrt(b))/sqrt(b))
|
||||
assert ( # (8)
|
||||
ILT(a**2/(sqrt(s)+a)/s**(S(3)/2)) ==
|
||||
(2*a*sqrt(t)/sqrt(pi) + exp(a**2*t)*erfc(a*sqrt(t)) - 1) *
|
||||
Heaviside(t))
|
||||
assert ( # (9)
|
||||
ILT((a-b)*sqrt(b)/(s-b)/sqrt(s)/(sqrt(s)+sqrt(a))) ==
|
||||
(sqrt(a)*exp(b*t)*erf(sqrt(b)*sqrt(t)) +
|
||||
sqrt(b)*exp(a*t)*erfc(sqrt(a)*sqrt(t)) -
|
||||
sqrt(b)*exp(b*t))*Heaviside(t))
|
||||
assert ( # (10)
|
||||
ILT(1/(sqrt(s)+sqrt(a))**2) ==
|
||||
(-2*sqrt(a)*sqrt(t)/sqrt(pi) +
|
||||
(-2*a*t + 1)*(erf(sqrt(a)*sqrt(t)) -
|
||||
1)*exp(a*t) + 1)*Heaviside(t))
|
||||
assert ( # (11)
|
||||
ILT(1/(sqrt(s)+sqrt(a))**2/s) ==
|
||||
((2*t - 1/a)*exp(a*t)*erfc(sqrt(a)*sqrt(t)) + 1/a -
|
||||
2*sqrt(t)/(sqrt(pi)*sqrt(a)))*Heaviside(t))
|
||||
assert ( # (12)
|
||||
ILT(1/(sqrt(s)+a)**2/sqrt(s)) ==
|
||||
(-2*a*t*exp(a**2*t)*erfc(a*sqrt(t)) +
|
||||
2*sqrt(t)/sqrt(pi))*Heaviside(t))
|
||||
assert ( # (13)
|
||||
ILT(1/(sqrt(s)+a)**3) ==
|
||||
(-a*t*(2*a**2*t + 3)*exp(a**2*t)*erfc(a*sqrt(t)) +
|
||||
2*sqrt(t)*(a**2*t + 1)/sqrt(pi))*Heaviside(t))
|
||||
x = (
|
||||
- ILT(sqrt(s)/(sqrt(s)+a)**3) +
|
||||
2*(sqrt(pi)*a**2*t*(-2*sqrt(pi)*erfc(a*sqrt(t)) +
|
||||
2*exp(-a**2*t)/(a*sqrt(t))) *
|
||||
(-a**4*t**2 - 5*a**2*t/2 - S.Half) * exp(a**2*t)/2 +
|
||||
sqrt(pi)*a*sqrt(t)*(a**2*t + 1)/2) *
|
||||
Heaviside(t)/(pi*a**2*t)).simplify()
|
||||
assert ( # (14)
|
||||
x == 0)
|
||||
x = (
|
||||
- ILT(1/sqrt(s)/(sqrt(s)+a)**3) +
|
||||
Heaviside(t)*(sqrt(t)*((2*a**2*t + 1) *
|
||||
(sqrt(pi)*a*sqrt(t)*exp(a**2*t) *
|
||||
erfc(a*sqrt(t)) - 1) + 1) /
|
||||
(sqrt(pi)*a))).simplify()
|
||||
assert ( # (15)
|
||||
x == 0)
|
||||
assert ( # (16)
|
||||
factor_terms(ILT(3/(sqrt(s)+a)**4)) ==
|
||||
3*(-2*a**3*t**(S(5)/2)*(2*a**2*t + 5)/(3*sqrt(pi)) +
|
||||
t*(4*a**4*t**2 + 12*a**2*t + 3)*exp(a**2*t) *
|
||||
erfc(a*sqrt(t))/3)*Heaviside(t))
|
||||
assert ( # (17)
|
||||
ILT((sqrt(s)-a)/(s*(sqrt(s)+a))) ==
|
||||
(2*exp(a**2*t)*erfc(a*sqrt(t))-1)*Heaviside(t))
|
||||
assert ( # (18)
|
||||
ILT((sqrt(s)-a)**2/(s*(sqrt(s)+a)**2)) == (
|
||||
1 + 8*a**2*t*exp(a**2*t)*erfc(a*sqrt(t)) -
|
||||
8/sqrt(pi)*a*sqrt(t))*Heaviside(t))
|
||||
assert ( # (19)
|
||||
ILT((sqrt(s)-a)**3/(s*(sqrt(s)+a)**3)) == Heaviside(t)*(
|
||||
2*(8*a**4*t**2+8*a**2*t+1)*exp(a**2*t) *
|
||||
erfc(a*sqrt(t))-8/sqrt(pi)*a*sqrt(t)*(2*a**2*t+1)-1))
|
||||
assert ( # (22)
|
||||
ILT(sqrt(s+a)/(s+b)) == Heaviside(t)*(
|
||||
exp(-a*t)/sqrt(t)/sqrt(pi) +
|
||||
sqrt(a-b)*exp(-b*t)*erf(sqrt(a-b)*sqrt(t))))
|
||||
assert ( # (23)
|
||||
ILT(1/sqrt(s+b)/(s+a)) == Heaviside(t)*(
|
||||
1/sqrt(b-a)*exp(-a*t)*erf(sqrt(b-a)*sqrt(t))))
|
||||
assert ( # (35)
|
||||
ILT(1/sqrt(s**2+a**2)) == Heaviside(t)*(
|
||||
besselj(0, a*t)))
|
||||
assert ( # (44)
|
||||
ILT(1/sqrt(s**2-a**2)) == Heaviside(t)*(
|
||||
besseli(0, a*t)))
|
||||
|
||||
# Miscellaneous tests
|
||||
# Can _inverse_laplace_time_shift deal with positive exponents?
|
||||
assert (
|
||||
- ILT((s**2*exp(2*s) + 4*exp(s) - 4)*exp(-2*s)/(s*(s**2 + 1))) +
|
||||
cos(t)*Heaviside(t) + 4*cos(t - 2)*Heaviside(t - 2) -
|
||||
4*cos(t - 1)*Heaviside(t - 1) - 4*Heaviside(t - 2) +
|
||||
4*Heaviside(t - 1)).simplify() == 0
|
||||
|
||||
|
||||
@slow
|
||||
def test_inverse_laplace_transform_old():
|
||||
from sympy.functions.special.delta_functions import DiracDelta
|
||||
ILT = inverse_laplace_transform
|
||||
a, b, c, d = symbols('a b c d', positive=True)
|
||||
n, r = symbols('n, r', real=True)
|
||||
t, z = symbols('t z')
|
||||
f = Function('f')
|
||||
F = Function('F')
|
||||
|
||||
def simp_hyp(expr):
|
||||
return factor_terms(expand_mul(expr)).rewrite(sin)
|
||||
|
||||
L = ILT(F(s), s, t)
|
||||
assert laplace_correspondence(L, {f: F}) == f(t)
|
||||
assert ILT(exp(-a*s)/s, s, t) == Heaviside(-a + t)
|
||||
assert ILT(exp(-a*s)/(b + s), s, t) == exp(-b*(-a + t))*Heaviside(-a + t)
|
||||
assert (ILT((b + s)/(a**2 + (b + s)**2), s, t) ==
|
||||
exp(-b*t)*cos(a*t)*Heaviside(t))
|
||||
assert (ILT(exp(-a*s)/s**b, s, t) ==
|
||||
(-a + t)**(b - 1)*Heaviside(-a + t)/gamma(b))
|
||||
assert (ILT(exp(-a*s)/sqrt(s**2 + 1), s, t) ==
|
||||
Heaviside(-a + t)*besselj(0, a - t))
|
||||
assert ILT(1/(s*sqrt(s + 1)), s, t) == Heaviside(t)*erf(sqrt(t))
|
||||
# TODO sinh/cosh shifted come out a mess. also delayed trig is a mess
|
||||
# TODO should this simplify further?
|
||||
assert (ILT(exp(-a*s)/s**b, s, t) ==
|
||||
(t - a)**(b - 1)*Heaviside(t - a)/gamma(b))
|
||||
assert (ILT(exp(-a*s)/sqrt(1 + s**2), s, t) ==
|
||||
Heaviside(t - a)*besselj(0, a - t)) # note: besselj(0, x) is even
|
||||
# XXX ILT turns these branch factor into trig functions ...
|
||||
assert (
|
||||
simplify(ILT(a**b*(s + sqrt(s**2 - a**2))**(-b)/sqrt(s**2 - a**2),
|
||||
s, t).rewrite(exp)) ==
|
||||
Heaviside(t)*besseli(b, a*t))
|
||||
assert (
|
||||
ILT(a**b*(s + sqrt(s**2 + a**2))**(-b)/sqrt(s**2 + a**2),
|
||||
s, t, simplify=True).rewrite(exp) ==
|
||||
Heaviside(t)*besselj(b, a*t))
|
||||
assert ILT(1/(s*sqrt(s + 1)), s, t) == Heaviside(t)*erf(sqrt(t))
|
||||
# TODO can we make erf(t) work?
|
||||
assert (ILT((s * eye(2) - Matrix([[1, 0], [0, 2]])).inv(), s, t) ==
|
||||
Matrix([[exp(t)*Heaviside(t), 0], [0, exp(2*t)*Heaviside(t)]]))
|
||||
# Test time_diff rule
|
||||
assert (ILT(s**42*f(s), s, t) ==
|
||||
Derivative(InverseLaplaceTransform(f(s), s, t, None), (t, 42)))
|
||||
assert ILT(cos(s), s, t) == InverseLaplaceTransform(cos(s), s, t, None)
|
||||
# Rules for testing different DiracDelta cases
|
||||
assert (
|
||||
ILT(1 + 2*s + 3*s**2 + 5*s**3, s, t) == DiracDelta(t) +
|
||||
2*DiracDelta(t, 1) + 3*DiracDelta(t, 2) + 5*DiracDelta(t, 3))
|
||||
assert (ILT(2*exp(3*s) - 5*exp(-7*s), s, t) ==
|
||||
2*InverseLaplaceTransform(exp(3*s), s, t, None) -
|
||||
5*DiracDelta(t - 7))
|
||||
a = cos(sin(7)/2)
|
||||
assert ILT(a*exp(-3*s), s, t) == a*DiracDelta(t - 3)
|
||||
assert ILT(exp(2*s), s, t) == InverseLaplaceTransform(exp(2*s), s, t, None)
|
||||
r = Symbol('r', real=True)
|
||||
assert ILT(exp(r*s), s, t) == InverseLaplaceTransform(exp(r*s), s, t, None)
|
||||
# Rules for testing whether Heaviside(t) is treated properly in diff rule
|
||||
assert ILT(s**2/(a**2 + s**2), s, t) == (
|
||||
-a*sin(a*t)*Heaviside(t) + DiracDelta(t))
|
||||
assert ILT(s**2*(f(s) + 1/(a**2 + s**2)), s, t) == (
|
||||
-a*sin(a*t)*Heaviside(t) + DiracDelta(t) +
|
||||
Derivative(InverseLaplaceTransform(f(s), s, t, None), (t, 2)))
|
||||
# Rules from the previous test_inverse_laplace_transform_delta_cond():
|
||||
assert (ILT(exp(r*s), s, t, noconds=False) ==
|
||||
(InverseLaplaceTransform(exp(r*s), s, t, None), True))
|
||||
# inversion does not exist: verify it doesn't evaluate to DiracDelta
|
||||
for z in (Symbol('z', extended_real=False),
|
||||
Symbol('z', imaginary=True, zero=False)):
|
||||
f = ILT(exp(z*s), s, t, noconds=False)
|
||||
f = f[0] if isinstance(f, tuple) else f
|
||||
assert f.func != DiracDelta
|
||||
|
||||
|
||||
@slow
|
||||
def test_expint():
|
||||
x = Symbol('x')
|
||||
a = Symbol('a')
|
||||
u = Symbol('u', polar=True)
|
||||
|
||||
# TODO LT of Si, Shi, Chi is a mess ...
|
||||
assert laplace_transform(Ci(x), x, s) == (-log(1 + s**2)/2/s, 0, True)
|
||||
assert (laplace_transform(expint(a, x), x, s, simplify=True) ==
|
||||
(lerchphi(s*exp_polar(I*pi), 1, a), 0, re(a) > S.Zero))
|
||||
assert (laplace_transform(expint(1, x), x, s, simplify=True) ==
|
||||
(log(s + 1)/s, 0, True))
|
||||
assert (laplace_transform(expint(2, x), x, s, simplify=True) ==
|
||||
((s - log(s + 1))/s**2, 0, True))
|
||||
assert (inverse_laplace_transform(-log(1 + s**2)/2/s, s, u).expand() ==
|
||||
Heaviside(u)*Ci(u))
|
||||
assert (
|
||||
inverse_laplace_transform(log(s + 1)/s, s, x,
|
||||
simplify=True).rewrite(expint) ==
|
||||
Heaviside(x)*E1(x))
|
||||
assert (
|
||||
inverse_laplace_transform(
|
||||
(s - log(s + 1))/s**2, s, x,
|
||||
simplify=True).rewrite(expint).expand() ==
|
||||
(expint(2, x)*Heaviside(x)).rewrite(Ei).rewrite(expint).expand())
|
||||
@@ -0,0 +1,13 @@
|
||||
from sympy.core.numbers import E
|
||||
from sympy.core.symbol import symbols
|
||||
from sympy.functions.elementary.exponential import log
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.geometry.curve import Curve
|
||||
from sympy.integrals.integrals import line_integrate
|
||||
|
||||
s, t, x, y, z = symbols('s,t,x,y,z')
|
||||
|
||||
|
||||
def test_lineintegral():
|
||||
c = Curve([E**t + 1, E**t - 1], (t, 0, log(2)))
|
||||
assert line_integrate(x + y, c, [x, y]) == 3*sqrt(2)
|
||||
@@ -0,0 +1,714 @@
|
||||
from sympy.core.expr import Expr
|
||||
from sympy.core.mul import Mul
|
||||
from sympy.core.function import (Derivative, Function, diff, expand)
|
||||
from sympy.core.numbers import (I, Rational, pi)
|
||||
from sympy.core.relational import Ne
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import (Dummy, Symbol, symbols)
|
||||
from sympy.functions.elementary.exponential import (exp, log)
|
||||
from sympy.functions.elementary.hyperbolic import (asinh, csch, cosh, coth, sech, sinh, tanh)
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.piecewise import Piecewise, piecewise_fold
|
||||
from sympy.functions.elementary.trigonometric import (acos, acot, acsc, asec, asin, atan, cos, cot, csc, sec, sin, tan)
|
||||
from sympy.functions.special.delta_functions import Heaviside, DiracDelta
|
||||
from sympy.functions.special.elliptic_integrals import (elliptic_e, elliptic_f)
|
||||
from sympy.functions.special.error_functions import (Chi, Ci, Ei, Shi, Si, erf, erfi, fresnelc, fresnels, li)
|
||||
from sympy.functions.special.gamma_functions import uppergamma
|
||||
from sympy.functions.special.polynomials import (assoc_laguerre, chebyshevt, chebyshevu, gegenbauer, hermite, jacobi, laguerre, legendre)
|
||||
from sympy.functions.special.zeta_functions import polylog
|
||||
from sympy.integrals.integrals import (Integral, integrate)
|
||||
from sympy.logic.boolalg import And
|
||||
from sympy.integrals.manualintegrate import (manualintegrate, find_substitutions,
|
||||
_parts_rule, integral_steps, manual_subs)
|
||||
from sympy.testing.pytest import raises, slow
|
||||
|
||||
x, y, z, u, n, a, b, c, d, e = symbols('x y z u n a b c d e')
|
||||
f = Function('f')
|
||||
|
||||
|
||||
def assert_is_integral_of(f: Expr, F: Expr):
|
||||
assert manualintegrate(f, x) == F
|
||||
assert F.diff(x).equals(f)
|
||||
|
||||
|
||||
def test_find_substitutions():
|
||||
assert find_substitutions((cot(x)**2 + 1)**2*csc(x)**2*cot(x)**2, x, u) == \
|
||||
[(cot(x), 1, -u**6 - 2*u**4 - u**2)]
|
||||
assert find_substitutions((sec(x)**2 + tan(x) * sec(x)) / (sec(x) + tan(x)),
|
||||
x, u) == [(sec(x) + tan(x), 1, 1/u)]
|
||||
assert (-x**2, Rational(-1, 2), exp(u)) in find_substitutions(x * exp(-x**2), x, u)
|
||||
assert not find_substitutions(Derivative(f(x), x)**2, x, u)
|
||||
|
||||
|
||||
def test_manualintegrate_polynomials():
|
||||
assert manualintegrate(y, x) == x*y
|
||||
assert manualintegrate(exp(2), x) == x * exp(2)
|
||||
assert manualintegrate(x**2, x) == x**3 / 3
|
||||
assert manualintegrate(3 * x**2 + 4 * x**3, x) == x**3 + x**4
|
||||
|
||||
assert manualintegrate((x + 2)**3, x) == (x + 2)**4 / 4
|
||||
assert manualintegrate((3*x + 4)**2, x) == (3*x + 4)**3 / 9
|
||||
|
||||
assert manualintegrate((u + 2)**3, u) == (u + 2)**4 / 4
|
||||
assert manualintegrate((3*u + 4)**2, u) == (3*u + 4)**3 / 9
|
||||
|
||||
|
||||
def test_manualintegrate_exponentials():
|
||||
assert manualintegrate(exp(2*x), x) == exp(2*x) / 2
|
||||
assert manualintegrate(2**x, x) == (2 ** x) / log(2)
|
||||
assert_is_integral_of(1/sqrt(1-exp(2*x)),
|
||||
log(sqrt(1 - exp(2*x)) - 1)/2 - log(sqrt(1 - exp(2*x)) + 1)/2)
|
||||
|
||||
assert manualintegrate(1 / x, x) == log(x)
|
||||
assert manualintegrate(1 / (2*x + 3), x) == log(2*x + 3) / 2
|
||||
assert manualintegrate(log(x)**2 / x, x) == log(x)**3 / 3
|
||||
|
||||
assert_is_integral_of(x**x*(log(x)+1), x**x)
|
||||
|
||||
|
||||
def test_manualintegrate_parts():
|
||||
assert manualintegrate(exp(x) * sin(x), x) == \
|
||||
(exp(x) * sin(x)) / 2 - (exp(x) * cos(x)) / 2
|
||||
assert manualintegrate(2*x*cos(x), x) == 2*x*sin(x) + 2*cos(x)
|
||||
assert manualintegrate(x * log(x), x) == x**2*log(x)/2 - x**2/4
|
||||
assert manualintegrate(log(x), x) == x * log(x) - x
|
||||
assert manualintegrate((3*x**2 + 5) * exp(x), x) == \
|
||||
3*x**2*exp(x) - 6*x*exp(x) + 11*exp(x)
|
||||
assert manualintegrate(atan(x), x) == x*atan(x) - log(x**2 + 1)/2
|
||||
|
||||
# Make sure _parts_rule doesn't pick u = constant but can pick dv =
|
||||
# constant if necessary, e.g. for integrate(atan(x))
|
||||
assert _parts_rule(cos(x), x) == None
|
||||
assert _parts_rule(exp(x), x) == None
|
||||
assert _parts_rule(x**2, x) == None
|
||||
result = _parts_rule(atan(x), x)
|
||||
assert result[0] == atan(x) and result[1] == 1
|
||||
|
||||
|
||||
def test_manualintegrate_trigonometry():
|
||||
assert manualintegrate(sin(x), x) == -cos(x)
|
||||
assert manualintegrate(tan(x), x) == -log(cos(x))
|
||||
|
||||
assert manualintegrate(sec(x), x) == log(sec(x) + tan(x))
|
||||
assert manualintegrate(csc(x), x) == -log(csc(x) + cot(x))
|
||||
|
||||
assert manualintegrate(sin(x) * cos(x), x) in [sin(x) ** 2 / 2, -cos(x)**2 / 2]
|
||||
assert manualintegrate(-sec(x) * tan(x), x) == -sec(x)
|
||||
assert manualintegrate(csc(x) * cot(x), x) == -csc(x)
|
||||
assert manualintegrate(sec(x)**2, x) == tan(x)
|
||||
assert manualintegrate(csc(x)**2, x) == -cot(x)
|
||||
|
||||
assert manualintegrate(x * sec(x**2), x) == log(tan(x**2) + sec(x**2))/2
|
||||
assert manualintegrate(cos(x)*csc(sin(x)), x) == -log(cot(sin(x)) + csc(sin(x)))
|
||||
assert manualintegrate(cos(3*x)*sec(x), x) == -x + sin(2*x)
|
||||
assert manualintegrate(sin(3*x)*sec(x), x) == \
|
||||
-3*log(cos(x)) + 2*log(cos(x)**2) - 2*cos(x)**2
|
||||
|
||||
assert_is_integral_of(sinh(2*x), cosh(2*x)/2)
|
||||
assert_is_integral_of(x*cosh(x**2), sinh(x**2)/2)
|
||||
assert_is_integral_of(tanh(x), log(cosh(x)))
|
||||
assert_is_integral_of(coth(x), log(sinh(x)))
|
||||
f, F = sech(x), 2*atan(tanh(x/2))
|
||||
assert manualintegrate(f, x) == F
|
||||
assert (F.diff(x) - f).rewrite(exp).simplify() == 0 # todo: equals returns None
|
||||
f, F = csch(x), log(tanh(x/2))
|
||||
assert manualintegrate(f, x) == F
|
||||
assert (F.diff(x) - f).rewrite(exp).simplify() == 0
|
||||
|
||||
|
||||
@slow
|
||||
def test_manualintegrate_trigpowers():
|
||||
assert manualintegrate(sin(x)**2 * cos(x), x) == sin(x)**3 / 3
|
||||
assert manualintegrate(sin(x)**2 * cos(x) **2, x) == \
|
||||
x / 8 - sin(4*x) / 32
|
||||
assert manualintegrate(sin(x) * cos(x)**3, x) == -cos(x)**4 / 4
|
||||
assert manualintegrate(sin(x)**3 * cos(x)**2, x) == \
|
||||
cos(x)**5 / 5 - cos(x)**3 / 3
|
||||
|
||||
assert manualintegrate(tan(x)**3 * sec(x), x) == sec(x)**3/3 - sec(x)
|
||||
assert manualintegrate(tan(x) * sec(x) **2, x) == sec(x)**2/2
|
||||
|
||||
assert manualintegrate(cot(x)**5 * csc(x), x) == \
|
||||
-csc(x)**5/5 + 2*csc(x)**3/3 - csc(x)
|
||||
assert manualintegrate(cot(x)**2 * csc(x)**6, x) == \
|
||||
-cot(x)**7/7 - 2*cot(x)**5/5 - cot(x)**3/3
|
||||
|
||||
|
||||
@slow
|
||||
def test_manualintegrate_inversetrig():
|
||||
# atan
|
||||
assert manualintegrate(exp(x) / (1 + exp(2*x)), x) == atan(exp(x))
|
||||
assert manualintegrate(1 / (4 + 9 * x**2), x) == atan(3 * x/2) / 6
|
||||
assert manualintegrate(1 / (16 + 16 * x**2), x) == atan(x) / 16
|
||||
assert manualintegrate(1 / (4 + x**2), x) == atan(x / 2) / 2
|
||||
assert manualintegrate(1 / (1 + 4 * x**2), x) == atan(2*x) / 2
|
||||
ra = Symbol('a', real=True)
|
||||
rb = Symbol('b', real=True)
|
||||
assert manualintegrate(1/(ra + rb*x**2), x) == \
|
||||
Piecewise((atan(x/sqrt(ra/rb))/(rb*sqrt(ra/rb)), ra/rb > 0),
|
||||
((log(x - sqrt(-ra/rb)) - log(x + sqrt(-ra/rb)))/(2*sqrt(rb)*sqrt(-ra)), True))
|
||||
assert manualintegrate(1/(4 + rb*x**2), x) == \
|
||||
Piecewise((atan(x/(2*sqrt(1/rb)))/(2*rb*sqrt(1/rb)), 1/rb > 0),
|
||||
(-I*(log(x - 2*sqrt(-1/rb)) - log(x + 2*sqrt(-1/rb)))/(4*sqrt(rb)), True))
|
||||
assert manualintegrate(1/(ra + 4*x**2), x) == \
|
||||
Piecewise((atan(2*x/sqrt(ra))/(2*sqrt(ra)), ra > 0),
|
||||
((log(x - sqrt(-ra)/2) - log(x + sqrt(-ra)/2))/(4*sqrt(-ra)), True))
|
||||
assert manualintegrate(1/(4 + 4*x**2), x) == atan(x) / 4
|
||||
|
||||
assert manualintegrate(1/(a + b*x**2), x) == Piecewise((atan(x/sqrt(a/b))/(b*sqrt(a/b)), Ne(a, 0)),
|
||||
(-1/(b*x), True))
|
||||
|
||||
# asin
|
||||
assert manualintegrate(1/sqrt(1-x**2), x) == asin(x)
|
||||
assert manualintegrate(1/sqrt(4-4*x**2), x) == asin(x)/2
|
||||
assert manualintegrate(3/sqrt(1-9*x**2), x) == asin(3*x)
|
||||
assert manualintegrate(1/sqrt(4-9*x**2), x) == asin(x*Rational(3, 2))/3
|
||||
|
||||
# asinh
|
||||
assert manualintegrate(1/sqrt(x**2 + 1), x) == \
|
||||
asinh(x)
|
||||
assert manualintegrate(1/sqrt(x**2 + 4), x) == \
|
||||
asinh(x/2)
|
||||
assert manualintegrate(1/sqrt(4*x**2 + 4), x) == \
|
||||
asinh(x)/2
|
||||
assert manualintegrate(1/sqrt(4*x**2 + 1), x) == \
|
||||
asinh(2*x)/2
|
||||
assert manualintegrate(1/sqrt(ra*x**2 + 1), x) == \
|
||||
Piecewise((asin(x*sqrt(-ra))/sqrt(-ra), ra < 0), (asinh(sqrt(ra)*x)/sqrt(ra), ra > 0), (x, True))
|
||||
assert manualintegrate(1/sqrt(ra + x**2), x) == \
|
||||
Piecewise((asinh(x*sqrt(1/ra)), ra > 0), (log(2*x + 2*sqrt(ra + x**2)), True))
|
||||
|
||||
# log
|
||||
assert manualintegrate(1/sqrt(x**2 - 1), x) == log(2*x + 2*sqrt(x**2 - 1))
|
||||
assert manualintegrate(1/sqrt(x**2 - 4), x) == log(2*x + 2*sqrt(x**2 - 4))
|
||||
assert manualintegrate(1/sqrt(4*x**2 - 4), x) == log(8*x + 4*sqrt(4*x**2 - 4))/2
|
||||
assert manualintegrate(1/sqrt(9*x**2 - 1), x) == log(18*x + 6*sqrt(9*x**2 - 1))/3
|
||||
assert manualintegrate(1/sqrt(ra*x**2 - 4), x) == \
|
||||
Piecewise((log(2*sqrt(ra)*sqrt(ra*x**2 - 4) + 2*ra*x)/sqrt(ra), Ne(ra, 0)), (-I*x/2, True))
|
||||
assert manualintegrate(1/sqrt(-ra + 4*x**2), x) == \
|
||||
Piecewise((asinh(2*x*sqrt(-1/ra))/2, ra < 0), (log(8*x + 4*sqrt(-ra + 4*x**2))/2, True))
|
||||
|
||||
# From https://www.wikiwand.com/en/List_of_integrals_of_inverse_trigonometric_functions
|
||||
# asin
|
||||
assert manualintegrate(asin(x), x) == x*asin(x) + sqrt(1 - x**2)
|
||||
assert manualintegrate(asin(a*x), x) == Piecewise(((a*x*asin(a*x) + sqrt(-a**2*x**2 + 1))/a, Ne(a, 0)), (0, True))
|
||||
assert manualintegrate(x*asin(a*x), x) == \
|
||||
-a*Piecewise((-x*sqrt(-a**2*x**2 + 1)/(2*a**2) +
|
||||
log(-2*a**2*x + 2*sqrt(-a**2)*sqrt(-a**2*x**2 + 1))/(2*a**2*sqrt(-a**2)), Ne(a**2, 0)),
|
||||
(x**3/3, True))/2 + x**2*asin(a*x)/2
|
||||
# acos
|
||||
assert manualintegrate(acos(x), x) == x*acos(x) - sqrt(1 - x**2)
|
||||
assert manualintegrate(acos(a*x), x) == Piecewise(((a*x*acos(a*x) - sqrt(-a**2*x**2 + 1))/a, Ne(a, 0)), (pi*x/2, True))
|
||||
assert manualintegrate(x*acos(a*x), x) == \
|
||||
a*Piecewise((-x*sqrt(-a**2*x**2 + 1)/(2*a**2) +
|
||||
log(-2*a**2*x + 2*sqrt(-a**2)*sqrt(-a**2*x**2 + 1))/(2*a**2*sqrt(-a**2)), Ne(a**2, 0)),
|
||||
(x**3/3, True))/2 + x**2*acos(a*x)/2
|
||||
# atan
|
||||
assert manualintegrate(atan(x), x) == x*atan(x) - log(x**2 + 1)/2
|
||||
assert manualintegrate(atan(a*x), x) == Piecewise(((a*x*atan(a*x) - log(a**2*x**2 + 1)/2)/a, Ne(a, 0)), (0, True))
|
||||
assert manualintegrate(x*atan(a*x), x) == -a*(x/a**2 - atan(x/sqrt(a**(-2)))/(a**4*sqrt(a**(-2))))/2 + x**2*atan(a*x)/2
|
||||
# acsc
|
||||
assert manualintegrate(acsc(x), x) == x*acsc(x) + Integral(1/(x*sqrt(1 - 1/x**2)), x)
|
||||
assert manualintegrate(acsc(a*x), x) == x*acsc(a*x) + Integral(1/(x*sqrt(1 - 1/(a**2*x**2))), x)/a
|
||||
assert manualintegrate(x*acsc(a*x), x) == x**2*acsc(a*x)/2 + Integral(1/sqrt(1 - 1/(a**2*x**2)), x)/(2*a)
|
||||
# asec
|
||||
assert manualintegrate(asec(x), x) == x*asec(x) - Integral(1/(x*sqrt(1 - 1/x**2)), x)
|
||||
assert manualintegrate(asec(a*x), x) == x*asec(a*x) - Integral(1/(x*sqrt(1 - 1/(a**2*x**2))), x)/a
|
||||
assert manualintegrate(x*asec(a*x), x) == x**2*asec(a*x)/2 - Integral(1/sqrt(1 - 1/(a**2*x**2)), x)/(2*a)
|
||||
# acot
|
||||
assert manualintegrate(acot(x), x) == x*acot(x) + log(x**2 + 1)/2
|
||||
assert manualintegrate(acot(a*x), x) == Piecewise(((a*x*acot(a*x) + log(a**2*x**2 + 1)/2)/a, Ne(a, 0)), (pi*x/2, True))
|
||||
assert manualintegrate(x*acot(a*x), x) == a*(x/a**2 - atan(x/sqrt(a**(-2)))/(a**4*sqrt(a**(-2))))/2 + x**2*acot(a*x)/2
|
||||
|
||||
# piecewise
|
||||
assert manualintegrate(1/sqrt(ra-rb*x**2), x) == \
|
||||
Piecewise((asin(x*sqrt(rb/ra))/sqrt(rb), And(-rb < 0, ra > 0)),
|
||||
(asinh(x*sqrt(-rb/ra))/sqrt(-rb), And(-rb > 0, ra > 0)),
|
||||
(log(-2*rb*x + 2*sqrt(-rb)*sqrt(ra - rb*x**2))/sqrt(-rb), Ne(rb, 0)),
|
||||
(x/sqrt(ra), True))
|
||||
assert manualintegrate(1/sqrt(ra + rb*x**2), x) == \
|
||||
Piecewise((asin(x*sqrt(-rb/ra))/sqrt(-rb), And(ra > 0, rb < 0)),
|
||||
(asinh(x*sqrt(rb/ra))/sqrt(rb), And(ra > 0, rb > 0)),
|
||||
(log(2*sqrt(rb)*sqrt(ra + rb*x**2) + 2*rb*x)/sqrt(rb), Ne(rb, 0)),
|
||||
(x/sqrt(ra), True))
|
||||
|
||||
|
||||
def test_manualintegrate_trig_substitution():
|
||||
assert manualintegrate(sqrt(16*x**2 - 9)/x, x) == \
|
||||
Piecewise((sqrt(16*x**2 - 9) - 3*acos(3/(4*x)),
|
||||
And(x < Rational(3, 4), x > Rational(-3, 4))))
|
||||
assert manualintegrate(1/(x**4 * sqrt(25-x**2)), x) == \
|
||||
Piecewise((-sqrt(-x**2/25 + 1)/(125*x) -
|
||||
(-x**2/25 + 1)**(3*S.Half)/(15*x**3), And(x < 5, x > -5)))
|
||||
assert manualintegrate(x**7/(49*x**2 + 1)**(3 * S.Half), x) == \
|
||||
((49*x**2 + 1)**(5*S.Half)/28824005 -
|
||||
(49*x**2 + 1)**(3*S.Half)/5764801 +
|
||||
3*sqrt(49*x**2 + 1)/5764801 + 1/(5764801*sqrt(49*x**2 + 1)))
|
||||
|
||||
def test_manualintegrate_trivial_substitution():
|
||||
assert manualintegrate((exp(x) - exp(-x))/x, x) == -Ei(-x) + Ei(x)
|
||||
f = Function('f')
|
||||
assert manualintegrate((f(x) - f(-x))/x, x) == \
|
||||
-Integral(f(-x)/x, x) + Integral(f(x)/x, x)
|
||||
|
||||
|
||||
def test_manualintegrate_rational():
|
||||
assert manualintegrate(1/(4 - x**2), x) == -log(x - 2)/4 + log(x + 2)/4
|
||||
assert manualintegrate(1/(-1 + x**2), x) == log(x - 1)/2 - log(x + 1)/2
|
||||
|
||||
|
||||
def test_manualintegrate_special():
|
||||
f, F = 4*exp(-x**2/3), 2*sqrt(3)*sqrt(pi)*erf(sqrt(3)*x/3)
|
||||
assert_is_integral_of(f, F)
|
||||
f, F = 3*exp(4*x**2), 3*sqrt(pi)*erfi(2*x)/4
|
||||
assert_is_integral_of(f, F)
|
||||
f, F = x**Rational(1, 3)*exp(-x/8), -16*uppergamma(Rational(4, 3), x/8)
|
||||
assert_is_integral_of(f, F)
|
||||
f, F = exp(2*x)/x, Ei(2*x)
|
||||
assert_is_integral_of(f, F)
|
||||
f, F = exp(1 + 2*x - x**2), sqrt(pi)*exp(2)*erf(x - 1)/2
|
||||
assert_is_integral_of(f, F)
|
||||
f = sin(x**2 + 4*x + 1)
|
||||
F = (sqrt(2)*sqrt(pi)*(-sin(3)*fresnelc(sqrt(2)*(2*x + 4)/(2*sqrt(pi))) +
|
||||
cos(3)*fresnels(sqrt(2)*(2*x + 4)/(2*sqrt(pi))))/2)
|
||||
assert_is_integral_of(f, F)
|
||||
f, F = cos(4*x**2), sqrt(2)*sqrt(pi)*fresnelc(2*sqrt(2)*x/sqrt(pi))/4
|
||||
assert_is_integral_of(f, F)
|
||||
f, F = sin(3*x + 2)/x, sin(2)*Ci(3*x) + cos(2)*Si(3*x)
|
||||
assert_is_integral_of(f, F)
|
||||
f, F = sinh(3*x - 2)/x, -sinh(2)*Chi(3*x) + cosh(2)*Shi(3*x)
|
||||
assert_is_integral_of(f, F)
|
||||
f, F = 5*cos(2*x - 3)/x, 5*cos(3)*Ci(2*x) + 5*sin(3)*Si(2*x)
|
||||
assert_is_integral_of(f, F)
|
||||
f, F = cosh(x/2)/x, Chi(x/2)
|
||||
assert_is_integral_of(f, F)
|
||||
f, F = cos(x**2)/x, Ci(x**2)/2
|
||||
assert_is_integral_of(f, F)
|
||||
f, F = 1/log(2*x + 1), li(2*x + 1)/2
|
||||
assert_is_integral_of(f, F)
|
||||
f, F = polylog(2, 5*x)/x, polylog(3, 5*x)
|
||||
assert_is_integral_of(f, F)
|
||||
f, F = 5/sqrt(3 - 2*sin(x)**2), 5*sqrt(3)*elliptic_f(x, Rational(2, 3))/3
|
||||
assert_is_integral_of(f, F)
|
||||
f, F = sqrt(4 + 9*sin(x)**2), 2*elliptic_e(x, Rational(-9, 4))
|
||||
assert_is_integral_of(f, F)
|
||||
|
||||
|
||||
def test_manualintegrate_derivative():
|
||||
assert manualintegrate(pi * Derivative(x**2 + 2*x + 3), x) == \
|
||||
pi * (x**2 + 2*x + 3)
|
||||
assert manualintegrate(Derivative(x**2 + 2*x + 3, y), x) == \
|
||||
Integral(Derivative(x**2 + 2*x + 3, y))
|
||||
assert manualintegrate(Derivative(sin(x), x, x, x, y), x) == \
|
||||
Derivative(sin(x), x, x, y)
|
||||
|
||||
|
||||
def test_manualintegrate_Heaviside():
|
||||
assert_is_integral_of(DiracDelta(3*x+2), Heaviside(3*x+2)/3)
|
||||
assert_is_integral_of(DiracDelta(3*x, 0), Heaviside(3*x)/3)
|
||||
assert manualintegrate(DiracDelta(a+b*x, 1), x) == \
|
||||
Piecewise((DiracDelta(a + b*x)/b, Ne(b, 0)), (x*DiracDelta(a, 1), True))
|
||||
assert_is_integral_of(DiracDelta(x/3-1, 2), 3*DiracDelta(x/3-1, 1))
|
||||
assert manualintegrate(Heaviside(x), x) == x*Heaviside(x)
|
||||
assert manualintegrate(x*Heaviside(2), x) == x**2/2
|
||||
assert manualintegrate(x*Heaviside(-2), x) == 0
|
||||
assert manualintegrate(x*Heaviside( x), x) == x**2*Heaviside( x)/2
|
||||
assert manualintegrate(x*Heaviside(-x), x) == x**2*Heaviside(-x)/2
|
||||
assert manualintegrate(Heaviside(2*x + 4), x) == (x+2)*Heaviside(2*x + 4)
|
||||
assert manualintegrate(x*Heaviside(x), x) == x**2*Heaviside(x)/2
|
||||
assert manualintegrate(Heaviside(x + 1)*Heaviside(1 - x)*x**2, x) == \
|
||||
((x**3/3 + Rational(1, 3))*Heaviside(x + 1) - Rational(2, 3))*Heaviside(-x + 1)
|
||||
|
||||
y = Symbol('y')
|
||||
assert manualintegrate(sin(7 + x)*Heaviside(3*x - 7), x) == \
|
||||
(- cos(x + 7) + cos(Rational(28, 3)))*Heaviside(3*x - S(7))
|
||||
|
||||
assert manualintegrate(sin(y + x)*Heaviside(3*x - y), x) == \
|
||||
(cos(y*Rational(4, 3)) - cos(x + y))*Heaviside(3*x - y)
|
||||
|
||||
|
||||
def test_manualintegrate_orthogonal_poly():
|
||||
n = symbols('n')
|
||||
a, b = 7, Rational(5, 3)
|
||||
polys = [jacobi(n, a, b, x), gegenbauer(n, a, x), chebyshevt(n, x),
|
||||
chebyshevu(n, x), legendre(n, x), hermite(n, x), laguerre(n, x),
|
||||
assoc_laguerre(n, a, x)]
|
||||
for p in polys:
|
||||
integral = manualintegrate(p, x)
|
||||
for deg in [-2, -1, 0, 1, 3, 5, 8]:
|
||||
# some accept negative "degree", some do not
|
||||
try:
|
||||
p_subbed = p.subs(n, deg)
|
||||
except ValueError:
|
||||
continue
|
||||
assert (integral.subs(n, deg).diff(x) - p_subbed).expand() == 0
|
||||
|
||||
# can also integrate simple expressions with these polynomials
|
||||
q = x*p.subs(x, 2*x + 1)
|
||||
integral = manualintegrate(q, x)
|
||||
for deg in [2, 4, 7]:
|
||||
assert (integral.subs(n, deg).diff(x) - q.subs(n, deg)).expand() == 0
|
||||
|
||||
# cannot integrate with respect to any other parameter
|
||||
t = symbols('t')
|
||||
for i in range(len(p.args) - 1):
|
||||
new_args = list(p.args)
|
||||
new_args[i] = t
|
||||
assert isinstance(manualintegrate(p.func(*new_args), t), Integral)
|
||||
|
||||
|
||||
@slow
|
||||
def test_issue_6799():
|
||||
r, x, phi = map(Symbol, 'r x phi'.split())
|
||||
n = Symbol('n', integer=True, positive=True)
|
||||
|
||||
integrand = (cos(n*(x-phi))*cos(n*x))
|
||||
limits = (x, -pi, pi)
|
||||
assert manualintegrate(integrand, x) == \
|
||||
((n*x/2 + sin(2*n*x)/4)*cos(n*phi) - sin(n*phi)*cos(n*x)**2/2)/n
|
||||
assert r * integrate(integrand, limits).trigsimp() / pi == r * cos(n * phi)
|
||||
assert not integrate(integrand, limits).has(Dummy)
|
||||
|
||||
|
||||
def test_issue_12251():
|
||||
assert manualintegrate(x**y, x) == Piecewise(
|
||||
(x**(y + 1)/(y + 1), Ne(y, -1)), (log(x), True))
|
||||
|
||||
|
||||
def test_issue_3796():
|
||||
assert manualintegrate(diff(exp(x + x**2)), x) == exp(x + x**2)
|
||||
assert integrate(x * exp(x**4), x, risch=False) == -I*sqrt(pi)*erf(I*x**2)/4
|
||||
|
||||
|
||||
def test_manual_true():
|
||||
assert integrate(exp(x) * sin(x), x, manual=True) == \
|
||||
(exp(x) * sin(x)) / 2 - (exp(x) * cos(x)) / 2
|
||||
assert integrate(sin(x) * cos(x), x, manual=True) in \
|
||||
[sin(x) ** 2 / 2, -cos(x)**2 / 2]
|
||||
|
||||
|
||||
def test_issue_6746():
|
||||
y = Symbol('y')
|
||||
n = Symbol('n')
|
||||
assert manualintegrate(y**x, x) == Piecewise(
|
||||
(y**x/log(y), Ne(log(y), 0)), (x, True))
|
||||
assert manualintegrate(y**(n*x), x) == Piecewise(
|
||||
(Piecewise(
|
||||
(y**(n*x)/log(y), Ne(log(y), 0)),
|
||||
(n*x, True)
|
||||
)/n, Ne(n, 0)),
|
||||
(x, True))
|
||||
assert manualintegrate(exp(n*x), x) == Piecewise(
|
||||
(exp(n*x)/n, Ne(n, 0)), (x, True))
|
||||
|
||||
y = Symbol('y', positive=True)
|
||||
assert manualintegrate((y + 1)**x, x) == (y + 1)**x/log(y + 1)
|
||||
y = Symbol('y', zero=True)
|
||||
assert manualintegrate((y + 1)**x, x) == x
|
||||
y = Symbol('y')
|
||||
n = Symbol('n', nonzero=True)
|
||||
assert manualintegrate(y**(n*x), x) == Piecewise(
|
||||
(y**(n*x)/log(y), Ne(log(y), 0)), (n*x, True))/n
|
||||
y = Symbol('y', positive=True)
|
||||
assert manualintegrate((y + 1)**(n*x), x) == \
|
||||
(y + 1)**(n*x)/(n*log(y + 1))
|
||||
a = Symbol('a', negative=True)
|
||||
b = Symbol('b')
|
||||
assert manualintegrate(1/(a + b*x**2), x) == atan(x/sqrt(a/b))/(b*sqrt(a/b))
|
||||
b = Symbol('b', negative=True)
|
||||
assert manualintegrate(1/(a + b*x**2), x) == \
|
||||
atan(x/(sqrt(-a)*sqrt(-1/b)))/(b*sqrt(-a)*sqrt(-1/b))
|
||||
assert manualintegrate(1/((x**a + y**b + 4)*sqrt(a*x**2 + 1)), x) == \
|
||||
y**(-b)*Integral(x**(-a)/(y**(-b)*sqrt(a*x**2 + 1) +
|
||||
x**(-a)*sqrt(a*x**2 + 1) + 4*x**(-a)*y**(-b)*sqrt(a*x**2 + 1)), x)
|
||||
assert manualintegrate(1/((x**2 + 4)*sqrt(4*x**2 + 1)), x) == \
|
||||
Integral(1/((x**2 + 4)*sqrt(4*x**2 + 1)), x)
|
||||
assert manualintegrate(1/(x - a**x + x*b**2), x) == \
|
||||
Integral(1/(-a**x + b**2*x + x), x)
|
||||
|
||||
|
||||
@slow
|
||||
def test_issue_2850():
|
||||
assert manualintegrate(asin(x)*log(x), x) == -x*asin(x) - sqrt(-x**2 + 1) \
|
||||
+ (x*asin(x) + sqrt(-x**2 + 1))*log(x) - Integral(sqrt(-x**2 + 1)/x, x)
|
||||
assert manualintegrate(acos(x)*log(x), x) == -x*acos(x) + sqrt(-x**2 + 1) + \
|
||||
(x*acos(x) - sqrt(-x**2 + 1))*log(x) + Integral(sqrt(-x**2 + 1)/x, x)
|
||||
assert manualintegrate(atan(x)*log(x), x) == -x*atan(x) + (x*atan(x) - \
|
||||
log(x**2 + 1)/2)*log(x) + log(x**2 + 1)/2 + Integral(log(x**2 + 1)/x, x)/2
|
||||
|
||||
|
||||
def test_issue_9462():
|
||||
assert manualintegrate(sin(2*x)*exp(x), x) == exp(x)*sin(2*x)/5 - 2*exp(x)*cos(2*x)/5
|
||||
assert not integral_steps(sin(2*x)*exp(x), x).contains_dont_know()
|
||||
assert manualintegrate((x - 3) / (x**2 - 2*x + 2)**2, x) == \
|
||||
Integral(x/(x**4 - 4*x**3 + 8*x**2 - 8*x + 4), x) \
|
||||
- 3*Integral(1/(x**4 - 4*x**3 + 8*x**2 - 8*x + 4), x)
|
||||
|
||||
|
||||
def test_cyclic_parts():
|
||||
f = cos(x)*exp(x/4)
|
||||
F = 16*exp(x/4)*sin(x)/17 + 4*exp(x/4)*cos(x)/17
|
||||
assert manualintegrate(f, x) == F and F.diff(x) == f
|
||||
f = x*cos(x)*exp(x/4)
|
||||
F = (x*(16*exp(x/4)*sin(x)/17 + 4*exp(x/4)*cos(x)/17) -
|
||||
128*exp(x/4)*sin(x)/289 + 240*exp(x/4)*cos(x)/289)
|
||||
assert manualintegrate(f, x) == F and F.diff(x) == f
|
||||
|
||||
|
||||
@slow
|
||||
def test_issue_10847_slow():
|
||||
assert manualintegrate((4*x**4 + 4*x**3 + 16*x**2 + 12*x + 8)
|
||||
/ (x**6 + 2*x**5 + 3*x**4 + 4*x**3 + 3*x**2 + 2*x + 1), x) == \
|
||||
2*x/(x**2 + 1) + 3*atan(x) - 1/(x**2 + 1) - 3/(x + 1)
|
||||
|
||||
|
||||
@slow
|
||||
def test_issue_10847():
|
||||
|
||||
assert manualintegrate(x**2 / (x**2 - c), x) == \
|
||||
c*Piecewise((atan(x/sqrt(-c))/sqrt(-c), Ne(c, 0)), (-1/x, True)) + x
|
||||
|
||||
rc = Symbol('c', real=True)
|
||||
assert manualintegrate(x**2 / (x**2 - rc), x) == \
|
||||
rc*Piecewise((atan(x/sqrt(-rc))/sqrt(-rc), rc < 0),
|
||||
((log(-sqrt(rc) + x) - log(sqrt(rc) + x))/(2*sqrt(rc)), True)) + x
|
||||
|
||||
assert manualintegrate(sqrt(x - y) * log(z / x), x) == \
|
||||
4*y**2*Piecewise((atan(sqrt(x - y)/sqrt(y))/sqrt(y), Ne(y, 0)),
|
||||
(-1/sqrt(x - y), True))/3 - 4*y*sqrt(x - y)/3 + \
|
||||
2*(x - y)**Rational(3, 2)*log(z/x)/3 + 4*(x - y)**Rational(3, 2)/9
|
||||
ry = Symbol('y', real=True)
|
||||
rz = Symbol('z', real=True)
|
||||
assert manualintegrate(sqrt(x - ry) * log(rz / x), x) == \
|
||||
4*ry**2*Piecewise((atan(sqrt(x - ry)/sqrt(ry))/sqrt(ry), ry > 0),
|
||||
((log(-sqrt(-ry) + sqrt(x - ry)) - log(sqrt(-ry) + sqrt(x - ry)))/(2*sqrt(-ry)), True))/3 \
|
||||
- 4*ry*sqrt(x - ry)/3 + 2*(x - ry)**Rational(3, 2)*log(rz/x)/3 \
|
||||
+ 4*(x - ry)**Rational(3, 2)/9
|
||||
|
||||
assert manualintegrate(sqrt(x) * log(x), x) == 2*x**Rational(3, 2)*log(x)/3 - 4*x**Rational(3, 2)/9
|
||||
|
||||
result = manualintegrate(sqrt(a*x + b) / x, x)
|
||||
assert result == Piecewise((-2*b*Piecewise(
|
||||
(-atan(sqrt(a*x + b)/sqrt(-b))/sqrt(-b), Ne(b, 0)),
|
||||
(1/sqrt(a*x + b), True)) + 2*sqrt(a*x + b), Ne(a, 0)),
|
||||
(sqrt(b)*log(x), True))
|
||||
assert piecewise_fold(result) == Piecewise(
|
||||
(2*b*atan(sqrt(a*x + b)/sqrt(-b))/sqrt(-b) + 2*sqrt(a*x + b), Ne(a, 0) & Ne(b, 0)),
|
||||
(-2*b/sqrt(a*x + b) + 2*sqrt(a*x + b), Ne(a, 0)),
|
||||
(sqrt(b)*log(x), True))
|
||||
|
||||
ra = Symbol('a', real=True)
|
||||
rb = Symbol('b', real=True)
|
||||
assert manualintegrate(sqrt(ra*x + rb) / x, x) == \
|
||||
Piecewise(
|
||||
(-2*rb*Piecewise(
|
||||
(-atan(sqrt(ra*x + rb)/sqrt(-rb))/sqrt(-rb), rb < 0),
|
||||
(-I*(log(-sqrt(rb) + sqrt(ra*x + rb)) - log(sqrt(rb) + sqrt(ra*x + rb)))/(2*sqrt(-rb)), True)) +
|
||||
2*sqrt(ra*x + rb), Ne(ra, 0)),
|
||||
(sqrt(rb)*log(x), True))
|
||||
|
||||
assert expand(manualintegrate(sqrt(ra*x + rb) / (x + rc), x)) == \
|
||||
Piecewise((-2*ra*rc*Piecewise((atan(sqrt(ra*x + rb)/sqrt(ra*rc - rb))/sqrt(ra*rc - rb), ra*rc - rb > 0),
|
||||
(log(-sqrt(-ra*rc + rb) + sqrt(ra*x + rb))/(2*sqrt(-ra*rc + rb)) -
|
||||
log(sqrt(-ra*rc + rb) + sqrt(ra*x + rb))/(2*sqrt(-ra*rc + rb)), True)) +
|
||||
2*rb*Piecewise((atan(sqrt(ra*x + rb)/sqrt(ra*rc - rb))/sqrt(ra*rc - rb), ra*rc - rb > 0),
|
||||
(log(-sqrt(-ra*rc + rb) + sqrt(ra*x + rb))/(2*sqrt(-ra*rc + rb)) -
|
||||
log(sqrt(-ra*rc + rb) + sqrt(ra*x + rb))/(2*sqrt(-ra*rc + rb)), True)) +
|
||||
2*sqrt(ra*x + rb), Ne(ra, 0)), (sqrt(rb)*log(rc + x), True))
|
||||
|
||||
assert manualintegrate(sqrt(2*x + 3) / (x + 1), x) == 2*sqrt(2*x + 3) - log(sqrt(2*x + 3) + 1) + log(sqrt(2*x + 3) - 1)
|
||||
assert manualintegrate(sqrt(2*x + 3) / 2 * x, x) == (2*x + 3)**Rational(5, 2)/20 - (2*x + 3)**Rational(3, 2)/4
|
||||
assert manualintegrate(x**Rational(3,2) * log(x), x) == 2*x**Rational(5,2)*log(x)/5 - 4*x**Rational(5,2)/25
|
||||
assert manualintegrate(x**(-3) * log(x), x) == -log(x)/(2*x**2) - 1/(4*x**2)
|
||||
assert manualintegrate(log(y)/(y**2*(1 - 1/y)), y) == \
|
||||
log(y)*log(-1 + 1/y) - Integral(log(-1 + 1/y)/y, y)
|
||||
|
||||
|
||||
def test_issue_12899():
|
||||
assert manualintegrate(f(x,y).diff(x),y) == Integral(Derivative(f(x,y),x),y)
|
||||
assert manualintegrate(f(x,y).diff(y).diff(x),y) == Derivative(f(x,y),x)
|
||||
|
||||
|
||||
def test_constant_independent_of_symbol():
|
||||
assert manualintegrate(Integral(y, (x, 1, 2)), x) == \
|
||||
x*Integral(y, (x, 1, 2))
|
||||
|
||||
|
||||
def test_issue_12641():
|
||||
assert manualintegrate(sin(2*x), x) == -cos(2*x)/2
|
||||
assert manualintegrate(cos(x)*sin(2*x), x) == -2*cos(x)**3/3
|
||||
assert manualintegrate((sin(2*x)*cos(x))/(1 + cos(x)), x) == \
|
||||
-2*log(cos(x) + 1) - cos(x)**2 + 2*cos(x)
|
||||
|
||||
|
||||
@slow
|
||||
def test_issue_13297():
|
||||
assert manualintegrate(sin(x) * cos(x)**5, x) == -cos(x)**6 / 6
|
||||
|
||||
|
||||
def test_issue_14470():
|
||||
assert_is_integral_of(1/(x*sqrt(x + 1)), log(sqrt(x + 1) - 1) - log(sqrt(x + 1) + 1))
|
||||
|
||||
|
||||
@slow
|
||||
def test_issue_9858():
|
||||
assert manualintegrate(exp(x)*cos(exp(x)), x) == sin(exp(x))
|
||||
assert manualintegrate(exp(2*x)*cos(exp(x)), x) == \
|
||||
exp(x)*sin(exp(x)) + cos(exp(x))
|
||||
res = manualintegrate(exp(10*x)*sin(exp(x)), x)
|
||||
assert not res.has(Integral)
|
||||
assert res.diff(x) == exp(10*x)*sin(exp(x))
|
||||
# an example with many similar integrations by parts
|
||||
assert manualintegrate(sum(x*exp(k*x) for k in range(1, 8)), x) == (
|
||||
x*exp(7*x)/7 + x*exp(6*x)/6 + x*exp(5*x)/5 + x*exp(4*x)/4 +
|
||||
x*exp(3*x)/3 + x*exp(2*x)/2 + x*exp(x) - exp(7*x)/49 -exp(6*x)/36 -
|
||||
exp(5*x)/25 - exp(4*x)/16 - exp(3*x)/9 - exp(2*x)/4 - exp(x))
|
||||
|
||||
|
||||
def test_issue_8520():
|
||||
assert manualintegrate(x/(x**4 + 1), x) == atan(x**2)/2
|
||||
assert manualintegrate(x**2/(x**6 + 25), x) == atan(x**3/5)/15
|
||||
f = x/(9*x**4 + 4)**2
|
||||
assert manualintegrate(f, x).diff(x).factor() == f
|
||||
|
||||
|
||||
def test_manual_subs():
|
||||
x, y = symbols('x y')
|
||||
expr = log(x) + exp(x)
|
||||
# if log(x) is y, then exp(y) is x
|
||||
assert manual_subs(expr, log(x), y) == y + exp(exp(y))
|
||||
# if exp(x) is y, then log(y) need not be x
|
||||
assert manual_subs(expr, exp(x), y) == log(x) + y
|
||||
|
||||
raises(ValueError, lambda: manual_subs(expr, x))
|
||||
raises(ValueError, lambda: manual_subs(expr, exp(x), x, y))
|
||||
|
||||
|
||||
@slow
|
||||
def test_issue_15471():
|
||||
f = log(x)*cos(log(x))/x**Rational(3, 4)
|
||||
F = -128*x**Rational(1, 4)*sin(log(x))/289 + 240*x**Rational(1, 4)*cos(log(x))/289 + (16*x**Rational(1, 4)*sin(log(x))/17 + 4*x**Rational(1, 4)*cos(log(x))/17)*log(x)
|
||||
assert_is_integral_of(f, F)
|
||||
|
||||
|
||||
def test_quadratic_denom():
|
||||
f = (5*x + 2)/(3*x**2 - 2*x + 8)
|
||||
assert manualintegrate(f, x) == 5*log(3*x**2 - 2*x + 8)/6 + 11*sqrt(23)*atan(3*sqrt(23)*(x - Rational(1, 3))/23)/69
|
||||
g = 3/(2*x**2 + 3*x + 1)
|
||||
assert manualintegrate(g, x) == 3*log(4*x + 2) - 3*log(4*x + 4)
|
||||
|
||||
def test_issue_22757():
|
||||
assert manualintegrate(sin(x), y) == y * sin(x)
|
||||
|
||||
|
||||
def test_issue_23348():
|
||||
steps = integral_steps(tan(x), x)
|
||||
constant_times_step = steps.substep.substep
|
||||
assert constant_times_step.integrand == constant_times_step.constant * constant_times_step.other
|
||||
|
||||
|
||||
def test_issue_23566():
|
||||
i = Integral(1/sqrt(x**2 - 1), (x, -2, -1)).doit(manual=True)
|
||||
assert i == -log(4 - 2*sqrt(3)) + log(2)
|
||||
assert str(i.n()) == '1.31695789692482'
|
||||
|
||||
|
||||
def test_issue_25093():
|
||||
ap = Symbol('ap', positive=True)
|
||||
an = Symbol('an', negative=True)
|
||||
assert manualintegrate(exp(a*x**2 + b), x) == sqrt(pi)*exp(b)*erfi(sqrt(a)*x)/(2*sqrt(a))
|
||||
assert manualintegrate(exp(ap*x**2 + b), x) == sqrt(pi)*exp(b)*erfi(sqrt(ap)*x)/(2*sqrt(ap))
|
||||
assert manualintegrate(exp(an*x**2 + b), x) == -sqrt(pi)*exp(b)*erf(an*x/sqrt(-an))/(2*sqrt(-an))
|
||||
assert manualintegrate(sin(a*x**2 + b), x) == (
|
||||
sqrt(2)*sqrt(pi)*(sin(b)*fresnelc(sqrt(2)*sqrt(a)*x/sqrt(pi))
|
||||
+ cos(b)*fresnels(sqrt(2)*sqrt(a)*x/sqrt(pi)))/(2*sqrt(a)))
|
||||
assert manualintegrate(cos(a*x**2 + b), x) == (
|
||||
sqrt(2)*sqrt(pi)*(-sin(b)*fresnels(sqrt(2)*sqrt(a)*x/sqrt(pi))
|
||||
+ cos(b)*fresnelc(sqrt(2)*sqrt(a)*x/sqrt(pi)))/(2*sqrt(a)))
|
||||
|
||||
|
||||
def test_nested_pow():
|
||||
assert_is_integral_of(sqrt(x**2), x*sqrt(x**2)/2)
|
||||
assert_is_integral_of(sqrt(x**(S(5)/3)), 6*x*sqrt(x**(S(5)/3))/11)
|
||||
assert_is_integral_of(1/sqrt(x**2), x*log(x)/sqrt(x**2))
|
||||
assert_is_integral_of(x*sqrt(x**(-4)), x**2*sqrt(x**-4)*log(x))
|
||||
f = (c*(a+b*x)**d)**e
|
||||
F1 = (c*(a + b*x)**d)**e*(a/b + x)/(d*e + 1)
|
||||
F2 = (c*(a + b*x)**d)**e*(a/b + x)*log(a/b + x)
|
||||
assert manualintegrate(f, x) == \
|
||||
Piecewise((Piecewise((F1, Ne(d*e, -1)), (F2, True)), Ne(b, 0)), (x*(a**d*c)**e, True))
|
||||
assert F1.diff(x).equals(f)
|
||||
assert F2.diff(x).subs(d*e, -1).equals(f)
|
||||
|
||||
|
||||
def test_manualintegrate_sqrt_linear():
|
||||
assert_is_integral_of((5*x**3+4)/sqrt(2+3*x),
|
||||
10*(3*x + 2)**(S(7)/2)/567 - 4*(3*x + 2)**(S(5)/2)/27 +
|
||||
40*(3*x + 2)**(S(3)/2)/81 + 136*sqrt(3*x + 2)/81)
|
||||
assert manualintegrate(x/sqrt(a+b*x)**3, x) == \
|
||||
Piecewise((Mul(2, b**-2, a/sqrt(a + b*x) + sqrt(a + b*x)), Ne(b, 0)), (x**2/(2*a**(S(3)/2)), True))
|
||||
assert_is_integral_of((sqrt(3*x+3)+1)/((2*x+2)**(1/S(3))+1),
|
||||
3*sqrt(6)*(2*x + 2)**(S(7)/6)/14 - 3*sqrt(6)*(2*x + 2)**(S(5)/6)/10 -
|
||||
3*sqrt(6)*(2*x + 2)**(S.One/6)/2 + 3*(2*x + 2)**(S(2)/3)/4 - 3*(2*x + 2)**(S.One/3)/2 +
|
||||
sqrt(6)*sqrt(2*x + 2)/2 + 3*log((2*x + 2)**(S.One/3) + 1)/2 +
|
||||
3*sqrt(6)*atan((2*x + 2)**(S.One/6))/2)
|
||||
assert_is_integral_of(sqrt(x+sqrt(x)),
|
||||
2*sqrt(sqrt(x) + x)*(sqrt(x)/12 + x/3 - S(1)/8) + log(2*sqrt(x) + 2*sqrt(sqrt(x) + x) + 1)/8)
|
||||
assert_is_integral_of(sqrt(2*x+3+sqrt(4*x+5))**3,
|
||||
sqrt(2*x + sqrt(4*x + 5) + 3) *
|
||||
(9*x/10 + 11*(4*x + 5)**(S(3)/2)/40 + sqrt(4*x + 5)/40 + (4*x + 5)**2/10 + S(11)/10)/2)
|
||||
|
||||
|
||||
def test_manualintegrate_sqrt_quadratic():
|
||||
assert_is_integral_of(1/sqrt((x - I)**2-1), log(2*x + 2*sqrt(x**2 - 2*I*x - 2) - 2*I))
|
||||
assert_is_integral_of(1/sqrt(3*x**2+4*x+5), sqrt(3)*asinh(3*sqrt(11)*(x + S(2)/3)/11)/3)
|
||||
assert_is_integral_of(1/sqrt(-3*x**2+4*x+5), sqrt(3)*asin(3*sqrt(19)*(x - S(2)/3)/19)/3)
|
||||
assert_is_integral_of(1/sqrt(3*x**2+4*x-5), sqrt(3)*log(6*x + 2*sqrt(3)*sqrt(3*x**2 + 4*x - 5) + 4)/3)
|
||||
assert_is_integral_of(1/sqrt(4*x**2-4*x+1), (x - S.Half)*log(x - S.Half)/(2*sqrt((x - S.Half)**2)))
|
||||
assert manualintegrate(1/sqrt(a+b*x+c*x**2), x) == \
|
||||
Piecewise((log(b + 2*sqrt(c)*sqrt(a + b*x + c*x**2) + 2*c*x)/sqrt(c), Ne(c, 0) & Ne(a - b**2/(4*c), 0)),
|
||||
((b/(2*c) + x)*log(b/(2*c) + x)/sqrt(c*(b/(2*c) + x)**2), Ne(c, 0)),
|
||||
(2*sqrt(a + b*x)/b, Ne(b, 0)), (x/sqrt(a), True))
|
||||
|
||||
assert_is_integral_of((7*x+6)/sqrt(3*x**2+4*x+5),
|
||||
7*sqrt(3*x**2 + 4*x + 5)/3 + 4*sqrt(3)*asinh(3*sqrt(11)*(x + S(2)/3)/11)/9)
|
||||
assert_is_integral_of((7*x+6)/sqrt(-3*x**2+4*x+5),
|
||||
-7*sqrt(-3*x**2 + 4*x + 5)/3 + 32*sqrt(3)*asin(3*sqrt(19)*(x - S(2)/3)/19)/9)
|
||||
assert_is_integral_of((7*x+6)/sqrt(3*x**2+4*x-5),
|
||||
7*sqrt(3*x**2 + 4*x - 5)/3 + 4*sqrt(3)*log(6*x + 2*sqrt(3)*sqrt(3*x**2 + 4*x - 5) + 4)/9)
|
||||
assert manualintegrate((d+e*x)/sqrt(a+b*x+c*x**2), x) == \
|
||||
Piecewise(((-b*e/(2*c) + d) *
|
||||
Piecewise((log(b + 2*sqrt(c)*sqrt(a + b*x + c*x**2) + 2*c*x)/sqrt(c), Ne(a - b**2/(4*c), 0)),
|
||||
((b/(2*c) + x)*log(b/(2*c) + x)/sqrt(c*(b/(2*c) + x)**2), True)) +
|
||||
e*sqrt(a + b*x + c*x**2)/c, Ne(c, 0)),
|
||||
((2*d*sqrt(a + b*x) + 2*e*(-a*sqrt(a + b*x) + (a + b*x)**(S(3)/2)/3)/b)/b, Ne(b, 0)),
|
||||
((d*x + e*x**2/2)/sqrt(a), True))
|
||||
|
||||
assert manualintegrate((3*x**3-x**2+2*x-4)/sqrt(x**2-3*x+2), x) == \
|
||||
sqrt(x**2 - 3*x + 2)*(x**2 + 13*x/4 + S(101)/8) + 135*log(2*x + 2*sqrt(x**2 - 3*x + 2) - 3)/16
|
||||
|
||||
assert_is_integral_of(sqrt(53225*x**2-66732*x+23013),
|
||||
(x/2 - S(16683)/53225)*sqrt(53225*x**2 - 66732*x + 23013) +
|
||||
111576969*sqrt(2129)*asinh(53225*x/10563 - S(11122)/3521)/1133160250)
|
||||
assert manualintegrate(sqrt(a+c*x**2), x) == \
|
||||
Piecewise((a*Piecewise((log(2*sqrt(c)*sqrt(a + c*x**2) + 2*c*x)/sqrt(c), Ne(a, 0)),
|
||||
(x*log(x)/sqrt(c*x**2), True))/2 + x*sqrt(a + c*x**2)/2, Ne(c, 0)),
|
||||
(sqrt(a)*x, True))
|
||||
assert manualintegrate(sqrt(a+b*x+c*x**2), x) == \
|
||||
Piecewise(((a/2 - b**2/(8*c)) *
|
||||
Piecewise((log(b + 2*sqrt(c)*sqrt(a + b*x + c*x**2) + 2*c*x)/sqrt(c), Ne(a - b**2/(4*c), 0)),
|
||||
((b/(2*c) + x)*log(b/(2*c) + x)/sqrt(c*(b/(2*c) + x)**2), True)) +
|
||||
(b/(4*c) + x/2)*sqrt(a + b*x + c*x**2), Ne(c, 0)),
|
||||
(2*(a + b*x)**(S(3)/2)/(3*b), Ne(b, 0)),
|
||||
(sqrt(a)*x, True))
|
||||
|
||||
assert_is_integral_of(x*sqrt(x**2+2*x+4),
|
||||
(x**2/3 + x/6 + S(5)/6)*sqrt(x**2 + 2*x + 4) - 3*asinh(sqrt(3)*(x + 1)/3)/2)
|
||||
|
||||
|
||||
def test_mul_pow_derivative():
|
||||
assert_is_integral_of(x*sec(x)*tan(x), x*sec(x) - log(tan(x) + sec(x)))
|
||||
assert_is_integral_of(x*sec(x)**2, x*tan(x) + log(cos(x)))
|
||||
assert_is_integral_of(x**3*Derivative(f(x), (x, 4)),
|
||||
x**3*Derivative(f(x), (x, 3)) - 3*x**2*Derivative(f(x), (x, 2)) +
|
||||
6*x*Derivative(f(x), x) - 6*f(x))
|
||||
@@ -0,0 +1,774 @@
|
||||
from sympy.core.function import expand_func
|
||||
from sympy.core.numbers import (I, Rational, oo, pi)
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.sorting import default_sort_key
|
||||
from sympy.functions.elementary.complexes import Abs, arg, re, unpolarify
|
||||
from sympy.functions.elementary.exponential import (exp, exp_polar, log)
|
||||
from sympy.functions.elementary.hyperbolic import cosh, acosh, sinh
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.piecewise import Piecewise, piecewise_fold
|
||||
from sympy.functions.elementary.trigonometric import (cos, sin, sinc, asin)
|
||||
from sympy.functions.special.error_functions import (erf, erfc)
|
||||
from sympy.functions.special.gamma_functions import (gamma, polygamma)
|
||||
from sympy.functions.special.hyper import (hyper, meijerg)
|
||||
from sympy.integrals.integrals import (Integral, integrate)
|
||||
from sympy.simplify.hyperexpand import hyperexpand
|
||||
from sympy.simplify.simplify import simplify
|
||||
from sympy.integrals.meijerint import (_rewrite_single, _rewrite1,
|
||||
meijerint_indefinite, _inflate_g, _create_lookup_table,
|
||||
meijerint_definite, meijerint_inversion)
|
||||
from sympy.testing.pytest import slow
|
||||
from sympy.core.random import (verify_numerically,
|
||||
random_complex_number as randcplx)
|
||||
from sympy.abc import x, y, a, b, c, d, s, t, z
|
||||
|
||||
|
||||
def test_rewrite_single():
|
||||
def t(expr, c, m):
|
||||
e = _rewrite_single(meijerg([a], [b], [c], [d], expr), x)
|
||||
assert e is not None
|
||||
assert isinstance(e[0][0][2], meijerg)
|
||||
assert e[0][0][2].argument.as_coeff_mul(x) == (c, (m,))
|
||||
|
||||
def tn(expr):
|
||||
assert _rewrite_single(meijerg([a], [b], [c], [d], expr), x) is None
|
||||
|
||||
t(x, 1, x)
|
||||
t(x**2, 1, x**2)
|
||||
t(x**2 + y*x**2, y + 1, x**2)
|
||||
tn(x**2 + x)
|
||||
tn(x**y)
|
||||
|
||||
def u(expr, x):
|
||||
from sympy.core.add import Add
|
||||
r = _rewrite_single(expr, x)
|
||||
e = Add(*[res[0]*res[2] for res in r[0]]).replace(
|
||||
exp_polar, exp) # XXX Hack?
|
||||
assert verify_numerically(e, expr, x)
|
||||
|
||||
u(exp(-x)*sin(x), x)
|
||||
|
||||
# The following has stopped working because hyperexpand changed slightly.
|
||||
# It is probably not worth fixing
|
||||
#u(exp(-x)*sin(x)*cos(x), x)
|
||||
|
||||
# This one cannot be done numerically, since it comes out as a g-function
|
||||
# of argument 4*pi
|
||||
# NOTE This also tests a bug in inverse mellin transform (which used to
|
||||
# turn exp(4*pi*I*t) into a factor of exp(4*pi*I)**t instead of
|
||||
# exp_polar).
|
||||
#u(exp(x)*sin(x), x)
|
||||
assert _rewrite_single(exp(x)*sin(x), x) == \
|
||||
([(-sqrt(2)/(2*sqrt(pi)), 0,
|
||||
meijerg(((Rational(-1, 2), 0, Rational(1, 4), S.Half, Rational(3, 4)), (1,)),
|
||||
((), (Rational(-1, 2), 0)), 64*exp_polar(-4*I*pi)/x**4))], True)
|
||||
|
||||
|
||||
def test_rewrite1():
|
||||
assert _rewrite1(x**3*meijerg([a], [b], [c], [d], x**2 + y*x**2)*5, x) == \
|
||||
(5, x**3, [(1, 0, meijerg([a], [b], [c], [d], x**2*(y + 1)))], True)
|
||||
|
||||
|
||||
def test_meijerint_indefinite_numerically():
|
||||
def t(fac, arg):
|
||||
g = meijerg([a], [b], [c], [d], arg)*fac
|
||||
subs = {a: randcplx()/10, b: randcplx()/10 + I,
|
||||
c: randcplx(), d: randcplx()}
|
||||
integral = meijerint_indefinite(g, x)
|
||||
assert integral is not None
|
||||
assert verify_numerically(g.subs(subs), integral.diff(x).subs(subs), x)
|
||||
t(1, x)
|
||||
t(2, x)
|
||||
t(1, 2*x)
|
||||
t(1, x**2)
|
||||
t(5, x**S('3/2'))
|
||||
t(x**3, x)
|
||||
t(3*x**S('3/2'), 4*x**S('7/3'))
|
||||
|
||||
|
||||
def test_meijerint_definite():
|
||||
v, b = meijerint_definite(x, x, 0, 0)
|
||||
assert v.is_zero and b is True
|
||||
v, b = meijerint_definite(x, x, oo, oo)
|
||||
assert v.is_zero and b is True
|
||||
|
||||
|
||||
def test_inflate():
|
||||
subs = {a: randcplx()/10, b: randcplx()/10 + I, c: randcplx(),
|
||||
d: randcplx(), y: randcplx()/10}
|
||||
|
||||
def t(a, b, arg, n):
|
||||
from sympy.core.mul import Mul
|
||||
m1 = meijerg(a, b, arg)
|
||||
m2 = Mul(*_inflate_g(m1, n))
|
||||
# NOTE: (the random number)**9 must still be on the principal sheet.
|
||||
# Thus make b&d small to create random numbers of small imaginary part.
|
||||
return verify_numerically(m1.subs(subs), m2.subs(subs), x, b=0.1, d=-0.1)
|
||||
assert t([[a], [b]], [[c], [d]], x, 3)
|
||||
assert t([[a, y], [b]], [[c], [d]], x, 3)
|
||||
assert t([[a], [b]], [[c, y], [d]], 2*x**3, 3)
|
||||
|
||||
|
||||
def test_recursive():
|
||||
from sympy.core.symbol import symbols
|
||||
a, b, c = symbols('a b c', positive=True)
|
||||
r = exp(-(x - a)**2)*exp(-(x - b)**2)
|
||||
e = integrate(r, (x, 0, oo), meijerg=True)
|
||||
assert simplify(e.expand()) == (
|
||||
sqrt(2)*sqrt(pi)*(
|
||||
(erf(sqrt(2)*(a + b)/2) + 1)*exp(-a**2/2 + a*b - b**2/2))/4)
|
||||
e = integrate(exp(-(x - a)**2)*exp(-(x - b)**2)*exp(c*x), (x, 0, oo), meijerg=True)
|
||||
assert simplify(e) == (
|
||||
sqrt(2)*sqrt(pi)*(erf(sqrt(2)*(2*a + 2*b + c)/4) + 1)*exp(-a**2 - b**2
|
||||
+ (2*a + 2*b + c)**2/8)/4)
|
||||
assert simplify(integrate(exp(-(x - a - b - c)**2), (x, 0, oo), meijerg=True)) == \
|
||||
sqrt(pi)/2*(1 + erf(a + b + c))
|
||||
assert simplify(integrate(exp(-(x + a + b + c)**2), (x, 0, oo), meijerg=True)) == \
|
||||
sqrt(pi)/2*(1 - erf(a + b + c))
|
||||
|
||||
|
||||
@slow
|
||||
def test_meijerint():
|
||||
from sympy.core.function import expand
|
||||
from sympy.core.symbol import symbols
|
||||
s, t, mu = symbols('s t mu', real=True)
|
||||
assert integrate(meijerg([], [], [0], [], s*t)
|
||||
*meijerg([], [], [mu/2], [-mu/2], t**2/4),
|
||||
(t, 0, oo)).is_Piecewise
|
||||
s = symbols('s', positive=True)
|
||||
assert integrate(x**s*meijerg([[], []], [[0], []], x), (x, 0, oo)) == \
|
||||
gamma(s + 1)
|
||||
assert integrate(x**s*meijerg([[], []], [[0], []], x), (x, 0, oo),
|
||||
meijerg=True) == gamma(s + 1)
|
||||
assert isinstance(integrate(x**s*meijerg([[], []], [[0], []], x),
|
||||
(x, 0, oo), meijerg=False),
|
||||
Integral)
|
||||
|
||||
assert meijerint_indefinite(exp(x), x) == exp(x)
|
||||
|
||||
# TODO what simplifications should be done automatically?
|
||||
# This tests "extra case" for antecedents_1.
|
||||
a, b = symbols('a b', positive=True)
|
||||
assert simplify(meijerint_definite(x**a, x, 0, b)[0]) == \
|
||||
b**(a + 1)/(a + 1)
|
||||
|
||||
# This tests various conditions and expansions:
|
||||
assert meijerint_definite((x + 1)**3*exp(-x), x, 0, oo) == (16, True)
|
||||
|
||||
# Again, how about simplifications?
|
||||
sigma, mu = symbols('sigma mu', positive=True)
|
||||
i, c = meijerint_definite(exp(-((x - mu)/(2*sigma))**2), x, 0, oo)
|
||||
assert simplify(i) == sqrt(pi)*sigma*(2 - erfc(mu/(2*sigma)))
|
||||
assert c == True
|
||||
|
||||
i, _ = meijerint_definite(exp(-mu*x)*exp(sigma*x), x, 0, oo)
|
||||
# TODO it would be nice to test the condition
|
||||
assert simplify(i) == 1/(mu - sigma)
|
||||
|
||||
# Test substitutions to change limits
|
||||
assert meijerint_definite(exp(x), x, -oo, 2) == (exp(2), True)
|
||||
# Note: causes a NaN in _check_antecedents
|
||||
assert expand(meijerint_definite(exp(x), x, 0, I)[0]) == exp(I) - 1
|
||||
assert expand(meijerint_definite(exp(-x), x, 0, x)[0]) == \
|
||||
1 - exp(-exp(I*arg(x))*abs(x))
|
||||
|
||||
# Test -oo to oo
|
||||
assert meijerint_definite(exp(-x**2), x, -oo, oo) == (sqrt(pi), True)
|
||||
assert meijerint_definite(exp(-abs(x)), x, -oo, oo) == (2, True)
|
||||
assert meijerint_definite(exp(-(2*x - 3)**2), x, -oo, oo) == \
|
||||
(sqrt(pi)/2, True)
|
||||
assert meijerint_definite(exp(-abs(2*x - 3)), x, -oo, oo) == (1, True)
|
||||
assert meijerint_definite(exp(-((x - mu)/sigma)**2/2)/sqrt(2*pi*sigma**2),
|
||||
x, -oo, oo) == (1, True)
|
||||
assert meijerint_definite(sinc(x)**2, x, -oo, oo) == (pi, True)
|
||||
|
||||
# Test one of the extra conditions for 2 g-functinos
|
||||
assert meijerint_definite(exp(-x)*sin(x), x, 0, oo) == (S.Half, True)
|
||||
|
||||
# Test a bug
|
||||
def res(n):
|
||||
return (1/(1 + x**2)).diff(x, n).subs(x, 1)*(-1)**n
|
||||
for n in range(6):
|
||||
assert integrate(exp(-x)*sin(x)*x**n, (x, 0, oo), meijerg=True) == \
|
||||
res(n)
|
||||
|
||||
# This used to test trigexpand... now it is done by linear substitution
|
||||
assert simplify(integrate(exp(-x)*sin(x + a), (x, 0, oo), meijerg=True)
|
||||
) == sqrt(2)*sin(a + pi/4)/2
|
||||
|
||||
# Test the condition 14 from prudnikov.
|
||||
# (This is besselj*besselj in disguise, to stop the product from being
|
||||
# recognised in the tables.)
|
||||
a, b, s = symbols('a b s')
|
||||
assert meijerint_definite(meijerg([], [], [a/2], [-a/2], x/4)
|
||||
*meijerg([], [], [b/2], [-b/2], x/4)*x**(s - 1), x, 0, oo
|
||||
) == (
|
||||
(4*2**(2*s - 2)*gamma(-2*s + 1)*gamma(a/2 + b/2 + s)
|
||||
/(gamma(-a/2 + b/2 - s + 1)*gamma(a/2 - b/2 - s + 1)
|
||||
*gamma(a/2 + b/2 - s + 1)),
|
||||
(re(s) < 1) & (re(s) < S(1)/2) & (re(a)/2 + re(b)/2 + re(s) > 0)))
|
||||
|
||||
# test a bug
|
||||
assert integrate(sin(x**a)*sin(x**b), (x, 0, oo), meijerg=True) == \
|
||||
Integral(sin(x**a)*sin(x**b), (x, 0, oo))
|
||||
|
||||
# test better hyperexpand
|
||||
assert integrate(exp(-x**2)*log(x), (x, 0, oo), meijerg=True) == \
|
||||
(sqrt(pi)*polygamma(0, S.Half)/4).expand()
|
||||
|
||||
# Test hyperexpand bug.
|
||||
from sympy.functions.special.gamma_functions import lowergamma
|
||||
n = symbols('n', integer=True)
|
||||
assert simplify(integrate(exp(-x)*x**n, x, meijerg=True)) == \
|
||||
lowergamma(n + 1, x)
|
||||
|
||||
# Test a bug with argument 1/x
|
||||
alpha = symbols('alpha', positive=True)
|
||||
assert meijerint_definite((2 - x)**alpha*sin(alpha/x), x, 0, 2) == \
|
||||
(sqrt(pi)*alpha*gamma(alpha + 1)*meijerg(((), (alpha/2 + S.Half,
|
||||
alpha/2 + 1)), ((0, 0, S.Half), (Rational(-1, 2),)), alpha**2/16)/4, True)
|
||||
|
||||
# test a bug related to 3016
|
||||
a, s = symbols('a s', positive=True)
|
||||
assert simplify(integrate(x**s*exp(-a*x**2), (x, -oo, oo))) == \
|
||||
a**(-s/2 - S.Half)*((-1)**s + 1)*gamma(s/2 + S.Half)/2
|
||||
|
||||
|
||||
def test_bessel():
|
||||
from sympy.functions.special.bessel import (besseli, besselj)
|
||||
assert simplify(integrate(besselj(a, z)*besselj(b, z)/z, (z, 0, oo),
|
||||
meijerg=True, conds='none')) == \
|
||||
2*sin(pi*(a/2 - b/2))/(pi*(a - b)*(a + b))
|
||||
assert simplify(integrate(besselj(a, z)*besselj(a, z)/z, (z, 0, oo),
|
||||
meijerg=True, conds='none')) == 1/(2*a)
|
||||
|
||||
# TODO more orthogonality integrals
|
||||
|
||||
assert simplify(integrate(sin(z*x)*(x**2 - 1)**(-(y + S.Half)),
|
||||
(x, 1, oo), meijerg=True, conds='none')
|
||||
*2/((z/2)**y*sqrt(pi)*gamma(S.Half - y))) == \
|
||||
besselj(y, z)
|
||||
|
||||
# Werner Rosenheinrich
|
||||
# SOME INDEFINITE INTEGRALS OF BESSEL FUNCTIONS
|
||||
|
||||
assert integrate(x*besselj(0, x), x, meijerg=True) == x*besselj(1, x)
|
||||
assert integrate(x*besseli(0, x), x, meijerg=True) == x*besseli(1, x)
|
||||
# TODO can do higher powers, but come out as high order ... should they be
|
||||
# reduced to order 0, 1?
|
||||
assert integrate(besselj(1, x), x, meijerg=True) == -besselj(0, x)
|
||||
assert integrate(besselj(1, x)**2/x, x, meijerg=True) == \
|
||||
-(besselj(0, x)**2 + besselj(1, x)**2)/2
|
||||
# TODO more besseli when tables are extended or recursive mellin works
|
||||
assert integrate(besselj(0, x)**2/x**2, x, meijerg=True) == \
|
||||
-2*x*besselj(0, x)**2 - 2*x*besselj(1, x)**2 \
|
||||
+ 2*besselj(0, x)*besselj(1, x) - besselj(0, x)**2/x
|
||||
assert integrate(besselj(0, x)*besselj(1, x), x, meijerg=True) == \
|
||||
-besselj(0, x)**2/2
|
||||
assert integrate(x**2*besselj(0, x)*besselj(1, x), x, meijerg=True) == \
|
||||
x**2*besselj(1, x)**2/2
|
||||
assert integrate(besselj(0, x)*besselj(1, x)/x, x, meijerg=True) == \
|
||||
(x*besselj(0, x)**2 + x*besselj(1, x)**2 -
|
||||
besselj(0, x)*besselj(1, x))
|
||||
# TODO how does besselj(0, a*x)*besselj(0, b*x) work?
|
||||
# TODO how does besselj(0, x)**2*besselj(1, x)**2 work?
|
||||
# TODO sin(x)*besselj(0, x) etc come out a mess
|
||||
# TODO can x*log(x)*besselj(0, x) be done?
|
||||
# TODO how does besselj(1, x)*besselj(0, x+a) work?
|
||||
# TODO more indefinite integrals when struve functions etc are implemented
|
||||
|
||||
# test a substitution
|
||||
assert integrate(besselj(1, x**2)*x, x, meijerg=True) == \
|
||||
-besselj(0, x**2)/2
|
||||
|
||||
|
||||
def test_inversion():
|
||||
from sympy.functions.special.bessel import besselj
|
||||
from sympy.functions.special.delta_functions import Heaviside
|
||||
|
||||
def inv(f):
|
||||
return piecewise_fold(meijerint_inversion(f, s, t))
|
||||
assert inv(1/(s**2 + 1)) == sin(t)*Heaviside(t)
|
||||
assert inv(s/(s**2 + 1)) == cos(t)*Heaviside(t)
|
||||
assert inv(exp(-s)/s) == Heaviside(t - 1)
|
||||
assert inv(1/sqrt(1 + s**2)) == besselj(0, t)*Heaviside(t)
|
||||
|
||||
# Test some antcedents checking.
|
||||
assert meijerint_inversion(sqrt(s)/sqrt(1 + s**2), s, t) is None
|
||||
assert inv(exp(s**2)) is None
|
||||
assert meijerint_inversion(exp(-s**2), s, t) is None
|
||||
|
||||
|
||||
def test_inversion_conditional_output():
|
||||
from sympy.core.symbol import Symbol
|
||||
from sympy.integrals.transforms import InverseLaplaceTransform
|
||||
|
||||
a = Symbol('a', positive=True)
|
||||
F = sqrt(pi/a)*exp(-2*sqrt(a)*sqrt(s))
|
||||
f = meijerint_inversion(F, s, t)
|
||||
assert not f.is_Piecewise
|
||||
|
||||
b = Symbol('b', real=True)
|
||||
F = F.subs(a, b)
|
||||
f2 = meijerint_inversion(F, s, t)
|
||||
assert f2.is_Piecewise
|
||||
# first piece is same as f
|
||||
assert f2.args[0][0] == f.subs(a, b)
|
||||
# last piece is an unevaluated transform
|
||||
assert f2.args[-1][1]
|
||||
ILT = InverseLaplaceTransform(F, s, t, None)
|
||||
assert f2.args[-1][0] == ILT or f2.args[-1][0] == ILT.as_integral
|
||||
|
||||
|
||||
def test_inversion_exp_real_nonreal_shift():
|
||||
from sympy.core.symbol import Symbol
|
||||
from sympy.functions.special.delta_functions import DiracDelta
|
||||
r = Symbol('r', real=True)
|
||||
c = Symbol('c', extended_real=False)
|
||||
a = 1 + 2*I
|
||||
z = Symbol('z')
|
||||
assert not meijerint_inversion(exp(r*s), s, t).is_Piecewise
|
||||
assert meijerint_inversion(exp(a*s), s, t) is None
|
||||
assert meijerint_inversion(exp(c*s), s, t) is None
|
||||
f = meijerint_inversion(exp(z*s), s, t)
|
||||
assert f.is_Piecewise
|
||||
assert isinstance(f.args[0][0], DiracDelta)
|
||||
|
||||
|
||||
@slow
|
||||
def test_lookup_table():
|
||||
from sympy.core.random import uniform, randrange
|
||||
from sympy.core.add import Add
|
||||
from sympy.integrals.meijerint import z as z_dummy
|
||||
table = {}
|
||||
_create_lookup_table(table)
|
||||
for l in table.values():
|
||||
for formula, terms, cond, hint in sorted(l, key=default_sort_key):
|
||||
subs = {}
|
||||
for ai in list(formula.free_symbols) + [z_dummy]:
|
||||
if hasattr(ai, 'properties') and ai.properties:
|
||||
# these Wilds match positive integers
|
||||
subs[ai] = randrange(1, 10)
|
||||
else:
|
||||
subs[ai] = uniform(1.5, 2.0)
|
||||
if not isinstance(terms, list):
|
||||
terms = terms(subs)
|
||||
|
||||
# First test that hyperexpand can do this.
|
||||
expanded = [hyperexpand(g) for (_, g) in terms]
|
||||
assert all(x.is_Piecewise or not x.has(meijerg) for x in expanded)
|
||||
|
||||
# Now test that the meijer g-function is indeed as advertised.
|
||||
expanded = Add(*[f*x for (f, x) in terms])
|
||||
a, b = formula.n(subs=subs), expanded.n(subs=subs)
|
||||
r = min(abs(a), abs(b))
|
||||
if r < 1:
|
||||
assert abs(a - b).n() <= 1e-10
|
||||
else:
|
||||
assert (abs(a - b)/r).n() <= 1e-10
|
||||
|
||||
|
||||
def test_branch_bug():
|
||||
from sympy.functions.special.gamma_functions import lowergamma
|
||||
from sympy.simplify.powsimp import powdenest
|
||||
# TODO gammasimp cannot prove that the factor is unity
|
||||
assert powdenest(integrate(erf(x**3), x, meijerg=True).diff(x),
|
||||
polar=True) == 2*erf(x**3)*gamma(Rational(2, 3))/3/gamma(Rational(5, 3))
|
||||
assert integrate(erf(x**3), x, meijerg=True) == \
|
||||
2*x*erf(x**3)*gamma(Rational(2, 3))/(3*gamma(Rational(5, 3))) \
|
||||
- 2*gamma(Rational(2, 3))*lowergamma(Rational(2, 3), x**6)/(3*sqrt(pi)*gamma(Rational(5, 3)))
|
||||
|
||||
|
||||
def test_linear_subs():
|
||||
from sympy.functions.special.bessel import besselj
|
||||
assert integrate(sin(x - 1), x, meijerg=True) == -cos(1 - x)
|
||||
assert integrate(besselj(1, x - 1), x, meijerg=True) == -besselj(0, 1 - x)
|
||||
|
||||
|
||||
@slow
|
||||
def test_probability():
|
||||
# various integrals from probability theory
|
||||
from sympy.core.function import expand_mul
|
||||
from sympy.core.symbol import (Symbol, symbols)
|
||||
from sympy.simplify.gammasimp import gammasimp
|
||||
from sympy.simplify.powsimp import powsimp
|
||||
mu1, mu2 = symbols('mu1 mu2', nonzero=True)
|
||||
sigma1, sigma2 = symbols('sigma1 sigma2', positive=True)
|
||||
rate = Symbol('lambda', positive=True)
|
||||
|
||||
def normal(x, mu, sigma):
|
||||
return 1/sqrt(2*pi*sigma**2)*exp(-(x - mu)**2/2/sigma**2)
|
||||
|
||||
def exponential(x, rate):
|
||||
return rate*exp(-rate*x)
|
||||
|
||||
assert integrate(normal(x, mu1, sigma1), (x, -oo, oo), meijerg=True) == 1
|
||||
assert integrate(x*normal(x, mu1, sigma1), (x, -oo, oo), meijerg=True) == \
|
||||
mu1
|
||||
assert integrate(x**2*normal(x, mu1, sigma1), (x, -oo, oo), meijerg=True) \
|
||||
== mu1**2 + sigma1**2
|
||||
assert integrate(x**3*normal(x, mu1, sigma1), (x, -oo, oo), meijerg=True) \
|
||||
== mu1**3 + 3*mu1*sigma1**2
|
||||
assert integrate(normal(x, mu1, sigma1)*normal(y, mu2, sigma2),
|
||||
(x, -oo, oo), (y, -oo, oo), meijerg=True) == 1
|
||||
assert integrate(x*normal(x, mu1, sigma1)*normal(y, mu2, sigma2),
|
||||
(x, -oo, oo), (y, -oo, oo), meijerg=True) == mu1
|
||||
assert integrate(y*normal(x, mu1, sigma1)*normal(y, mu2, sigma2),
|
||||
(x, -oo, oo), (y, -oo, oo), meijerg=True) == mu2
|
||||
assert integrate(x*y*normal(x, mu1, sigma1)*normal(y, mu2, sigma2),
|
||||
(x, -oo, oo), (y, -oo, oo), meijerg=True) == mu1*mu2
|
||||
assert integrate((x + y + 1)*normal(x, mu1, sigma1)*normal(y, mu2, sigma2),
|
||||
(x, -oo, oo), (y, -oo, oo), meijerg=True) == 1 + mu1 + mu2
|
||||
assert integrate((x + y - 1)*normal(x, mu1, sigma1)*normal(y, mu2, sigma2),
|
||||
(x, -oo, oo), (y, -oo, oo), meijerg=True) == \
|
||||
-1 + mu1 + mu2
|
||||
|
||||
i = integrate(x**2*normal(x, mu1, sigma1)*normal(y, mu2, sigma2),
|
||||
(x, -oo, oo), (y, -oo, oo), meijerg=True)
|
||||
assert not i.has(Abs)
|
||||
assert simplify(i) == mu1**2 + sigma1**2
|
||||
assert integrate(y**2*normal(x, mu1, sigma1)*normal(y, mu2, sigma2),
|
||||
(x, -oo, oo), (y, -oo, oo), meijerg=True) == \
|
||||
sigma2**2 + mu2**2
|
||||
|
||||
assert integrate(exponential(x, rate), (x, 0, oo), meijerg=True) == 1
|
||||
assert integrate(x*exponential(x, rate), (x, 0, oo), meijerg=True) == \
|
||||
1/rate
|
||||
assert integrate(x**2*exponential(x, rate), (x, 0, oo), meijerg=True) == \
|
||||
2/rate**2
|
||||
|
||||
def E(expr):
|
||||
res1 = integrate(expr*exponential(x, rate)*normal(y, mu1, sigma1),
|
||||
(x, 0, oo), (y, -oo, oo), meijerg=True)
|
||||
res2 = integrate(expr*exponential(x, rate)*normal(y, mu1, sigma1),
|
||||
(y, -oo, oo), (x, 0, oo), meijerg=True)
|
||||
assert expand_mul(res1) == expand_mul(res2)
|
||||
return res1
|
||||
|
||||
assert E(1) == 1
|
||||
assert E(x*y) == mu1/rate
|
||||
assert E(x*y**2) == mu1**2/rate + sigma1**2/rate
|
||||
ans = sigma1**2 + 1/rate**2
|
||||
assert simplify(E((x + y + 1)**2) - E(x + y + 1)**2) == ans
|
||||
assert simplify(E((x + y - 1)**2) - E(x + y - 1)**2) == ans
|
||||
assert simplify(E((x + y)**2) - E(x + y)**2) == ans
|
||||
|
||||
# Beta' distribution
|
||||
alpha, beta = symbols('alpha beta', positive=True)
|
||||
betadist = x**(alpha - 1)*(1 + x)**(-alpha - beta)*gamma(alpha + beta) \
|
||||
/gamma(alpha)/gamma(beta)
|
||||
assert integrate(betadist, (x, 0, oo), meijerg=True) == 1
|
||||
i = integrate(x*betadist, (x, 0, oo), meijerg=True, conds='separate')
|
||||
assert (gammasimp(i[0]), i[1]) == (alpha/(beta - 1), 1 < beta)
|
||||
j = integrate(x**2*betadist, (x, 0, oo), meijerg=True, conds='separate')
|
||||
assert j[1] == (beta > 2)
|
||||
assert gammasimp(j[0] - i[0]**2) == (alpha + beta - 1)*alpha \
|
||||
/(beta - 2)/(beta - 1)**2
|
||||
|
||||
# Beta distribution
|
||||
# NOTE: this is evaluated using antiderivatives. It also tests that
|
||||
# meijerint_indefinite returns the simplest possible answer.
|
||||
a, b = symbols('a b', positive=True)
|
||||
betadist = x**(a - 1)*(-x + 1)**(b - 1)*gamma(a + b)/(gamma(a)*gamma(b))
|
||||
assert simplify(integrate(betadist, (x, 0, 1), meijerg=True)) == 1
|
||||
assert simplify(integrate(x*betadist, (x, 0, 1), meijerg=True)) == \
|
||||
a/(a + b)
|
||||
assert simplify(integrate(x**2*betadist, (x, 0, 1), meijerg=True)) == \
|
||||
a*(a + 1)/(a + b)/(a + b + 1)
|
||||
assert simplify(integrate(x**y*betadist, (x, 0, 1), meijerg=True)) == \
|
||||
gamma(a + b)*gamma(a + y)/gamma(a)/gamma(a + b + y)
|
||||
|
||||
# Chi distribution
|
||||
k = Symbol('k', integer=True, positive=True)
|
||||
chi = 2**(1 - k/2)*x**(k - 1)*exp(-x**2/2)/gamma(k/2)
|
||||
assert powsimp(integrate(chi, (x, 0, oo), meijerg=True)) == 1
|
||||
assert simplify(integrate(x*chi, (x, 0, oo), meijerg=True)) == \
|
||||
sqrt(2)*gamma((k + 1)/2)/gamma(k/2)
|
||||
assert simplify(integrate(x**2*chi, (x, 0, oo), meijerg=True)) == k
|
||||
|
||||
# Chi^2 distribution
|
||||
chisquared = 2**(-k/2)/gamma(k/2)*x**(k/2 - 1)*exp(-x/2)
|
||||
assert powsimp(integrate(chisquared, (x, 0, oo), meijerg=True)) == 1
|
||||
assert simplify(integrate(x*chisquared, (x, 0, oo), meijerg=True)) == k
|
||||
assert simplify(integrate(x**2*chisquared, (x, 0, oo), meijerg=True)) == \
|
||||
k*(k + 2)
|
||||
assert gammasimp(integrate(((x - k)/sqrt(2*k))**3*chisquared, (x, 0, oo),
|
||||
meijerg=True)) == 2*sqrt(2)/sqrt(k)
|
||||
|
||||
# Dagum distribution
|
||||
a, b, p = symbols('a b p', positive=True)
|
||||
# XXX (x/b)**a does not work
|
||||
dagum = a*p/x*(x/b)**(a*p)/(1 + x**a/b**a)**(p + 1)
|
||||
assert simplify(integrate(dagum, (x, 0, oo), meijerg=True)) == 1
|
||||
# XXX conditions are a mess
|
||||
arg = x*dagum
|
||||
assert simplify(integrate(arg, (x, 0, oo), meijerg=True, conds='none')
|
||||
) == a*b*gamma(1 - 1/a)*gamma(p + 1 + 1/a)/(
|
||||
(a*p + 1)*gamma(p))
|
||||
assert simplify(integrate(x*arg, (x, 0, oo), meijerg=True, conds='none')
|
||||
) == a*b**2*gamma(1 - 2/a)*gamma(p + 1 + 2/a)/(
|
||||
(a*p + 2)*gamma(p))
|
||||
|
||||
# F-distribution
|
||||
d1, d2 = symbols('d1 d2', positive=True)
|
||||
f = sqrt(((d1*x)**d1 * d2**d2)/(d1*x + d2)**(d1 + d2))/x \
|
||||
/gamma(d1/2)/gamma(d2/2)*gamma((d1 + d2)/2)
|
||||
assert simplify(integrate(f, (x, 0, oo), meijerg=True)) == 1
|
||||
# TODO conditions are a mess
|
||||
assert simplify(integrate(x*f, (x, 0, oo), meijerg=True, conds='none')
|
||||
) == d2/(d2 - 2)
|
||||
assert simplify(integrate(x**2*f, (x, 0, oo), meijerg=True, conds='none')
|
||||
) == d2**2*(d1 + 2)/d1/(d2 - 4)/(d2 - 2)
|
||||
|
||||
# TODO gamma, rayleigh
|
||||
|
||||
# inverse gaussian
|
||||
lamda, mu = symbols('lamda mu', positive=True)
|
||||
dist = sqrt(lamda/2/pi)*x**(Rational(-3, 2))*exp(-lamda*(x - mu)**2/x/2/mu**2)
|
||||
mysimp = lambda expr: simplify(expr.rewrite(exp))
|
||||
assert mysimp(integrate(dist, (x, 0, oo))) == 1
|
||||
assert mysimp(integrate(x*dist, (x, 0, oo))) == mu
|
||||
assert mysimp(integrate((x - mu)**2*dist, (x, 0, oo))) == mu**3/lamda
|
||||
assert mysimp(integrate((x - mu)**3*dist, (x, 0, oo))) == 3*mu**5/lamda**2
|
||||
|
||||
# Levi
|
||||
c = Symbol('c', positive=True)
|
||||
assert integrate(sqrt(c/2/pi)*exp(-c/2/(x - mu))/(x - mu)**S('3/2'),
|
||||
(x, mu, oo)) == 1
|
||||
# higher moments oo
|
||||
|
||||
# log-logistic
|
||||
alpha, beta = symbols('alpha beta', positive=True)
|
||||
distn = (beta/alpha)*x**(beta - 1)/alpha**(beta - 1)/ \
|
||||
(1 + x**beta/alpha**beta)**2
|
||||
# FIXME: If alpha, beta are not declared as finite the line below hangs
|
||||
# after the changes in:
|
||||
# https://github.com/sympy/sympy/pull/16603
|
||||
assert simplify(integrate(distn, (x, 0, oo))) == 1
|
||||
# NOTE the conditions are a mess, but correctly state beta > 1
|
||||
assert simplify(integrate(x*distn, (x, 0, oo), conds='none')) == \
|
||||
pi*alpha/beta/sin(pi/beta)
|
||||
# (similar comment for conditions applies)
|
||||
assert simplify(integrate(x**y*distn, (x, 0, oo), conds='none')) == \
|
||||
pi*alpha**y*y/beta/sin(pi*y/beta)
|
||||
|
||||
# weibull
|
||||
k = Symbol('k', positive=True)
|
||||
n = Symbol('n', positive=True)
|
||||
distn = k/lamda*(x/lamda)**(k - 1)*exp(-(x/lamda)**k)
|
||||
assert simplify(integrate(distn, (x, 0, oo))) == 1
|
||||
assert simplify(integrate(x**n*distn, (x, 0, oo))) == \
|
||||
lamda**n*gamma(1 + n/k)
|
||||
|
||||
# rice distribution
|
||||
from sympy.functions.special.bessel import besseli
|
||||
nu, sigma = symbols('nu sigma', positive=True)
|
||||
rice = x/sigma**2*exp(-(x**2 + nu**2)/2/sigma**2)*besseli(0, x*nu/sigma**2)
|
||||
assert integrate(rice, (x, 0, oo), meijerg=True) == 1
|
||||
# can someone verify higher moments?
|
||||
|
||||
# Laplace distribution
|
||||
mu = Symbol('mu', real=True)
|
||||
b = Symbol('b', positive=True)
|
||||
laplace = exp(-abs(x - mu)/b)/2/b
|
||||
assert integrate(laplace, (x, -oo, oo), meijerg=True) == 1
|
||||
assert integrate(x*laplace, (x, -oo, oo), meijerg=True) == mu
|
||||
assert integrate(x**2*laplace, (x, -oo, oo), meijerg=True) == \
|
||||
2*b**2 + mu**2
|
||||
|
||||
# TODO are there other distributions supported on (-oo, oo) that we can do?
|
||||
|
||||
# misc tests
|
||||
k = Symbol('k', positive=True)
|
||||
assert gammasimp(expand_mul(integrate(log(x)*x**(k - 1)*exp(-x)/gamma(k),
|
||||
(x, 0, oo)))) == polygamma(0, k)
|
||||
|
||||
|
||||
@slow
|
||||
def test_expint():
|
||||
""" Test various exponential integrals. """
|
||||
from sympy.core.symbol import Symbol
|
||||
from sympy.functions.elementary.hyperbolic import sinh
|
||||
from sympy.functions.special.error_functions import (Chi, Ci, Ei, Shi, Si, expint)
|
||||
assert simplify(unpolarify(integrate(exp(-z*x)/x**y, (x, 1, oo),
|
||||
meijerg=True, conds='none'
|
||||
).rewrite(expint).expand(func=True))) == expint(y, z)
|
||||
|
||||
assert integrate(exp(-z*x)/x, (x, 1, oo), meijerg=True,
|
||||
conds='none').rewrite(expint).expand() == \
|
||||
expint(1, z)
|
||||
assert integrate(exp(-z*x)/x**2, (x, 1, oo), meijerg=True,
|
||||
conds='none').rewrite(expint).expand() == \
|
||||
expint(2, z).rewrite(Ei).rewrite(expint)
|
||||
assert integrate(exp(-z*x)/x**3, (x, 1, oo), meijerg=True,
|
||||
conds='none').rewrite(expint).expand() == \
|
||||
expint(3, z).rewrite(Ei).rewrite(expint).expand()
|
||||
|
||||
t = Symbol('t', positive=True)
|
||||
assert integrate(-cos(x)/x, (x, t, oo), meijerg=True).expand() == Ci(t)
|
||||
assert integrate(-sin(x)/x, (x, t, oo), meijerg=True).expand() == \
|
||||
Si(t) - pi/2
|
||||
assert integrate(sin(x)/x, (x, 0, z), meijerg=True) == Si(z)
|
||||
assert integrate(sinh(x)/x, (x, 0, z), meijerg=True) == Shi(z)
|
||||
assert integrate(exp(-x)/x, x, meijerg=True).expand().rewrite(expint) == \
|
||||
I*pi - expint(1, x)
|
||||
assert integrate(exp(-x)/x**2, x, meijerg=True).rewrite(expint).expand() \
|
||||
== expint(1, x) - exp(-x)/x - I*pi
|
||||
|
||||
u = Symbol('u', polar=True)
|
||||
assert integrate(cos(u)/u, u, meijerg=True).expand().as_independent(u)[1] \
|
||||
== Ci(u)
|
||||
assert integrate(cosh(u)/u, u, meijerg=True).expand().as_independent(u)[1] \
|
||||
== Chi(u)
|
||||
|
||||
assert integrate(expint(1, x), x, meijerg=True
|
||||
).rewrite(expint).expand() == x*expint(1, x) - exp(-x)
|
||||
assert integrate(expint(2, x), x, meijerg=True
|
||||
).rewrite(expint).expand() == \
|
||||
-x**2*expint(1, x)/2 + x*exp(-x)/2 - exp(-x)/2
|
||||
assert simplify(unpolarify(integrate(expint(y, x), x,
|
||||
meijerg=True).rewrite(expint).expand(func=True))) == \
|
||||
-expint(y + 1, x)
|
||||
|
||||
assert integrate(Si(x), x, meijerg=True) == x*Si(x) + cos(x)
|
||||
assert integrate(Ci(u), u, meijerg=True).expand() == u*Ci(u) - sin(u)
|
||||
assert integrate(Shi(x), x, meijerg=True) == x*Shi(x) - cosh(x)
|
||||
assert integrate(Chi(u), u, meijerg=True).expand() == u*Chi(u) - sinh(u)
|
||||
|
||||
assert integrate(Si(x)*exp(-x), (x, 0, oo), meijerg=True) == pi/4
|
||||
assert integrate(expint(1, x)*sin(x), (x, 0, oo), meijerg=True) == log(2)/2
|
||||
|
||||
|
||||
def test_messy():
|
||||
from sympy.functions.elementary.hyperbolic import (acosh, acoth)
|
||||
from sympy.functions.elementary.trigonometric import (asin, atan)
|
||||
from sympy.functions.special.bessel import besselj
|
||||
from sympy.functions.special.error_functions import (Chi, E1, Shi, Si)
|
||||
from sympy.integrals.transforms import (fourier_transform, laplace_transform)
|
||||
assert (laplace_transform(Si(x), x, s, simplify=True) ==
|
||||
((-atan(s) + pi/2)/s, 0, True))
|
||||
|
||||
assert laplace_transform(Shi(x), x, s, simplify=True) == (
|
||||
acoth(s)/s, -oo, s**2 > 1)
|
||||
|
||||
# where should the logs be simplified?
|
||||
assert laplace_transform(Chi(x), x, s, simplify=True) == (
|
||||
(log(s**(-2)) - log(1 - 1/s**2))/(2*s), -oo, s**2 > 1)
|
||||
|
||||
# TODO maybe simplify the inequalities? when the simplification
|
||||
# allows for generators instead of symbols this will work
|
||||
assert laplace_transform(besselj(a, x), x, s)[1:] == \
|
||||
(0, (re(a) > -2) & (re(a) > -1))
|
||||
|
||||
# NOTE s < 0 can be done, but argument reduction is not good enough yet
|
||||
ans = fourier_transform(besselj(1, x)/x, x, s, noconds=False)
|
||||
assert (ans[0].factor(deep=True).expand(), ans[1]) == \
|
||||
(Piecewise((0, (s > 1/(2*pi)) | (s < -1/(2*pi))),
|
||||
(2*sqrt(-4*pi**2*s**2 + 1), True)), s > 0)
|
||||
# TODO FT(besselj(0,x)) - conditions are messy (but for acceptable reasons)
|
||||
# - folding could be better
|
||||
|
||||
assert integrate(E1(x)*besselj(0, x), (x, 0, oo), meijerg=True) == \
|
||||
log(1 + sqrt(2))
|
||||
assert integrate(E1(x)*besselj(1, x), (x, 0, oo), meijerg=True) == \
|
||||
log(S.Half + sqrt(2)/2)
|
||||
|
||||
assert integrate(1/x/sqrt(1 - x**2), x, meijerg=True) == \
|
||||
Piecewise((-acosh(1/x), abs(x**(-2)) > 1), (I*asin(1/x), True))
|
||||
|
||||
|
||||
def test_issue_6122():
|
||||
assert integrate(exp(-I*x**2), (x, -oo, oo), meijerg=True) == \
|
||||
-I*sqrt(pi)*exp(I*pi/4)
|
||||
|
||||
|
||||
def test_issue_6252():
|
||||
expr = 1/x/(a + b*x)**Rational(1, 3)
|
||||
anti = integrate(expr, x, meijerg=True)
|
||||
assert not anti.has(hyper)
|
||||
# XXX the expression is a mess, but actually upon differentiation and
|
||||
# putting in numerical values seems to work...
|
||||
|
||||
|
||||
def test_issue_6348():
|
||||
assert integrate(exp(I*x)/(1 + x**2), (x, -oo, oo)).simplify().rewrite(exp) \
|
||||
== pi*exp(-1)
|
||||
|
||||
|
||||
def test_fresnel():
|
||||
from sympy.functions.special.error_functions import (fresnelc, fresnels)
|
||||
|
||||
assert expand_func(integrate(sin(pi*x**2/2), x)) == fresnels(x)
|
||||
assert expand_func(integrate(cos(pi*x**2/2), x)) == fresnelc(x)
|
||||
|
||||
|
||||
def test_issue_6860():
|
||||
assert meijerint_indefinite(x**x**x, x) is None
|
||||
|
||||
|
||||
def test_issue_7337():
|
||||
f = meijerint_indefinite(x*sqrt(2*x + 3), x).together()
|
||||
assert f == sqrt(2*x + 3)*(2*x**2 + x - 3)/5
|
||||
assert f._eval_interval(x, S.NegativeOne, S.One) == Rational(2, 5)
|
||||
|
||||
|
||||
def test_issue_8368():
|
||||
assert meijerint_indefinite(cosh(x)*exp(-x*t), x) == (
|
||||
(-t - 1)*exp(x) + (-t + 1)*exp(-x))*exp(-t*x)/2/(t**2 - 1)
|
||||
|
||||
|
||||
def test_issue_10211():
|
||||
from sympy.abc import h, w
|
||||
assert integrate((1/sqrt((y-x)**2 + h**2)**3), (x,0,w), (y,0,w)) == \
|
||||
2*sqrt(1 + w**2/h**2)/h - 2/h
|
||||
|
||||
|
||||
def test_issue_11806():
|
||||
from sympy.core.symbol import symbols
|
||||
y, L = symbols('y L', positive=True)
|
||||
assert integrate(1/sqrt(x**2 + y**2)**3, (x, -L, L)) == \
|
||||
2*L/(y**2*sqrt(L**2 + y**2))
|
||||
|
||||
def test_issue_10681():
|
||||
from sympy.polys.domains.realfield import RR
|
||||
from sympy.abc import R, r
|
||||
f = integrate(r**2*(R**2-r**2)**0.5, r, meijerg=True)
|
||||
g = (1.0/3)*R**1.0*r**3*hyper((-0.5, Rational(3, 2)), (Rational(5, 2),),
|
||||
r**2*exp_polar(2*I*pi)/R**2)
|
||||
assert RR.almosteq((f/g).n(), 1.0, 1e-12)
|
||||
|
||||
def test_issue_13536():
|
||||
from sympy.core.symbol import Symbol
|
||||
a = Symbol('a', positive=True)
|
||||
assert integrate(1/x**2, (x, oo, a)) == -1/a
|
||||
|
||||
|
||||
def test_issue_6462():
|
||||
from sympy.core.symbol import Symbol
|
||||
x = Symbol('x')
|
||||
n = Symbol('n')
|
||||
# Not the actual issue, still wrong answer for n = 1, but that there is no
|
||||
# exception
|
||||
assert integrate(cos(x**n)/x**n, x, meijerg=True).subs(n, 2).equals(
|
||||
integrate(cos(x**2)/x**2, x, meijerg=True))
|
||||
|
||||
|
||||
def test_indefinite_1_bug():
|
||||
assert integrate((b + t)**(-a), t, meijerg=True) == -b*(1 + t/b)**(1 - a)/(a*b**a - b**a)
|
||||
|
||||
|
||||
def test_pr_23583():
|
||||
# This result is wrong. Check whether new result is correct when this test fail.
|
||||
assert integrate(1/sqrt((x - I)**2-1), meijerg=True) == \
|
||||
Piecewise((acosh(x - I), Abs((x - I)**2) > 1), (-I*asin(x - I), True))
|
||||
|
||||
|
||||
# 25786
|
||||
def test_integrate_function_of_square_over_negatives():
|
||||
assert integrate(exp(-x**2), (x,-5,0), meijerg=True) == sqrt(pi)/2 * erf(5)
|
||||
|
||||
|
||||
def test_issue_25949():
|
||||
from sympy.core.symbol import symbols
|
||||
y = symbols("y", nonzero=True)
|
||||
assert integrate(cosh(y*(x + 1)), (x, -1, -0.25), meijerg=True) == sinh(0.75*y)/y
|
||||
@@ -0,0 +1,322 @@
|
||||
"""Most of these tests come from the examples in Bronstein's book."""
|
||||
from sympy.integrals.risch import DifferentialExtension, derivation
|
||||
from sympy.integrals.prde import (prde_normal_denom, prde_special_denom,
|
||||
prde_linear_constraints, constant_system, prde_spde, prde_no_cancel_b_large,
|
||||
prde_no_cancel_b_small, limited_integrate_reduce, limited_integrate,
|
||||
is_deriv_k, is_log_deriv_k_t_radical, parametric_log_deriv_heu,
|
||||
is_log_deriv_k_t_radical_in_field, param_poly_rischDE, param_rischDE,
|
||||
prde_cancel_liouvillian)
|
||||
|
||||
from sympy.polys.polymatrix import PolyMatrix as Matrix
|
||||
|
||||
from sympy.core.numbers import Rational
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import symbols
|
||||
from sympy.polys.domains.rationalfield import QQ
|
||||
from sympy.polys.polytools import Poly
|
||||
from sympy.abc import x, t, n
|
||||
|
||||
t0, t1, t2, t3, k = symbols('t:4 k')
|
||||
|
||||
|
||||
def test_prde_normal_denom():
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t**2, t)]})
|
||||
fa = Poly(1, t)
|
||||
fd = Poly(x, t)
|
||||
G = [(Poly(t, t), Poly(1 + t**2, t)), (Poly(1, t), Poly(x + x*t**2, t))]
|
||||
assert prde_normal_denom(fa, fd, G, DE) == \
|
||||
(Poly(x, t, domain='ZZ(x)'), (Poly(1, t, domain='ZZ(x)'), Poly(1, t,
|
||||
domain='ZZ(x)')), [(Poly(x*t, t, domain='ZZ(x)'),
|
||||
Poly(t**2 + 1, t, domain='ZZ(x)')), (Poly(1, t, domain='ZZ(x)'),
|
||||
Poly(t**2 + 1, t, domain='ZZ(x)'))], Poly(1, t, domain='ZZ(x)'))
|
||||
G = [(Poly(t, t), Poly(t**2 + 2*t + 1, t)), (Poly(x*t, t),
|
||||
Poly(t**2 + 2*t + 1, t)), (Poly(x*t**2, t), Poly(t**2 + 2*t + 1, t))]
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]})
|
||||
assert prde_normal_denom(Poly(x, t), Poly(1, t), G, DE) == \
|
||||
(Poly(t + 1, t), (Poly((-1 + x)*t + x, t), Poly(1, t, domain='ZZ[x]')), [(Poly(t, t),
|
||||
Poly(1, t)), (Poly(x*t, t), Poly(1, t, domain='ZZ[x]')), (Poly(x*t**2, t),
|
||||
Poly(1, t, domain='ZZ[x]'))], Poly(t + 1, t))
|
||||
|
||||
|
||||
def test_prde_special_denom():
|
||||
a = Poly(t + 1, t)
|
||||
ba = Poly(t**2, t)
|
||||
bd = Poly(1, t)
|
||||
G = [(Poly(t, t), Poly(1, t)), (Poly(t**2, t), Poly(1, t)), (Poly(t**3, t), Poly(1, t))]
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]})
|
||||
assert prde_special_denom(a, ba, bd, G, DE) == \
|
||||
(Poly(t + 1, t), Poly(t**2, t), [(Poly(t, t), Poly(1, t)),
|
||||
(Poly(t**2, t), Poly(1, t)), (Poly(t**3, t), Poly(1, t))], Poly(1, t))
|
||||
G = [(Poly(t, t), Poly(1, t)), (Poly(1, t), Poly(t, t))]
|
||||
assert prde_special_denom(Poly(1, t), Poly(t**2, t), Poly(1, t), G, DE) == \
|
||||
(Poly(1, t), Poly(t**2 - 1, t), [(Poly(t**2, t), Poly(1, t)),
|
||||
(Poly(1, t), Poly(1, t))], Poly(t, t))
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-2*x*t0, t0)]})
|
||||
DE.decrement_level()
|
||||
G = [(Poly(t, t), Poly(t**2, t)), (Poly(2*t, t), Poly(t, t))]
|
||||
assert prde_special_denom(Poly(5*x*t + 1, t), Poly(t**2 + 2*x**3*t, t), Poly(t**3 + 2, t), G, DE) == \
|
||||
(Poly(5*x*t + 1, t), Poly(0, t, domain='ZZ[x]'), [(Poly(t, t), Poly(t**2, t)),
|
||||
(Poly(2*t, t), Poly(t, t))], Poly(1, x))
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly((t**2 + 1)*2*x, t)]})
|
||||
G = [(Poly(t + x, t), Poly(t*x, t)), (Poly(2*t, t), Poly(x**2, x))]
|
||||
assert prde_special_denom(Poly(5*x*t + 1, t), Poly(t**2 + 2*x**3*t, t), Poly(t**3, t), G, DE) == \
|
||||
(Poly(5*x*t + 1, t), Poly(0, t, domain='ZZ[x]'), [(Poly(t + x, t), Poly(x*t, t)),
|
||||
(Poly(2*t, t, x), Poly(x**2, t, x))], Poly(1, t))
|
||||
assert prde_special_denom(Poly(t + 1, t), Poly(t**2, t), Poly(t**3, t), G, DE) == \
|
||||
(Poly(t + 1, t), Poly(0, t, domain='ZZ[x]'), [(Poly(t + x, t), Poly(x*t, t)), (Poly(2*t, t, x),
|
||||
Poly(x**2, t, x))], Poly(1, t))
|
||||
|
||||
|
||||
def test_prde_linear_constraints():
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x)]})
|
||||
G = [(Poly(2*x**3 + 3*x + 1, x), Poly(x**2 - 1, x)), (Poly(1, x), Poly(x - 1, x)),
|
||||
(Poly(1, x), Poly(x + 1, x))]
|
||||
assert prde_linear_constraints(Poly(1, x), Poly(0, x), G, DE) == \
|
||||
((Poly(2*x, x, domain='QQ'), Poly(0, x, domain='QQ'), Poly(0, x, domain='QQ')),
|
||||
Matrix([[1, 1, -1], [5, 1, 1]], x))
|
||||
G = [(Poly(t, t), Poly(1, t)), (Poly(t**2, t), Poly(1, t)), (Poly(t**3, t), Poly(1, t))]
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]})
|
||||
assert prde_linear_constraints(Poly(t + 1, t), Poly(t**2, t), G, DE) == \
|
||||
((Poly(t, t, domain='QQ'), Poly(t**2, t, domain='QQ'), Poly(t**3, t, domain='QQ')),
|
||||
Matrix(0, 3, [], t))
|
||||
G = [(Poly(2*x, t), Poly(t, t)), (Poly(-x, t), Poly(t, t))]
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]})
|
||||
assert prde_linear_constraints(Poly(1, t), Poly(0, t), G, DE) == \
|
||||
((Poly(0, t, domain='QQ[x]'), Poly(0, t, domain='QQ[x]')), Matrix([[2*x, -x]], t))
|
||||
|
||||
|
||||
def test_constant_system():
|
||||
A = Matrix([[-(x + 3)/(x - 1), (x + 1)/(x - 1), 1],
|
||||
[-x - 3, x + 1, x - 1],
|
||||
[2*(x + 3)/(x - 1), 0, 0]], t)
|
||||
u = Matrix([[(x + 1)/(x - 1)], [x + 1], [0]], t)
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x)]})
|
||||
R = QQ.frac_field(x)[t]
|
||||
assert constant_system(A, u, DE) == \
|
||||
(Matrix([[1, 0, 0],
|
||||
[0, 1, 0],
|
||||
[0, 0, 0],
|
||||
[0, 0, 1]], ring=R), Matrix([0, 1, 0, 0], ring=R))
|
||||
|
||||
|
||||
def test_prde_spde():
|
||||
D = [Poly(x, t), Poly(-x*t, t)]
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]})
|
||||
# TODO: when bound_degree() can handle this, test degree bound from that too
|
||||
assert prde_spde(Poly(t, t), Poly(-1/x, t), D, n, DE) == \
|
||||
(Poly(t, t), Poly(0, t, domain='ZZ(x)'),
|
||||
[Poly(2*x, t, domain='ZZ(x)'), Poly(-x, t, domain='ZZ(x)')],
|
||||
[Poly(-x**2, t, domain='ZZ(x)'), Poly(0, t, domain='ZZ(x)')], n - 1)
|
||||
|
||||
|
||||
def test_prde_no_cancel():
|
||||
# b large
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x)]})
|
||||
assert prde_no_cancel_b_large(Poly(1, x), [Poly(x**2, x), Poly(1, x)], 2, DE) == \
|
||||
([Poly(x**2 - 2*x + 2, x), Poly(1, x)], Matrix([[1, 0, -1, 0],
|
||||
[0, 1, 0, -1]], x))
|
||||
assert prde_no_cancel_b_large(Poly(1, x), [Poly(x**3, x), Poly(1, x)], 3, DE) == \
|
||||
([Poly(x**3 - 3*x**2 + 6*x - 6, x), Poly(1, x)], Matrix([[1, 0, -1, 0],
|
||||
[0, 1, 0, -1]], x))
|
||||
assert prde_no_cancel_b_large(Poly(x, x), [Poly(x**2, x), Poly(1, x)], 1, DE) == \
|
||||
([Poly(x, x, domain='ZZ'), Poly(0, x, domain='ZZ')], Matrix([[1, -1, 0, 0],
|
||||
[1, 0, -1, 0],
|
||||
[0, 1, 0, -1]], x))
|
||||
# b small
|
||||
# XXX: Is there a better example of a monomial with D.degree() > 2?
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**3 + 1, t)]})
|
||||
|
||||
# My original q was t**4 + t + 1, but this solution implies q == t**4
|
||||
# (c1 = 4), with some of the ci for the original q equal to 0.
|
||||
G = [Poly(t**6, t), Poly(x*t**5, t), Poly(t**3, t), Poly(x*t**2, t), Poly(1 + x, t)]
|
||||
R = QQ.frac_field(x)[t]
|
||||
assert prde_no_cancel_b_small(Poly(x*t, t), G, 4, DE) == \
|
||||
([Poly(t**4/4 - x/12*t**3 + x**2/24*t**2 + (Rational(-11, 12) - x**3/24)*t + x/24, t),
|
||||
Poly(x/3*t**3 - x**2/6*t**2 + (Rational(-1, 3) + x**3/6)*t - x/6, t), Poly(t, t),
|
||||
Poly(0, t), Poly(0, t)], Matrix([[1, 0, -1, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 1, Rational(-1, 4), 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
|
||||
[1, 0, 0, 0, 0, -1, 0, 0, 0, 0],
|
||||
[0, 1, 0, 0, 0, 0, -1, 0, 0, 0],
|
||||
[0, 0, 1, 0, 0, 0, 0, -1, 0, 0],
|
||||
[0, 0, 0, 1, 0, 0, 0, 0, -1, 0],
|
||||
[0, 0, 0, 0, 1, 0, 0, 0, 0, -1]], ring=R))
|
||||
|
||||
# TODO: Add test for deg(b) <= 0 with b small
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t**2, t)]})
|
||||
b = Poly(-1/x**2, t, field=True) # deg(b) == 0
|
||||
q = [Poly(x**i*t**j, t, field=True) for i in range(2) for j in range(3)]
|
||||
h, A = prde_no_cancel_b_small(b, q, 3, DE)
|
||||
V = A.nullspace()
|
||||
R = QQ.frac_field(x)[t]
|
||||
assert len(V) == 1
|
||||
assert V[0] == Matrix([Rational(-1, 2), 0, 0, 1, 0, 0]*3, ring=R)
|
||||
assert (Matrix([h])*V[0][6:, :])[0] == Poly(x**2/2, t, domain='QQ(x)')
|
||||
assert (Matrix([q])*V[0][:6, :])[0] == Poly(x - S.Half, t, domain='QQ(x)')
|
||||
|
||||
|
||||
def test_prde_cancel_liouvillian():
|
||||
### 1. case == 'primitive'
|
||||
# used when integrating f = log(x) - log(x - 1)
|
||||
# Not taken from 'the' book
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]})
|
||||
p0 = Poly(0, t, field=True)
|
||||
p1 = Poly((x - 1)*t, t, domain='ZZ(x)')
|
||||
p2 = Poly(x - 1, t, domain='ZZ(x)')
|
||||
p3 = Poly(-x**2 + x, t, domain='ZZ(x)')
|
||||
h, A = prde_cancel_liouvillian(Poly(-1/(x - 1), t), [Poly(-x + 1, t), Poly(1, t)], 1, DE)
|
||||
V = A.nullspace()
|
||||
assert h == [p0, p0, p1, p0, p0, p0, p0, p0, p0, p0, p2, p3, p0, p0, p0, p0]
|
||||
assert A.rank() == 16
|
||||
assert (Matrix([h])*V[0][:16, :]) == Matrix([[Poly(0, t, domain='QQ(x)')]])
|
||||
|
||||
### 2. case == 'exp'
|
||||
# used when integrating log(x/exp(x) + 1)
|
||||
# Not taken from book
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-t, t)]})
|
||||
assert prde_cancel_liouvillian(Poly(0, t, domain='QQ[x]'), [Poly(1, t, domain='QQ(x)')], 0, DE) == \
|
||||
([Poly(1, t, domain='QQ'), Poly(x, t, domain='ZZ(x)')], Matrix([[-1, 0, 1]], DE.t))
|
||||
|
||||
|
||||
def test_param_poly_rischDE():
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x)]})
|
||||
a = Poly(x**2 - x, x, field=True)
|
||||
b = Poly(1, x, field=True)
|
||||
q = [Poly(x, x, field=True), Poly(x**2, x, field=True)]
|
||||
h, A = param_poly_rischDE(a, b, q, 3, DE)
|
||||
|
||||
assert A.nullspace() == [Matrix([0, 1, 1, 1], DE.t)] # c1, c2, d1, d2
|
||||
# Solution of a*Dp + b*p = c1*q1 + c2*q2 = q2 = x**2
|
||||
# is d1*h1 + d2*h2 = h1 + h2 = x.
|
||||
assert h[0] + h[1] == Poly(x, x, domain='QQ')
|
||||
# a*Dp + b*p = q1 = x has no solution.
|
||||
|
||||
a = Poly(x**2 - x, x, field=True)
|
||||
b = Poly(x**2 - 5*x + 3, x, field=True)
|
||||
q = [Poly(1, x, field=True), Poly(x, x, field=True),
|
||||
Poly(x**2, x, field=True)]
|
||||
h, A = param_poly_rischDE(a, b, q, 3, DE)
|
||||
|
||||
assert A.nullspace() == [Matrix([3, -5, 1, -5, 1, 1], DE.t)]
|
||||
p = -Poly(5, DE.t)*h[0] + h[1] + h[2] # Poly(1, x)
|
||||
assert a*derivation(p, DE) + b*p == Poly(x**2 - 5*x + 3, x, domain='QQ')
|
||||
|
||||
|
||||
def test_param_rischDE():
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x)]})
|
||||
p1, px = Poly(1, x, field=True), Poly(x, x, field=True)
|
||||
G = [(p1, px), (p1, p1), (px, p1)] # [1/x, 1, x]
|
||||
h, A = param_rischDE(-p1, Poly(x**2, x, field=True), G, DE)
|
||||
assert len(h) == 3
|
||||
p = [hi[0].as_expr()/hi[1].as_expr() for hi in h]
|
||||
V = A.nullspace()
|
||||
assert len(V) == 2
|
||||
assert V[0] == Matrix([-1, 1, 0, -1, 1, 0], DE.t)
|
||||
y = -p[0] + p[1] + 0*p[2] # x
|
||||
assert y.diff(x) - y/x**2 == 1 - 1/x # Dy + f*y == -G0 + G1 + 0*G2
|
||||
|
||||
# the below test computation takes place while computing the integral
|
||||
# of 'f = log(log(x + exp(x)))'
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]})
|
||||
G = [(Poly(t + x, t, domain='ZZ(x)'), Poly(1, t, domain='QQ')), (Poly(0, t, domain='QQ'), Poly(1, t, domain='QQ'))]
|
||||
h, A = param_rischDE(Poly(-t - 1, t, field=True), Poly(t + x, t, field=True), G, DE)
|
||||
assert len(h) == 5
|
||||
p = [hi[0].as_expr()/hi[1].as_expr() for hi in h]
|
||||
V = A.nullspace()
|
||||
assert len(V) == 3
|
||||
assert V[0] == Matrix([0, 0, 0, 0, 1, 0, 0], DE.t)
|
||||
y = 0*p[0] + 0*p[1] + 1*p[2] + 0*p[3] + 0*p[4]
|
||||
assert y.diff(t) - y/(t + x) == 0 # Dy + f*y = 0*G0 + 0*G1
|
||||
|
||||
|
||||
def test_limited_integrate_reduce():
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]})
|
||||
assert limited_integrate_reduce(Poly(x, t), Poly(t**2, t), [(Poly(x, t),
|
||||
Poly(t, t))], DE) == \
|
||||
(Poly(t, t), Poly(-1/x, t), Poly(t, t), 1, (Poly(x, t), Poly(1, t, domain='ZZ[x]')),
|
||||
[(Poly(-x*t, t), Poly(1, t, domain='ZZ[x]'))])
|
||||
|
||||
|
||||
def test_limited_integrate():
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x)]})
|
||||
G = [(Poly(x, x), Poly(x + 1, x))]
|
||||
assert limited_integrate(Poly(-(1 + x + 5*x**2 - 3*x**3), x),
|
||||
Poly(1 - x - x**2 + x**3, x), G, DE) == \
|
||||
((Poly(x**2 - x + 2, x), Poly(x - 1, x, domain='QQ')), [2])
|
||||
G = [(Poly(1, x), Poly(x, x))]
|
||||
assert limited_integrate(Poly(5*x**2, x), Poly(3, x), G, DE) == \
|
||||
((Poly(5*x**3/9, x), Poly(1, x, domain='QQ')), [0])
|
||||
|
||||
|
||||
def test_is_log_deriv_k_t_radical():
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x)], 'exts': [None],
|
||||
'extargs': [None]})
|
||||
assert is_log_deriv_k_t_radical(Poly(2*x, x), Poly(1, x), DE) is None
|
||||
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(2*t1, t1), Poly(1/x, t2)],
|
||||
'exts': [None, 'exp', 'log'], 'extargs': [None, 2*x, x]})
|
||||
assert is_log_deriv_k_t_radical(Poly(x + t2/2, t2), Poly(1, t2), DE) == \
|
||||
([(t1, 1), (x, 1)], t1*x, 2, 0)
|
||||
# TODO: Add more tests
|
||||
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t0, t0), Poly(1/x, t)],
|
||||
'exts': [None, 'exp', 'log'], 'extargs': [None, x, x]})
|
||||
assert is_log_deriv_k_t_radical(Poly(x + t/2 + 3, t), Poly(1, t), DE) == \
|
||||
([(t0, 2), (x, 1)], x*t0**2, 2, 3)
|
||||
|
||||
|
||||
def test_is_deriv_k():
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t1), Poly(1/(x + 1), t2)],
|
||||
'exts': [None, 'log', 'log'], 'extargs': [None, x, x + 1]})
|
||||
assert is_deriv_k(Poly(2*x**2 + 2*x, t2), Poly(1, t2), DE) == \
|
||||
([(t1, 1), (t2, 1)], t1 + t2, 2)
|
||||
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t1), Poly(t2, t2)],
|
||||
'exts': [None, 'log', 'exp'], 'extargs': [None, x, x]})
|
||||
assert is_deriv_k(Poly(x**2*t2**3, t2), Poly(1, t2), DE) == \
|
||||
([(x, 3), (t1, 2)], 2*t1 + 3*x, 1)
|
||||
# TODO: Add more tests, including ones with exponentials
|
||||
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(2/x, t1)],
|
||||
'exts': [None, 'log'], 'extargs': [None, x**2]})
|
||||
assert is_deriv_k(Poly(x, t1), Poly(1, t1), DE) == \
|
||||
([(t1, S.Half)], t1/2, 1)
|
||||
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(2/(1 + x), t0)],
|
||||
'exts': [None, 'log'], 'extargs': [None, x**2 + 2*x + 1]})
|
||||
assert is_deriv_k(Poly(1 + x, t0), Poly(1, t0), DE) == \
|
||||
([(t0, S.Half)], t0/2, 1)
|
||||
|
||||
# Issue 10798
|
||||
# DE = DifferentialExtension(log(1/x), x)
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-1/x, t)],
|
||||
'exts': [None, 'log'], 'extargs': [None, 1/x]})
|
||||
assert is_deriv_k(Poly(1, t), Poly(x, t), DE) == ([(t, 1)], t, 1)
|
||||
|
||||
|
||||
def test_is_log_deriv_k_t_radical_in_field():
|
||||
# NOTE: any potential constant factor in the second element of the result
|
||||
# doesn't matter, because it cancels in Da/a.
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]})
|
||||
assert is_log_deriv_k_t_radical_in_field(Poly(5*t + 1, t), Poly(2*t*x, t), DE) == \
|
||||
(2, t*x**5)
|
||||
assert is_log_deriv_k_t_radical_in_field(Poly(2 + 3*t, t), Poly(5*x*t, t), DE) == \
|
||||
(5, x**3*t**2)
|
||||
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-t/x**2, t)]})
|
||||
assert is_log_deriv_k_t_radical_in_field(Poly(-(1 + 2*t), t),
|
||||
Poly(2*x**2 + 2*x**2*t, t), DE) == \
|
||||
(2, t + t**2)
|
||||
assert is_log_deriv_k_t_radical_in_field(Poly(-1, t), Poly(x**2, t), DE) == \
|
||||
(1, t)
|
||||
assert is_log_deriv_k_t_radical_in_field(Poly(1, t), Poly(2*x**2, t), DE) == \
|
||||
(2, 1/t)
|
||||
|
||||
|
||||
def test_parametric_log_deriv():
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]})
|
||||
assert parametric_log_deriv_heu(Poly(5*t**2 + t - 6, t), Poly(2*x*t**2, t),
|
||||
Poly(-1, t), Poly(x*t**2, t), DE) == \
|
||||
(2, 6, t*x**5)
|
||||
@@ -0,0 +1,601 @@
|
||||
from sympy.core import S, Rational
|
||||
from sympy.integrals.quadrature import (gauss_legendre, gauss_laguerre,
|
||||
gauss_hermite, gauss_gen_laguerre,
|
||||
gauss_chebyshev_t, gauss_chebyshev_u,
|
||||
gauss_jacobi, gauss_lobatto)
|
||||
|
||||
|
||||
def test_legendre():
|
||||
x, w = gauss_legendre(1, 17)
|
||||
assert [str(r) for r in x] == ['0']
|
||||
assert [str(r) for r in w] == ['2.0000000000000000']
|
||||
|
||||
x, w = gauss_legendre(2, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'-0.57735026918962576',
|
||||
'0.57735026918962576']
|
||||
assert [str(r) for r in w] == [
|
||||
'1.0000000000000000',
|
||||
'1.0000000000000000']
|
||||
|
||||
x, w = gauss_legendre(3, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'-0.77459666924148338',
|
||||
'0',
|
||||
'0.77459666924148338']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.55555555555555556',
|
||||
'0.88888888888888889',
|
||||
'0.55555555555555556']
|
||||
|
||||
x, w = gauss_legendre(4, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'-0.86113631159405258',
|
||||
'-0.33998104358485626',
|
||||
'0.33998104358485626',
|
||||
'0.86113631159405258']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.34785484513745386',
|
||||
'0.65214515486254614',
|
||||
'0.65214515486254614',
|
||||
'0.34785484513745386']
|
||||
|
||||
|
||||
def test_legendre_precise():
|
||||
x, w = gauss_legendre(3, 40)
|
||||
assert [str(r) for r in x] == [
|
||||
'-0.7745966692414833770358530799564799221666',
|
||||
'0',
|
||||
'0.7745966692414833770358530799564799221666']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.5555555555555555555555555555555555555556',
|
||||
'0.8888888888888888888888888888888888888889',
|
||||
'0.5555555555555555555555555555555555555556']
|
||||
|
||||
|
||||
def test_laguerre():
|
||||
x, w = gauss_laguerre(1, 17)
|
||||
assert [str(r) for r in x] == ['1.0000000000000000']
|
||||
assert [str(r) for r in w] == ['1.0000000000000000']
|
||||
|
||||
x, w = gauss_laguerre(2, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'0.58578643762690495',
|
||||
'3.4142135623730950']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.85355339059327376',
|
||||
'0.14644660940672624']
|
||||
|
||||
x, w = gauss_laguerre(3, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'0.41577455678347908',
|
||||
'2.2942803602790417',
|
||||
'6.2899450829374792',
|
||||
]
|
||||
assert [str(r) for r in w] == [
|
||||
'0.71109300992917302',
|
||||
'0.27851773356924085',
|
||||
'0.010389256501586136',
|
||||
]
|
||||
|
||||
x, w = gauss_laguerre(4, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'0.32254768961939231',
|
||||
'1.7457611011583466',
|
||||
'4.5366202969211280',
|
||||
'9.3950709123011331']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.60315410434163360',
|
||||
'0.35741869243779969',
|
||||
'0.038887908515005384',
|
||||
'0.00053929470556132745']
|
||||
|
||||
x, w = gauss_laguerre(5, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'0.26356031971814091',
|
||||
'1.4134030591065168',
|
||||
'3.5964257710407221',
|
||||
'7.0858100058588376',
|
||||
'12.640800844275783']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.52175561058280865',
|
||||
'0.39866681108317593',
|
||||
'0.075942449681707595',
|
||||
'0.0036117586799220485',
|
||||
'2.3369972385776228e-5']
|
||||
|
||||
|
||||
def test_laguerre_precise():
|
||||
x, w = gauss_laguerre(3, 40)
|
||||
assert [str(r) for r in x] == [
|
||||
'0.4157745567834790833115338731282744735466',
|
||||
'2.294280360279041719822050361359593868960',
|
||||
'6.289945082937479196866415765512131657493']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.7110930099291730154495901911425944313094',
|
||||
'0.2785177335692408488014448884567264810349',
|
||||
'0.01038925650158613574896492040067908765572']
|
||||
|
||||
|
||||
def test_hermite():
|
||||
x, w = gauss_hermite(1, 17)
|
||||
assert [str(r) for r in x] == ['0']
|
||||
assert [str(r) for r in w] == ['1.7724538509055160']
|
||||
|
||||
x, w = gauss_hermite(2, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'-0.70710678118654752',
|
||||
'0.70710678118654752']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.88622692545275801',
|
||||
'0.88622692545275801']
|
||||
|
||||
x, w = gauss_hermite(3, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'-1.2247448713915890',
|
||||
'0',
|
||||
'1.2247448713915890']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.29540897515091934',
|
||||
'1.1816359006036774',
|
||||
'0.29540897515091934']
|
||||
|
||||
x, w = gauss_hermite(4, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'-1.6506801238857846',
|
||||
'-0.52464762327529032',
|
||||
'0.52464762327529032',
|
||||
'1.6506801238857846']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.081312835447245177',
|
||||
'0.80491409000551284',
|
||||
'0.80491409000551284',
|
||||
'0.081312835447245177']
|
||||
|
||||
x, w = gauss_hermite(5, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'-2.0201828704560856',
|
||||
'-0.95857246461381851',
|
||||
'0',
|
||||
'0.95857246461381851',
|
||||
'2.0201828704560856']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.019953242059045913',
|
||||
'0.39361932315224116',
|
||||
'0.94530872048294188',
|
||||
'0.39361932315224116',
|
||||
'0.019953242059045913']
|
||||
|
||||
|
||||
def test_hermite_precise():
|
||||
x, w = gauss_hermite(3, 40)
|
||||
assert [str(r) for r in x] == [
|
||||
'-1.224744871391589049098642037352945695983',
|
||||
'0',
|
||||
'1.224744871391589049098642037352945695983']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.2954089751509193378830279138901908637996',
|
||||
'1.181635900603677351532111655560763455198',
|
||||
'0.2954089751509193378830279138901908637996']
|
||||
|
||||
|
||||
def test_gen_laguerre():
|
||||
x, w = gauss_gen_laguerre(1, Rational(-1, 2), 17)
|
||||
assert [str(r) for r in x] == ['0.50000000000000000']
|
||||
assert [str(r) for r in w] == ['1.7724538509055160']
|
||||
|
||||
x, w = gauss_gen_laguerre(2, Rational(-1, 2), 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'0.27525512860841095',
|
||||
'2.7247448713915890']
|
||||
assert [str(r) for r in w] == [
|
||||
'1.6098281800110257',
|
||||
'0.16262567089449035']
|
||||
|
||||
x, w = gauss_gen_laguerre(3, Rational(-1, 2), 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'0.19016350919348813',
|
||||
'1.7844927485432516',
|
||||
'5.5253437422632603']
|
||||
assert [str(r) for r in w] == [
|
||||
'1.4492591904487850',
|
||||
'0.31413464064571329',
|
||||
'0.0090600198110176913']
|
||||
|
||||
x, w = gauss_gen_laguerre(4, Rational(-1, 2), 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'0.14530352150331709',
|
||||
'1.3390972881263614',
|
||||
'3.9269635013582872',
|
||||
'8.5886356890120343']
|
||||
assert [str(r) for r in w] == [
|
||||
'1.3222940251164826',
|
||||
'0.41560465162978376',
|
||||
'0.034155966014826951',
|
||||
'0.00039920814442273524']
|
||||
|
||||
x, w = gauss_gen_laguerre(5, Rational(-1, 2), 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'0.11758132021177814',
|
||||
'1.0745620124369040',
|
||||
'3.0859374437175500',
|
||||
'6.4147297336620305',
|
||||
'11.807189489971737']
|
||||
assert [str(r) for r in w] == [
|
||||
'1.2217252674706516',
|
||||
'0.48027722216462937',
|
||||
'0.067748788910962126',
|
||||
'0.0026872914935624654',
|
||||
'1.5280865710465241e-5']
|
||||
|
||||
x, w = gauss_gen_laguerre(1, 2, 17)
|
||||
assert [str(r) for r in x] == ['3.0000000000000000']
|
||||
assert [str(r) for r in w] == ['2.0000000000000000']
|
||||
|
||||
x, w = gauss_gen_laguerre(2, 2, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'2.0000000000000000',
|
||||
'6.0000000000000000']
|
||||
assert [str(r) for r in w] == [
|
||||
'1.5000000000000000',
|
||||
'0.50000000000000000']
|
||||
|
||||
x, w = gauss_gen_laguerre(3, 2, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'1.5173870806774125',
|
||||
'4.3115831337195203',
|
||||
'9.1710297856030672']
|
||||
assert [str(r) for r in w] == [
|
||||
'1.0374949614904253',
|
||||
'0.90575000470306537',
|
||||
'0.056755033806509347']
|
||||
|
||||
x, w = gauss_gen_laguerre(4, 2, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'1.2267632635003021',
|
||||
'3.4125073586969460',
|
||||
'6.9026926058516134',
|
||||
'12.458036771951139']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.72552499769865438',
|
||||
'1.0634242919791946',
|
||||
'0.20669613102835355',
|
||||
'0.0043545792937974889']
|
||||
|
||||
x, w = gauss_gen_laguerre(5, 2, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'1.0311091440933816',
|
||||
'2.8372128239538217',
|
||||
'5.6202942725987079',
|
||||
'9.6829098376640271',
|
||||
'15.828473921690062']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.52091739683509184',
|
||||
'1.0667059331592211',
|
||||
'0.38354972366693113',
|
||||
'0.028564233532974658',
|
||||
'0.00026271280578124935']
|
||||
|
||||
|
||||
def test_gen_laguerre_precise():
|
||||
x, w = gauss_gen_laguerre(3, Rational(-1, 2), 40)
|
||||
assert [str(r) for r in x] == [
|
||||
'0.1901635091934881328718554276203028970878',
|
||||
'1.784492748543251591186722461957367638500',
|
||||
'5.525343742263260275941422110422329464413']
|
||||
assert [str(r) for r in w] == [
|
||||
'1.449259190448785048183829411195134343108',
|
||||
'0.3141346406457132878326231270167565378246',
|
||||
'0.009060019811017691281714945129254301865020']
|
||||
|
||||
x, w = gauss_gen_laguerre(3, 2, 40)
|
||||
assert [str(r) for r in x] == [
|
||||
'1.517387080677412495020323111016672547482',
|
||||
'4.311583133719520302881184669723530562299',
|
||||
'9.171029785603067202098492219259796890218']
|
||||
assert [str(r) for r in w] == [
|
||||
'1.037494961490425285817554606541269153041',
|
||||
'0.9057500047030653669269785048806009945254',
|
||||
'0.05675503380650934725546688857812985243312']
|
||||
|
||||
|
||||
def test_chebyshev_t():
|
||||
x, w = gauss_chebyshev_t(1, 17)
|
||||
assert [str(r) for r in x] == ['0']
|
||||
assert [str(r) for r in w] == ['3.1415926535897932']
|
||||
|
||||
x, w = gauss_chebyshev_t(2, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'0.70710678118654752',
|
||||
'-0.70710678118654752']
|
||||
assert [str(r) for r in w] == [
|
||||
'1.5707963267948966',
|
||||
'1.5707963267948966']
|
||||
|
||||
x, w = gauss_chebyshev_t(3, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'0.86602540378443865',
|
||||
'0',
|
||||
'-0.86602540378443865']
|
||||
assert [str(r) for r in w] == [
|
||||
'1.0471975511965977',
|
||||
'1.0471975511965977',
|
||||
'1.0471975511965977']
|
||||
|
||||
x, w = gauss_chebyshev_t(4, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'0.92387953251128676',
|
||||
'0.38268343236508977',
|
||||
'-0.38268343236508977',
|
||||
'-0.92387953251128676']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.78539816339744831',
|
||||
'0.78539816339744831',
|
||||
'0.78539816339744831',
|
||||
'0.78539816339744831']
|
||||
|
||||
x, w = gauss_chebyshev_t(5, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'0.95105651629515357',
|
||||
'0.58778525229247313',
|
||||
'0',
|
||||
'-0.58778525229247313',
|
||||
'-0.95105651629515357']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.62831853071795865',
|
||||
'0.62831853071795865',
|
||||
'0.62831853071795865',
|
||||
'0.62831853071795865',
|
||||
'0.62831853071795865']
|
||||
|
||||
|
||||
def test_chebyshev_t_precise():
|
||||
x, w = gauss_chebyshev_t(3, 40)
|
||||
assert [str(r) for r in x] == [
|
||||
'0.8660254037844386467637231707529361834714',
|
||||
'0',
|
||||
'-0.8660254037844386467637231707529361834714']
|
||||
assert [str(r) for r in w] == [
|
||||
'1.047197551196597746154214461093167628066',
|
||||
'1.047197551196597746154214461093167628066',
|
||||
'1.047197551196597746154214461093167628066']
|
||||
|
||||
|
||||
def test_chebyshev_u():
|
||||
x, w = gauss_chebyshev_u(1, 17)
|
||||
assert [str(r) for r in x] == ['0']
|
||||
assert [str(r) for r in w] == ['1.5707963267948966']
|
||||
|
||||
x, w = gauss_chebyshev_u(2, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'0.50000000000000000',
|
||||
'-0.50000000000000000']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.78539816339744831',
|
||||
'0.78539816339744831']
|
||||
|
||||
x, w = gauss_chebyshev_u(3, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'0.70710678118654752',
|
||||
'0',
|
||||
'-0.70710678118654752']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.39269908169872415',
|
||||
'0.78539816339744831',
|
||||
'0.39269908169872415']
|
||||
|
||||
x, w = gauss_chebyshev_u(4, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'0.80901699437494742',
|
||||
'0.30901699437494742',
|
||||
'-0.30901699437494742',
|
||||
'-0.80901699437494742']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.21707871342270599',
|
||||
'0.56831944997474231',
|
||||
'0.56831944997474231',
|
||||
'0.21707871342270599']
|
||||
|
||||
x, w = gauss_chebyshev_u(5, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'0.86602540378443865',
|
||||
'0.50000000000000000',
|
||||
'0',
|
||||
'-0.50000000000000000',
|
||||
'-0.86602540378443865']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.13089969389957472',
|
||||
'0.39269908169872415',
|
||||
'0.52359877559829887',
|
||||
'0.39269908169872415',
|
||||
'0.13089969389957472']
|
||||
|
||||
|
||||
def test_chebyshev_u_precise():
|
||||
x, w = gauss_chebyshev_u(3, 40)
|
||||
assert [str(r) for r in x] == [
|
||||
'0.7071067811865475244008443621048490392848',
|
||||
'0',
|
||||
'-0.7071067811865475244008443621048490392848']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.3926990816987241548078304229099378605246',
|
||||
'0.7853981633974483096156608458198757210493',
|
||||
'0.3926990816987241548078304229099378605246']
|
||||
|
||||
|
||||
def test_jacobi():
|
||||
x, w = gauss_jacobi(1, Rational(-1, 2), S.Half, 17)
|
||||
assert [str(r) for r in x] == ['0.50000000000000000']
|
||||
assert [str(r) for r in w] == ['3.1415926535897932']
|
||||
|
||||
x, w = gauss_jacobi(2, Rational(-1, 2), S.Half, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'-0.30901699437494742',
|
||||
'0.80901699437494742']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.86831485369082398',
|
||||
'2.2732777998989693']
|
||||
|
||||
x, w = gauss_jacobi(3, Rational(-1, 2), S.Half, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'-0.62348980185873353',
|
||||
'0.22252093395631440',
|
||||
'0.90096886790241913']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.33795476356635433',
|
||||
'1.0973322242791115',
|
||||
'1.7063056657443274']
|
||||
|
||||
x, w = gauss_jacobi(4, Rational(-1, 2), S.Half, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'-0.76604444311897804',
|
||||
'-0.17364817766693035',
|
||||
'0.50000000000000000',
|
||||
'0.93969262078590838']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.16333179083642836',
|
||||
'0.57690240318269103',
|
||||
'1.0471975511965977',
|
||||
'1.3541609083740761']
|
||||
|
||||
x, w = gauss_jacobi(5, Rational(-1, 2), S.Half, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'-0.84125353283118117',
|
||||
'-0.41541501300188643',
|
||||
'0.14231483827328514',
|
||||
'0.65486073394528506',
|
||||
'0.95949297361449739']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.090675770007435372',
|
||||
'0.33391416373675607',
|
||||
'0.65248870981926643',
|
||||
'0.94525424081394926',
|
||||
'1.1192597692123861']
|
||||
|
||||
x, w = gauss_jacobi(1, 2, 3, 17)
|
||||
assert [str(r) for r in x] == ['0.14285714285714286']
|
||||
assert [str(r) for r in w] == ['1.0666666666666667']
|
||||
|
||||
x, w = gauss_jacobi(2, 2, 3, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'-0.24025307335204215',
|
||||
'0.46247529557426437']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.48514624517838660',
|
||||
'0.58152042148828007']
|
||||
|
||||
x, w = gauss_jacobi(3, 2, 3, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'-0.46115870378089762',
|
||||
'0.10438533038323902',
|
||||
'0.62950064612493132']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.17937613502213266',
|
||||
'0.61595640991147154',
|
||||
'0.27133412173306246']
|
||||
|
||||
x, w = gauss_jacobi(4, 2, 3, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'-0.59903470850824782',
|
||||
'-0.14761105199952565',
|
||||
'0.32554377081188859',
|
||||
'0.72879429738819258']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.067809641836772187',
|
||||
'0.38956404952032481',
|
||||
'0.47995970868024150',
|
||||
'0.12933326662932816']
|
||||
|
||||
x, w = gauss_jacobi(5, 2, 3, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'-0.69045775012676106',
|
||||
'-0.32651993134900065',
|
||||
'0.082337849552034905',
|
||||
'0.47517887061283164',
|
||||
'0.79279429464422850']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.027410178066337099',
|
||||
'0.21291786060364828',
|
||||
'0.43908437944395081',
|
||||
'0.32220656547221822',
|
||||
'0.065047683080512268']
|
||||
|
||||
|
||||
def test_jacobi_precise():
|
||||
x, w = gauss_jacobi(3, Rational(-1, 2), S.Half, 40)
|
||||
assert [str(r) for r in x] == [
|
||||
'-0.6234898018587335305250048840042398106323',
|
||||
'0.2225209339563144042889025644967947594664',
|
||||
'0.9009688679024191262361023195074450511659']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.3379547635663543330553835737094171534907',
|
||||
'1.097332224279111467485302294320899710461',
|
||||
'1.706305665744327437921957515249186020246']
|
||||
|
||||
x, w = gauss_jacobi(3, 2, 3, 40)
|
||||
assert [str(r) for r in x] == [
|
||||
'-0.4611587037808976179121958105554375981274',
|
||||
'0.1043853303832390210914918407615869143233',
|
||||
'0.6295006461249313240934312425211234110769']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.1793761350221326596137764371503859752628',
|
||||
'0.6159564099114715430909548532229749439714',
|
||||
'0.2713341217330624639619353762933057474325']
|
||||
|
||||
|
||||
def test_lobatto():
|
||||
x, w = gauss_lobatto(2, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'-1',
|
||||
'1']
|
||||
assert [str(r) for r in w] == [
|
||||
'1.0000000000000000',
|
||||
'1.0000000000000000']
|
||||
|
||||
x, w = gauss_lobatto(3, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'-1',
|
||||
'0',
|
||||
'1']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.33333333333333333',
|
||||
'1.3333333333333333',
|
||||
'0.33333333333333333']
|
||||
|
||||
x, w = gauss_lobatto(4, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'-1',
|
||||
'-0.44721359549995794',
|
||||
'0.44721359549995794',
|
||||
'1']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.16666666666666667',
|
||||
'0.83333333333333333',
|
||||
'0.83333333333333333',
|
||||
'0.16666666666666667']
|
||||
|
||||
x, w = gauss_lobatto(5, 17)
|
||||
assert [str(r) for r in x] == [
|
||||
'-1',
|
||||
'-0.65465367070797714',
|
||||
'0',
|
||||
'0.65465367070797714',
|
||||
'1']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.10000000000000000',
|
||||
'0.54444444444444444',
|
||||
'0.71111111111111111',
|
||||
'0.54444444444444444',
|
||||
'0.10000000000000000']
|
||||
|
||||
|
||||
def test_lobatto_precise():
|
||||
x, w = gauss_lobatto(3, 40)
|
||||
assert [str(r) for r in x] == [
|
||||
'-1',
|
||||
'0',
|
||||
'1']
|
||||
assert [str(r) for r in w] == [
|
||||
'0.3333333333333333333333333333333333333333',
|
||||
'1.333333333333333333333333333333333333333',
|
||||
'0.3333333333333333333333333333333333333333']
|
||||
@@ -0,0 +1,183 @@
|
||||
from sympy.core.numbers import (I, Rational)
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import (Dummy, symbols)
|
||||
from sympy.functions.elementary.exponential import log
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.trigonometric import atan
|
||||
from sympy.integrals.integrals import integrate
|
||||
from sympy.polys.polytools import Poly
|
||||
from sympy.simplify.simplify import simplify
|
||||
|
||||
from sympy.integrals.rationaltools import ratint, ratint_logpart, log_to_atan
|
||||
|
||||
from sympy.abc import a, b, x, t
|
||||
|
||||
half = S.Half
|
||||
|
||||
|
||||
def test_ratint():
|
||||
assert ratint(S.Zero, x) == 0
|
||||
assert ratint(S(7), x) == 7*x
|
||||
|
||||
assert ratint(x, x) == x**2/2
|
||||
assert ratint(2*x, x) == x**2
|
||||
assert ratint(-2*x, x) == -x**2
|
||||
|
||||
assert ratint(8*x**7 + 2*x + 1, x) == x**8 + x**2 + x
|
||||
|
||||
f = S.One
|
||||
g = x + 1
|
||||
|
||||
assert ratint(f / g, x) == log(x + 1)
|
||||
assert ratint((f, g), x) == log(x + 1)
|
||||
|
||||
f = x**3 - x
|
||||
g = x - 1
|
||||
|
||||
assert ratint(f/g, x) == x**3/3 + x**2/2
|
||||
|
||||
f = x
|
||||
g = (x - a)*(x + a)
|
||||
|
||||
assert ratint(f/g, x) == log(x**2 - a**2)/2
|
||||
|
||||
f = S.One
|
||||
g = x**2 + 1
|
||||
|
||||
assert ratint(f/g, x, real=None) == atan(x)
|
||||
assert ratint(f/g, x, real=True) == atan(x)
|
||||
|
||||
assert ratint(f/g, x, real=False) == I*log(x + I)/2 - I*log(x - I)/2
|
||||
|
||||
f = S(36)
|
||||
g = x**5 - 2*x**4 - 2*x**3 + 4*x**2 + x - 2
|
||||
|
||||
assert ratint(f/g, x) == \
|
||||
-4*log(x + 1) + 4*log(x - 2) + (12*x + 6)/(x**2 - 1)
|
||||
|
||||
f = x**4 - 3*x**2 + 6
|
||||
g = x**6 - 5*x**4 + 5*x**2 + 4
|
||||
|
||||
assert ratint(f/g, x) == \
|
||||
atan(x) + atan(x**3) + atan(x/2 - Rational(3, 2)*x**3 + S.Half*x**5)
|
||||
|
||||
f = x**7 - 24*x**4 - 4*x**2 + 8*x - 8
|
||||
g = x**8 + 6*x**6 + 12*x**4 + 8*x**2
|
||||
|
||||
assert ratint(f/g, x) == \
|
||||
(4 + 6*x + 8*x**2 + 3*x**3)/(4*x + 4*x**3 + x**5) + log(x)
|
||||
|
||||
assert ratint((x**3*f)/(x*g), x) == \
|
||||
-(12 - 16*x + 6*x**2 - 14*x**3)/(4 + 4*x**2 + x**4) - \
|
||||
5*sqrt(2)*atan(x*sqrt(2)/2) + S.Half*x**2 - 3*log(2 + x**2)
|
||||
|
||||
f = x**5 - x**4 + 4*x**3 + x**2 - x + 5
|
||||
g = x**4 - 2*x**3 + 5*x**2 - 4*x + 4
|
||||
|
||||
assert ratint(f/g, x) == \
|
||||
x + S.Half*x**2 + S.Half*log(2 - x + x**2) + (9 - 4*x)/(7*x**2 - 7*x + 14) + \
|
||||
13*sqrt(7)*atan(Rational(-1, 7)*sqrt(7) + 2*x*sqrt(7)/7)/49
|
||||
|
||||
assert ratint(1/(x**2 + x + 1), x) == \
|
||||
2*sqrt(3)*atan(sqrt(3)/3 + 2*x*sqrt(3)/3)/3
|
||||
|
||||
assert ratint(1/(x**3 + 1), x) == \
|
||||
-log(1 - x + x**2)/6 + log(1 + x)/3 + sqrt(3)*atan(-sqrt(3)
|
||||
/3 + 2*x*sqrt(3)/3)/3
|
||||
|
||||
assert ratint(1/(x**2 + x + 1), x, real=False) == \
|
||||
-I*3**half*log(half + x - half*I*3**half)/3 + \
|
||||
I*3**half*log(half + x + half*I*3**half)/3
|
||||
|
||||
assert ratint(1/(x**3 + 1), x, real=False) == log(1 + x)/3 + \
|
||||
(Rational(-1, 6) + I*3**half/6)*log(-half + x + I*3**half/2) + \
|
||||
(Rational(-1, 6) - I*3**half/6)*log(-half + x - I*3**half/2)
|
||||
|
||||
# issue 4991
|
||||
assert ratint(1/(x*(a + b*x)**3), x) == \
|
||||
(3*a + 2*b*x)/(2*a**4 + 4*a**3*b*x + 2*a**2*b**2*x**2) + (
|
||||
log(x) - log(a/b + x))/a**3
|
||||
|
||||
assert ratint(x/(1 - x**2), x) == -log(x**2 - 1)/2
|
||||
assert ratint(-x/(1 - x**2), x) == log(x**2 - 1)/2
|
||||
|
||||
assert ratint((x/4 - 4/(1 - x)).diff(x), x) == x/4 + 4/(x - 1)
|
||||
|
||||
ans = atan(x)
|
||||
assert ratint(1/(x**2 + 1), x, symbol=x) == ans
|
||||
assert ratint(1/(x**2 + 1), x, symbol='x') == ans
|
||||
assert ratint(1/(x**2 + 1), x, symbol=a) == ans
|
||||
# this asserts that as_dummy must return a unique symbol
|
||||
# even if the symbol is already a Dummy
|
||||
d = Dummy()
|
||||
assert ratint(1/(d**2 + 1), d, symbol=d) == atan(d)
|
||||
|
||||
|
||||
def test_ratint_logpart():
|
||||
assert ratint_logpart(x, x**2 - 9, x, t) == \
|
||||
[(Poly(x**2 - 9, x), Poly(-2*t + 1, t))]
|
||||
assert ratint_logpart(x**2, x**3 - 5, x, t) == \
|
||||
[(Poly(x**3 - 5, x), Poly(-3*t + 1, t))]
|
||||
|
||||
|
||||
def test_issue_5414():
|
||||
assert ratint(1/(x**2 + 16), x) == atan(x/4)/4
|
||||
|
||||
|
||||
def test_issue_5249():
|
||||
assert ratint(
|
||||
1/(x**2 + a**2), x) == (-I*log(-I*a + x)/2 + I*log(I*a + x)/2)/a
|
||||
|
||||
|
||||
def test_issue_5817():
|
||||
a, b, c = symbols('a,b,c', positive=True)
|
||||
|
||||
assert simplify(ratint(a/(b*c*x**2 + a**2 + b*a), x)) == \
|
||||
sqrt(a)*atan(sqrt(
|
||||
b)*sqrt(c)*x/(sqrt(a)*sqrt(a + b)))/(sqrt(b)*sqrt(c)*sqrt(a + b))
|
||||
|
||||
|
||||
def test_issue_5981():
|
||||
u = symbols('u')
|
||||
assert integrate(1/(u**2 + 1)) == atan(u)
|
||||
|
||||
def test_issue_10488():
|
||||
a,b,c,x = symbols('a b c x', positive=True)
|
||||
assert integrate(x/(a*x+b),x) == x/a - b*log(a*x + b)/a**2
|
||||
|
||||
|
||||
def test_issues_8246_12050_13501_14080():
|
||||
a = symbols('a', nonzero=True)
|
||||
assert integrate(a/(x**2 + a**2), x) == atan(x/a)
|
||||
assert integrate(1/(x**2 + a**2), x) == atan(x/a)/a
|
||||
assert integrate(1/(1 + a**2*x**2), x) == atan(a*x)/a
|
||||
|
||||
|
||||
def test_issue_6308():
|
||||
k, a0 = symbols('k a0', real=True)
|
||||
assert integrate((x**2 + 1 - k**2)/(x**2 + 1 + a0**2), x) == \
|
||||
x - (a0**2 + k**2)*atan(x/sqrt(a0**2 + 1))/sqrt(a0**2 + 1)
|
||||
|
||||
|
||||
def test_issue_5907():
|
||||
a = symbols('a', nonzero=True)
|
||||
assert integrate(1/(x**2 + a**2)**2, x) == \
|
||||
x/(2*a**4 + 2*a**2*x**2) + atan(x/a)/(2*a**3)
|
||||
|
||||
|
||||
def test_log_to_atan():
|
||||
f, g = (Poly(x + S.Half, x, domain='QQ'), Poly(sqrt(3)/2, x, domain='EX'))
|
||||
fg_ans = 2*atan(2*sqrt(3)*x/3 + sqrt(3)/3)
|
||||
assert log_to_atan(f, g) == fg_ans
|
||||
assert log_to_atan(g, f) == -fg_ans
|
||||
|
||||
|
||||
def test_issue_25896():
|
||||
# for both tests, C = 0 in log_to_real
|
||||
# but this only has a log result
|
||||
e = (2*x + 1)/(x**2 + x + 1) + 1/x
|
||||
assert ratint(e, x) == log(x**3 + x**2 + x)
|
||||
# while this has more
|
||||
assert ratint((4*x + 7)/(x**2 + 4*x + 6) + 2/x, x) == (
|
||||
2*log(x) + 2*log(x**2 + 4*x + 6) - sqrt(2)*atan(
|
||||
sqrt(2)*x/2 + sqrt(2))/2)
|
||||
@@ -0,0 +1,202 @@
|
||||
"""Most of these tests come from the examples in Bronstein's book."""
|
||||
from sympy.core.numbers import (I, Rational, oo)
|
||||
from sympy.core.symbol import symbols
|
||||
from sympy.polys.polytools import Poly
|
||||
from sympy.integrals.risch import (DifferentialExtension,
|
||||
NonElementaryIntegralException)
|
||||
from sympy.integrals.rde import (order_at, order_at_oo, weak_normalizer,
|
||||
normal_denom, special_denom, bound_degree, spde, solve_poly_rde,
|
||||
no_cancel_equal, cancel_primitive, cancel_exp, rischDE)
|
||||
|
||||
from sympy.testing.pytest import raises
|
||||
from sympy.abc import x, t, z, n
|
||||
|
||||
t0, t1, t2, k = symbols('t:3 k')
|
||||
|
||||
|
||||
def test_order_at():
|
||||
a = Poly(t**4, t)
|
||||
b = Poly((t**2 + 1)**3*t, t)
|
||||
c = Poly((t**2 + 1)**6*t, t)
|
||||
d = Poly((t**2 + 1)**10*t**10, t)
|
||||
e = Poly((t**2 + 1)**100*t**37, t)
|
||||
p1 = Poly(t, t)
|
||||
p2 = Poly(1 + t**2, t)
|
||||
assert order_at(a, p1, t) == 4
|
||||
assert order_at(b, p1, t) == 1
|
||||
assert order_at(c, p1, t) == 1
|
||||
assert order_at(d, p1, t) == 10
|
||||
assert order_at(e, p1, t) == 37
|
||||
assert order_at(a, p2, t) == 0
|
||||
assert order_at(b, p2, t) == 3
|
||||
assert order_at(c, p2, t) == 6
|
||||
assert order_at(d, p1, t) == 10
|
||||
assert order_at(e, p2, t) == 100
|
||||
assert order_at(Poly(0, t), Poly(t, t), t) is oo
|
||||
assert order_at_oo(Poly(t**2 - 1, t), Poly(t + 1), t) == \
|
||||
order_at_oo(Poly(t - 1, t), Poly(1, t), t) == -1
|
||||
assert order_at_oo(Poly(0, t), Poly(1, t), t) is oo
|
||||
|
||||
def test_weak_normalizer():
|
||||
a = Poly((1 + x)*t**5 + 4*t**4 + (-1 - 3*x)*t**3 - 4*t**2 + (-2 + 2*x)*t, t)
|
||||
d = Poly(t**4 - 3*t**2 + 2, t)
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]})
|
||||
r = weak_normalizer(a, d, DE, z)
|
||||
assert r == (Poly(t**5 - t**4 - 4*t**3 + 4*t**2 + 4*t - 4, t, domain='ZZ[x]'),
|
||||
(Poly((1 + x)*t**2 + x*t, t, domain='ZZ[x]'),
|
||||
Poly(t + 1, t, domain='ZZ[x]')))
|
||||
assert weak_normalizer(r[1][0], r[1][1], DE) == (Poly(1, t), r[1])
|
||||
r = weak_normalizer(Poly(1 + t**2), Poly(t**2 - 1, t), DE, z)
|
||||
assert r == (Poly(t**4 - 2*t**2 + 1, t), (Poly(-3*t**2 + 1, t), Poly(t**2 - 1, t)))
|
||||
assert weak_normalizer(r[1][0], r[1][1], DE, z) == (Poly(1, t), r[1])
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t**2)]})
|
||||
r = weak_normalizer(Poly(1 + t**2), Poly(t, t), DE, z)
|
||||
assert r == (Poly(t, t), (Poly(0, t), Poly(1, t)))
|
||||
assert weak_normalizer(r[1][0], r[1][1], DE, z) == (Poly(1, t), r[1])
|
||||
|
||||
|
||||
def test_normal_denom():
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x)]})
|
||||
raises(NonElementaryIntegralException, lambda: normal_denom(Poly(1, x), Poly(1, x),
|
||||
Poly(1, x), Poly(x, x), DE))
|
||||
fa, fd = Poly(t**2 + 1, t), Poly(1, t)
|
||||
ga, gd = Poly(1, t), Poly(t**2, t)
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]})
|
||||
assert normal_denom(fa, fd, ga, gd, DE) == \
|
||||
(Poly(t, t), (Poly(t**3 - t**2 + t - 1, t), Poly(1, t)), (Poly(1, t),
|
||||
Poly(1, t)), Poly(t, t))
|
||||
|
||||
|
||||
def test_special_denom():
|
||||
# TODO: add more tests here
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]})
|
||||
assert special_denom(Poly(1, t), Poly(t**2, t), Poly(1, t), Poly(t**2 - 1, t),
|
||||
Poly(t, t), DE) == \
|
||||
(Poly(1, t), Poly(t**2 - 1, t), Poly(t**2 - 1, t), Poly(t, t))
|
||||
# assert special_denom(Poly(1, t), Poly(2*x, t), Poly((1 + 2*x)*t, t), DE) == 1
|
||||
|
||||
# issue 3940
|
||||
# Note, this isn't a very good test, because the denominator is just 1,
|
||||
# but at least it tests the exp cancellation case
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-2*x*t0, t0),
|
||||
Poly(I*k*t1, t1)]})
|
||||
DE.decrement_level()
|
||||
assert special_denom(Poly(1, t0), Poly(I*k, t0), Poly(1, t0), Poly(t0, t0),
|
||||
Poly(1, t0), DE) == \
|
||||
(Poly(1, t0, domain='ZZ'), Poly(I*k, t0, domain='ZZ_I[k,x]'),
|
||||
Poly(t0, t0, domain='ZZ'), Poly(1, t0, domain='ZZ'))
|
||||
|
||||
|
||||
assert special_denom(Poly(1, t), Poly(t**2, t), Poly(1, t), Poly(t**2 - 1, t),
|
||||
Poly(t, t), DE, case='tan') == \
|
||||
(Poly(1, t, t0, domain='ZZ'), Poly(t**2, t0, t, domain='ZZ[x]'),
|
||||
Poly(t, t, t0, domain='ZZ'), Poly(1, t0, domain='ZZ'))
|
||||
|
||||
raises(ValueError, lambda: special_denom(Poly(1, t), Poly(t**2, t), Poly(1, t), Poly(t**2 - 1, t),
|
||||
Poly(t, t), DE, case='unrecognized_case'))
|
||||
|
||||
|
||||
def test_bound_degree_fail():
|
||||
# Primitive
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x),
|
||||
Poly(t0/x**2, t0), Poly(1/x, t)]})
|
||||
assert bound_degree(Poly(t**2, t), Poly(-(1/x**2*t**2 + 1/x), t),
|
||||
Poly((2*x - 1)*t**4 + (t0 + x)/x*t**3 - (t0 + 4*x**2)/2*x*t**2 + x*t,
|
||||
t), DE) == 3
|
||||
|
||||
|
||||
def test_bound_degree():
|
||||
# Base
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x)]})
|
||||
assert bound_degree(Poly(1, x), Poly(-2*x, x), Poly(1, x), DE) == 0
|
||||
|
||||
# Primitive (see above test_bound_degree_fail)
|
||||
# TODO: Add test for when the degree bound becomes larger after limited_integrate
|
||||
# TODO: Add test for db == da - 1 case
|
||||
|
||||
# Exp
|
||||
# TODO: Add tests
|
||||
# TODO: Add test for when the degree becomes larger after parametric_log_deriv()
|
||||
|
||||
# Nonlinear
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]})
|
||||
assert bound_degree(Poly(t, t), Poly((t - 1)*(t**2 + 1), t), Poly(1, t), DE) == 0
|
||||
|
||||
|
||||
def test_spde():
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]})
|
||||
raises(NonElementaryIntegralException, lambda: spde(Poly(t, t), Poly((t - 1)*(t**2 + 1), t), Poly(1, t), 0, DE))
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]})
|
||||
assert spde(Poly(t**2 + x*t*2 + x**2, t), Poly(t**2/x**2 + (2/x - 1)*t, t),
|
||||
Poly(t**2/x**2 + (2/x - 1)*t, t), 0, DE) == \
|
||||
(Poly(0, t), Poly(0, t), 0, Poly(0, t), Poly(1, t, domain='ZZ(x)'))
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t0/x**2, t0), Poly(1/x, t)]})
|
||||
assert spde(Poly(t**2, t), Poly(-t**2/x**2 - 1/x, t),
|
||||
Poly((2*x - 1)*t**4 + (t0 + x)/x*t**3 - (t0 + 4*x**2)/(2*x)*t**2 + x*t, t), 3, DE) == \
|
||||
(Poly(0, t), Poly(0, t), 0, Poly(0, t),
|
||||
Poly(t0*t**2/2 + x**2*t**2 - x**2*t, t, domain='ZZ(x,t0)'))
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x)]})
|
||||
assert spde(Poly(x**2 + x + 1, x), Poly(-2*x - 1, x), Poly(x**5/2 +
|
||||
3*x**4/4 + x**3 - x**2 + 1, x), 4, DE) == \
|
||||
(Poly(0, x, domain='QQ'), Poly(x/2 - Rational(1, 4), x), 2, Poly(x**2 + x + 1, x), Poly(x*Rational(5, 4), x))
|
||||
assert spde(Poly(x**2 + x + 1, x), Poly(-2*x - 1, x), Poly(x**5/2 +
|
||||
3*x**4/4 + x**3 - x**2 + 1, x), n, DE) == \
|
||||
(Poly(0, x, domain='QQ'), Poly(x/2 - Rational(1, 4), x), -2 + n, Poly(x**2 + x + 1, x), Poly(x*Rational(5, 4), x))
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1, t)]})
|
||||
raises(NonElementaryIntegralException, lambda: spde(Poly((t - 1)*(t**2 + 1)**2, t), Poly((t - 1)*(t**2 + 1), t), Poly(1, t), 0, DE))
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x)]})
|
||||
assert spde(Poly(x**2 - x, x), Poly(1, x), Poly(9*x**4 - 10*x**3 + 2*x**2, x), 4, DE) == \
|
||||
(Poly(0, x, domain='ZZ'), Poly(0, x), 0, Poly(0, x), Poly(3*x**3 - 2*x**2, x, domain='QQ'))
|
||||
assert spde(Poly(x**2 - x, x), Poly(x**2 - 5*x + 3, x), Poly(x**7 - x**6 - 2*x**4 + 3*x**3 - x**2, x), 5, DE) == \
|
||||
(Poly(1, x, domain='QQ'), Poly(x + 1, x, domain='QQ'), 1, Poly(x**4 - x**3, x), Poly(x**3 - x**2, x, domain='QQ'))
|
||||
|
||||
def test_solve_poly_rde_no_cancel():
|
||||
# deg(b) large
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t**2, t)]})
|
||||
assert solve_poly_rde(Poly(t**2 + 1, t), Poly(t**3 + (x + 1)*t**2 + t + x + 2, t),
|
||||
oo, DE) == Poly(t + x, t)
|
||||
# deg(b) small
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x)]})
|
||||
assert solve_poly_rde(Poly(0, x), Poly(x/2 - Rational(1, 4), x), oo, DE) == \
|
||||
Poly(x**2/4 - x/4, x)
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]})
|
||||
assert solve_poly_rde(Poly(2, t), Poly(t**2 + 2*t + 3, t), 1, DE) == \
|
||||
Poly(t + 1, t, x)
|
||||
# deg(b) == deg(D) - 1
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]})
|
||||
assert no_cancel_equal(Poly(1 - t, t),
|
||||
Poly(t**3 + t**2 - 2*x*t - 2*x, t), oo, DE) == \
|
||||
(Poly(t**2, t), 1, Poly((-2 - 2*x)*t - 2*x, t))
|
||||
|
||||
|
||||
def test_solve_poly_rde_cancel():
|
||||
# exp
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]})
|
||||
assert cancel_exp(Poly(2*x, t), Poly(2*x, t), 0, DE) == \
|
||||
Poly(1, t)
|
||||
assert cancel_exp(Poly(2*x, t), Poly((1 + 2*x)*t, t), 1, DE) == \
|
||||
Poly(t, t)
|
||||
# TODO: Add more exp tests, including tests that require is_deriv_in_field()
|
||||
|
||||
# primitive
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]})
|
||||
|
||||
# If the DecrementLevel context manager is working correctly, this shouldn't
|
||||
# cause any problems with the further tests.
|
||||
raises(NonElementaryIntegralException, lambda: cancel_primitive(Poly(1, t), Poly(t, t), oo, DE))
|
||||
|
||||
assert cancel_primitive(Poly(1, t), Poly(t + 1/x, t), 2, DE) == \
|
||||
Poly(t, t)
|
||||
assert cancel_primitive(Poly(4*x, t), Poly(4*x*t**2 + 2*t/x, t), 3, DE) == \
|
||||
Poly(t**2, t)
|
||||
|
||||
# TODO: Add more primitive tests, including tests that require is_deriv_in_field()
|
||||
|
||||
|
||||
def test_rischDE():
|
||||
# TODO: Add more tests for rischDE, including ones from the text
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]})
|
||||
DE.decrement_level()
|
||||
assert rischDE(Poly(-2*x, x), Poly(1, x), Poly(1 - 2*x - 2*x**2, x),
|
||||
Poly(1, x), DE) == \
|
||||
(Poly(x + 1, x), Poly(1, x))
|
||||
@@ -0,0 +1,763 @@
|
||||
"""Most of these tests come from the examples in Bronstein's book."""
|
||||
from sympy.core.function import (Function, Lambda, diff, expand_log)
|
||||
from sympy.core.numbers import (I, Rational, pi)
|
||||
from sympy.core.relational import Ne
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import (Symbol, symbols)
|
||||
from sympy.functions.elementary.exponential import (exp, log)
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.piecewise import Piecewise
|
||||
from sympy.functions.elementary.trigonometric import (atan, sin, tan)
|
||||
from sympy.polys.polytools import (Poly, cancel, factor)
|
||||
from sympy.integrals.risch import (gcdex_diophantine, frac_in, as_poly_1t,
|
||||
derivation, splitfactor, splitfactor_sqf, canonical_representation,
|
||||
hermite_reduce, polynomial_reduce, residue_reduce, residue_reduce_to_basic,
|
||||
integrate_primitive, integrate_hyperexponential_polynomial,
|
||||
integrate_hyperexponential, integrate_hypertangent_polynomial,
|
||||
integrate_nonlinear_no_specials, integer_powers, DifferentialExtension,
|
||||
risch_integrate, DecrementLevel, NonElementaryIntegral, recognize_log_derivative,
|
||||
recognize_derivative, laurent_series)
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
from sympy.abc import x, t, nu, z, a, y
|
||||
t0, t1, t2 = symbols('t:3')
|
||||
i = Symbol('i')
|
||||
|
||||
def test_gcdex_diophantine():
|
||||
assert gcdex_diophantine(Poly(x**4 - 2*x**3 - 6*x**2 + 12*x + 15),
|
||||
Poly(x**3 + x**2 - 4*x - 4), Poly(x**2 - 1)) == \
|
||||
(Poly((-x**2 + 4*x - 3)/5), Poly((x**3 - 7*x**2 + 16*x - 10)/5))
|
||||
assert gcdex_diophantine(Poly(x**3 + 6*x + 7), Poly(x**2 + 3*x + 2), Poly(x + 1)) == \
|
||||
(Poly(1/13, x, domain='QQ'), Poly(-1/13*x + 3/13, x, domain='QQ'))
|
||||
|
||||
|
||||
def test_frac_in():
|
||||
assert frac_in(Poly((x + 1)/x*t, t), x) == \
|
||||
(Poly(t*x + t, x), Poly(x, x))
|
||||
assert frac_in((x + 1)/x*t, x) == \
|
||||
(Poly(t*x + t, x), Poly(x, x))
|
||||
assert frac_in((Poly((x + 1)/x*t, t), Poly(t + 1, t)), x) == \
|
||||
(Poly(t*x + t, x), Poly((1 + t)*x, x))
|
||||
raises(ValueError, lambda: frac_in((x + 1)/log(x)*t, x))
|
||||
assert frac_in(Poly((2 + 2*x + x*(1 + x))/(1 + x)**2, t), x, cancel=True) == \
|
||||
(Poly(x + 2, x), Poly(x + 1, x))
|
||||
|
||||
|
||||
def test_as_poly_1t():
|
||||
assert as_poly_1t(2/t + t, t, z) in [
|
||||
Poly(t + 2*z, t, z), Poly(t + 2*z, z, t)]
|
||||
assert as_poly_1t(2/t + 3/t**2, t, z) in [
|
||||
Poly(2*z + 3*z**2, t, z), Poly(2*z + 3*z**2, z, t)]
|
||||
assert as_poly_1t(2/((exp(2) + 1)*t), t, z) in [
|
||||
Poly(2/(exp(2) + 1)*z, t, z), Poly(2/(exp(2) + 1)*z, z, t)]
|
||||
assert as_poly_1t(2/((exp(2) + 1)*t) + t, t, z) in [
|
||||
Poly(t + 2/(exp(2) + 1)*z, t, z), Poly(t + 2/(exp(2) + 1)*z, z, t)]
|
||||
assert as_poly_1t(S.Zero, t, z) == Poly(0, t, z)
|
||||
|
||||
|
||||
def test_derivation():
|
||||
p = Poly(4*x**4*t**5 + (-4*x**3 - 4*x**4)*t**4 + (-3*x**2 + 2*x**3)*t**3 +
|
||||
(2*x + 7*x**2 + 2*x**3)*t**2 + (1 - 4*x - 4*x**2)*t - 1 + 2*x, t)
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-t**2 - 3/(2*x)*t + 1/(2*x), t)]})
|
||||
assert derivation(p, DE) == Poly(-20*x**4*t**6 + (2*x**3 + 16*x**4)*t**5 +
|
||||
(21*x**2 + 12*x**3)*t**4 + (x*Rational(7, 2) - 25*x**2 - 12*x**3)*t**3 +
|
||||
(-5 - x*Rational(15, 2) + 7*x**2)*t**2 - (3 - 8*x - 10*x**2 - 4*x**3)/(2*x)*t +
|
||||
(1 - 4*x**2)/(2*x), t)
|
||||
assert derivation(Poly(1, t), DE) == Poly(0, t)
|
||||
assert derivation(Poly(t, t), DE) == DE.d
|
||||
assert derivation(Poly(t**2 + 1/x*t + (1 - 2*x)/(4*x**2), t), DE) == \
|
||||
Poly(-2*t**3 - 4/x*t**2 - (5 - 2*x)/(2*x**2)*t - (1 - 2*x)/(2*x**3), t, domain='ZZ(x)')
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t1), Poly(t, t)]})
|
||||
assert derivation(Poly(x*t*t1, t), DE) == Poly(t*t1 + x*t*t1 + t, t)
|
||||
assert derivation(Poly(x*t*t1, t), DE, coefficientD=True) == \
|
||||
Poly((1 + t1)*t, t)
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x)]})
|
||||
assert derivation(Poly(x, x), DE) == Poly(1, x)
|
||||
# Test basic option
|
||||
assert derivation((x + 1)/(x - 1), DE, basic=True) == -2/(1 - 2*x + x**2)
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]})
|
||||
assert derivation((t + 1)/(t - 1), DE, basic=True) == -2*t/(1 - 2*t + t**2)
|
||||
assert derivation(t + 1, DE, basic=True) == t
|
||||
|
||||
|
||||
def test_splitfactor():
|
||||
p = Poly(4*x**4*t**5 + (-4*x**3 - 4*x**4)*t**4 + (-3*x**2 + 2*x**3)*t**3 +
|
||||
(2*x + 7*x**2 + 2*x**3)*t**2 + (1 - 4*x - 4*x**2)*t - 1 + 2*x, t, field=True)
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-t**2 - 3/(2*x)*t + 1/(2*x), t)]})
|
||||
assert splitfactor(p, DE) == (Poly(4*x**4*t**3 + (-8*x**3 - 4*x**4)*t**2 +
|
||||
(4*x**2 + 8*x**3)*t - 4*x**2, t, domain='ZZ(x)'),
|
||||
Poly(t**2 + 1/x*t + (1 - 2*x)/(4*x**2), t, domain='ZZ(x)'))
|
||||
assert splitfactor(Poly(x, t), DE) == (Poly(x, t), Poly(1, t))
|
||||
r = Poly(-4*x**4*z**2 + 4*x**6*z**2 - z*x**3 - 4*x**5*z**3 + 4*x**3*z**3 + x**4 + z*x**5 - x**6, t)
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]})
|
||||
assert splitfactor(r, DE, coefficientD=True) == \
|
||||
(Poly(x*z - x**2 - z*x**3 + x**4, t), Poly(-x**2 + 4*x**2*z**2, t))
|
||||
assert splitfactor_sqf(r, DE, coefficientD=True) == \
|
||||
(((Poly(x*z - x**2 - z*x**3 + x**4, t), 1),), ((Poly(-x**2 + 4*x**2*z**2, t), 1),))
|
||||
assert splitfactor(Poly(0, t), DE) == (Poly(0, t), Poly(1, t))
|
||||
assert splitfactor_sqf(Poly(0, t), DE) == (((Poly(0, t), 1),), ())
|
||||
|
||||
|
||||
def test_canonical_representation():
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t**2, t)]})
|
||||
assert canonical_representation(Poly(x - t, t), Poly(t**2, t), DE) == \
|
||||
(Poly(0, t, domain='ZZ[x]'), (Poly(0, t, domain='QQ[x]'),
|
||||
Poly(1, t, domain='ZZ')), (Poly(-t + x, t, domain='QQ[x]'),
|
||||
Poly(t**2, t)))
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]})
|
||||
assert canonical_representation(Poly(t**5 + t**3 + x**2*t + 1, t),
|
||||
Poly((t**2 + 1)**3, t), DE) == \
|
||||
(Poly(0, t, domain='ZZ[x]'), (Poly(t**5 + t**3 + x**2*t + 1, t, domain='QQ[x]'),
|
||||
Poly(t**6 + 3*t**4 + 3*t**2 + 1, t, domain='QQ')),
|
||||
(Poly(0, t, domain='QQ[x]'), Poly(1, t, domain='QQ')))
|
||||
|
||||
|
||||
def test_hermite_reduce():
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]})
|
||||
|
||||
assert hermite_reduce(Poly(x - t, t), Poly(t**2, t), DE) == \
|
||||
((Poly(-x, t, domain='QQ[x]'), Poly(t, t, domain='QQ[x]')),
|
||||
(Poly(0, t, domain='QQ[x]'), Poly(1, t, domain='QQ[x]')),
|
||||
(Poly(-x, t, domain='QQ[x]'), Poly(1, t, domain='QQ[x]')))
|
||||
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-t**2 - t/x - (1 - nu**2/x**2), t)]})
|
||||
|
||||
assert hermite_reduce(
|
||||
Poly(x**2*t**5 + x*t**4 - nu**2*t**3 - x*(x**2 + 1)*t**2 - (x**2 - nu**2)*t - x**5/4, t),
|
||||
Poly(x**2*t**4 + x**2*(x**2 + 2)*t**2 + x**2 + x**4 + x**6/4, t), DE) == \
|
||||
((Poly(-x**2 - 4, t, domain='ZZ(x,nu)'), Poly(4*t**2 + 2*x**2 + 4, t, domain='ZZ(x,nu)')),
|
||||
(Poly((-2*nu**2 - x**4)*t - (2*x**3 + 2*x), t, domain='ZZ(x,nu)'),
|
||||
Poly(2*x**2*t**2 + x**4 + 2*x**2, t, domain='ZZ(x,nu)')),
|
||||
(Poly(x*t + 1, t, domain='ZZ(x,nu)'), Poly(x, t, domain='ZZ(x,nu)')))
|
||||
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]})
|
||||
|
||||
a = Poly((-2 + 3*x)*t**3 + (-1 + x)*t**2 + (-4*x + 2*x**2)*t + x**2, t)
|
||||
d = Poly(x*t**6 - 4*x**2*t**5 + 6*x**3*t**4 - 4*x**4*t**3 + x**5*t**2, t)
|
||||
|
||||
assert hermite_reduce(a, d, DE) == \
|
||||
((Poly(3*t**2 + t + 3*x, t, domain='ZZ(x)'),
|
||||
Poly(3*t**4 - 9*x*t**3 + 9*x**2*t**2 - 3*x**3*t, t, domain='ZZ(x)')),
|
||||
(Poly(0, t, domain='ZZ(x)'), Poly(1, t, domain='ZZ(x)')),
|
||||
(Poly(0, t, domain='ZZ(x)'), Poly(1, t, domain='ZZ(x)')))
|
||||
|
||||
assert hermite_reduce(
|
||||
Poly(-t**2 + 2*t + 2, t, domain='ZZ(x)'),
|
||||
Poly(-x*t**2 + 2*x*t - x, t, domain='ZZ(x)'), DE) == \
|
||||
((Poly(3, t, domain='ZZ(x)'), Poly(t - 1, t, domain='ZZ(x)')),
|
||||
(Poly(0, t, domain='ZZ(x)'), Poly(1, t, domain='ZZ(x)')),
|
||||
(Poly(1, t, domain='ZZ(x)'), Poly(x, t, domain='ZZ(x)')))
|
||||
|
||||
assert hermite_reduce(
|
||||
Poly(-x**2*t**6 + (-1 - 2*x**3 + x**4)*t**3 + (-3 - 3*x**4)*t**2 -
|
||||
2*x*t - x - 3*x**2, t, domain='ZZ(x)'),
|
||||
Poly(x**4*t**6 - 2*x**2*t**3 + 1, t, domain='ZZ(x)'), DE) == \
|
||||
((Poly(x**3*t + x**4 + 1, t, domain='ZZ(x)'), Poly(x**3*t**3 - x, t, domain='ZZ(x)')),
|
||||
(Poly(0, t, domain='ZZ(x)'), Poly(1, t, domain='ZZ(x)')),
|
||||
(Poly(-1, t, domain='ZZ(x)'), Poly(x**2, t, domain='ZZ(x)')))
|
||||
|
||||
assert hermite_reduce(
|
||||
Poly((-2 + 3*x)*t**3 + (-1 + x)*t**2 + (-4*x + 2*x**2)*t + x**2, t),
|
||||
Poly(x*t**6 - 4*x**2*t**5 + 6*x**3*t**4 - 4*x**4*t**3 + x**5*t**2, t), DE) == \
|
||||
((Poly(3*t**2 + t + 3*x, t, domain='ZZ(x)'),
|
||||
Poly(3*t**4 - 9*x*t**3 + 9*x**2*t**2 - 3*x**3*t, t, domain='ZZ(x)')),
|
||||
(Poly(0, t, domain='ZZ(x)'), Poly(1, t, domain='ZZ(x)')),
|
||||
(Poly(0, t, domain='ZZ(x)'), Poly(1, t, domain='ZZ(x)')))
|
||||
|
||||
|
||||
def test_polynomial_reduce():
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t**2, t)]})
|
||||
assert polynomial_reduce(Poly(1 + x*t + t**2, t), DE) == \
|
||||
(Poly(t, t), Poly(x*t, t))
|
||||
assert polynomial_reduce(Poly(0, t), DE) == \
|
||||
(Poly(0, t), Poly(0, t))
|
||||
|
||||
|
||||
def test_laurent_series():
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1, t)]})
|
||||
a = Poly(36, t)
|
||||
d = Poly((t - 2)*(t**2 - 1)**2, t)
|
||||
F = Poly(t**2 - 1, t)
|
||||
n = 2
|
||||
assert laurent_series(a, d, F, n, DE) == \
|
||||
(Poly(-3*t**3 + 3*t**2 - 6*t - 8, t), Poly(t**5 + t**4 - 2*t**3 - 2*t**2 + t + 1, t),
|
||||
[Poly(-3*t**3 - 6*t**2, t, domain='QQ'), Poly(2*t**6 + 6*t**5 - 8*t**3, t, domain='QQ')])
|
||||
|
||||
|
||||
def test_recognize_derivative():
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, t)]})
|
||||
a = Poly(36, t)
|
||||
d = Poly((t - 2)*(t**2 - 1)**2, t)
|
||||
assert recognize_derivative(a, d, DE) == False
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]})
|
||||
a = Poly(2, t)
|
||||
d = Poly(t**2 - 1, t)
|
||||
assert recognize_derivative(a, d, DE) == False
|
||||
assert recognize_derivative(Poly(x*t, t), Poly(1, t), DE) == True
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]})
|
||||
assert recognize_derivative(Poly(t, t), Poly(1, t), DE) == True
|
||||
|
||||
|
||||
def test_recognize_log_derivative():
|
||||
|
||||
a = Poly(2*x**2 + 4*x*t - 2*t - x**2*t, t)
|
||||
d = Poly((2*x + t)*(t + x**2), t)
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]})
|
||||
assert recognize_log_derivative(a, d, DE, z) == True
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]})
|
||||
assert recognize_log_derivative(Poly(t + 1, t), Poly(t + x, t), DE) == True
|
||||
assert recognize_log_derivative(Poly(2, t), Poly(t**2 - 1, t), DE) == True
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x)]})
|
||||
assert recognize_log_derivative(Poly(1, x), Poly(x**2 - 2, x), DE) == False
|
||||
assert recognize_log_derivative(Poly(1, x), Poly(x**2 + x, x), DE) == True
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]})
|
||||
assert recognize_log_derivative(Poly(1, t), Poly(t**2 - 2, t), DE) == False
|
||||
assert recognize_log_derivative(Poly(1, t), Poly(t**2 + t, t), DE) == False
|
||||
|
||||
|
||||
def test_residue_reduce():
|
||||
a = Poly(2*t**2 - t - x**2, t)
|
||||
d = Poly(t**3 - x**2*t, t)
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)], 'Tfuncs': [log]})
|
||||
assert residue_reduce(a, d, DE, z, invert=False) == \
|
||||
([(Poly(z**2 - Rational(1, 4), z, domain='ZZ(x)'),
|
||||
Poly((1 + 3*x*z - 6*z**2 - 2*x**2 + 4*x**2*z**2)*t - x*z + x**2 +
|
||||
2*x**2*z**2 - 2*z*x**3, t, domain='ZZ(z, x)'))], False)
|
||||
assert residue_reduce(a, d, DE, z, invert=True) == \
|
||||
([(Poly(z**2 - Rational(1, 4), z, domain='ZZ(x)'), Poly(t + 2*x*z, t))], False)
|
||||
assert residue_reduce(Poly(-2/x, t), Poly(t**2 - 1, t,), DE, z, invert=False) == \
|
||||
([(Poly(z**2 - 1, z, domain='QQ'), Poly(-2*z*t/x - 2/x, t, domain='ZZ(z,x)'))], True)
|
||||
ans = residue_reduce(Poly(-2/x, t), Poly(t**2 - 1, t), DE, z, invert=True)
|
||||
assert ans == ([(Poly(z**2 - 1, z, domain='QQ'), Poly(t + z, t))], True)
|
||||
assert residue_reduce_to_basic(ans[0], DE, z) == -log(-1 + log(x)) + log(1 + log(x))
|
||||
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-t**2 - t/x - (1 - nu**2/x**2), t)]})
|
||||
# TODO: Skip or make faster
|
||||
assert residue_reduce(Poly((-2*nu**2 - x**4)/(2*x**2)*t - (1 + x**2)/x, t),
|
||||
Poly(t**2 + 1 + x**2/2, t), DE, z) == \
|
||||
([(Poly(z + S.Half, z, domain='QQ'), Poly(t**2 + 1 + x**2/2, t,
|
||||
domain='ZZ(x,nu)'))], True)
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t**2, t)]})
|
||||
assert residue_reduce(Poly(-2*x*t + 1 - x**2, t),
|
||||
Poly(t**2 + 2*x*t + 1 + x**2, t), DE, z) == \
|
||||
([(Poly(z**2 + Rational(1, 4), z), Poly(t + x + 2*z, t))], True)
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]})
|
||||
assert residue_reduce(Poly(t, t), Poly(t + sqrt(2), t), DE, z) == \
|
||||
([(Poly(z - 1, z, domain='QQ'), Poly(t + sqrt(2), t))], True)
|
||||
|
||||
|
||||
def test_integrate_hyperexponential():
|
||||
# TODO: Add tests for integrate_hyperexponential() from the book
|
||||
a = Poly((1 + 2*t1 + t1**2 + 2*t1**3)*t**2 + (1 + t1**2)*t + 1 + t1**2, t)
|
||||
d = Poly(1, t)
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t1**2, t1),
|
||||
Poly(t*(1 + t1**2), t)], 'Tfuncs': [tan, Lambda(i, exp(tan(i)))]})
|
||||
assert integrate_hyperexponential(a, d, DE) == \
|
||||
(exp(2*tan(x))*tan(x) + exp(tan(x)), 1 + t1**2, True)
|
||||
a = Poly((t1**3 + (x + 1)*t1**2 + t1 + x + 2)*t, t)
|
||||
assert integrate_hyperexponential(a, d, DE) == \
|
||||
((x + tan(x))*exp(tan(x)), 0, True)
|
||||
|
||||
a = Poly(t, t)
|
||||
d = Poly(1, t)
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(2*x*t, t)],
|
||||
'Tfuncs': [Lambda(i, exp(x**2))]})
|
||||
|
||||
assert integrate_hyperexponential(a, d, DE) == \
|
||||
(0, NonElementaryIntegral(exp(x**2), x), False)
|
||||
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)], 'Tfuncs': [exp]})
|
||||
assert integrate_hyperexponential(a, d, DE) == (exp(x), 0, True)
|
||||
|
||||
a = Poly(25*t**6 - 10*t**5 + 7*t**4 - 8*t**3 + 13*t**2 + 2*t - 1, t)
|
||||
d = Poly(25*t**6 + 35*t**4 + 11*t**2 + 1, t)
|
||||
assert integrate_hyperexponential(a, d, DE) == \
|
||||
(-(11 - 10*exp(x))/(5 + 25*exp(2*x)) + log(1 + exp(2*x)), -1, True)
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t0, t0), Poly(t0*t, t)],
|
||||
'Tfuncs': [exp, Lambda(i, exp(exp(i)))]})
|
||||
assert integrate_hyperexponential(Poly(2*t0*t**2, t), Poly(1, t), DE) == (exp(2*exp(x)), 0, True)
|
||||
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t0, t0), Poly(-t0*t, t)],
|
||||
'Tfuncs': [exp, Lambda(i, exp(-exp(i)))]})
|
||||
assert integrate_hyperexponential(Poly(-27*exp(9) - 162*t0*exp(9) +
|
||||
27*x*t0*exp(9), t), Poly((36*exp(18) + x**2*exp(18) - 12*x*exp(18))*t, t), DE) == \
|
||||
(27*exp(exp(x))/(-6*exp(9) + x*exp(9)), 0, True)
|
||||
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)], 'Tfuncs': [exp]})
|
||||
assert integrate_hyperexponential(Poly(x**2/2*t, t), Poly(1, t), DE) == \
|
||||
((2 - 2*x + x**2)*exp(x)/2, 0, True)
|
||||
assert integrate_hyperexponential(Poly(1 + t, t), Poly(t, t), DE) == \
|
||||
(-exp(-x), 1, True) # x - exp(-x)
|
||||
assert integrate_hyperexponential(Poly(x, t), Poly(t + 1, t), DE) == \
|
||||
(0, NonElementaryIntegral(x/(1 + exp(x)), x), False)
|
||||
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t0), Poly(2*x*t1, t1)],
|
||||
'Tfuncs': [log, Lambda(i, exp(i**2))]})
|
||||
|
||||
elem, nonelem, b = integrate_hyperexponential(Poly((8*x**7 - 12*x**5 + 6*x**3 - x)*t1**4 +
|
||||
(8*t0*x**7 - 8*t0*x**6 - 4*t0*x**5 + 2*t0*x**3 + 2*t0*x**2 - t0*x +
|
||||
24*x**8 - 36*x**6 - 4*x**5 + 22*x**4 + 4*x**3 - 7*x**2 - x + 1)*t1**3
|
||||
+ (8*t0*x**8 - 4*t0*x**6 - 16*t0*x**5 - 2*t0*x**4 + 12*t0*x**3 +
|
||||
t0*x**2 - 2*t0*x + 24*x**9 - 36*x**7 - 8*x**6 + 22*x**5 + 12*x**4 -
|
||||
7*x**3 - 6*x**2 + x + 1)*t1**2 + (8*t0*x**8 - 8*t0*x**6 - 16*t0*x**5 +
|
||||
6*t0*x**4 + 10*t0*x**3 - 2*t0*x**2 - t0*x + 8*x**10 - 12*x**8 - 4*x**7
|
||||
+ 2*x**6 + 12*x**5 + 3*x**4 - 9*x**3 - x**2 + 2*x)*t1 + 8*t0*x**7 -
|
||||
12*t0*x**6 - 4*t0*x**5 + 8*t0*x**4 - t0*x**2 - 4*x**7 + 4*x**6 +
|
||||
4*x**5 - 4*x**4 - x**3 + x**2, t1), Poly((8*x**7 - 12*x**5 + 6*x**3 -
|
||||
x)*t1**4 + (24*x**8 + 8*x**7 - 36*x**6 - 12*x**5 + 18*x**4 + 6*x**3 -
|
||||
3*x**2 - x)*t1**3 + (24*x**9 + 24*x**8 - 36*x**7 - 36*x**6 + 18*x**5 +
|
||||
18*x**4 - 3*x**3 - 3*x**2)*t1**2 + (8*x**10 + 24*x**9 - 12*x**8 -
|
||||
36*x**7 + 6*x**6 + 18*x**5 - x**4 - 3*x**3)*t1 + 8*x**10 - 12*x**8 +
|
||||
6*x**6 - x**4, t1), DE)
|
||||
|
||||
assert factor(elem) == -((x - 1)*log(x)/((x + exp(x**2))*(2*x**2 - 1)))
|
||||
assert (nonelem, b) == (NonElementaryIntegral(exp(x**2)/(exp(x**2) + 1), x), False)
|
||||
|
||||
def test_integrate_hyperexponential_polynomial():
|
||||
# Without proper cancellation within integrate_hyperexponential_polynomial(),
|
||||
# this will take a long time to complete, and will return a complicated
|
||||
# expression
|
||||
p = Poly((-28*x**11*t0 - 6*x**8*t0 + 6*x**9*t0 - 15*x**8*t0**2 +
|
||||
15*x**7*t0**2 + 84*x**10*t0**2 - 140*x**9*t0**3 - 20*x**6*t0**3 +
|
||||
20*x**7*t0**3 - 15*x**6*t0**4 + 15*x**5*t0**4 + 140*x**8*t0**4 -
|
||||
84*x**7*t0**5 - 6*x**4*t0**5 + 6*x**5*t0**5 + x**3*t0**6 - x**4*t0**6 +
|
||||
28*x**6*t0**6 - 4*x**5*t0**7 + x**9 - x**10 + 4*x**12)/(-8*x**11*t0 +
|
||||
28*x**10*t0**2 - 56*x**9*t0**3 + 70*x**8*t0**4 - 56*x**7*t0**5 +
|
||||
28*x**6*t0**6 - 8*x**5*t0**7 + x**4*t0**8 + x**12)*t1**2 +
|
||||
(-28*x**11*t0 - 12*x**8*t0 + 12*x**9*t0 - 30*x**8*t0**2 +
|
||||
30*x**7*t0**2 + 84*x**10*t0**2 - 140*x**9*t0**3 - 40*x**6*t0**3 +
|
||||
40*x**7*t0**3 - 30*x**6*t0**4 + 30*x**5*t0**4 + 140*x**8*t0**4 -
|
||||
84*x**7*t0**5 - 12*x**4*t0**5 + 12*x**5*t0**5 - 2*x**4*t0**6 +
|
||||
2*x**3*t0**6 + 28*x**6*t0**6 - 4*x**5*t0**7 + 2*x**9 - 2*x**10 +
|
||||
4*x**12)/(-8*x**11*t0 + 28*x**10*t0**2 - 56*x**9*t0**3 +
|
||||
70*x**8*t0**4 - 56*x**7*t0**5 + 28*x**6*t0**6 - 8*x**5*t0**7 +
|
||||
x**4*t0**8 + x**12)*t1 + (-2*x**2*t0 + 2*x**3*t0 + x*t0**2 -
|
||||
x**2*t0**2 + x**3 - x**4)/(-4*x**5*t0 + 6*x**4*t0**2 - 4*x**3*t0**3 +
|
||||
x**2*t0**4 + x**6), t1, z, expand=False)
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t0), Poly(2*x*t1, t1)]})
|
||||
assert integrate_hyperexponential_polynomial(p, DE, z) == (
|
||||
Poly((x - t0)*t1**2 + (-2*t0 + 2*x)*t1, t1), Poly(-2*x*t0 + x**2 +
|
||||
t0**2, t1), True)
|
||||
|
||||
DE = DifferentialExtension(extension={'D':[Poly(1, x), Poly(t0, t0)]})
|
||||
assert integrate_hyperexponential_polynomial(Poly(0, t0), DE, z) == (
|
||||
Poly(0, t0), Poly(1, t0), True)
|
||||
|
||||
|
||||
def test_integrate_hyperexponential_returns_piecewise():
|
||||
a, b = symbols('a b')
|
||||
DE = DifferentialExtension(a**x, x)
|
||||
assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise(
|
||||
(exp(x*log(a))/log(a), Ne(log(a), 0)), (x, True)), 0, True)
|
||||
DE = DifferentialExtension(a**(b*x), x)
|
||||
assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise(
|
||||
(exp(b*x*log(a))/(b*log(a)), Ne(b*log(a), 0)), (x, True)), 0, True)
|
||||
DE = DifferentialExtension(exp(a*x), x)
|
||||
assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise(
|
||||
(exp(a*x)/a, Ne(a, 0)), (x, True)), 0, True)
|
||||
DE = DifferentialExtension(x*exp(a*x), x)
|
||||
assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise(
|
||||
((a*x - 1)*exp(a*x)/a**2, Ne(a**2, 0)), (x**2/2, True)), 0, True)
|
||||
DE = DifferentialExtension(x**2*exp(a*x), x)
|
||||
assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise(
|
||||
((x**2*a**2 - 2*a*x + 2)*exp(a*x)/a**3, Ne(a**3, 0)),
|
||||
(x**3/3, True)), 0, True)
|
||||
DE = DifferentialExtension(x**y + z, y)
|
||||
assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise(
|
||||
(exp(log(x)*y)/log(x), Ne(log(x), 0)), (y, True)), z, True)
|
||||
DE = DifferentialExtension(x**y + z + x**(2*y), y)
|
||||
assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise(
|
||||
((exp(2*log(x)*y)*log(x) +
|
||||
2*exp(log(x)*y)*log(x))/(2*log(x)**2), Ne(2*log(x)**2, 0)),
|
||||
(2*y, True),
|
||||
), z, True)
|
||||
# TODO: Add a test where two different parts of the extension use a
|
||||
# Piecewise, like y**x + z**x.
|
||||
|
||||
|
||||
def test_issue_13947():
|
||||
a, t, s = symbols('a t s')
|
||||
assert risch_integrate(2**(-pi)/(2**t + 1), t) == \
|
||||
2**(-pi)*t - 2**(-pi)*log(2**t + 1)/log(2)
|
||||
assert risch_integrate(a**(t - s)/(a**t + 1), t) == \
|
||||
exp(-s*log(a))*log(a**t + 1)/log(a)
|
||||
|
||||
|
||||
def test_integrate_primitive():
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)],
|
||||
'Tfuncs': [log]})
|
||||
assert integrate_primitive(Poly(t, t), Poly(1, t), DE) == (x*log(x), -1, True)
|
||||
assert integrate_primitive(Poly(x, t), Poly(t, t), DE) == (0, NonElementaryIntegral(x/log(x), x), False)
|
||||
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t1), Poly(1/(x + 1), t2)],
|
||||
'Tfuncs': [log, Lambda(i, log(i + 1))]})
|
||||
assert integrate_primitive(Poly(t1, t2), Poly(t2, t2), DE) == \
|
||||
(0, NonElementaryIntegral(log(x)/log(1 + x), x), False)
|
||||
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t1), Poly(1/(x*t1), t2)],
|
||||
'Tfuncs': [log, Lambda(i, log(log(i)))]})
|
||||
assert integrate_primitive(Poly(t2, t2), Poly(t1, t2), DE) == \
|
||||
(0, NonElementaryIntegral(log(log(x))/log(x), x), False)
|
||||
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t0)],
|
||||
'Tfuncs': [log]})
|
||||
assert integrate_primitive(Poly(x**2*t0**3 + (3*x**2 + x)*t0**2 + (3*x**2
|
||||
+ 2*x)*t0 + x**2 + x, t0), Poly(x**2*t0**4 + 4*x**2*t0**3 + 6*x**2*t0**2 +
|
||||
4*x**2*t0 + x**2, t0), DE) == \
|
||||
(-1/(log(x) + 1), NonElementaryIntegral(1/(log(x) + 1), x), False)
|
||||
|
||||
def test_integrate_hypertangent_polynomial():
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]})
|
||||
assert integrate_hypertangent_polynomial(Poly(t**2 + x*t + 1, t), DE) == \
|
||||
(Poly(t, t), Poly(x/2, t))
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(a*(t**2 + 1), t)]})
|
||||
assert integrate_hypertangent_polynomial(Poly(t**5, t), DE) == \
|
||||
(Poly(1/(4*a)*t**4 - 1/(2*a)*t**2, t), Poly(1/(2*a), t))
|
||||
|
||||
|
||||
def test_integrate_nonlinear_no_specials():
|
||||
a, d, = Poly(x**2*t**5 + x*t**4 - nu**2*t**3 - x*(x**2 + 1)*t**2 - (x**2 -
|
||||
nu**2)*t - x**5/4, t), Poly(x**2*t**4 + x**2*(x**2 + 2)*t**2 + x**2 + x**4 + x**6/4, t)
|
||||
# f(x) == phi_nu(x), the logarithmic derivative of J_v, the Bessel function,
|
||||
# which has no specials (see Chapter 5, note 4 of Bronstein's book).
|
||||
f = Function('phi_nu')
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x),
|
||||
Poly(-t**2 - t/x - (1 - nu**2/x**2), t)], 'Tfuncs': [f]})
|
||||
assert integrate_nonlinear_no_specials(a, d, DE) == \
|
||||
(-log(1 + f(x)**2 + x**2/2)/2 + (- 4 - x**2)/(4 + 2*x**2 + 4*f(x)**2), True)
|
||||
assert integrate_nonlinear_no_specials(Poly(t, t), Poly(1, t), DE) == \
|
||||
(0, False)
|
||||
|
||||
|
||||
def test_integer_powers():
|
||||
assert integer_powers([x, x/2, x**2 + 1, x*Rational(2, 3)]) == [
|
||||
(x/6, [(x, 6), (x/2, 3), (x*Rational(2, 3), 4)]),
|
||||
(1 + x**2, [(1 + x**2, 1)])]
|
||||
|
||||
|
||||
def test_DifferentialExtension_exp():
|
||||
assert DifferentialExtension(exp(x) + exp(x**2), x)._important_attrs == \
|
||||
(Poly(t1 + t0, t1), Poly(1, t1), [Poly(1, x,), Poly(t0, t0),
|
||||
Poly(2*x*t1, t1)], [x, t0, t1], [Lambda(i, exp(i)),
|
||||
Lambda(i, exp(i**2))], [], [None, 'exp', 'exp'], [None, x, x**2])
|
||||
assert DifferentialExtension(exp(x) + exp(2*x), x)._important_attrs == \
|
||||
(Poly(t0**2 + t0, t0), Poly(1, t0), [Poly(1, x), Poly(t0, t0)], [x, t0],
|
||||
[Lambda(i, exp(i))], [], [None, 'exp'], [None, x])
|
||||
assert DifferentialExtension(exp(x) + exp(x/2), x)._important_attrs == \
|
||||
(Poly(t0**2 + t0, t0), Poly(1, t0), [Poly(1, x), Poly(t0/2, t0)],
|
||||
[x, t0], [Lambda(i, exp(i/2))], [], [None, 'exp'], [None, x/2])
|
||||
assert DifferentialExtension(exp(x) + exp(x**2) + exp(x + x**2), x)._important_attrs == \
|
||||
(Poly((1 + t0)*t1 + t0, t1), Poly(1, t1), [Poly(1, x), Poly(t0, t0),
|
||||
Poly(2*x*t1, t1)], [x, t0, t1], [Lambda(i, exp(i)),
|
||||
Lambda(i, exp(i**2))], [], [None, 'exp', 'exp'], [None, x, x**2])
|
||||
assert DifferentialExtension(exp(x) + exp(x**2) + exp(x + x**2 + 1), x)._important_attrs == \
|
||||
(Poly((1 + S.Exp1*t0)*t1 + t0, t1), Poly(1, t1), [Poly(1, x),
|
||||
Poly(t0, t0), Poly(2*x*t1, t1)], [x, t0, t1], [Lambda(i, exp(i)),
|
||||
Lambda(i, exp(i**2))], [], [None, 'exp', 'exp'], [None, x, x**2])
|
||||
assert DifferentialExtension(exp(x) + exp(x**2) + exp(x/2 + x**2), x)._important_attrs == \
|
||||
(Poly((t0 + 1)*t1 + t0**2, t1), Poly(1, t1), [Poly(1, x),
|
||||
Poly(t0/2, t0), Poly(2*x*t1, t1)], [x, t0, t1],
|
||||
[Lambda(i, exp(i/2)), Lambda(i, exp(i**2))],
|
||||
[(exp(x/2), sqrt(exp(x)))], [None, 'exp', 'exp'], [None, x/2, x**2])
|
||||
assert DifferentialExtension(exp(x) + exp(x**2) + exp(x/2 + x**2 + 3), x)._important_attrs == \
|
||||
(Poly((t0*exp(3) + 1)*t1 + t0**2, t1), Poly(1, t1), [Poly(1, x),
|
||||
Poly(t0/2, t0), Poly(2*x*t1, t1)], [x, t0, t1], [Lambda(i, exp(i/2)),
|
||||
Lambda(i, exp(i**2))], [(exp(x/2), sqrt(exp(x)))], [None, 'exp', 'exp'],
|
||||
[None, x/2, x**2])
|
||||
assert DifferentialExtension(sqrt(exp(x)), x)._important_attrs == \
|
||||
(Poly(t0, t0), Poly(1, t0), [Poly(1, x), Poly(t0/2, t0)], [x, t0],
|
||||
[Lambda(i, exp(i/2))], [(exp(x/2), sqrt(exp(x)))], [None, 'exp'], [None, x/2])
|
||||
|
||||
assert DifferentialExtension(exp(x/2), x)._important_attrs == \
|
||||
(Poly(t0, t0), Poly(1, t0), [Poly(1, x), Poly(t0/2, t0)], [x, t0],
|
||||
[Lambda(i, exp(i/2))], [], [None, 'exp'], [None, x/2])
|
||||
|
||||
|
||||
def test_DifferentialExtension_log():
|
||||
assert DifferentialExtension(log(x)*log(x + 1)*log(2*x**2 + 2*x), x)._important_attrs == \
|
||||
(Poly(t0*t1**2 + (t0*log(2) + t0**2)*t1, t1), Poly(1, t1),
|
||||
[Poly(1, x), Poly(1/x, t0),
|
||||
Poly(1/(x + 1), t1, expand=False)], [x, t0, t1],
|
||||
[Lambda(i, log(i)), Lambda(i, log(i + 1))], [], [None, 'log', 'log'],
|
||||
[None, x, x + 1])
|
||||
assert DifferentialExtension(x**x*log(x), x)._important_attrs == \
|
||||
(Poly(t0*t1, t1), Poly(1, t1), [Poly(1, x), Poly(1/x, t0),
|
||||
Poly((1 + t0)*t1, t1)], [x, t0, t1], [Lambda(i, log(i)),
|
||||
Lambda(i, exp(t0*i))], [(exp(x*log(x)), x**x)], [None, 'log', 'exp'],
|
||||
[None, x, t0*x])
|
||||
|
||||
|
||||
def test_DifferentialExtension_symlog():
|
||||
# See comment on test_risch_integrate below
|
||||
assert DifferentialExtension(log(x**x), x)._important_attrs == \
|
||||
(Poly(t0*x, t1), Poly(1, t1), [Poly(1, x), Poly(1/x, t0), Poly((t0 +
|
||||
1)*t1, t1)], [x, t0, t1], [Lambda(i, log(i)), Lambda(i, exp(i*t0))],
|
||||
[(exp(x*log(x)), x**x)], [None, 'log', 'exp'], [None, x, t0*x])
|
||||
assert DifferentialExtension(log(x**y), x)._important_attrs == \
|
||||
(Poly(y*t0, t0), Poly(1, t0), [Poly(1, x), Poly(1/x, t0)], [x, t0],
|
||||
[Lambda(i, log(i))], [(y*log(x), log(x**y))], [None, 'log'],
|
||||
[None, x])
|
||||
assert DifferentialExtension(log(sqrt(x)), x)._important_attrs == \
|
||||
(Poly(t0, t0), Poly(2, t0), [Poly(1, x), Poly(1/x, t0)], [x, t0],
|
||||
[Lambda(i, log(i))], [(log(x)/2, log(sqrt(x)))], [None, 'log'],
|
||||
[None, x])
|
||||
|
||||
|
||||
def test_DifferentialExtension_handle_first():
|
||||
assert DifferentialExtension(exp(x)*log(x), x, handle_first='log')._important_attrs == \
|
||||
(Poly(t0*t1, t1), Poly(1, t1), [Poly(1, x), Poly(1/x, t0),
|
||||
Poly(t1, t1)], [x, t0, t1], [Lambda(i, log(i)), Lambda(i, exp(i))],
|
||||
[], [None, 'log', 'exp'], [None, x, x])
|
||||
assert DifferentialExtension(exp(x)*log(x), x, handle_first='exp')._important_attrs == \
|
||||
(Poly(t0*t1, t1), Poly(1, t1), [Poly(1, x), Poly(t0, t0),
|
||||
Poly(1/x, t1)], [x, t0, t1], [Lambda(i, exp(i)), Lambda(i, log(i))],
|
||||
[], [None, 'exp', 'log'], [None, x, x])
|
||||
|
||||
# This one must have the log first, regardless of what we set it to
|
||||
# (because the log is inside of the exponential: x**x == exp(x*log(x)))
|
||||
assert DifferentialExtension(-x**x*log(x)**2 + x**x - x**x/x, x,
|
||||
handle_first='exp')._important_attrs == \
|
||||
DifferentialExtension(-x**x*log(x)**2 + x**x - x**x/x, x,
|
||||
handle_first='log')._important_attrs == \
|
||||
(Poly((-1 + x - x*t0**2)*t1, t1), Poly(x, t1),
|
||||
[Poly(1, x), Poly(1/x, t0), Poly((1 + t0)*t1, t1)], [x, t0, t1],
|
||||
[Lambda(i, log(i)), Lambda(i, exp(t0*i))], [(exp(x*log(x)), x**x)],
|
||||
[None, 'log', 'exp'], [None, x, t0*x])
|
||||
|
||||
|
||||
def test_DifferentialExtension_all_attrs():
|
||||
# Test 'unimportant' attributes
|
||||
DE = DifferentialExtension(exp(x)*log(x), x, handle_first='exp')
|
||||
assert DE.f == exp(x)*log(x)
|
||||
assert DE.newf == t0*t1
|
||||
assert DE.x == x
|
||||
assert DE.cases == ['base', 'exp', 'primitive']
|
||||
assert DE.case == 'primitive'
|
||||
|
||||
assert DE.level == -1
|
||||
assert DE.t == t1 == DE.T[DE.level]
|
||||
assert DE.d == Poly(1/x, t1) == DE.D[DE.level]
|
||||
raises(ValueError, lambda: DE.increment_level())
|
||||
DE.decrement_level()
|
||||
assert DE.level == -2
|
||||
assert DE.t == t0 == DE.T[DE.level]
|
||||
assert DE.d == Poly(t0, t0) == DE.D[DE.level]
|
||||
assert DE.case == 'exp'
|
||||
DE.decrement_level()
|
||||
assert DE.level == -3
|
||||
assert DE.t == x == DE.T[DE.level] == DE.x
|
||||
assert DE.d == Poly(1, x) == DE.D[DE.level]
|
||||
assert DE.case == 'base'
|
||||
raises(ValueError, lambda: DE.decrement_level())
|
||||
DE.increment_level()
|
||||
DE.increment_level()
|
||||
assert DE.level == -1
|
||||
assert DE.t == t1 == DE.T[DE.level]
|
||||
assert DE.d == Poly(1/x, t1) == DE.D[DE.level]
|
||||
assert DE.case == 'primitive'
|
||||
|
||||
# Test methods
|
||||
assert DE.indices('log') == [2]
|
||||
assert DE.indices('exp') == [1]
|
||||
|
||||
|
||||
def test_DifferentialExtension_extension_flag():
|
||||
raises(ValueError, lambda: DifferentialExtension(extension={'T': [x, t]}))
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]})
|
||||
assert DE._important_attrs == (None, None, [Poly(1, x), Poly(t, t)], [x, t],
|
||||
None, None, None, None)
|
||||
assert DE.d == Poly(t, t)
|
||||
assert DE.t == t
|
||||
assert DE.level == -1
|
||||
assert DE.cases == ['base', 'exp']
|
||||
assert DE.x == x
|
||||
assert DE.case == 'exp'
|
||||
|
||||
DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)],
|
||||
'exts': [None, 'exp'], 'extargs': [None, x]})
|
||||
assert DE._important_attrs == (None, None, [Poly(1, x), Poly(t, t)], [x, t],
|
||||
None, None, [None, 'exp'], [None, x])
|
||||
raises(ValueError, lambda: DifferentialExtension())
|
||||
|
||||
|
||||
def test_DifferentialExtension_misc():
|
||||
# Odd ends
|
||||
assert DifferentialExtension(sin(y)*exp(x), x)._important_attrs == \
|
||||
(Poly(sin(y)*t0, t0, domain='ZZ[sin(y)]'), Poly(1, t0, domain='ZZ'),
|
||||
[Poly(1, x, domain='ZZ'), Poly(t0, t0, domain='ZZ')], [x, t0],
|
||||
[Lambda(i, exp(i))], [], [None, 'exp'], [None, x])
|
||||
raises(NotImplementedError, lambda: DifferentialExtension(sin(x), x))
|
||||
assert DifferentialExtension(10**x, x)._important_attrs == \
|
||||
(Poly(t0, t0), Poly(1, t0), [Poly(1, x), Poly(log(10)*t0, t0)], [x, t0],
|
||||
[Lambda(i, exp(i*log(10)))], [(exp(x*log(10)), 10**x)], [None, 'exp'],
|
||||
[None, x*log(10)])
|
||||
assert DifferentialExtension(log(x) + log(x**2), x)._important_attrs in [
|
||||
(Poly(3*t0, t0), Poly(2, t0), [Poly(1, x), Poly(2/x, t0)], [x, t0],
|
||||
[Lambda(i, log(i**2))], [], [None, ], [], [1], [x**2]),
|
||||
(Poly(3*t0, t0), Poly(1, t0), [Poly(1, x), Poly(1/x, t0)], [x, t0],
|
||||
[Lambda(i, log(i))], [], [None, 'log'], [None, x])]
|
||||
assert DifferentialExtension(S.Zero, x)._important_attrs == \
|
||||
(Poly(0, x), Poly(1, x), [Poly(1, x)], [x], [], [], [None], [None])
|
||||
assert DifferentialExtension(tan(atan(x).rewrite(log)), x)._important_attrs == \
|
||||
(Poly(x, x), Poly(1, x), [Poly(1, x)], [x], [], [], [None], [None])
|
||||
|
||||
|
||||
def test_DifferentialExtension_Rothstein():
|
||||
# Rothstein's integral
|
||||
f = (2581284541*exp(x) + 1757211400)/(39916800*exp(3*x) +
|
||||
119750400*exp(x)**2 + 119750400*exp(x) + 39916800)*exp(1/(exp(x) + 1) - 10*x)
|
||||
assert DifferentialExtension(f, x)._important_attrs == \
|
||||
(Poly((1757211400 + 2581284541*t0)*t1, t1), Poly(39916800 +
|
||||
119750400*t0 + 119750400*t0**2 + 39916800*t0**3, t1),
|
||||
[Poly(1, x), Poly(t0, t0), Poly(-(10 + 21*t0 + 10*t0**2)/(1 + 2*t0 +
|
||||
t0**2)*t1, t1, domain='ZZ(t0)')], [x, t0, t1],
|
||||
[Lambda(i, exp(i)), Lambda(i, exp(1/(t0 + 1) - 10*i))], [],
|
||||
[None, 'exp', 'exp'], [None, x, 1/(t0 + 1) - 10*x])
|
||||
|
||||
|
||||
class _TestingException(Exception):
|
||||
"""Dummy Exception class for testing."""
|
||||
pass
|
||||
|
||||
|
||||
def test_DecrementLevel():
|
||||
DE = DifferentialExtension(x*log(exp(x) + 1), x)
|
||||
assert DE.level == -1
|
||||
assert DE.t == t1
|
||||
assert DE.d == Poly(t0/(t0 + 1), t1)
|
||||
assert DE.case == 'primitive'
|
||||
|
||||
with DecrementLevel(DE):
|
||||
assert DE.level == -2
|
||||
assert DE.t == t0
|
||||
assert DE.d == Poly(t0, t0)
|
||||
assert DE.case == 'exp'
|
||||
|
||||
with DecrementLevel(DE):
|
||||
assert DE.level == -3
|
||||
assert DE.t == x
|
||||
assert DE.d == Poly(1, x)
|
||||
assert DE.case == 'base'
|
||||
|
||||
assert DE.level == -2
|
||||
assert DE.t == t0
|
||||
assert DE.d == Poly(t0, t0)
|
||||
assert DE.case == 'exp'
|
||||
|
||||
assert DE.level == -1
|
||||
assert DE.t == t1
|
||||
assert DE.d == Poly(t0/(t0 + 1), t1)
|
||||
assert DE.case == 'primitive'
|
||||
|
||||
# Test that __exit__ is called after an exception correctly
|
||||
try:
|
||||
with DecrementLevel(DE):
|
||||
raise _TestingException
|
||||
except _TestingException:
|
||||
pass
|
||||
else:
|
||||
raise AssertionError("Did not raise.")
|
||||
|
||||
assert DE.level == -1
|
||||
assert DE.t == t1
|
||||
assert DE.d == Poly(t0/(t0 + 1), t1)
|
||||
assert DE.case == 'primitive'
|
||||
|
||||
|
||||
def test_risch_integrate():
|
||||
assert risch_integrate(t0*exp(x), x) == t0*exp(x)
|
||||
assert risch_integrate(sin(x), x, rewrite_complex=True) == -exp(I*x)/2 - exp(-I*x)/2
|
||||
|
||||
# From my GSoC writeup
|
||||
assert risch_integrate((1 + 2*x**2 + x**4 + 2*x**3*exp(2*x**2))/
|
||||
(x**4*exp(x**2) + 2*x**2*exp(x**2) + exp(x**2)), x) == \
|
||||
NonElementaryIntegral(exp(-x**2), x) + exp(x**2)/(1 + x**2)
|
||||
|
||||
|
||||
assert risch_integrate(0, x) == 0
|
||||
|
||||
# also tests prde_cancel()
|
||||
e1 = log(x/exp(x) + 1)
|
||||
ans1 = risch_integrate(e1, x)
|
||||
assert ans1 == (x*log(x*exp(-x) + 1) + NonElementaryIntegral((x**2 - x)/(x + exp(x)), x))
|
||||
assert cancel(diff(ans1, x) - e1) == 0
|
||||
|
||||
# also tests issue #10798
|
||||
e2 = (log(-1/y)/2 - log(1/y)/2)/y - (log(1 - 1/y)/2 - log(1 + 1/y)/2)/y
|
||||
ans2 = risch_integrate(e2, y)
|
||||
assert ans2 == log(1/y)*log(1 - 1/y)/2 - log(1/y)*log(1 + 1/y)/2 + \
|
||||
NonElementaryIntegral((I*pi*y**2 - 2*y*log(1/y) - I*pi)/(2*y**3 - 2*y), y)
|
||||
assert expand_log(cancel(diff(ans2, y) - e2), force=True) == 0
|
||||
|
||||
# These are tested here in addition to in test_DifferentialExtension above
|
||||
# (symlogs) to test that backsubs works correctly. The integrals should be
|
||||
# written in terms of the original logarithms in the integrands.
|
||||
|
||||
# XXX: Unfortunately, making backsubs work on this one is a little
|
||||
# trickier, because x**x is converted to exp(x*log(x)), and so log(x**x)
|
||||
# is converted to x*log(x). (x**2*log(x)).subs(x*log(x), log(x**x)) is
|
||||
# smart enough, the issue is that these splits happen at different places
|
||||
# in the algorithm. Maybe a heuristic is in order
|
||||
assert risch_integrate(log(x**x), x) == x**2*log(x)/2 - x**2/4
|
||||
|
||||
assert risch_integrate(log(x**y), x) == x*log(x**y) - x*y
|
||||
assert risch_integrate(log(sqrt(x)), x) == x*log(sqrt(x)) - x/2
|
||||
|
||||
|
||||
def test_risch_integrate_float():
|
||||
assert risch_integrate((-60*exp(x) - 19.2*exp(4*x))*exp(4*x), x) == -2.4*exp(8*x) - 12.0*exp(5*x)
|
||||
|
||||
|
||||
def test_NonElementaryIntegral():
|
||||
assert isinstance(risch_integrate(exp(x**2), x), NonElementaryIntegral)
|
||||
assert isinstance(risch_integrate(x**x*log(x), x), NonElementaryIntegral)
|
||||
# Make sure methods of Integral still give back a NonElementaryIntegral
|
||||
assert isinstance(NonElementaryIntegral(x**x*t0, x).subs(t0, log(x)), NonElementaryIntegral)
|
||||
|
||||
|
||||
def test_xtothex():
|
||||
a = risch_integrate(x**x, x)
|
||||
assert a == NonElementaryIntegral(x**x, x)
|
||||
assert isinstance(a, NonElementaryIntegral)
|
||||
|
||||
|
||||
def test_DifferentialExtension_equality():
|
||||
DE1 = DE2 = DifferentialExtension(log(x), x)
|
||||
assert DE1 == DE2
|
||||
|
||||
|
||||
def test_DifferentialExtension_printing():
|
||||
DE = DifferentialExtension(exp(2*x**2) + log(exp(x**2) + 1), x)
|
||||
assert repr(DE) == ("DifferentialExtension(dict([('f', exp(2*x**2) + log(exp(x**2) + 1)), "
|
||||
"('x', x), ('T', [x, t0, t1]), ('D', [Poly(1, x, domain='ZZ'), Poly(2*x*t0, t0, domain='ZZ[x]'), "
|
||||
"Poly(2*t0*x/(t0 + 1), t1, domain='ZZ(x,t0)')]), ('fa', Poly(t1 + t0**2, t1, domain='ZZ[t0]')), "
|
||||
"('fd', Poly(1, t1, domain='ZZ')), ('Tfuncs', [Lambda(i, exp(i**2)), Lambda(i, log(t0 + 1))]), "
|
||||
"('backsubs', []), ('exts', [None, 'exp', 'log']), ('extargs', [None, x**2, t0 + 1]), "
|
||||
"('cases', ['base', 'exp', 'primitive']), ('case', 'primitive'), ('t', t1), "
|
||||
"('d', Poly(2*t0*x/(t0 + 1), t1, domain='ZZ(x,t0)')), ('newf', t0**2 + t1), ('level', -1), "
|
||||
"('dummy', False)]))")
|
||||
|
||||
assert str(DE) == ("DifferentialExtension({fa=Poly(t1 + t0**2, t1, domain='ZZ[t0]'), "
|
||||
"fd=Poly(1, t1, domain='ZZ'), D=[Poly(1, x, domain='ZZ'), Poly(2*x*t0, t0, domain='ZZ[x]'), "
|
||||
"Poly(2*t0*x/(t0 + 1), t1, domain='ZZ(x,t0)')]})")
|
||||
|
||||
|
||||
def test_issue_23948():
|
||||
f = (
|
||||
( (-2*x**5 + 28*x**4 - 144*x**3 + 324*x**2 - 270*x)*log(x)**2
|
||||
+(-4*x**6 + 56*x**5 - 288*x**4 + 648*x**3 - 540*x**2)*log(x)
|
||||
+(2*x**5 - 28*x**4 + 144*x**3 - 324*x**2 + 270*x)*exp(x)
|
||||
+(2*x**5 - 28*x**4 + 144*x**3 - 324*x**2 + 270*x)*log(5)
|
||||
-2*x**7 + 26*x**6 - 116*x**5 + 180*x**4 + 54*x**3 - 270*x**2
|
||||
)*log(-log(x)**2 - 2*x*log(x) + exp(x) + log(5) - x**2 - x)**2
|
||||
+( (4*x**5 - 44*x**4 + 168*x**3 - 216*x**2 - 108*x + 324)*log(x)
|
||||
+(-2*x**5 + 24*x**4 - 108*x**3 + 216*x**2 - 162*x)*exp(x)
|
||||
+4*x**6 - 42*x**5 + 144*x**4 - 108*x**3 - 324*x**2 + 486*x
|
||||
)*log(-log(x)**2 - 2*x*log(x) + exp(x) + log(5) - x**2 - x)
|
||||
)/(x*exp(x)**2*log(x)**2 + 2*x**2*exp(x)**2*log(x) - x*exp(x)**3
|
||||
+(-x*log(5) + x**3 + x**2)*exp(x)**2)
|
||||
|
||||
F = ((x**4 - 12*x**3 + 54*x**2 - 108*x + 81)*exp(-2*x)
|
||||
*log(-x**2 - 2*x*log(x) - x + exp(x) - log(x)**2 + log(5))**2)
|
||||
|
||||
assert risch_integrate(f, x) == F
|
||||
@@ -0,0 +1,22 @@
|
||||
from sympy.integrals.singularityfunctions import singularityintegrate
|
||||
from sympy.core.function import Function
|
||||
from sympy.core.symbol import symbols
|
||||
from sympy.functions.special.singularity_functions import SingularityFunction
|
||||
|
||||
x, a, n, y = symbols('x a n y')
|
||||
f = Function('f')
|
||||
|
||||
|
||||
def test_singularityintegrate():
|
||||
assert singularityintegrate(x, x) is None
|
||||
assert singularityintegrate(x + SingularityFunction(x, 9, 1), x) is None
|
||||
|
||||
assert 4*singularityintegrate(SingularityFunction(x, a, 3), x) == 4*SingularityFunction(x, a, 4)/4
|
||||
assert singularityintegrate(5*SingularityFunction(x, 5, -2), x) == 5*SingularityFunction(x, 5, -1)
|
||||
assert singularityintegrate(6*SingularityFunction(x, 5, -1), x) == 6*SingularityFunction(x, 5, 0)
|
||||
assert singularityintegrate(x*SingularityFunction(x, 0, -1), x) == 0
|
||||
assert singularityintegrate((x - 5)*SingularityFunction(x, 5, -1), x) == 0
|
||||
assert singularityintegrate(SingularityFunction(x, 0, -1) * f(x), x) == f(0) * SingularityFunction(x, 0, 0)
|
||||
assert singularityintegrate(SingularityFunction(x, 1, -1) * f(x), x) == f(1) * SingularityFunction(x, 1, 0)
|
||||
assert singularityintegrate(y*SingularityFunction(x, 0, -1)**2, x) == \
|
||||
y*SingularityFunction(0, 0, -1)*SingularityFunction(x, 0, 0)
|
||||
@@ -0,0 +1,637 @@
|
||||
from sympy.integrals.transforms import (
|
||||
mellin_transform, inverse_mellin_transform,
|
||||
fourier_transform, inverse_fourier_transform,
|
||||
sine_transform, inverse_sine_transform,
|
||||
cosine_transform, inverse_cosine_transform,
|
||||
hankel_transform, inverse_hankel_transform,
|
||||
FourierTransform, SineTransform, CosineTransform, InverseFourierTransform,
|
||||
InverseSineTransform, InverseCosineTransform, IntegralTransformError)
|
||||
from sympy.integrals.laplace import (
|
||||
laplace_transform, inverse_laplace_transform)
|
||||
from sympy.core.function import Function, expand_mul
|
||||
from sympy.core import EulerGamma
|
||||
from sympy.core.numbers import I, Rational, oo, pi
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import Symbol, symbols
|
||||
from sympy.functions.combinatorial.factorials import factorial
|
||||
from sympy.functions.elementary.complexes import re, unpolarify
|
||||
from sympy.functions.elementary.exponential import exp, exp_polar, log
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.trigonometric import atan, cos, sin, tan
|
||||
from sympy.functions.special.bessel import besseli, besselj, besselk, bessely
|
||||
from sympy.functions.special.delta_functions import Heaviside
|
||||
from sympy.functions.special.error_functions import erf, expint
|
||||
from sympy.functions.special.gamma_functions import gamma
|
||||
from sympy.functions.special.hyper import meijerg
|
||||
from sympy.simplify.gammasimp import gammasimp
|
||||
from sympy.simplify.hyperexpand import hyperexpand
|
||||
from sympy.simplify.trigsimp import trigsimp
|
||||
from sympy.testing.pytest import XFAIL, slow, skip, raises
|
||||
from sympy.abc import x, s, a, b, c, d
|
||||
|
||||
|
||||
nu, beta, rho = symbols('nu beta rho')
|
||||
|
||||
|
||||
def test_undefined_function():
|
||||
from sympy.integrals.transforms import MellinTransform
|
||||
f = Function('f')
|
||||
assert mellin_transform(f(x), x, s) == MellinTransform(f(x), x, s)
|
||||
assert mellin_transform(f(x) + exp(-x), x, s) == \
|
||||
(MellinTransform(f(x), x, s) + gamma(s + 1)/s, (0, oo), True)
|
||||
|
||||
|
||||
def test_free_symbols():
|
||||
f = Function('f')
|
||||
assert mellin_transform(f(x), x, s).free_symbols == {s}
|
||||
assert mellin_transform(f(x)*a, x, s).free_symbols == {s, a}
|
||||
|
||||
|
||||
def test_as_integral():
|
||||
from sympy.integrals.integrals import Integral
|
||||
f = Function('f')
|
||||
assert mellin_transform(f(x), x, s).rewrite('Integral') == \
|
||||
Integral(x**(s - 1)*f(x), (x, 0, oo))
|
||||
assert fourier_transform(f(x), x, s).rewrite('Integral') == \
|
||||
Integral(f(x)*exp(-2*I*pi*s*x), (x, -oo, oo))
|
||||
assert laplace_transform(f(x), x, s, noconds=True).rewrite('Integral') == \
|
||||
Integral(f(x)*exp(-s*x), (x, 0, oo))
|
||||
assert str(2*pi*I*inverse_mellin_transform(f(s), s, x, (a, b)).rewrite('Integral')) \
|
||||
== "Integral(f(s)/x**s, (s, _c - oo*I, _c + oo*I))"
|
||||
assert str(2*pi*I*inverse_laplace_transform(f(s), s, x).rewrite('Integral')) == \
|
||||
"Integral(f(s)*exp(s*x), (s, _c - oo*I, _c + oo*I))"
|
||||
assert inverse_fourier_transform(f(s), s, x).rewrite('Integral') == \
|
||||
Integral(f(s)*exp(2*I*pi*s*x), (s, -oo, oo))
|
||||
|
||||
# NOTE this is stuck in risch because meijerint cannot handle it
|
||||
|
||||
|
||||
@slow
|
||||
@XFAIL
|
||||
def test_mellin_transform_fail():
|
||||
skip("Risch takes forever.")
|
||||
|
||||
MT = mellin_transform
|
||||
|
||||
bpos = symbols('b', positive=True)
|
||||
# bneg = symbols('b', negative=True)
|
||||
|
||||
expr = (sqrt(x + b**2) + b)**a/sqrt(x + b**2)
|
||||
# TODO does not work with bneg, argument wrong. Needs changes to matching.
|
||||
assert MT(expr.subs(b, -bpos), x, s) == \
|
||||
((-1)**(a + 1)*2**(a + 2*s)*bpos**(a + 2*s - 1)*gamma(a + s)
|
||||
*gamma(1 - a - 2*s)/gamma(1 - s),
|
||||
(-re(a), -re(a)/2 + S.Half), True)
|
||||
|
||||
expr = (sqrt(x + b**2) + b)**a
|
||||
assert MT(expr.subs(b, -bpos), x, s) == \
|
||||
(
|
||||
2**(a + 2*s)*a*bpos**(a + 2*s)*gamma(-a - 2*
|
||||
s)*gamma(a + s)/gamma(-s + 1),
|
||||
(-re(a), -re(a)/2), True)
|
||||
|
||||
# Test exponent 1:
|
||||
assert MT(expr.subs({b: -bpos, a: 1}), x, s) == \
|
||||
(-bpos**(2*s + 1)*gamma(s)*gamma(-s - S.Half)/(2*sqrt(pi)),
|
||||
(-1, Rational(-1, 2)), True)
|
||||
|
||||
|
||||
def test_mellin_transform():
|
||||
from sympy.functions.elementary.miscellaneous import (Max, Min)
|
||||
MT = mellin_transform
|
||||
|
||||
bpos = symbols('b', positive=True)
|
||||
|
||||
# 8.4.2
|
||||
assert MT(x**nu*Heaviside(x - 1), x, s) == \
|
||||
(-1/(nu + s), (-oo, -re(nu)), True)
|
||||
assert MT(x**nu*Heaviside(1 - x), x, s) == \
|
||||
(1/(nu + s), (-re(nu), oo), True)
|
||||
|
||||
assert MT((1 - x)**(beta - 1)*Heaviside(1 - x), x, s) == \
|
||||
(gamma(beta)*gamma(s)/gamma(beta + s), (0, oo), re(beta) > 0)
|
||||
assert MT((x - 1)**(beta - 1)*Heaviside(x - 1), x, s) == \
|
||||
(gamma(beta)*gamma(1 - beta - s)/gamma(1 - s),
|
||||
(-oo, 1 - re(beta)), re(beta) > 0)
|
||||
|
||||
assert MT((1 + x)**(-rho), x, s) == \
|
||||
(gamma(s)*gamma(rho - s)/gamma(rho), (0, re(rho)), True)
|
||||
|
||||
assert MT(abs(1 - x)**(-rho), x, s) == (
|
||||
2*sin(pi*rho/2)*gamma(1 - rho)*
|
||||
cos(pi*(s - rho/2))*gamma(s)*gamma(rho-s)/pi,
|
||||
(0, re(rho)), re(rho) < 1)
|
||||
mt = MT((1 - x)**(beta - 1)*Heaviside(1 - x)
|
||||
+ a*(x - 1)**(beta - 1)*Heaviside(x - 1), x, s)
|
||||
assert mt[1], mt[2] == ((0, -re(beta) + 1), re(beta) > 0)
|
||||
|
||||
assert MT((x**a - b**a)/(x - b), x, s)[0] == \
|
||||
pi*b**(a + s - 1)*sin(pi*a)/(sin(pi*s)*sin(pi*(a + s)))
|
||||
assert MT((x**a - bpos**a)/(x - bpos), x, s) == \
|
||||
(pi*bpos**(a + s - 1)*sin(pi*a)/(sin(pi*s)*sin(pi*(a + s))),
|
||||
(Max(0, -re(a)), Min(1, 1 - re(a))), True)
|
||||
|
||||
expr = (sqrt(x + b**2) + b)**a
|
||||
assert MT(expr.subs(b, bpos), x, s) == \
|
||||
(-a*(2*bpos)**(a + 2*s)*gamma(s)*gamma(-a - 2*s)/gamma(-a - s + 1),
|
||||
(0, -re(a)/2), True)
|
||||
|
||||
expr = (sqrt(x + b**2) + b)**a/sqrt(x + b**2)
|
||||
assert MT(expr.subs(b, bpos), x, s) == \
|
||||
(2**(a + 2*s)*bpos**(a + 2*s - 1)*gamma(s)
|
||||
*gamma(1 - a - 2*s)/gamma(1 - a - s),
|
||||
(0, -re(a)/2 + S.Half), True)
|
||||
|
||||
# 8.4.2
|
||||
assert MT(exp(-x), x, s) == (gamma(s), (0, oo), True)
|
||||
assert MT(exp(-1/x), x, s) == (gamma(-s), (-oo, 0), True)
|
||||
|
||||
# 8.4.5
|
||||
assert MT(log(x)**4*Heaviside(1 - x), x, s) == (24/s**5, (0, oo), True)
|
||||
assert MT(log(x)**3*Heaviside(x - 1), x, s) == (6/s**4, (-oo, 0), True)
|
||||
assert MT(log(x + 1), x, s) == (pi/(s*sin(pi*s)), (-1, 0), True)
|
||||
assert MT(log(1/x + 1), x, s) == (pi/(s*sin(pi*s)), (0, 1), True)
|
||||
assert MT(log(abs(1 - x)), x, s) == (pi/(s*tan(pi*s)), (-1, 0), True)
|
||||
assert MT(log(abs(1 - 1/x)), x, s) == (pi/(s*tan(pi*s)), (0, 1), True)
|
||||
|
||||
# 8.4.14
|
||||
assert MT(erf(sqrt(x)), x, s) == \
|
||||
(-gamma(s + S.Half)/(sqrt(pi)*s), (Rational(-1, 2), 0), True)
|
||||
|
||||
|
||||
def test_mellin_transform2():
|
||||
MT = mellin_transform
|
||||
# TODO we cannot currently do these (needs summation of 3F2(-1))
|
||||
# this also implies that they cannot be written as a single g-function
|
||||
# (although this is possible)
|
||||
mt = MT(log(x)/(x + 1), x, s)
|
||||
assert mt[1:] == ((0, 1), True)
|
||||
assert not hyperexpand(mt[0], allow_hyper=True).has(meijerg)
|
||||
mt = MT(log(x)**2/(x + 1), x, s)
|
||||
assert mt[1:] == ((0, 1), True)
|
||||
assert not hyperexpand(mt[0], allow_hyper=True).has(meijerg)
|
||||
mt = MT(log(x)/(x + 1)**2, x, s)
|
||||
assert mt[1:] == ((0, 2), True)
|
||||
assert not hyperexpand(mt[0], allow_hyper=True).has(meijerg)
|
||||
|
||||
|
||||
@slow
|
||||
def test_mellin_transform_bessel():
|
||||
from sympy.functions.elementary.miscellaneous import Max
|
||||
MT = mellin_transform
|
||||
|
||||
# 8.4.19
|
||||
assert MT(besselj(a, 2*sqrt(x)), x, s) == \
|
||||
(gamma(a/2 + s)/gamma(a/2 - s + 1), (-re(a)/2, Rational(3, 4)), True)
|
||||
assert MT(sin(sqrt(x))*besselj(a, sqrt(x)), x, s) == \
|
||||
(2**a*gamma(-2*s + S.Half)*gamma(a/2 + s + S.Half)/(
|
||||
gamma(-a/2 - s + 1)*gamma(a - 2*s + 1)), (
|
||||
-re(a)/2 - S.Half, Rational(1, 4)), True)
|
||||
assert MT(cos(sqrt(x))*besselj(a, sqrt(x)), x, s) == \
|
||||
(2**a*gamma(a/2 + s)*gamma(-2*s + S.Half)/(
|
||||
gamma(-a/2 - s + S.Half)*gamma(a - 2*s + 1)), (
|
||||
-re(a)/2, Rational(1, 4)), True)
|
||||
assert MT(besselj(a, sqrt(x))**2, x, s) == \
|
||||
(gamma(a + s)*gamma(S.Half - s)
|
||||
/ (sqrt(pi)*gamma(1 - s)*gamma(1 + a - s)),
|
||||
(-re(a), S.Half), True)
|
||||
assert MT(besselj(a, sqrt(x))*besselj(-a, sqrt(x)), x, s) == \
|
||||
(gamma(s)*gamma(S.Half - s)
|
||||
/ (sqrt(pi)*gamma(1 - a - s)*gamma(1 + a - s)),
|
||||
(0, S.Half), True)
|
||||
# NOTE: prudnikov gives the strip below as (1/2 - re(a), 1). As far as
|
||||
# I can see this is wrong (since besselj(z) ~ 1/sqrt(z) for z large)
|
||||
assert MT(besselj(a - 1, sqrt(x))*besselj(a, sqrt(x)), x, s) == \
|
||||
(gamma(1 - s)*gamma(a + s - S.Half)
|
||||
/ (sqrt(pi)*gamma(Rational(3, 2) - s)*gamma(a - s + S.Half)),
|
||||
(S.Half - re(a), S.Half), True)
|
||||
assert MT(besselj(a, sqrt(x))*besselj(b, sqrt(x)), x, s) == \
|
||||
(4**s*gamma(1 - 2*s)*gamma((a + b)/2 + s)
|
||||
/ (gamma(1 - s + (b - a)/2)*gamma(1 - s + (a - b)/2)
|
||||
*gamma( 1 - s + (a + b)/2)),
|
||||
(-(re(a) + re(b))/2, S.Half), True)
|
||||
assert MT(besselj(a, sqrt(x))**2 + besselj(-a, sqrt(x))**2, x, s)[1:] == \
|
||||
((Max(re(a), -re(a)), S.Half), True)
|
||||
|
||||
# Section 8.4.20
|
||||
assert MT(bessely(a, 2*sqrt(x)), x, s) == \
|
||||
(-cos(pi*(a/2 - s))*gamma(s - a/2)*gamma(s + a/2)/pi,
|
||||
(Max(-re(a)/2, re(a)/2), Rational(3, 4)), True)
|
||||
assert MT(sin(sqrt(x))*bessely(a, sqrt(x)), x, s) == \
|
||||
(-4**s*sin(pi*(a/2 - s))*gamma(S.Half - 2*s)
|
||||
* gamma((1 - a)/2 + s)*gamma((1 + a)/2 + s)
|
||||
/ (sqrt(pi)*gamma(1 - s - a/2)*gamma(1 - s + a/2)),
|
||||
(Max(-(re(a) + 1)/2, (re(a) - 1)/2), Rational(1, 4)), True)
|
||||
assert MT(cos(sqrt(x))*bessely(a, sqrt(x)), x, s) == \
|
||||
(-4**s*cos(pi*(a/2 - s))*gamma(s - a/2)*gamma(s + a/2)*gamma(S.Half - 2*s)
|
||||
/ (sqrt(pi)*gamma(S.Half - s - a/2)*gamma(S.Half - s + a/2)),
|
||||
(Max(-re(a)/2, re(a)/2), Rational(1, 4)), True)
|
||||
assert MT(besselj(a, sqrt(x))*bessely(a, sqrt(x)), x, s) == \
|
||||
(-cos(pi*s)*gamma(s)*gamma(a + s)*gamma(S.Half - s)
|
||||
/ (pi**S('3/2')*gamma(1 + a - s)),
|
||||
(Max(-re(a), 0), S.Half), True)
|
||||
assert MT(besselj(a, sqrt(x))*bessely(b, sqrt(x)), x, s) == \
|
||||
(-4**s*cos(pi*(a/2 - b/2 + s))*gamma(1 - 2*s)
|
||||
* gamma(a/2 - b/2 + s)*gamma(a/2 + b/2 + s)
|
||||
/ (pi*gamma(a/2 - b/2 - s + 1)*gamma(a/2 + b/2 - s + 1)),
|
||||
(Max((-re(a) + re(b))/2, (-re(a) - re(b))/2), S.Half), True)
|
||||
# NOTE bessely(a, sqrt(x))**2 and bessely(a, sqrt(x))*bessely(b, sqrt(x))
|
||||
# are a mess (no matter what way you look at it ...)
|
||||
assert MT(bessely(a, sqrt(x))**2, x, s)[1:] == \
|
||||
((Max(-re(a), 0, re(a)), S.Half), True)
|
||||
|
||||
# Section 8.4.22
|
||||
# TODO we can't do any of these (delicate cancellation)
|
||||
|
||||
# Section 8.4.23
|
||||
assert MT(besselk(a, 2*sqrt(x)), x, s) == \
|
||||
(gamma(
|
||||
s - a/2)*gamma(s + a/2)/2, (Max(-re(a)/2, re(a)/2), oo), True)
|
||||
assert MT(besselj(a, 2*sqrt(2*sqrt(x)))*besselk(
|
||||
a, 2*sqrt(2*sqrt(x))), x, s) == (4**(-s)*gamma(2*s)*
|
||||
gamma(a/2 + s)/(2*gamma(a/2 - s + 1)), (Max(0, -re(a)/2), oo), True)
|
||||
# TODO bessely(a, x)*besselk(a, x) is a mess
|
||||
assert MT(besseli(a, sqrt(x))*besselk(a, sqrt(x)), x, s) == \
|
||||
(gamma(s)*gamma(
|
||||
a + s)*gamma(-s + S.Half)/(2*sqrt(pi)*gamma(a - s + 1)),
|
||||
(Max(-re(a), 0), S.Half), True)
|
||||
assert MT(besseli(b, sqrt(x))*besselk(a, sqrt(x)), x, s) == \
|
||||
(2**(2*s - 1)*gamma(-2*s + 1)*gamma(-a/2 + b/2 + s)* \
|
||||
gamma(a/2 + b/2 + s)/(gamma(-a/2 + b/2 - s + 1)* \
|
||||
gamma(a/2 + b/2 - s + 1)), (Max(-re(a)/2 - re(b)/2, \
|
||||
re(a)/2 - re(b)/2), S.Half), True)
|
||||
|
||||
# TODO products of besselk are a mess
|
||||
|
||||
mt = MT(exp(-x/2)*besselk(a, x/2), x, s)
|
||||
mt0 = gammasimp(trigsimp(gammasimp(mt[0].expand(func=True))))
|
||||
assert mt0 == 2*pi**Rational(3, 2)*cos(pi*s)*gamma(S.Half - s)/(
|
||||
(cos(2*pi*a) - cos(2*pi*s))*gamma(-a - s + 1)*gamma(a - s + 1))
|
||||
assert mt[1:] == ((Max(-re(a), re(a)), oo), True)
|
||||
# TODO exp(x/2)*besselk(a, x/2) [etc] cannot currently be done
|
||||
# TODO various strange products of special orders
|
||||
|
||||
|
||||
@slow
|
||||
def test_expint():
|
||||
from sympy.functions.elementary.miscellaneous import Max
|
||||
from sympy.functions.special.error_functions import Ci, E1, Si
|
||||
from sympy.simplify.simplify import simplify
|
||||
|
||||
aneg = Symbol('a', negative=True)
|
||||
u = Symbol('u', polar=True)
|
||||
|
||||
assert mellin_transform(E1(x), x, s) == (gamma(s)/s, (0, oo), True)
|
||||
assert inverse_mellin_transform(gamma(s)/s, s, x,
|
||||
(0, oo)).rewrite(expint).expand() == E1(x)
|
||||
assert mellin_transform(expint(a, x), x, s) == \
|
||||
(gamma(s)/(a + s - 1), (Max(1 - re(a), 0), oo), True)
|
||||
# XXX IMT has hickups with complicated strips ...
|
||||
assert simplify(unpolarify(
|
||||
inverse_mellin_transform(gamma(s)/(aneg + s - 1), s, x,
|
||||
(1 - aneg, oo)).rewrite(expint).expand(func=True))) == \
|
||||
expint(aneg, x)
|
||||
|
||||
assert mellin_transform(Si(x), x, s) == \
|
||||
(-2**s*sqrt(pi)*gamma(s/2 + S.Half)/(
|
||||
2*s*gamma(-s/2 + 1)), (-1, 0), True)
|
||||
assert inverse_mellin_transform(-2**s*sqrt(pi)*gamma((s + 1)/2)
|
||||
/(2*s*gamma(-s/2 + 1)), s, x, (-1, 0)) \
|
||||
== Si(x)
|
||||
|
||||
assert mellin_transform(Ci(sqrt(x)), x, s) == \
|
||||
(-2**(2*s - 1)*sqrt(pi)*gamma(s)/(s*gamma(-s + S.Half)), (0, 1), True)
|
||||
assert inverse_mellin_transform(
|
||||
-4**s*sqrt(pi)*gamma(s)/(2*s*gamma(-s + S.Half)),
|
||||
s, u, (0, 1)).expand() == Ci(sqrt(u))
|
||||
|
||||
|
||||
@slow
|
||||
def test_inverse_mellin_transform():
|
||||
from sympy.core.function import expand
|
||||
from sympy.functions.elementary.miscellaneous import (Max, Min)
|
||||
from sympy.functions.elementary.trigonometric import cot
|
||||
from sympy.simplify.powsimp import powsimp
|
||||
from sympy.simplify.simplify import simplify
|
||||
IMT = inverse_mellin_transform
|
||||
|
||||
assert IMT(gamma(s), s, x, (0, oo)) == exp(-x)
|
||||
assert IMT(gamma(-s), s, x, (-oo, 0)) == exp(-1/x)
|
||||
assert simplify(IMT(s/(2*s**2 - 2), s, x, (2, oo))) == \
|
||||
(x**2 + 1)*Heaviside(1 - x)/(4*x)
|
||||
|
||||
# test passing "None"
|
||||
assert IMT(1/(s**2 - 1), s, x, (-1, None)) == \
|
||||
-x*Heaviside(-x + 1)/2 - Heaviside(x - 1)/(2*x)
|
||||
assert IMT(1/(s**2 - 1), s, x, (None, 1)) == \
|
||||
-x*Heaviside(-x + 1)/2 - Heaviside(x - 1)/(2*x)
|
||||
|
||||
# test expansion of sums
|
||||
assert IMT(gamma(s) + gamma(s - 1), s, x, (1, oo)) == (x + 1)*exp(-x)/x
|
||||
|
||||
# test factorisation of polys
|
||||
r = symbols('r', real=True)
|
||||
assert IMT(1/(s**2 + 1), s, exp(-x), (None, oo)
|
||||
).subs(x, r).rewrite(sin).simplify() \
|
||||
== sin(r)*Heaviside(1 - exp(-r))
|
||||
|
||||
# test multiplicative substitution
|
||||
_a, _b = symbols('a b', positive=True)
|
||||
assert IMT(_b**(-s/_a)*factorial(s/_a)/s, s, x, (0, oo)) == exp(-_b*x**_a)
|
||||
assert IMT(factorial(_a/_b + s/_b)/(_a + s), s, x, (-_a, oo)) == x**_a*exp(-x**_b)
|
||||
|
||||
def simp_pows(expr):
|
||||
return simplify(powsimp(expand_mul(expr, deep=False), force=True)).replace(exp_polar, exp)
|
||||
|
||||
# Now test the inverses of all direct transforms tested above
|
||||
|
||||
# Section 8.4.2
|
||||
nu = symbols('nu', real=True)
|
||||
assert IMT(-1/(nu + s), s, x, (-oo, None)) == x**nu*Heaviside(x - 1)
|
||||
assert IMT(1/(nu + s), s, x, (None, oo)) == x**nu*Heaviside(1 - x)
|
||||
assert simp_pows(IMT(gamma(beta)*gamma(s)/gamma(s + beta), s, x, (0, oo))) \
|
||||
== (1 - x)**(beta - 1)*Heaviside(1 - x)
|
||||
assert simp_pows(IMT(gamma(beta)*gamma(1 - beta - s)/gamma(1 - s),
|
||||
s, x, (-oo, None))) \
|
||||
== (x - 1)**(beta - 1)*Heaviside(x - 1)
|
||||
assert simp_pows(IMT(gamma(s)*gamma(rho - s)/gamma(rho), s, x, (0, None))) \
|
||||
== (1/(x + 1))**rho
|
||||
expr = IMT(d**c*d**(s - 1)*sin(pi*c)
|
||||
*gamma(s)*gamma(s + c)*gamma(1 - s)*gamma(1 - s - c)/pi,
|
||||
s, x, (Max(-re(c), 0), Min(1 - re(c), 1)))
|
||||
assert powsimp(expand_mul(expr, deep=False)).replace(exp_polar, exp).simplify() \
|
||||
== (-d**c + x**c)/(-d + x)
|
||||
|
||||
assert simplify(IMT(1/sqrt(pi)*(-c/2)*gamma(s)*gamma((1 - c)/2 - s)
|
||||
*gamma(-c/2 - s)/gamma(1 - c - s),
|
||||
s, x, (0, -re(c)/2))) == \
|
||||
(1 + sqrt(x + 1))**c
|
||||
assert simplify(IMT(2**(a + 2*s)*b**(a + 2*s - 1)*gamma(s)*gamma(1 - a - 2*s)
|
||||
/gamma(1 - a - s), s, x, (0, (-re(a) + 1)/2))) == \
|
||||
b**(a - 1)*(b**2*(sqrt(1 + x/b**2) + 1)**a + x*(sqrt(1 + x/b**2) + 1
|
||||
)**(a - 1))/(b**2 + x)
|
||||
assert simplify(IMT(-2**(c + 2*s)*c*b**(c + 2*s)*gamma(s)*gamma(-c - 2*s)
|
||||
/ gamma(-c - s + 1), s, x, (0, -re(c)/2))) == \
|
||||
b**c*(sqrt(1 + x/b**2) + 1)**c
|
||||
|
||||
# Section 8.4.5
|
||||
assert IMT(24/s**5, s, x, (0, oo)) == log(x)**4*Heaviside(1 - x)
|
||||
assert expand(IMT(6/s**4, s, x, (-oo, 0)), force=True) == \
|
||||
log(x)**3*Heaviside(x - 1)
|
||||
assert IMT(pi/(s*sin(pi*s)), s, x, (-1, 0)) == log(x + 1)
|
||||
assert IMT(pi/(s*sin(pi*s/2)), s, x, (-2, 0)) == log(x**2 + 1)
|
||||
assert IMT(pi/(s*sin(2*pi*s)), s, x, (Rational(-1, 2), 0)) == log(sqrt(x) + 1)
|
||||
assert IMT(pi/(s*sin(pi*s)), s, x, (0, 1)) == log(1 + 1/x)
|
||||
|
||||
# TODO
|
||||
def mysimp(expr):
|
||||
from sympy.core.function import expand
|
||||
from sympy.simplify.powsimp import powsimp
|
||||
from sympy.simplify.simplify import logcombine
|
||||
return expand(
|
||||
powsimp(logcombine(expr, force=True), force=True, deep=True),
|
||||
force=True).replace(exp_polar, exp)
|
||||
|
||||
assert mysimp(mysimp(IMT(pi/(s*tan(pi*s)), s, x, (-1, 0)))) in [
|
||||
log(1 - x)*Heaviside(1 - x) + log(x - 1)*Heaviside(x - 1),
|
||||
log(x)*Heaviside(x - 1) + log(1 - 1/x)*Heaviside(x - 1) + log(-x +
|
||||
1)*Heaviside(-x + 1)]
|
||||
# test passing cot
|
||||
assert mysimp(IMT(pi*cot(pi*s)/s, s, x, (0, 1))) in [
|
||||
log(1/x - 1)*Heaviside(1 - x) + log(1 - 1/x)*Heaviside(x - 1),
|
||||
-log(x)*Heaviside(-x + 1) + log(1 - 1/x)*Heaviside(x - 1) + log(-x +
|
||||
1)*Heaviside(-x + 1), ]
|
||||
|
||||
# 8.4.14
|
||||
assert IMT(-gamma(s + S.Half)/(sqrt(pi)*s), s, x, (Rational(-1, 2), 0)) == \
|
||||
erf(sqrt(x))
|
||||
|
||||
# 8.4.19
|
||||
assert simplify(IMT(gamma(a/2 + s)/gamma(a/2 - s + 1), s, x, (-re(a)/2, Rational(3, 4)))) \
|
||||
== besselj(a, 2*sqrt(x))
|
||||
assert simplify(IMT(2**a*gamma(S.Half - 2*s)*gamma(s + (a + 1)/2)
|
||||
/ (gamma(1 - s - a/2)*gamma(1 - 2*s + a)),
|
||||
s, x, (-(re(a) + 1)/2, Rational(1, 4)))) == \
|
||||
sin(sqrt(x))*besselj(a, sqrt(x))
|
||||
assert simplify(IMT(2**a*gamma(a/2 + s)*gamma(S.Half - 2*s)
|
||||
/ (gamma(S.Half - s - a/2)*gamma(1 - 2*s + a)),
|
||||
s, x, (-re(a)/2, Rational(1, 4)))) == \
|
||||
cos(sqrt(x))*besselj(a, sqrt(x))
|
||||
# TODO this comes out as an amazing mess, but simplifies nicely
|
||||
assert simplify(IMT(gamma(a + s)*gamma(S.Half - s)
|
||||
/ (sqrt(pi)*gamma(1 - s)*gamma(1 + a - s)),
|
||||
s, x, (-re(a), S.Half))) == \
|
||||
besselj(a, sqrt(x))**2
|
||||
assert simplify(IMT(gamma(s)*gamma(S.Half - s)
|
||||
/ (sqrt(pi)*gamma(1 - s - a)*gamma(1 + a - s)),
|
||||
s, x, (0, S.Half))) == \
|
||||
besselj(-a, sqrt(x))*besselj(a, sqrt(x))
|
||||
assert simplify(IMT(4**s*gamma(-2*s + 1)*gamma(a/2 + b/2 + s)
|
||||
/ (gamma(-a/2 + b/2 - s + 1)*gamma(a/2 - b/2 - s + 1)
|
||||
*gamma(a/2 + b/2 - s + 1)),
|
||||
s, x, (-(re(a) + re(b))/2, S.Half))) == \
|
||||
besselj(a, sqrt(x))*besselj(b, sqrt(x))
|
||||
|
||||
# Section 8.4.20
|
||||
# TODO this can be further simplified!
|
||||
assert simplify(IMT(-2**(2*s)*cos(pi*a/2 - pi*b/2 + pi*s)*gamma(-2*s + 1) *
|
||||
gamma(a/2 - b/2 + s)*gamma(a/2 + b/2 + s) /
|
||||
(pi*gamma(a/2 - b/2 - s + 1)*gamma(a/2 + b/2 - s + 1)),
|
||||
s, x,
|
||||
(Max(-re(a)/2 - re(b)/2, -re(a)/2 + re(b)/2), S.Half))) == \
|
||||
besselj(a, sqrt(x))*-(besselj(-b, sqrt(x)) -
|
||||
besselj(b, sqrt(x))*cos(pi*b))/sin(pi*b)
|
||||
# TODO more
|
||||
|
||||
# for coverage
|
||||
|
||||
assert IMT(pi/cos(pi*s), s, x, (0, S.Half)) == sqrt(x)/(x + 1)
|
||||
|
||||
|
||||
def test_fourier_transform():
|
||||
from sympy.core.function import (expand, expand_complex, expand_trig)
|
||||
from sympy.polys.polytools import factor
|
||||
from sympy.simplify.simplify import simplify
|
||||
FT = fourier_transform
|
||||
IFT = inverse_fourier_transform
|
||||
|
||||
def simp(x):
|
||||
return simplify(expand_trig(expand_complex(expand(x))))
|
||||
|
||||
def sinc(x):
|
||||
return sin(pi*x)/(pi*x)
|
||||
k = symbols('k', real=True)
|
||||
f = Function("f")
|
||||
|
||||
# TODO for this to work with real a, need to expand abs(a*x) to abs(a)*abs(x)
|
||||
a = symbols('a', positive=True)
|
||||
b = symbols('b', positive=True)
|
||||
|
||||
posk = symbols('posk', positive=True)
|
||||
|
||||
# Test unevaluated form
|
||||
assert fourier_transform(f(x), x, k) == FourierTransform(f(x), x, k)
|
||||
assert inverse_fourier_transform(
|
||||
f(k), k, x) == InverseFourierTransform(f(k), k, x)
|
||||
|
||||
# basic examples from wikipedia
|
||||
assert simp(FT(Heaviside(1 - abs(2*a*x)), x, k)) == sinc(k/a)/a
|
||||
# TODO IFT is a *mess*
|
||||
assert simp(FT(Heaviside(1 - abs(a*x))*(1 - abs(a*x)), x, k)) == sinc(k/a)**2/a
|
||||
# TODO IFT
|
||||
|
||||
assert factor(FT(exp(-a*x)*Heaviside(x), x, k), extension=I) == \
|
||||
1/(a + 2*pi*I*k)
|
||||
# NOTE: the ift comes out in pieces
|
||||
assert IFT(1/(a + 2*pi*I*x), x, posk,
|
||||
noconds=False) == (exp(-a*posk), True)
|
||||
assert IFT(1/(a + 2*pi*I*x), x, -posk,
|
||||
noconds=False) == (0, True)
|
||||
assert IFT(1/(a + 2*pi*I*x), x, symbols('k', negative=True),
|
||||
noconds=False) == (0, True)
|
||||
# TODO IFT without factoring comes out as meijer g
|
||||
|
||||
assert factor(FT(x*exp(-a*x)*Heaviside(x), x, k), extension=I) == \
|
||||
1/(a + 2*pi*I*k)**2
|
||||
assert FT(exp(-a*x)*sin(b*x)*Heaviside(x), x, k) == \
|
||||
b/(b**2 + (a + 2*I*pi*k)**2)
|
||||
|
||||
assert FT(exp(-a*x**2), x, k) == sqrt(pi)*exp(-pi**2*k**2/a)/sqrt(a)
|
||||
assert IFT(sqrt(pi/a)*exp(-(pi*k)**2/a), k, x) == exp(-a*x**2)
|
||||
assert FT(exp(-a*abs(x)), x, k) == 2*a/(a**2 + 4*pi**2*k**2)
|
||||
# TODO IFT (comes out as meijer G)
|
||||
|
||||
# TODO besselj(n, x), n an integer > 0 actually can be done...
|
||||
|
||||
# TODO are there other common transforms (no distributions!)?
|
||||
|
||||
|
||||
def test_sine_transform():
|
||||
t = symbols("t")
|
||||
w = symbols("w")
|
||||
a = symbols("a")
|
||||
f = Function("f")
|
||||
|
||||
# Test unevaluated form
|
||||
assert sine_transform(f(t), t, w) == SineTransform(f(t), t, w)
|
||||
assert inverse_sine_transform(
|
||||
f(w), w, t) == InverseSineTransform(f(w), w, t)
|
||||
|
||||
assert sine_transform(1/sqrt(t), t, w) == 1/sqrt(w)
|
||||
assert inverse_sine_transform(1/sqrt(w), w, t) == 1/sqrt(t)
|
||||
|
||||
assert sine_transform((1/sqrt(t))**3, t, w) == 2*sqrt(w)
|
||||
|
||||
assert sine_transform(t**(-a), t, w) == 2**(
|
||||
-a + S.Half)*w**(a - 1)*gamma(-a/2 + 1)/gamma((a + 1)/2)
|
||||
assert inverse_sine_transform(2**(-a + S(
|
||||
1)/2)*w**(a - 1)*gamma(-a/2 + 1)/gamma(a/2 + S.Half), w, t) == t**(-a)
|
||||
|
||||
assert sine_transform(
|
||||
exp(-a*t), t, w) == sqrt(2)*w/(sqrt(pi)*(a**2 + w**2))
|
||||
assert inverse_sine_transform(
|
||||
sqrt(2)*w/(sqrt(pi)*(a**2 + w**2)), w, t) == exp(-a*t)
|
||||
|
||||
assert sine_transform(
|
||||
log(t)/t, t, w) == sqrt(2)*sqrt(pi)*-(log(w**2) + 2*EulerGamma)/4
|
||||
|
||||
assert sine_transform(
|
||||
t*exp(-a*t**2), t, w) == sqrt(2)*w*exp(-w**2/(4*a))/(4*a**Rational(3, 2))
|
||||
assert inverse_sine_transform(
|
||||
sqrt(2)*w*exp(-w**2/(4*a))/(4*a**Rational(3, 2)), w, t) == t*exp(-a*t**2)
|
||||
|
||||
|
||||
def test_cosine_transform():
|
||||
from sympy.functions.special.error_functions import (Ci, Si)
|
||||
|
||||
t = symbols("t")
|
||||
w = symbols("w")
|
||||
a = symbols("a")
|
||||
f = Function("f")
|
||||
|
||||
# Test unevaluated form
|
||||
assert cosine_transform(f(t), t, w) == CosineTransform(f(t), t, w)
|
||||
assert inverse_cosine_transform(
|
||||
f(w), w, t) == InverseCosineTransform(f(w), w, t)
|
||||
|
||||
assert cosine_transform(1/sqrt(t), t, w) == 1/sqrt(w)
|
||||
assert inverse_cosine_transform(1/sqrt(w), w, t) == 1/sqrt(t)
|
||||
|
||||
assert cosine_transform(1/(
|
||||
a**2 + t**2), t, w) == sqrt(2)*sqrt(pi)*exp(-a*w)/(2*a)
|
||||
|
||||
assert cosine_transform(t**(
|
||||
-a), t, w) == 2**(-a + S.Half)*w**(a - 1)*gamma((-a + 1)/2)/gamma(a/2)
|
||||
assert inverse_cosine_transform(2**(-a + S(
|
||||
1)/2)*w**(a - 1)*gamma(-a/2 + S.Half)/gamma(a/2), w, t) == t**(-a)
|
||||
|
||||
assert cosine_transform(
|
||||
exp(-a*t), t, w) == sqrt(2)*a/(sqrt(pi)*(a**2 + w**2))
|
||||
assert inverse_cosine_transform(
|
||||
sqrt(2)*a/(sqrt(pi)*(a**2 + w**2)), w, t) == exp(-a*t)
|
||||
|
||||
assert cosine_transform(exp(-a*sqrt(t))*cos(a*sqrt(
|
||||
t)), t, w) == a*exp(-a**2/(2*w))/(2*w**Rational(3, 2))
|
||||
|
||||
assert cosine_transform(1/(a + t), t, w) == sqrt(2)*(
|
||||
(-2*Si(a*w) + pi)*sin(a*w)/2 - cos(a*w)*Ci(a*w))/sqrt(pi)
|
||||
assert inverse_cosine_transform(sqrt(2)*meijerg(((S.Half, 0), ()), (
|
||||
(S.Half, 0, 0), (S.Half,)), a**2*w**2/4)/(2*pi), w, t) == 1/(a + t)
|
||||
|
||||
assert cosine_transform(1/sqrt(a**2 + t**2), t, w) == sqrt(2)*meijerg(
|
||||
((S.Half,), ()), ((0, 0), (S.Half,)), a**2*w**2/4)/(2*sqrt(pi))
|
||||
assert inverse_cosine_transform(sqrt(2)*meijerg(((S.Half,), ()), ((0, 0), (S.Half,)), a**2*w**2/4)/(2*sqrt(pi)), w, t) == 1/(t*sqrt(a**2/t**2 + 1))
|
||||
|
||||
|
||||
def test_hankel_transform():
|
||||
r = Symbol("r")
|
||||
k = Symbol("k")
|
||||
nu = Symbol("nu")
|
||||
m = Symbol("m")
|
||||
a = symbols("a")
|
||||
|
||||
assert hankel_transform(1/r, r, k, 0) == 1/k
|
||||
assert inverse_hankel_transform(1/k, k, r, 0) == 1/r
|
||||
|
||||
assert hankel_transform(
|
||||
1/r**m, r, k, 0) == 2**(-m + 1)*k**(m - 2)*gamma(-m/2 + 1)/gamma(m/2)
|
||||
assert inverse_hankel_transform(
|
||||
2**(-m + 1)*k**(m - 2)*gamma(-m/2 + 1)/gamma(m/2), k, r, 0) == r**(-m)
|
||||
|
||||
assert hankel_transform(1/r**m, r, k, nu) == (
|
||||
2*2**(-m)*k**(m - 2)*gamma(-m/2 + nu/2 + 1)/gamma(m/2 + nu/2))
|
||||
assert inverse_hankel_transform(2**(-m + 1)*k**(
|
||||
m - 2)*gamma(-m/2 + nu/2 + 1)/gamma(m/2 + nu/2), k, r, nu) == r**(-m)
|
||||
|
||||
assert hankel_transform(r**nu*exp(-a*r), r, k, nu) == \
|
||||
2**(nu + 1)*a*k**(-nu - 3)*(a**2/k**2 + 1)**(-nu - S(
|
||||
3)/2)*gamma(nu + Rational(3, 2))/sqrt(pi)
|
||||
assert inverse_hankel_transform(
|
||||
2**(nu + 1)*a*k**(-nu - 3)*(a**2/k**2 + 1)**(-nu - Rational(3, 2))*gamma(
|
||||
nu + Rational(3, 2))/sqrt(pi), k, r, nu) == r**nu*exp(-a*r)
|
||||
|
||||
|
||||
def test_issue_7181():
|
||||
assert mellin_transform(1/(1 - x), x, s) != None
|
||||
|
||||
|
||||
def test_issue_8882():
|
||||
# This is the original test.
|
||||
# from sympy import diff, Integral, integrate
|
||||
# r = Symbol('r')
|
||||
# psi = 1/r*sin(r)*exp(-(a0*r))
|
||||
# h = -1/2*diff(psi, r, r) - 1/r*psi
|
||||
# f = 4*pi*psi*h*r**2
|
||||
# assert integrate(f, (r, -oo, 3), meijerg=True).has(Integral) == True
|
||||
|
||||
# To save time, only the critical part is included.
|
||||
F = -a**(-s + 1)*(4 + 1/a**2)**(-s/2)*sqrt(1/a**2)*exp(-s*I*pi)* \
|
||||
sin(s*atan(sqrt(1/a**2)/2))*gamma(s)
|
||||
raises(IntegralTransformError, lambda:
|
||||
inverse_mellin_transform(F, s, x, (-1, oo),
|
||||
**{'as_meijerg': True, 'needeval': True}))
|
||||
|
||||
|
||||
def test_issue_12591():
|
||||
x, y = symbols("x y", real=True)
|
||||
assert fourier_transform(exp(x), x, y) == FourierTransform(exp(x), x, y)
|
||||
@@ -0,0 +1,98 @@
|
||||
from sympy.core import Ne, Rational, Symbol
|
||||
from sympy.functions import sin, cos, tan, csc, sec, cot, log, Piecewise
|
||||
from sympy.integrals.trigonometry import trigintegrate
|
||||
|
||||
x = Symbol('x')
|
||||
|
||||
|
||||
def test_trigintegrate_odd():
|
||||
assert trigintegrate(Rational(1), x) == x
|
||||
assert trigintegrate(x, x) is None
|
||||
assert trigintegrate(x**2, x) is None
|
||||
|
||||
assert trigintegrate(sin(x), x) == -cos(x)
|
||||
assert trigintegrate(cos(x), x) == sin(x)
|
||||
|
||||
assert trigintegrate(sin(3*x), x) == -cos(3*x)/3
|
||||
assert trigintegrate(cos(3*x), x) == sin(3*x)/3
|
||||
|
||||
y = Symbol('y')
|
||||
assert trigintegrate(sin(y*x), x) == Piecewise(
|
||||
(-cos(y*x)/y, Ne(y, 0)), (0, True))
|
||||
assert trigintegrate(cos(y*x), x) == Piecewise(
|
||||
(sin(y*x)/y, Ne(y, 0)), (x, True))
|
||||
assert trigintegrate(sin(y*x)**2, x) == Piecewise(
|
||||
((x*y/2 - sin(x*y)*cos(x*y)/2)/y, Ne(y, 0)), (0, True))
|
||||
assert trigintegrate(sin(y*x)*cos(y*x), x) == Piecewise(
|
||||
(sin(x*y)**2/(2*y), Ne(y, 0)), (0, True))
|
||||
assert trigintegrate(cos(y*x)**2, x) == Piecewise(
|
||||
((x*y/2 + sin(x*y)*cos(x*y)/2)/y, Ne(y, 0)), (x, True))
|
||||
|
||||
y = Symbol('y', positive=True)
|
||||
# TODO: remove conds='none' below. For this to work we would have to rule
|
||||
# out (e.g. by trying solve) the condition y = 0, incompatible with
|
||||
# y.is_positive being True.
|
||||
assert trigintegrate(sin(y*x), x, conds='none') == -cos(y*x)/y
|
||||
assert trigintegrate(cos(y*x), x, conds='none') == sin(y*x)/y
|
||||
|
||||
assert trigintegrate(sin(x)*cos(x), x) == sin(x)**2/2
|
||||
assert trigintegrate(sin(x)*cos(x)**2, x) == -cos(x)**3/3
|
||||
assert trigintegrate(sin(x)**2*cos(x), x) == sin(x)**3/3
|
||||
|
||||
# check if it selects right function to substitute,
|
||||
# so the result is kept simple
|
||||
assert trigintegrate(sin(x)**7 * cos(x), x) == sin(x)**8/8
|
||||
assert trigintegrate(sin(x) * cos(x)**7, x) == -cos(x)**8/8
|
||||
|
||||
assert trigintegrate(sin(x)**7 * cos(x)**3, x) == \
|
||||
-sin(x)**10/10 + sin(x)**8/8
|
||||
assert trigintegrate(sin(x)**3 * cos(x)**7, x) == \
|
||||
cos(x)**10/10 - cos(x)**8/8
|
||||
|
||||
# both n, m are odd and -ve, and not necessarily equal
|
||||
assert trigintegrate(sin(x)**-1*cos(x)**-1, x) == \
|
||||
-log(sin(x)**2 - 1)/2 + log(sin(x))
|
||||
|
||||
|
||||
def test_trigintegrate_even():
|
||||
assert trigintegrate(sin(x)**2, x) == x/2 - cos(x)*sin(x)/2
|
||||
assert trigintegrate(cos(x)**2, x) == x/2 + cos(x)*sin(x)/2
|
||||
|
||||
assert trigintegrate(sin(3*x)**2, x) == x/2 - cos(3*x)*sin(3*x)/6
|
||||
assert trigintegrate(cos(3*x)**2, x) == x/2 + cos(3*x)*sin(3*x)/6
|
||||
assert trigintegrate(sin(x)**2 * cos(x)**2, x) == \
|
||||
x/8 - sin(2*x)*cos(2*x)/16
|
||||
|
||||
assert trigintegrate(sin(x)**4 * cos(x)**2, x) == \
|
||||
x/16 - sin(x) *cos(x)/16 - sin(x)**3*cos(x)/24 + \
|
||||
sin(x)**5*cos(x)/6
|
||||
|
||||
assert trigintegrate(sin(x)**2 * cos(x)**4, x) == \
|
||||
x/16 + cos(x) *sin(x)/16 + cos(x)**3*sin(x)/24 - \
|
||||
cos(x)**5*sin(x)/6
|
||||
|
||||
assert trigintegrate(sin(x)**(-4), x) == -2*cos(x)/(3*sin(x)) \
|
||||
- cos(x)/(3*sin(x)**3)
|
||||
|
||||
assert trigintegrate(cos(x)**(-6), x) == sin(x)/(5*cos(x)**5) \
|
||||
+ 4*sin(x)/(15*cos(x)**3) + 8*sin(x)/(15*cos(x))
|
||||
|
||||
|
||||
def test_trigintegrate_mixed():
|
||||
assert trigintegrate(sin(x)*sec(x), x) == -log(cos(x))
|
||||
assert trigintegrate(sin(x)*csc(x), x) == x
|
||||
assert trigintegrate(sin(x)*cot(x), x) == sin(x)
|
||||
|
||||
assert trigintegrate(cos(x)*sec(x), x) == x
|
||||
assert trigintegrate(cos(x)*csc(x), x) == log(sin(x))
|
||||
assert trigintegrate(cos(x)*tan(x), x) == -cos(x)
|
||||
assert trigintegrate(cos(x)*cot(x), x) == log(cos(x) - 1)/2 \
|
||||
- log(cos(x) + 1)/2 + cos(x)
|
||||
assert trigintegrate(cot(x)*cos(x)**2, x) == log(sin(x)) - sin(x)**2/2
|
||||
|
||||
|
||||
def test_trigintegrate_symbolic():
|
||||
n = Symbol('n', integer=True)
|
||||
assert trigintegrate(cos(x)**n, x) is None
|
||||
assert trigintegrate(sin(x)**n, x) is None
|
||||
assert trigintegrate(cot(x)**n, x) is None
|
||||
1590
venv/lib/python3.12/site-packages/sympy/integrals/transforms.py
Normal file
1590
venv/lib/python3.12/site-packages/sympy/integrals/transforms.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,335 @@
|
||||
from sympy.core import cacheit, Dummy, Ne, Integer, Rational, S, Wild
|
||||
from sympy.functions import binomial, sin, cos, Piecewise, Abs
|
||||
from .integrals import integrate
|
||||
|
||||
# TODO sin(a*x)*cos(b*x) -> sin((a+b)x) + sin((a-b)x) ?
|
||||
|
||||
# creating, each time, Wild's and sin/cos/Mul is expensive. Also, our match &
|
||||
# subs are very slow when not cached, and if we create Wild each time, we
|
||||
# effectively block caching.
|
||||
#
|
||||
# so we cache the pattern
|
||||
|
||||
# need to use a function instead of lamda since hash of lambda changes on
|
||||
# each call to _pat_sincos
|
||||
def _integer_instance(n):
|
||||
return isinstance(n, Integer)
|
||||
|
||||
@cacheit
|
||||
def _pat_sincos(x):
|
||||
a = Wild('a', exclude=[x])
|
||||
n, m = [Wild(s, exclude=[x], properties=[_integer_instance])
|
||||
for s in 'nm']
|
||||
pat = sin(a*x)**n * cos(a*x)**m
|
||||
return pat, a, n, m
|
||||
|
||||
_u = Dummy('u')
|
||||
|
||||
|
||||
def trigintegrate(f, x, conds='piecewise'):
|
||||
"""
|
||||
Integrate f = Mul(trig) over x.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy import sin, cos, tan, sec
|
||||
>>> from sympy.integrals.trigonometry import trigintegrate
|
||||
>>> from sympy.abc import x
|
||||
|
||||
>>> trigintegrate(sin(x)*cos(x), x)
|
||||
sin(x)**2/2
|
||||
|
||||
>>> trigintegrate(sin(x)**2, x)
|
||||
x/2 - sin(x)*cos(x)/2
|
||||
|
||||
>>> trigintegrate(tan(x)*sec(x), x)
|
||||
1/cos(x)
|
||||
|
||||
>>> trigintegrate(sin(x)*tan(x), x)
|
||||
-log(sin(x) - 1)/2 + log(sin(x) + 1)/2 - sin(x)
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://en.wikibooks.org/wiki/Calculus/Integration_techniques
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
sympy.integrals.integrals.Integral.doit
|
||||
sympy.integrals.integrals.Integral
|
||||
"""
|
||||
pat, a, n, m = _pat_sincos(x)
|
||||
|
||||
f = f.rewrite('sincos')
|
||||
M = f.match(pat)
|
||||
|
||||
if M is None:
|
||||
return
|
||||
|
||||
n, m = M[n], M[m]
|
||||
if n.is_zero and m.is_zero:
|
||||
return x
|
||||
zz = x if n.is_zero else S.Zero
|
||||
|
||||
a = M[a]
|
||||
|
||||
if n.is_odd or m.is_odd:
|
||||
u = _u
|
||||
n_, m_ = n.is_odd, m.is_odd
|
||||
|
||||
# take smallest n or m -- to choose simplest substitution
|
||||
if n_ and m_:
|
||||
|
||||
# Make sure to choose the positive one
|
||||
# otherwise an incorrect integral can occur.
|
||||
if n < 0 and m > 0:
|
||||
m_ = True
|
||||
n_ = False
|
||||
elif m < 0 and n > 0:
|
||||
n_ = True
|
||||
m_ = False
|
||||
# Both are negative so choose the smallest n or m
|
||||
# in absolute value for simplest substitution.
|
||||
elif (n < 0 and m < 0):
|
||||
n_ = n > m
|
||||
m_ = not (n > m)
|
||||
|
||||
# Both n and m are odd and positive
|
||||
else:
|
||||
n_ = (n < m) # NB: careful here, one of the
|
||||
m_ = not (n < m) # conditions *must* be true
|
||||
|
||||
# n m u=C (n-1)/2 m
|
||||
# S(x) * C(x) dx --> -(1-u^2) * u du
|
||||
if n_:
|
||||
ff = -(1 - u**2)**((n - 1)/2) * u**m
|
||||
uu = cos(a*x)
|
||||
|
||||
# n m u=S n (m-1)/2
|
||||
# S(x) * C(x) dx --> u * (1-u^2) du
|
||||
elif m_:
|
||||
ff = u**n * (1 - u**2)**((m - 1)/2)
|
||||
uu = sin(a*x)
|
||||
|
||||
fi = integrate(ff, u) # XXX cyclic deps
|
||||
fx = fi.subs(u, uu)
|
||||
if conds == 'piecewise':
|
||||
return Piecewise((fx / a, Ne(a, 0)), (zz, True))
|
||||
return fx / a
|
||||
|
||||
# n & m are both even
|
||||
#
|
||||
# 2k 2m 2l 2l
|
||||
# we transform S (x) * C (x) into terms with only S (x) or C (x)
|
||||
#
|
||||
# example:
|
||||
# 100 4 100 2 2 100 4 2
|
||||
# S (x) * C (x) = S (x) * (1-S (x)) = S (x) * (1 + S (x) - 2*S (x))
|
||||
#
|
||||
# 104 102 100
|
||||
# = S (x) - 2*S (x) + S (x)
|
||||
# 2k
|
||||
# then S is integrated with recursive formula
|
||||
|
||||
# take largest n or m -- to choose simplest substitution
|
||||
n_ = (Abs(n) > Abs(m))
|
||||
m_ = (Abs(m) > Abs(n))
|
||||
res = S.Zero
|
||||
|
||||
if n_:
|
||||
# 2k 2 k i 2i
|
||||
# C = (1 - S ) = sum(i, (-) * B(k, i) * S )
|
||||
if m > 0:
|
||||
for i in range(0, m//2 + 1):
|
||||
res += (S.NegativeOne**i * binomial(m//2, i) *
|
||||
_sin_pow_integrate(n + 2*i, x))
|
||||
|
||||
elif m == 0:
|
||||
res = _sin_pow_integrate(n, x)
|
||||
else:
|
||||
|
||||
# m < 0 , |n| > |m|
|
||||
# /
|
||||
# |
|
||||
# | m n
|
||||
# | cos (x) sin (x) dx =
|
||||
# |
|
||||
# |
|
||||
#/
|
||||
# /
|
||||
# |
|
||||
# -1 m+1 n-1 n - 1 | m+2 n-2
|
||||
# ________ cos (x) sin (x) + _______ | cos (x) sin (x) dx
|
||||
# |
|
||||
# m + 1 m + 1 |
|
||||
# /
|
||||
|
||||
res = (Rational(-1, m + 1) * cos(x)**(m + 1) * sin(x)**(n - 1) +
|
||||
Rational(n - 1, m + 1) *
|
||||
trigintegrate(cos(x)**(m + 2)*sin(x)**(n - 2), x))
|
||||
|
||||
elif m_:
|
||||
# 2k 2 k i 2i
|
||||
# S = (1 - C ) = sum(i, (-) * B(k, i) * C )
|
||||
if n > 0:
|
||||
|
||||
# / /
|
||||
# | |
|
||||
# | m n | -m n
|
||||
# | cos (x)*sin (x) dx or | cos (x) * sin (x) dx
|
||||
# | |
|
||||
# / /
|
||||
#
|
||||
# |m| > |n| ; m, n >0 ; m, n belong to Z - {0}
|
||||
# n 2
|
||||
# sin (x) term is expanded here in terms of cos (x),
|
||||
# and then integrated.
|
||||
#
|
||||
|
||||
for i in range(0, n//2 + 1):
|
||||
res += (S.NegativeOne**i * binomial(n//2, i) *
|
||||
_cos_pow_integrate(m + 2*i, x))
|
||||
|
||||
elif n == 0:
|
||||
|
||||
# /
|
||||
# |
|
||||
# | 1
|
||||
# | _ _ _
|
||||
# | m
|
||||
# | cos (x)
|
||||
# /
|
||||
#
|
||||
|
||||
res = _cos_pow_integrate(m, x)
|
||||
else:
|
||||
|
||||
# n < 0 , |m| > |n|
|
||||
# /
|
||||
# |
|
||||
# | m n
|
||||
# | cos (x) sin (x) dx =
|
||||
# |
|
||||
# |
|
||||
#/
|
||||
# /
|
||||
# |
|
||||
# 1 m-1 n+1 m - 1 | m-2 n+2
|
||||
# _______ cos (x) sin (x) + _______ | cos (x) sin (x) dx
|
||||
# |
|
||||
# n + 1 n + 1 |
|
||||
# /
|
||||
|
||||
res = (Rational(1, n + 1) * cos(x)**(m - 1)*sin(x)**(n + 1) +
|
||||
Rational(m - 1, n + 1) *
|
||||
trigintegrate(cos(x)**(m - 2)*sin(x)**(n + 2), x))
|
||||
|
||||
else:
|
||||
if m == n:
|
||||
##Substitute sin(2x)/2 for sin(x)cos(x) and then Integrate.
|
||||
res = integrate((sin(2*x)*S.Half)**m, x)
|
||||
elif (m == -n):
|
||||
if n < 0:
|
||||
# Same as the scheme described above.
|
||||
# the function argument to integrate in the end will
|
||||
# be 1, this cannot be integrated by trigintegrate.
|
||||
# Hence use sympy.integrals.integrate.
|
||||
res = (Rational(1, n + 1) * cos(x)**(m - 1) * sin(x)**(n + 1) +
|
||||
Rational(m - 1, n + 1) *
|
||||
integrate(cos(x)**(m - 2) * sin(x)**(n + 2), x))
|
||||
else:
|
||||
res = (Rational(-1, m + 1) * cos(x)**(m + 1) * sin(x)**(n - 1) +
|
||||
Rational(n - 1, m + 1) *
|
||||
integrate(cos(x)**(m + 2)*sin(x)**(n - 2), x))
|
||||
if conds == 'piecewise':
|
||||
return Piecewise((res.subs(x, a*x) / a, Ne(a, 0)), (zz, True))
|
||||
return res.subs(x, a*x) / a
|
||||
|
||||
|
||||
def _sin_pow_integrate(n, x):
|
||||
if n > 0:
|
||||
if n == 1:
|
||||
#Recursion break
|
||||
return -cos(x)
|
||||
|
||||
# n > 0
|
||||
# / /
|
||||
# | |
|
||||
# | n -1 n-1 n - 1 | n-2
|
||||
# | sin (x) dx = ______ cos (x) sin (x) + _______ | sin (x) dx
|
||||
# | |
|
||||
# | n n |
|
||||
#/ /
|
||||
#
|
||||
#
|
||||
|
||||
return (Rational(-1, n) * cos(x) * sin(x)**(n - 1) +
|
||||
Rational(n - 1, n) * _sin_pow_integrate(n - 2, x))
|
||||
|
||||
if n < 0:
|
||||
if n == -1:
|
||||
##Make sure this does not come back here again.
|
||||
##Recursion breaks here or at n==0.
|
||||
return trigintegrate(1/sin(x), x)
|
||||
|
||||
# n < 0
|
||||
# / /
|
||||
# | |
|
||||
# | n 1 n+1 n + 2 | n+2
|
||||
# | sin (x) dx = _______ cos (x) sin (x) + _______ | sin (x) dx
|
||||
# | |
|
||||
# | n + 1 n + 1 |
|
||||
#/ /
|
||||
#
|
||||
|
||||
return (Rational(1, n + 1) * cos(x) * sin(x)**(n + 1) +
|
||||
Rational(n + 2, n + 1) * _sin_pow_integrate(n + 2, x))
|
||||
|
||||
else:
|
||||
#n == 0
|
||||
#Recursion break.
|
||||
return x
|
||||
|
||||
|
||||
def _cos_pow_integrate(n, x):
|
||||
if n > 0:
|
||||
if n == 1:
|
||||
#Recursion break.
|
||||
return sin(x)
|
||||
|
||||
# n > 0
|
||||
# / /
|
||||
# | |
|
||||
# | n 1 n-1 n - 1 | n-2
|
||||
# | sin (x) dx = ______ sin (x) cos (x) + _______ | cos (x) dx
|
||||
# | |
|
||||
# | n n |
|
||||
#/ /
|
||||
#
|
||||
|
||||
return (Rational(1, n) * sin(x) * cos(x)**(n - 1) +
|
||||
Rational(n - 1, n) * _cos_pow_integrate(n - 2, x))
|
||||
|
||||
if n < 0:
|
||||
if n == -1:
|
||||
##Recursion break
|
||||
return trigintegrate(1/cos(x), x)
|
||||
|
||||
# n < 0
|
||||
# / /
|
||||
# | |
|
||||
# | n -1 n+1 n + 2 | n+2
|
||||
# | cos (x) dx = _______ sin (x) cos (x) + _______ | cos (x) dx
|
||||
# | |
|
||||
# | n + 1 n + 1 |
|
||||
#/ /
|
||||
#
|
||||
|
||||
return (Rational(-1, n + 1) * sin(x) * cos(x)**(n + 1) +
|
||||
Rational(n + 2, n + 1) * _cos_pow_integrate(n + 2, x))
|
||||
else:
|
||||
# n == 0
|
||||
#Recursion Break.
|
||||
return x
|
||||
Reference in New Issue
Block a user