I am done

This commit is contained in:
2024-10-30 22:14:35 +01:00
parent 720dc28c09
commit 40e2a747cf
36901 changed files with 5011519 additions and 0 deletions

View File

@ -0,0 +1,23 @@
"""A module that handles series: find a limit, order the series etc.
"""
from .order import Order
from .limits import limit, Limit
from .gruntz import gruntz
from .series import series
from .approximants import approximants
from .residues import residue
from .sequences import SeqPer, SeqFormula, sequence, SeqAdd, SeqMul
from .fourier import fourier_series
from .formal import fps
from .limitseq import difference_delta, limit_seq
from sympy.core.singleton import S
EmptySequence = S.EmptySequence
O = Order
__all__ = ['Order', 'O', 'limit', 'Limit', 'gruntz', 'series', 'approximants',
'residue', 'EmptySequence', 'SeqPer', 'SeqFormula', 'sequence',
'SeqAdd', 'SeqMul', 'fourier_series', 'fps', 'difference_delta',
'limit_seq'
]

View File

@ -0,0 +1,101 @@
"""
Convergence acceleration / extrapolation methods for series and
sequences.
References:
Carl M. Bender & Steven A. Orszag, "Advanced Mathematical Methods for
Scientists and Engineers: Asymptotic Methods and Perturbation Theory",
Springer 1999. (Shanks transformation: pp. 368-375, Richardson
extrapolation: pp. 375-377.)
"""
from sympy.core.numbers import Integer
from sympy.core.singleton import S
from sympy.functions.combinatorial.factorials import factorial
def richardson(A, k, n, N):
"""
Calculate an approximation for lim k->oo A(k) using Richardson
extrapolation with the terms A(n), A(n+1), ..., A(n+N+1).
Choosing N ~= 2*n often gives good results.
Examples
========
A simple example is to calculate exp(1) using the limit definition.
This limit converges slowly; n = 100 only produces two accurate
digits:
>>> from sympy.abc import n
>>> e = (1 + 1/n)**n
>>> print(round(e.subs(n, 100).evalf(), 10))
2.7048138294
Richardson extrapolation with 11 appropriately chosen terms gives
a value that is accurate to the indicated precision:
>>> from sympy import E
>>> from sympy.series.acceleration import richardson
>>> print(round(richardson(e, n, 10, 20).evalf(), 10))
2.7182818285
>>> print(round(E.evalf(), 10))
2.7182818285
Another useful application is to speed up convergence of series.
Computing 100 terms of the zeta(2) series 1/k**2 yields only
two accurate digits:
>>> from sympy.abc import k, n
>>> from sympy import Sum
>>> A = Sum(k**-2, (k, 1, n))
>>> print(round(A.subs(n, 100).evalf(), 10))
1.6349839002
Richardson extrapolation performs much better:
>>> from sympy import pi
>>> print(round(richardson(A, n, 10, 20).evalf(), 10))
1.6449340668
>>> print(round(((pi**2)/6).evalf(), 10)) # Exact value
1.6449340668
"""
s = S.Zero
for j in range(0, N + 1):
s += (A.subs(k, Integer(n + j)).doit() * (n + j)**N *
S.NegativeOne**(j + N) / (factorial(j) * factorial(N - j)))
return s
def shanks(A, k, n, m=1):
"""
Calculate an approximation for lim k->oo A(k) using the n-term Shanks
transformation S(A)(n). With m > 1, calculate the m-fold recursive
Shanks transformation S(S(...S(A)...))(n).
The Shanks transformation is useful for summing Taylor series that
converge slowly near a pole or singularity, e.g. for log(2):
>>> from sympy.abc import k, n
>>> from sympy import Sum, Integer
>>> from sympy.series.acceleration import shanks
>>> A = Sum(Integer(-1)**(k+1) / k, (k, 1, n))
>>> print(round(A.subs(n, 100).doit().evalf(), 10))
0.6881721793
>>> print(round(shanks(A, n, 25).evalf(), 10))
0.6931396564
>>> print(round(shanks(A, n, 25, 5).evalf(), 10))
0.6931471806
The correct value is 0.6931471805599453094172321215.
"""
table = [A.subs(k, Integer(j)).doit() for j in range(n + m + 2)]
table2 = table[:]
for i in range(1, m + 1):
for j in range(i, n + m + 1):
x, y, z = table[j - 1], table[j], table[j + 1]
table2[j] = (z*x - y**2) / (z + x - 2*y)
table = table2[:]
return table[n]

View File

@ -0,0 +1,103 @@
from sympy.core.singleton import S
from sympy.core.symbol import Symbol
from sympy.polys.polytools import lcm
from sympy.utilities import public
@public
def approximants(l, X=Symbol('x'), simplify=False):
"""
Return a generator for consecutive Pade approximants for a series.
It can also be used for computing the rational generating function of a
series when possible, since the last approximant returned by the generator
will be the generating function (if any).
Explanation
===========
The input list can contain more complex expressions than integer or rational
numbers; symbols may also be involved in the computation. An example below
show how to compute the generating function of the whole Pascal triangle.
The generator can be asked to apply the sympy.simplify function on each
generated term, which will make the computation slower; however it may be
useful when symbols are involved in the expressions.
Examples
========
>>> from sympy.series import approximants
>>> from sympy import lucas, fibonacci, symbols, binomial
>>> g = [lucas(k) for k in range(16)]
>>> [e for e in approximants(g)]
[2, -4/(x - 2), (5*x - 2)/(3*x - 1), (x - 2)/(x**2 + x - 1)]
>>> h = [fibonacci(k) for k in range(16)]
>>> [e for e in approximants(h)]
[x, -x/(x - 1), (x**2 - x)/(2*x - 1), -x/(x**2 + x - 1)]
>>> x, t = symbols("x,t")
>>> p=[sum(binomial(k,i)*x**i for i in range(k+1)) for k in range(16)]
>>> y = approximants(p, t)
>>> for k in range(3): print(next(y))
1
(x + 1)/((-x - 1)*(t*(x + 1) + (x + 1)/(-x - 1)))
nan
>>> y = approximants(p, t, simplify=True)
>>> for k in range(3): print(next(y))
1
-1/(t*(x + 1) - 1)
nan
See Also
========
sympy.concrete.guess.guess_generating_function_rational
mpmath.pade
"""
from sympy.simplify import simplify as simp
from sympy.simplify.radsimp import denom
p1, q1 = [S.One], [S.Zero]
p2, q2 = [S.Zero], [S.One]
while len(l):
b = 0
while l[b]==0:
b += 1
if b == len(l):
return
m = [S.One/l[b]]
for k in range(b+1, len(l)):
s = 0
for j in range(b, k):
s -= l[j+1] * m[b-j-1]
m.append(s/l[b])
l = m
a, l[0] = l[0], 0
p = [0] * max(len(p2), b+len(p1))
q = [0] * max(len(q2), b+len(q1))
for k in range(len(p2)):
p[k] = a*p2[k]
for k in range(b, b+len(p1)):
p[k] += p1[k-b]
for k in range(len(q2)):
q[k] = a*q2[k]
for k in range(b, b+len(q1)):
q[k] += q1[k-b]
while p[-1]==0: p.pop()
while q[-1]==0: q.pop()
p1, p2 = p2, p
q1, q2 = q2, q
# yield result
c = 1
for x in p:
c = lcm(c, denom(x))
for x in q:
c = lcm(c, denom(x))
out = ( sum(c*e*X**k for k, e in enumerate(p))
/ sum(c*e*X**k for k, e in enumerate(q)) )
if simplify:
yield(simp(out))
else:
yield out
return

View File

@ -0,0 +1,10 @@
from sympy.core.sympify import sympify
def aseries(expr, x=None, n=6, bound=0, hir=False):
"""
See the docstring of Expr.aseries() for complete details of this wrapper.
"""
expr = sympify(expr)
return expr.aseries(x, n, bound, hir)

View File

@ -0,0 +1,9 @@
from sympy.core.numbers import oo
from sympy.core.symbol import Symbol
from sympy.series.limits import limit
x = Symbol('x')
def timeit_limit_1x():
limit(1/x, x, oo)

View File

@ -0,0 +1,10 @@
from sympy.core.add import Add
from sympy.core.symbol import Symbol
from sympy.series.order import O
x = Symbol('x')
l = [x**i for i in range(1000)]
l.append(O(x**1001))
def timeit_order_1x():
Add(*l)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,811 @@
"""Fourier Series"""
from sympy.core.numbers import (oo, pi)
from sympy.core.symbol import Wild
from sympy.core.expr import Expr
from sympy.core.add import Add
from sympy.core.containers import Tuple
from sympy.core.singleton import S
from sympy.core.symbol import Dummy, Symbol
from sympy.core.sympify import sympify
from sympy.functions.elementary.trigonometric import sin, cos, sinc
from sympy.series.series_class import SeriesBase
from sympy.series.sequences import SeqFormula
from sympy.sets.sets import Interval
from sympy.utilities.iterables import is_sequence
__doctest_requires__ = {('fourier_series',): ['matplotlib']}
def fourier_cos_seq(func, limits, n):
"""Returns the cos sequence in a Fourier series"""
from sympy.integrals import integrate
x, L = limits[0], limits[2] - limits[1]
cos_term = cos(2*n*pi*x / L)
formula = 2 * cos_term * integrate(func * cos_term, limits) / L
a0 = formula.subs(n, S.Zero) / 2
return a0, SeqFormula(2 * cos_term * integrate(func * cos_term, limits)
/ L, (n, 1, oo))
def fourier_sin_seq(func, limits, n):
"""Returns the sin sequence in a Fourier series"""
from sympy.integrals import integrate
x, L = limits[0], limits[2] - limits[1]
sin_term = sin(2*n*pi*x / L)
return SeqFormula(2 * sin_term * integrate(func * sin_term, limits)
/ L, (n, 1, oo))
def _process_limits(func, limits):
"""
Limits should be of the form (x, start, stop).
x should be a symbol. Both start and stop should be bounded.
Explanation
===========
* If x is not given, x is determined from func.
* If limits is None. Limit of the form (x, -pi, pi) is returned.
Examples
========
>>> from sympy.series.fourier import _process_limits as pari
>>> from sympy.abc import x
>>> pari(x**2, (x, -2, 2))
(x, -2, 2)
>>> pari(x**2, (-2, 2))
(x, -2, 2)
>>> pari(x**2, None)
(x, -pi, pi)
"""
def _find_x(func):
free = func.free_symbols
if len(free) == 1:
return free.pop()
elif not free:
return Dummy('k')
else:
raise ValueError(
" specify dummy variables for %s. If the function contains"
" more than one free symbol, a dummy variable should be"
" supplied explicitly e.g. FourierSeries(m*n**2, (n, -pi, pi))"
% func)
x, start, stop = None, None, None
if limits is None:
x, start, stop = _find_x(func), -pi, pi
if is_sequence(limits, Tuple):
if len(limits) == 3:
x, start, stop = limits
elif len(limits) == 2:
x = _find_x(func)
start, stop = limits
if not isinstance(x, Symbol) or start is None or stop is None:
raise ValueError('Invalid limits given: %s' % str(limits))
unbounded = [S.NegativeInfinity, S.Infinity]
if start in unbounded or stop in unbounded:
raise ValueError("Both the start and end value should be bounded")
return sympify((x, start, stop))
def finite_check(f, x, L):
def check_fx(exprs, x):
return x not in exprs.free_symbols
def check_sincos(_expr, x, L):
if isinstance(_expr, (sin, cos)):
sincos_args = _expr.args[0]
if sincos_args.match(a*(pi/L)*x + b) is not None:
return True
else:
return False
from sympy.simplify.fu import TR2, TR1, sincos_to_sum
_expr = sincos_to_sum(TR2(TR1(f)))
add_coeff = _expr.as_coeff_add()
a = Wild('a', properties=[lambda k: k.is_Integer, lambda k: k != S.Zero, ])
b = Wild('b', properties=[lambda k: x not in k.free_symbols, ])
for s in add_coeff[1]:
mul_coeffs = s.as_coeff_mul()[1]
for t in mul_coeffs:
if not (check_fx(t, x) or check_sincos(t, x, L)):
return False, f
return True, _expr
class FourierSeries(SeriesBase):
r"""Represents Fourier sine/cosine series.
Explanation
===========
This class only represents a fourier series.
No computation is performed.
For how to compute Fourier series, see the :func:`fourier_series`
docstring.
See Also
========
sympy.series.fourier.fourier_series
"""
def __new__(cls, *args):
args = map(sympify, args)
return Expr.__new__(cls, *args)
@property
def function(self):
return self.args[0]
@property
def x(self):
return self.args[1][0]
@property
def period(self):
return (self.args[1][1], self.args[1][2])
@property
def a0(self):
return self.args[2][0]
@property
def an(self):
return self.args[2][1]
@property
def bn(self):
return self.args[2][2]
@property
def interval(self):
return Interval(0, oo)
@property
def start(self):
return self.interval.inf
@property
def stop(self):
return self.interval.sup
@property
def length(self):
return oo
@property
def L(self):
return abs(self.period[1] - self.period[0]) / 2
def _eval_subs(self, old, new):
x = self.x
if old.has(x):
return self
def truncate(self, n=3):
"""
Return the first n nonzero terms of the series.
If ``n`` is None return an iterator.
Parameters
==========
n : int or None
Amount of non-zero terms in approximation or None.
Returns
=======
Expr or iterator :
Approximation of function expanded into Fourier series.
Examples
========
>>> from sympy import fourier_series, pi
>>> from sympy.abc import x
>>> s = fourier_series(x, (x, -pi, pi))
>>> s.truncate(4)
2*sin(x) - sin(2*x) + 2*sin(3*x)/3 - sin(4*x)/2
See Also
========
sympy.series.fourier.FourierSeries.sigma_approximation
"""
if n is None:
return iter(self)
terms = []
for t in self:
if len(terms) == n:
break
if t is not S.Zero:
terms.append(t)
return Add(*terms)
def sigma_approximation(self, n=3):
r"""
Return :math:`\sigma`-approximation of Fourier series with respect
to order n.
Explanation
===========
Sigma approximation adjusts a Fourier summation to eliminate the Gibbs
phenomenon which would otherwise occur at discontinuities.
A sigma-approximated summation for a Fourier series of a T-periodical
function can be written as
.. math::
s(\theta) = \frac{1}{2} a_0 + \sum _{k=1}^{m-1}
\operatorname{sinc} \Bigl( \frac{k}{m} \Bigr) \cdot
\left[ a_k \cos \Bigl( \frac{2\pi k}{T} \theta \Bigr)
+ b_k \sin \Bigl( \frac{2\pi k}{T} \theta \Bigr) \right],
where :math:`a_0, a_k, b_k, k=1,\ldots,{m-1}` are standard Fourier
series coefficients and
:math:`\operatorname{sinc} \Bigl( \frac{k}{m} \Bigr)` is a Lanczos
:math:`\sigma` factor (expressed in terms of normalized
:math:`\operatorname{sinc}` function).
Parameters
==========
n : int
Highest order of the terms taken into account in approximation.
Returns
=======
Expr :
Sigma approximation of function expanded into Fourier series.
Examples
========
>>> from sympy import fourier_series, pi
>>> from sympy.abc import x
>>> s = fourier_series(x, (x, -pi, pi))
>>> s.sigma_approximation(4)
2*sin(x)*sinc(pi/4) - 2*sin(2*x)/pi + 2*sin(3*x)*sinc(3*pi/4)/3
See Also
========
sympy.series.fourier.FourierSeries.truncate
Notes
=====
The behaviour of
:meth:`~sympy.series.fourier.FourierSeries.sigma_approximation`
is different from :meth:`~sympy.series.fourier.FourierSeries.truncate`
- it takes all nonzero terms of degree smaller than n, rather than
first n nonzero ones.
References
==========
.. [1] https://en.wikipedia.org/wiki/Gibbs_phenomenon
.. [2] https://en.wikipedia.org/wiki/Sigma_approximation
"""
terms = [sinc(pi * i / n) * t for i, t in enumerate(self[:n])
if t is not S.Zero]
return Add(*terms)
def shift(self, s):
"""
Shift the function by a term independent of x.
Explanation
===========
f(x) -> f(x) + s
This is fast, if Fourier series of f(x) is already
computed.
Examples
========
>>> from sympy import fourier_series, pi
>>> from sympy.abc import x
>>> s = fourier_series(x**2, (x, -pi, pi))
>>> s.shift(1).truncate()
-4*cos(x) + cos(2*x) + 1 + pi**2/3
"""
s, x = sympify(s), self.x
if x in s.free_symbols:
raise ValueError("'%s' should be independent of %s" % (s, x))
a0 = self.a0 + s
sfunc = self.function + s
return self.func(sfunc, self.args[1], (a0, self.an, self.bn))
def shiftx(self, s):
"""
Shift x by a term independent of x.
Explanation
===========
f(x) -> f(x + s)
This is fast, if Fourier series of f(x) is already
computed.
Examples
========
>>> from sympy import fourier_series, pi
>>> from sympy.abc import x
>>> s = fourier_series(x**2, (x, -pi, pi))
>>> s.shiftx(1).truncate()
-4*cos(x + 1) + cos(2*x + 2) + pi**2/3
"""
s, x = sympify(s), self.x
if x in s.free_symbols:
raise ValueError("'%s' should be independent of %s" % (s, x))
an = self.an.subs(x, x + s)
bn = self.bn.subs(x, x + s)
sfunc = self.function.subs(x, x + s)
return self.func(sfunc, self.args[1], (self.a0, an, bn))
def scale(self, s):
"""
Scale the function by a term independent of x.
Explanation
===========
f(x) -> s * f(x)
This is fast, if Fourier series of f(x) is already
computed.
Examples
========
>>> from sympy import fourier_series, pi
>>> from sympy.abc import x
>>> s = fourier_series(x**2, (x, -pi, pi))
>>> s.scale(2).truncate()
-8*cos(x) + 2*cos(2*x) + 2*pi**2/3
"""
s, x = sympify(s), self.x
if x in s.free_symbols:
raise ValueError("'%s' should be independent of %s" % (s, x))
an = self.an.coeff_mul(s)
bn = self.bn.coeff_mul(s)
a0 = self.a0 * s
sfunc = self.args[0] * s
return self.func(sfunc, self.args[1], (a0, an, bn))
def scalex(self, s):
"""
Scale x by a term independent of x.
Explanation
===========
f(x) -> f(s*x)
This is fast, if Fourier series of f(x) is already
computed.
Examples
========
>>> from sympy import fourier_series, pi
>>> from sympy.abc import x
>>> s = fourier_series(x**2, (x, -pi, pi))
>>> s.scalex(2).truncate()
-4*cos(2*x) + cos(4*x) + pi**2/3
"""
s, x = sympify(s), self.x
if x in s.free_symbols:
raise ValueError("'%s' should be independent of %s" % (s, x))
an = self.an.subs(x, x * s)
bn = self.bn.subs(x, x * s)
sfunc = self.function.subs(x, x * s)
return self.func(sfunc, self.args[1], (self.a0, an, bn))
def _eval_as_leading_term(self, x, logx=None, cdir=0):
for t in self:
if t is not S.Zero:
return t
def _eval_term(self, pt):
if pt == 0:
return self.a0
return self.an.coeff(pt) + self.bn.coeff(pt)
def __neg__(self):
return self.scale(-1)
def __add__(self, other):
if isinstance(other, FourierSeries):
if self.period != other.period:
raise ValueError("Both the series should have same periods")
x, y = self.x, other.x
function = self.function + other.function.subs(y, x)
if self.x not in function.free_symbols:
return function
an = self.an + other.an
bn = self.bn + other.bn
a0 = self.a0 + other.a0
return self.func(function, self.args[1], (a0, an, bn))
return Add(self, other)
def __sub__(self, other):
return self.__add__(-other)
class FiniteFourierSeries(FourierSeries):
r"""Represents Finite Fourier sine/cosine series.
For how to compute Fourier series, see the :func:`fourier_series`
docstring.
Parameters
==========
f : Expr
Expression for finding fourier_series
limits : ( x, start, stop)
x is the independent variable for the expression f
(start, stop) is the period of the fourier series
exprs: (a0, an, bn) or Expr
a0 is the constant term a0 of the fourier series
an is a dictionary of coefficients of cos terms
an[k] = coefficient of cos(pi*(k/L)*x)
bn is a dictionary of coefficients of sin terms
bn[k] = coefficient of sin(pi*(k/L)*x)
or exprs can be an expression to be converted to fourier form
Methods
=======
This class is an extension of FourierSeries class.
Please refer to sympy.series.fourier.FourierSeries for
further information.
See Also
========
sympy.series.fourier.FourierSeries
sympy.series.fourier.fourier_series
"""
def __new__(cls, f, limits, exprs):
f = sympify(f)
limits = sympify(limits)
exprs = sympify(exprs)
if not (isinstance(exprs, Tuple) and len(exprs) == 3): # exprs is not of form (a0, an, bn)
# Converts the expression to fourier form
c, e = exprs.as_coeff_add()
from sympy.simplify.fu import TR10
rexpr = c + Add(*[TR10(i) for i in e])
a0, exp_ls = rexpr.expand(trig=False, power_base=False, power_exp=False, log=False).as_coeff_add()
x = limits[0]
L = abs(limits[2] - limits[1]) / 2
a = Wild('a', properties=[lambda k: k.is_Integer, lambda k: k is not S.Zero, ])
b = Wild('b', properties=[lambda k: x not in k.free_symbols, ])
an = {}
bn = {}
# separates the coefficients of sin and cos terms in dictionaries an, and bn
for p in exp_ls:
t = p.match(b * cos(a * (pi / L) * x))
q = p.match(b * sin(a * (pi / L) * x))
if t:
an[t[a]] = t[b] + an.get(t[a], S.Zero)
elif q:
bn[q[a]] = q[b] + bn.get(q[a], S.Zero)
else:
a0 += p
exprs = Tuple(a0, an, bn)
return Expr.__new__(cls, f, limits, exprs)
@property
def interval(self):
_length = 1 if self.a0 else 0
_length += max(set(self.an.keys()).union(set(self.bn.keys()))) + 1
return Interval(0, _length)
@property
def length(self):
return self.stop - self.start
def shiftx(self, s):
s, x = sympify(s), self.x
if x in s.free_symbols:
raise ValueError("'%s' should be independent of %s" % (s, x))
_expr = self.truncate().subs(x, x + s)
sfunc = self.function.subs(x, x + s)
return self.func(sfunc, self.args[1], _expr)
def scale(self, s):
s, x = sympify(s), self.x
if x in s.free_symbols:
raise ValueError("'%s' should be independent of %s" % (s, x))
_expr = self.truncate() * s
sfunc = self.function * s
return self.func(sfunc, self.args[1], _expr)
def scalex(self, s):
s, x = sympify(s), self.x
if x in s.free_symbols:
raise ValueError("'%s' should be independent of %s" % (s, x))
_expr = self.truncate().subs(x, x * s)
sfunc = self.function.subs(x, x * s)
return self.func(sfunc, self.args[1], _expr)
def _eval_term(self, pt):
if pt == 0:
return self.a0
_term = self.an.get(pt, S.Zero) * cos(pt * (pi / self.L) * self.x) \
+ self.bn.get(pt, S.Zero) * sin(pt * (pi / self.L) * self.x)
return _term
def __add__(self, other):
if isinstance(other, FourierSeries):
return other.__add__(fourier_series(self.function, self.args[1],\
finite=False))
elif isinstance(other, FiniteFourierSeries):
if self.period != other.period:
raise ValueError("Both the series should have same periods")
x, y = self.x, other.x
function = self.function + other.function.subs(y, x)
if self.x not in function.free_symbols:
return function
return fourier_series(function, limits=self.args[1])
def fourier_series(f, limits=None, finite=True):
r"""Computes the Fourier trigonometric series expansion.
Explanation
===========
Fourier trigonometric series of $f(x)$ over the interval $(a, b)$
is defined as:
.. math::
\frac{a_0}{2} + \sum_{n=1}^{\infty}
(a_n \cos(\frac{2n \pi x}{L}) + b_n \sin(\frac{2n \pi x}{L}))
where the coefficients are:
.. math::
L = b - a
.. math::
a_0 = \frac{2}{L} \int_{a}^{b}{f(x) dx}
.. math::
a_n = \frac{2}{L} \int_{a}^{b}{f(x) \cos(\frac{2n \pi x}{L}) dx}
.. math::
b_n = \frac{2}{L} \int_{a}^{b}{f(x) \sin(\frac{2n \pi x}{L}) dx}
The condition whether the function $f(x)$ given should be periodic
or not is more than necessary, because it is sufficient to consider
the series to be converging to $f(x)$ only in the given interval,
not throughout the whole real line.
This also brings a lot of ease for the computation because
you do not have to make $f(x)$ artificially periodic by
wrapping it with piecewise, modulo operations,
but you can shape the function to look like the desired periodic
function only in the interval $(a, b)$, and the computed series will
automatically become the series of the periodic version of $f(x)$.
This property is illustrated in the examples section below.
Parameters
==========
limits : (sym, start, end), optional
*sym* denotes the symbol the series is computed with respect to.
*start* and *end* denotes the start and the end of the interval
where the fourier series converges to the given function.
Default range is specified as $-\pi$ and $\pi$.
Returns
=======
FourierSeries
A symbolic object representing the Fourier trigonometric series.
Examples
========
Computing the Fourier series of $f(x) = x^2$:
>>> from sympy import fourier_series, pi
>>> from sympy.abc import x
>>> f = x**2
>>> s = fourier_series(f, (x, -pi, pi))
>>> s1 = s.truncate(n=3)
>>> s1
-4*cos(x) + cos(2*x) + pi**2/3
Shifting of the Fourier series:
>>> s.shift(1).truncate()
-4*cos(x) + cos(2*x) + 1 + pi**2/3
>>> s.shiftx(1).truncate()
-4*cos(x + 1) + cos(2*x + 2) + pi**2/3
Scaling of the Fourier series:
>>> s.scale(2).truncate()
-8*cos(x) + 2*cos(2*x) + 2*pi**2/3
>>> s.scalex(2).truncate()
-4*cos(2*x) + cos(4*x) + pi**2/3
Computing the Fourier series of $f(x) = x$:
This illustrates how truncating to the higher order gives better
convergence.
.. plot::
:context: reset
:format: doctest
:include-source: True
>>> from sympy import fourier_series, pi, plot
>>> from sympy.abc import x
>>> f = x
>>> s = fourier_series(f, (x, -pi, pi))
>>> s1 = s.truncate(n = 3)
>>> s2 = s.truncate(n = 5)
>>> s3 = s.truncate(n = 7)
>>> p = plot(f, s1, s2, s3, (x, -pi, pi), show=False, legend=True)
>>> p[0].line_color = (0, 0, 0)
>>> p[0].label = 'x'
>>> p[1].line_color = (0.7, 0.7, 0.7)
>>> p[1].label = 'n=3'
>>> p[2].line_color = (0.5, 0.5, 0.5)
>>> p[2].label = 'n=5'
>>> p[3].line_color = (0.3, 0.3, 0.3)
>>> p[3].label = 'n=7'
>>> p.show()
This illustrates how the series converges to different sawtooth
waves if the different ranges are specified.
.. plot::
:context: close-figs
:format: doctest
:include-source: True
>>> s1 = fourier_series(x, (x, -1, 1)).truncate(10)
>>> s2 = fourier_series(x, (x, -pi, pi)).truncate(10)
>>> s3 = fourier_series(x, (x, 0, 1)).truncate(10)
>>> p = plot(x, s1, s2, s3, (x, -5, 5), show=False, legend=True)
>>> p[0].line_color = (0, 0, 0)
>>> p[0].label = 'x'
>>> p[1].line_color = (0.7, 0.7, 0.7)
>>> p[1].label = '[-1, 1]'
>>> p[2].line_color = (0.5, 0.5, 0.5)
>>> p[2].label = '[-pi, pi]'
>>> p[3].line_color = (0.3, 0.3, 0.3)
>>> p[3].label = '[0, 1]'
>>> p.show()
Notes
=====
Computing Fourier series can be slow
due to the integration required in computing
an, bn.
It is faster to compute Fourier series of a function
by using shifting and scaling on an already
computed Fourier series rather than computing
again.
e.g. If the Fourier series of ``x**2`` is known
the Fourier series of ``x**2 - 1`` can be found by shifting by ``-1``.
See Also
========
sympy.series.fourier.FourierSeries
References
==========
.. [1] https://mathworld.wolfram.com/FourierSeries.html
"""
f = sympify(f)
limits = _process_limits(f, limits)
x = limits[0]
if x not in f.free_symbols:
return f
if finite:
L = abs(limits[2] - limits[1]) / 2
is_finite, res_f = finite_check(f, x, L)
if is_finite:
return FiniteFourierSeries(f, limits, res_f)
n = Dummy('n')
center = (limits[1] + limits[2]) / 2
if center.is_zero:
neg_f = f.subs(x, -x)
if f == neg_f:
a0, an = fourier_cos_seq(f, limits, n)
bn = SeqFormula(0, (1, oo))
return FourierSeries(f, limits, (a0, an, bn))
elif f == -neg_f:
a0 = S.Zero
an = SeqFormula(0, (1, oo))
bn = fourier_sin_seq(f, limits, n)
return FourierSeries(f, limits, (a0, an, bn))
a0, an = fourier_cos_seq(f, limits, n)
bn = fourier_sin_seq(f, limits, n)
return FourierSeries(f, limits, (a0, an, bn))

View File

@ -0,0 +1,739 @@
"""
Limits
======
Implemented according to the PhD thesis
https://www.cybertester.com/data/gruntz.pdf, which contains very thorough
descriptions of the algorithm including many examples. We summarize here
the gist of it.
All functions are sorted according to how rapidly varying they are at
infinity using the following rules. Any two functions f and g can be
compared using the properties of L:
L=lim log|f(x)| / log|g(x)| (for x -> oo)
We define >, < ~ according to::
1. f > g .... L=+-oo
we say that:
- f is greater than any power of g
- f is more rapidly varying than g
- f goes to infinity/zero faster than g
2. f < g .... L=0
we say that:
- f is lower than any power of g
3. f ~ g .... L!=0, +-oo
we say that:
- both f and g are bounded from above and below by suitable integral
powers of the other
Examples
========
::
2 < x < exp(x) < exp(x**2) < exp(exp(x))
2 ~ 3 ~ -5
x ~ x**2 ~ x**3 ~ 1/x ~ x**m ~ -x
exp(x) ~ exp(-x) ~ exp(2x) ~ exp(x)**2 ~ exp(x+exp(-x))
f ~ 1/f
So we can divide all the functions into comparability classes (x and x^2
belong to one class, exp(x) and exp(-x) belong to some other class). In
principle, we could compare any two functions, but in our algorithm, we
do not compare anything below the class 2~3~-5 (for example log(x) is
below this), so we set 2~3~-5 as the lowest comparability class.
Given the function f, we find the list of most rapidly varying (mrv set)
subexpressions of it. This list belongs to the same comparability class.
Let's say it is {exp(x), exp(2x)}. Using the rule f ~ 1/f we find an
element "w" (either from the list or a new one) from the same
comparability class which goes to zero at infinity. In our example we
set w=exp(-x) (but we could also set w=exp(-2x) or w=exp(-3x) ...). We
rewrite the mrv set using w, in our case {1/w, 1/w^2}, and substitute it
into f. Then we expand f into a series in w::
f = c0*w^e0 + c1*w^e1 + ... + O(w^en), where e0<e1<...<en, c0!=0
but for x->oo, lim f = lim c0*w^e0, because all the other terms go to zero,
because w goes to zero faster than the ci and ei. So::
for e0>0, lim f = 0
for e0<0, lim f = +-oo (the sign depends on the sign of c0)
for e0=0, lim f = lim c0
We need to recursively compute limits at several places of the algorithm, but
as is shown in the PhD thesis, it always finishes.
Important functions from the implementation:
compare(a, b, x) compares "a" and "b" by computing the limit L.
mrv(e, x) returns list of most rapidly varying (mrv) subexpressions of "e"
rewrite(e, Omega, x, wsym) rewrites "e" in terms of w
leadterm(f, x) returns the lowest power term in the series of f
mrv_leadterm(e, x) returns the lead term (c0, e0) for e
limitinf(e, x) computes lim e (for x->oo)
limit(e, z, z0) computes any limit by converting it to the case x->oo
All the functions are really simple and straightforward except
rewrite(), which is the most difficult/complex part of the algorithm.
When the algorithm fails, the bugs are usually in the series expansion
(i.e. in SymPy) or in rewrite.
This code is almost exact rewrite of the Maple code inside the Gruntz
thesis.
Debugging
---------
Because the gruntz algorithm is highly recursive, it's difficult to
figure out what went wrong inside a debugger. Instead, turn on nice
debug prints by defining the environment variable SYMPY_DEBUG. For
example:
[user@localhost]: SYMPY_DEBUG=True ./bin/isympy
In [1]: limit(sin(x)/x, x, 0)
limitinf(_x*sin(1/_x), _x) = 1
+-mrv_leadterm(_x*sin(1/_x), _x) = (1, 0)
| +-mrv(_x*sin(1/_x), _x) = set([_x])
| | +-mrv(_x, _x) = set([_x])
| | +-mrv(sin(1/_x), _x) = set([_x])
| | +-mrv(1/_x, _x) = set([_x])
| | +-mrv(_x, _x) = set([_x])
| +-mrv_leadterm(exp(_x)*sin(exp(-_x)), _x, set([exp(_x)])) = (1, 0)
| +-rewrite(exp(_x)*sin(exp(-_x)), set([exp(_x)]), _x, _w) = (1/_w*sin(_w), -_x)
| +-sign(_x, _x) = 1
| +-mrv_leadterm(1, _x) = (1, 0)
+-sign(0, _x) = 0
+-limitinf(1, _x) = 1
And check manually which line is wrong. Then go to the source code and
debug this function to figure out the exact problem.
"""
from functools import reduce
from sympy.core import Basic, S, Mul, PoleError, expand_mul
from sympy.core.cache import cacheit
from sympy.core.intfunc import ilcm
from sympy.core.numbers import I, oo
from sympy.core.symbol import Dummy, Wild
from sympy.core.traversal import bottom_up
from sympy.functions import log, exp, sign as _sign
from sympy.series.order import Order
from sympy.utilities.exceptions import SymPyDeprecationWarning
from sympy.utilities.misc import debug_decorator as debug
from sympy.utilities.timeutils import timethis
timeit = timethis('gruntz')
def compare(a, b, x):
"""Returns "<" if a<b, "=" for a == b, ">" for a>b"""
# log(exp(...)) must always be simplified here for termination
la, lb = log(a), log(b)
if isinstance(a, Basic) and (isinstance(a, exp) or (a.is_Pow and a.base == S.Exp1)):
la = a.exp
if isinstance(b, Basic) and (isinstance(b, exp) or (b.is_Pow and b.base == S.Exp1)):
lb = b.exp
c = limitinf(la/lb, x)
if c == 0:
return "<"
elif c.is_infinite:
return ">"
else:
return "="
class SubsSet(dict):
"""
Stores (expr, dummy) pairs, and how to rewrite expr-s.
Explanation
===========
The gruntz algorithm needs to rewrite certain expressions in term of a new
variable w. We cannot use subs, because it is just too smart for us. For
example::
> Omega=[exp(exp(_p - exp(-_p))/(1 - 1/_p)), exp(exp(_p))]
> O2=[exp(-exp(_p) + exp(-exp(-_p))*exp(_p)/(1 - 1/_p))/_w, 1/_w]
> e = exp(exp(_p - exp(-_p))/(1 - 1/_p)) - exp(exp(_p))
> e.subs(Omega[0],O2[0]).subs(Omega[1],O2[1])
-1/w + exp(exp(p)*exp(-exp(-p))/(1 - 1/p))
is really not what we want!
So we do it the hard way and keep track of all the things we potentially
want to substitute by dummy variables. Consider the expression::
exp(x - exp(-x)) + exp(x) + x.
The mrv set is {exp(x), exp(-x), exp(x - exp(-x))}.
We introduce corresponding dummy variables d1, d2, d3 and rewrite::
d3 + d1 + x.
This class first of all keeps track of the mapping expr->variable, i.e.
will at this stage be a dictionary::
{exp(x): d1, exp(-x): d2, exp(x - exp(-x)): d3}.
[It turns out to be more convenient this way round.]
But sometimes expressions in the mrv set have other expressions from the
mrv set as subexpressions, and we need to keep track of that as well. In
this case, d3 is really exp(x - d2), so rewrites at this stage is::
{d3: exp(x-d2)}.
The function rewrite uses all this information to correctly rewrite our
expression in terms of w. In this case w can be chosen to be exp(-x),
i.e. d2. The correct rewriting then is::
exp(-w)/w + 1/w + x.
"""
def __init__(self):
self.rewrites = {}
def __repr__(self):
return super().__repr__() + ', ' + self.rewrites.__repr__()
def __getitem__(self, key):
if key not in self:
self[key] = Dummy()
return dict.__getitem__(self, key)
def do_subs(self, e):
"""Substitute the variables with expressions"""
for expr, var in self.items():
e = e.xreplace({var: expr})
return e
def meets(self, s2):
"""Tell whether or not self and s2 have non-empty intersection"""
return set(self.keys()).intersection(list(s2.keys())) != set()
def union(self, s2, exps=None):
"""Compute the union of self and s2, adjusting exps"""
res = self.copy()
tr = {}
for expr, var in s2.items():
if expr in self:
if exps:
exps = exps.xreplace({var: res[expr]})
tr[var] = res[expr]
else:
res[expr] = var
for var, rewr in s2.rewrites.items():
res.rewrites[var] = rewr.xreplace(tr)
return res, exps
def copy(self):
"""Create a shallow copy of SubsSet"""
r = SubsSet()
r.rewrites = self.rewrites.copy()
for expr, var in self.items():
r[expr] = var
return r
@debug
def mrv(e, x):
"""Returns a SubsSet of most rapidly varying (mrv) subexpressions of 'e',
and e rewritten in terms of these"""
from sympy.simplify.powsimp import powsimp
e = powsimp(e, deep=True, combine='exp')
if not isinstance(e, Basic):
raise TypeError("e should be an instance of Basic")
if not e.has(x):
return SubsSet(), e
elif e == x:
s = SubsSet()
return s, s[x]
elif e.is_Mul or e.is_Add:
i, d = e.as_independent(x) # throw away x-independent terms
if d.func != e.func:
s, expr = mrv(d, x)
return s, e.func(i, expr)
a, b = d.as_two_terms()
s1, e1 = mrv(a, x)
s2, e2 = mrv(b, x)
return mrv_max1(s1, s2, e.func(i, e1, e2), x)
elif e.is_Pow and e.base != S.Exp1:
e1 = S.One
while e.is_Pow:
b1 = e.base
e1 *= e.exp
e = b1
if b1 == 1:
return SubsSet(), b1
if e1.has(x):
if limitinf(b1, x) is S.One:
if limitinf(e1, x).is_infinite is False:
return mrv(exp(e1*(b1 - 1)), x)
return mrv(exp(e1*log(b1)), x)
else:
s, expr = mrv(b1, x)
return s, expr**e1
elif isinstance(e, log):
s, expr = mrv(e.args[0], x)
return s, log(expr)
elif isinstance(e, exp) or (e.is_Pow and e.base == S.Exp1):
# We know from the theory of this algorithm that exp(log(...)) may always
# be simplified here, and doing so is vital for termination.
if isinstance(e.exp, log):
return mrv(e.exp.args[0], x)
# if a product has an infinite factor the result will be
# infinite if there is no zero, otherwise NaN; here, we
# consider the result infinite if any factor is infinite
li = limitinf(e.exp, x)
if any(_.is_infinite for _ in Mul.make_args(li)):
s1 = SubsSet()
e1 = s1[e]
s2, e2 = mrv(e.exp, x)
su = s1.union(s2)[0]
su.rewrites[e1] = exp(e2)
return mrv_max3(s1, e1, s2, exp(e2), su, e1, x)
else:
s, expr = mrv(e.exp, x)
return s, exp(expr)
elif e.is_Function:
l = [mrv(a, x) for a in e.args]
l2 = [s for (s, _) in l if s != SubsSet()]
if len(l2) != 1:
# e.g. something like BesselJ(x, x)
raise NotImplementedError("MRV set computation for functions in"
" several variables not implemented.")
s, ss = l2[0], SubsSet()
args = [ss.do_subs(x[1]) for x in l]
return s, e.func(*args)
elif e.is_Derivative:
raise NotImplementedError("MRV set computation for derivatives"
" not implemented yet.")
raise NotImplementedError(
"Don't know how to calculate the mrv of '%s'" % e)
def mrv_max3(f, expsf, g, expsg, union, expsboth, x):
"""
Computes the maximum of two sets of expressions f and g, which
are in the same comparability class, i.e. max() compares (two elements of)
f and g and returns either (f, expsf) [if f is larger], (g, expsg)
[if g is larger] or (union, expsboth) [if f, g are of the same class].
"""
if not isinstance(f, SubsSet):
raise TypeError("f should be an instance of SubsSet")
if not isinstance(g, SubsSet):
raise TypeError("g should be an instance of SubsSet")
if f == SubsSet():
return g, expsg
elif g == SubsSet():
return f, expsf
elif f.meets(g):
return union, expsboth
c = compare(list(f.keys())[0], list(g.keys())[0], x)
if c == ">":
return f, expsf
elif c == "<":
return g, expsg
else:
if c != "=":
raise ValueError("c should be =")
return union, expsboth
def mrv_max1(f, g, exps, x):
"""Computes the maximum of two sets of expressions f and g, which
are in the same comparability class, i.e. mrv_max1() compares (two elements of)
f and g and returns the set, which is in the higher comparability class
of the union of both, if they have the same order of variation.
Also returns exps, with the appropriate substitutions made.
"""
u, b = f.union(g, exps)
return mrv_max3(f, g.do_subs(exps), g, f.do_subs(exps),
u, b, x)
@debug
@cacheit
@timeit
def sign(e, x):
"""
Returns a sign of an expression e(x) for x->oo.
::
e > 0 for x sufficiently large ... 1
e == 0 for x sufficiently large ... 0
e < 0 for x sufficiently large ... -1
The result of this function is currently undefined if e changes sign
arbitrarily often for arbitrarily large x (e.g. sin(x)).
Note that this returns zero only if e is *constantly* zero
for x sufficiently large. [If e is constant, of course, this is just
the same thing as the sign of e.]
"""
if not isinstance(e, Basic):
raise TypeError("e should be an instance of Basic")
if e.is_positive:
return 1
elif e.is_negative:
return -1
elif e.is_zero:
return 0
elif not e.has(x):
from sympy.simplify import logcombine
e = logcombine(e)
return _sign(e)
elif e == x:
return 1
elif e.is_Mul:
a, b = e.as_two_terms()
sa = sign(a, x)
if not sa:
return 0
return sa * sign(b, x)
elif isinstance(e, exp):
return 1
elif e.is_Pow:
if e.base == S.Exp1:
return 1
s = sign(e.base, x)
if s == 1:
return 1
if e.exp.is_Integer:
return s**e.exp
elif isinstance(e, log):
return sign(e.args[0] - 1, x)
# if all else fails, do it the hard way
c0, e0 = mrv_leadterm(e, x)
return sign(c0, x)
@debug
@timeit
@cacheit
def limitinf(e, x):
"""Limit e(x) for x-> oo."""
# rewrite e in terms of tractable functions only
old = e
if not e.has(x):
return e # e is a constant
from sympy.simplify.powsimp import powdenest
from sympy.calculus.util import AccumBounds
if e.has(Order):
e = e.expand().removeO()
if not x.is_positive or x.is_integer:
# We make sure that x.is_positive is True and x.is_integer is None
# so we get all the correct mathematical behavior from the expression.
# We need a fresh variable.
p = Dummy('p', positive=True)
e = e.subs(x, p)
x = p
e = e.rewrite('tractable', deep=True, limitvar=x)
e = powdenest(e)
if isinstance(e, AccumBounds):
if mrv_leadterm(e.min, x) != mrv_leadterm(e.max, x):
raise NotImplementedError
c0, e0 = mrv_leadterm(e.min, x)
else:
c0, e0 = mrv_leadterm(e, x)
sig = sign(e0, x)
if sig == 1:
return S.Zero # e0>0: lim f = 0
elif sig == -1: # e0<0: lim f = +-oo (the sign depends on the sign of c0)
if c0.match(I*Wild("a", exclude=[I])):
return c0*oo
s = sign(c0, x)
# the leading term shouldn't be 0:
if s == 0:
raise ValueError("Leading term should not be 0")
return s*oo
elif sig == 0:
if c0 == old:
c0 = c0.cancel()
return limitinf(c0, x) # e0=0: lim f = lim c0
else:
raise ValueError("{} could not be evaluated".format(sig))
def moveup2(s, x):
r = SubsSet()
for expr, var in s.items():
r[expr.xreplace({x: exp(x)})] = var
for var, expr in s.rewrites.items():
r.rewrites[var] = s.rewrites[var].xreplace({x: exp(x)})
return r
def moveup(l, x):
return [e.xreplace({x: exp(x)}) for e in l]
@debug
@timeit
def calculate_series(e, x, logx=None):
""" Calculates at least one term of the series of ``e`` in ``x``.
This is a place that fails most often, so it is in its own function.
"""
SymPyDeprecationWarning(
feature="calculate_series",
useinstead="series() with suitable n, or as_leading_term",
issue=21838,
deprecated_since_version="1.12"
).warn()
from sympy.simplify.powsimp import powdenest
for t in e.lseries(x, logx=logx):
# bottom_up function is required for a specific case - when e is
# -exp(p/(p + 1)) + exp(-p**2/(p + 1) + p)
t = bottom_up(t, lambda w:
getattr(w, 'normal', lambda: w)())
# And the expression
# `(-sin(1/x) + sin((x + exp(x))*exp(-x)/x))*exp(x)`
# from the first test of test_gruntz_eval_special needs to
# be expanded. But other forms need to be have at least
# factor_terms applied. `factor` accomplishes both and is
# faster than using `factor_terms` for the gruntz suite. It
# does not appear that use of `cancel` is necessary.
# t = cancel(t, expand=False)
t = t.factor()
if t.has(exp) and t.has(log):
t = powdenest(t)
if not t.is_zero:
break
return t
@debug
@timeit
@cacheit
def mrv_leadterm(e, x):
"""Returns (c0, e0) for e."""
Omega = SubsSet()
if not e.has(x):
return (e, S.Zero)
if Omega == SubsSet():
Omega, exps = mrv(e, x)
if not Omega:
# e really does not depend on x after simplification
return exps, S.Zero
if x in Omega:
# move the whole omega up (exponentiate each term):
Omega_up = moveup2(Omega, x)
exps_up = moveup([exps], x)[0]
# NOTE: there is no need to move this down!
Omega = Omega_up
exps = exps_up
#
# The positive dummy, w, is used here so log(w*2) etc. will expand;
# a unique dummy is needed in this algorithm
#
# For limits of complex functions, the algorithm would have to be
# improved, or just find limits of Re and Im components separately.
#
w = Dummy("w", positive=True)
f, logw = rewrite(exps, Omega, x, w)
try:
lt = f.leadterm(w, logx=logw)
except (NotImplementedError, PoleError, ValueError):
n0 = 1
_series = Order(1)
incr = S.One
while _series.is_Order:
_series = f._eval_nseries(w, n=n0+incr, logx=logw)
incr *= 2
series = _series.expand().removeO()
try:
lt = series.leadterm(w, logx=logw)
except (NotImplementedError, PoleError, ValueError):
lt = f.as_coeff_exponent(w)
if lt[0].has(w):
base = f.as_base_exp()[0].as_coeff_exponent(w)
ex = f.as_base_exp()[1]
lt = (base[0]**ex, base[1]*ex)
return (lt[0].subs(log(w), logw), lt[1])
def build_expression_tree(Omega, rewrites):
r""" Helper function for rewrite.
We need to sort Omega (mrv set) so that we replace an expression before
we replace any expression in terms of which it has to be rewritten::
e1 ---> e2 ---> e3
\
-> e4
Here we can do e1, e2, e3, e4 or e1, e2, e4, e3.
To do this we assemble the nodes into a tree, and sort them by height.
This function builds the tree, rewrites then sorts the nodes.
"""
class Node:
def __init__(self):
self.before = []
self.expr = None
self.var = None
def ht(self):
return reduce(lambda x, y: x + y,
[x.ht() for x in self.before], 1)
nodes = {}
for expr, v in Omega:
n = Node()
n.var = v
n.expr = expr
nodes[v] = n
for _, v in Omega:
if v in rewrites:
n = nodes[v]
r = rewrites[v]
for _, v2 in Omega:
if r.has(v2):
n.before.append(nodes[v2])
return nodes
@debug
@timeit
def rewrite(e, Omega, x, wsym):
"""e(x) ... the function
Omega ... the mrv set
wsym ... the symbol which is going to be used for w
Returns the rewritten e in terms of w and log(w). See test_rewrite1()
for examples and correct results.
"""
from sympy import AccumBounds
if not isinstance(Omega, SubsSet):
raise TypeError("Omega should be an instance of SubsSet")
if len(Omega) == 0:
raise ValueError("Length cannot be 0")
# all items in Omega must be exponentials
for t in Omega.keys():
if not isinstance(t, exp):
raise ValueError("Value should be exp")
rewrites = Omega.rewrites
Omega = list(Omega.items())
nodes = build_expression_tree(Omega, rewrites)
Omega.sort(key=lambda x: nodes[x[1]].ht(), reverse=True)
# make sure we know the sign of each exp() term; after the loop,
# g is going to be the "w" - the simplest one in the mrv set
for g, _ in Omega:
sig = sign(g.exp, x)
if sig != 1 and sig != -1 and not sig.has(AccumBounds):
raise NotImplementedError('Result depends on the sign of %s' % sig)
if sig == 1:
wsym = 1/wsym # if g goes to oo, substitute 1/w
# O2 is a list, which results by rewriting each item in Omega using "w"
O2 = []
denominators = []
for f, var in Omega:
c = limitinf(f.exp/g.exp, x)
if c.is_Rational:
denominators.append(c.q)
arg = f.exp
if var in rewrites:
if not isinstance(rewrites[var], exp):
raise ValueError("Value should be exp")
arg = rewrites[var].args[0]
O2.append((var, exp((arg - c*g.exp).expand())*wsym**c))
# Remember that Omega contains subexpressions of "e". So now we find
# them in "e" and substitute them for our rewriting, stored in O2
# the following powsimp is necessary to automatically combine exponentials,
# so that the .xreplace() below succeeds:
# TODO this should not be necessary
from sympy.simplify.powsimp import powsimp
f = powsimp(e, deep=True, combine='exp')
for a, b in O2:
f = f.xreplace({a: b})
for _, var in Omega:
assert not f.has(var)
# finally compute the logarithm of w (logw).
logw = g.exp
if sig == 1:
logw = -logw # log(w)->log(1/w)=-log(w)
# Some parts of SymPy have difficulty computing series expansions with
# non-integral exponents. The following heuristic improves the situation:
exponent = reduce(ilcm, denominators, 1)
f = f.subs({wsym: wsym**exponent})
logw /= exponent
# bottom_up function is required for a specific case - when f is
# -exp(p/(p + 1)) + exp(-p**2/(p + 1) + p). No current simplification
# methods reduce this to 0 while not expanding polynomials.
f = bottom_up(f, lambda w: getattr(w, 'normal', lambda: w)())
f = expand_mul(f)
return f, logw
def gruntz(e, z, z0, dir="+"):
"""
Compute the limit of e(z) at the point z0 using the Gruntz algorithm.
Explanation
===========
``z0`` can be any expression, including oo and -oo.
For ``dir="+"`` (default) it calculates the limit from the right
(z->z0+) and for ``dir="-"`` the limit from the left (z->z0-). For infinite z0
(oo or -oo), the dir argument does not matter.
This algorithm is fully described in the module docstring in the gruntz.py
file. It relies heavily on the series expansion. Most frequently, gruntz()
is only used if the faster limit() function (which uses heuristics) fails.
"""
if not z.is_symbol:
raise NotImplementedError("Second argument must be a Symbol")
# convert all limits to the limit z->oo; sign of z is handled in limitinf
r = None
if z0 in (oo, I*oo):
e0 = e
elif z0 in (-oo, -I*oo):
e0 = e.subs(z, -z)
else:
if str(dir) == "-":
e0 = e.subs(z, z0 - 1/z)
elif str(dir) == "+":
e0 = e.subs(z, z0 + 1/z)
else:
raise NotImplementedError("dir must be '+' or '-'")
r = limitinf(e0, z)
# This is a bit of a heuristic for nice results... we always rewrite
# tractable functions in terms of familiar intractable ones.
# It might be nicer to rewrite the exactly to what they were initially,
# but that would take some work to implement.
return r.rewrite('intractable', deep=True)

View File

@ -0,0 +1,51 @@
def finite_diff(expression, variable, increment=1):
"""
Takes as input a polynomial expression and the variable used to construct
it and returns the difference between function's value when the input is
incremented to 1 and the original function value. If you want an increment
other than one supply it as a third argument.
Examples
========
>>> from sympy.abc import x, y, z
>>> from sympy.series.kauers import finite_diff
>>> finite_diff(x**2, x)
2*x + 1
>>> finite_diff(y**3 + 2*y**2 + 3*y + 4, y)
3*y**2 + 7*y + 6
>>> finite_diff(x**2 + 3*x + 8, x, 2)
4*x + 10
>>> finite_diff(z**3 + 8*z, z, 3)
9*z**2 + 27*z + 51
"""
expression = expression.expand()
expression2 = expression.subs(variable, variable + increment)
expression2 = expression2.expand()
return expression2 - expression
def finite_diff_kauers(sum):
"""
Takes as input a Sum instance and returns the difference between the sum
with the upper index incremented by 1 and the original sum. For example,
if S(n) is a sum, then finite_diff_kauers will return S(n + 1) - S(n).
Examples
========
>>> from sympy.series.kauers import finite_diff_kauers
>>> from sympy import Sum
>>> from sympy.abc import x, y, m, n, k
>>> finite_diff_kauers(Sum(k, (k, 1, n)))
n + 1
>>> finite_diff_kauers(Sum(1/k, (k, 1, n)))
1/(n + 1)
>>> finite_diff_kauers(Sum((x*y**2), (x, 1, n), (y, 1, m)))
(m + 1)**2*(n + 1)
>>> finite_diff_kauers(Sum((x*y), (x, 1, m), (y, 1, n)))
(m + 1)*(n + 1)
"""
function = sum.function
for l in sum.limits:
function = function.subs(l[0], l[- 1] + 1)
return function

View File

@ -0,0 +1,385 @@
from sympy.calculus.accumulationbounds import AccumBounds
from sympy.core import S, Symbol, Add, sympify, Expr, PoleError, Mul
from sympy.core.exprtools import factor_terms
from sympy.core.numbers import Float, _illegal
from sympy.functions.combinatorial.factorials import factorial
from sympy.functions.elementary.complexes import (Abs, sign, arg, re)
from sympy.functions.elementary.exponential import (exp, log)
from sympy.functions.special.gamma_functions import gamma
from sympy.polys import PolynomialError, factor
from sympy.series.order import Order
from .gruntz import gruntz
def limit(e, z, z0, dir="+"):
"""Computes the limit of ``e(z)`` at the point ``z0``.
Parameters
==========
e : expression, the limit of which is to be taken
z : symbol representing the variable in the limit.
Other symbols are treated as constants. Multivariate limits
are not supported.
z0 : the value toward which ``z`` tends. Can be any expression,
including ``oo`` and ``-oo``.
dir : string, optional (default: "+")
The limit is bi-directional if ``dir="+-"``, from the right
(z->z0+) if ``dir="+"``, and from the left (z->z0-) if
``dir="-"``. For infinite ``z0`` (``oo`` or ``-oo``), the ``dir``
argument is determined from the direction of the infinity
(i.e., ``dir="-"`` for ``oo``).
Examples
========
>>> from sympy import limit, sin, oo
>>> from sympy.abc import x
>>> limit(sin(x)/x, x, 0)
1
>>> limit(1/x, x, 0) # default dir='+'
oo
>>> limit(1/x, x, 0, dir="-")
-oo
>>> limit(1/x, x, 0, dir='+-')
zoo
>>> limit(1/x, x, oo)
0
Notes
=====
First we try some heuristics for easy and frequent cases like "x", "1/x",
"x**2" and similar, so that it's fast. For all other cases, we use the
Gruntz algorithm (see the gruntz() function).
See Also
========
limit_seq : returns the limit of a sequence.
"""
return Limit(e, z, z0, dir).doit(deep=False)
def heuristics(e, z, z0, dir):
"""Computes the limit of an expression term-wise.
Parameters are the same as for the ``limit`` function.
Works with the arguments of expression ``e`` one by one, computing
the limit of each and then combining the results. This approach
works only for simple limits, but it is fast.
"""
rv = None
if z0 is S.Infinity:
rv = limit(e.subs(z, 1/z), z, S.Zero, "+")
if isinstance(rv, Limit):
return
elif e.is_Mul or e.is_Add or e.is_Pow or e.is_Function:
r = []
from sympy.simplify.simplify import together
for a in e.args:
l = limit(a, z, z0, dir)
if l.has(S.Infinity) and l.is_finite is None:
if isinstance(e, Add):
m = factor_terms(e)
if not isinstance(m, Mul): # try together
m = together(m)
if not isinstance(m, Mul): # try factor if the previous methods failed
m = factor(e)
if isinstance(m, Mul):
return heuristics(m, z, z0, dir)
return
return
elif isinstance(l, Limit):
return
elif l is S.NaN:
return
else:
r.append(l)
if r:
rv = e.func(*r)
if rv is S.NaN and e.is_Mul and any(isinstance(rr, AccumBounds) for rr in r):
r2 = []
e2 = []
for ii, rval in enumerate(r):
if isinstance(rval, AccumBounds):
r2.append(rval)
else:
e2.append(e.args[ii])
if len(e2) > 0:
e3 = Mul(*e2).simplify()
l = limit(e3, z, z0, dir)
rv = l * Mul(*r2)
if rv is S.NaN:
try:
from sympy.simplify.ratsimp import ratsimp
rat_e = ratsimp(e)
except PolynomialError:
return
if rat_e is S.NaN or rat_e == e:
return
return limit(rat_e, z, z0, dir)
return rv
class Limit(Expr):
"""Represents an unevaluated limit.
Examples
========
>>> from sympy import Limit, sin
>>> from sympy.abc import x
>>> Limit(sin(x)/x, x, 0)
Limit(sin(x)/x, x, 0, dir='+')
>>> Limit(1/x, x, 0, dir="-")
Limit(1/x, x, 0, dir='-')
"""
def __new__(cls, e, z, z0, dir="+"):
e = sympify(e)
z = sympify(z)
z0 = sympify(z0)
if z0 in (S.Infinity, S.ImaginaryUnit*S.Infinity):
dir = "-"
elif z0 in (S.NegativeInfinity, S.ImaginaryUnit*S.NegativeInfinity):
dir = "+"
if(z0.has(z)):
raise NotImplementedError("Limits approaching a variable point are"
" not supported (%s -> %s)" % (z, z0))
if isinstance(dir, str):
dir = Symbol(dir)
elif not isinstance(dir, Symbol):
raise TypeError("direction must be of type basestring or "
"Symbol, not %s" % type(dir))
if str(dir) not in ('+', '-', '+-'):
raise ValueError("direction must be one of '+', '-' "
"or '+-', not %s" % dir)
obj = Expr.__new__(cls)
obj._args = (e, z, z0, dir)
return obj
@property
def free_symbols(self):
e = self.args[0]
isyms = e.free_symbols
isyms.difference_update(self.args[1].free_symbols)
isyms.update(self.args[2].free_symbols)
return isyms
def pow_heuristics(self, e):
_, z, z0, _ = self.args
b1, e1 = e.base, e.exp
if not b1.has(z):
res = limit(e1*log(b1), z, z0)
return exp(res)
ex_lim = limit(e1, z, z0)
base_lim = limit(b1, z, z0)
if base_lim is S.One:
if ex_lim in (S.Infinity, S.NegativeInfinity):
res = limit(e1*(b1 - 1), z, z0)
return exp(res)
if base_lim is S.NegativeInfinity and ex_lim is S.Infinity:
return S.ComplexInfinity
def doit(self, **hints):
"""Evaluates the limit.
Parameters
==========
deep : bool, optional (default: True)
Invoke the ``doit`` method of the expressions involved before
taking the limit.
hints : optional keyword arguments
To be passed to ``doit`` methods; only used if deep is True.
"""
e, z, z0, dir = self.args
if str(dir) == '+-':
r = limit(e, z, z0, dir='+')
l = limit(e, z, z0, dir='-')
if isinstance(r, Limit) and isinstance(l, Limit):
if r.args[0] == l.args[0]:
return self
if r == l:
return l
if r.is_infinite and l.is_infinite:
return S.ComplexInfinity
raise ValueError("The limit does not exist since "
"left hand limit = %s and right hand limit = %s"
% (l, r))
if z0 is S.ComplexInfinity:
raise NotImplementedError("Limits at complex "
"infinity are not implemented")
if z0.is_infinite:
cdir = sign(z0)
cdir = cdir/abs(cdir)
e = e.subs(z, cdir*z)
dir = "-"
z0 = S.Infinity
if hints.get('deep', True):
e = e.doit(**hints)
z = z.doit(**hints)
z0 = z0.doit(**hints)
if e == z:
return z0
if not e.has(z):
return e
if z0 is S.NaN:
return S.NaN
if e.has(*_illegal):
return self
if e.is_Order:
return Order(limit(e.expr, z, z0), *e.args[1:])
cdir = 0
if str(dir) == "+":
cdir = 1
elif str(dir) == "-":
cdir = -1
def set_signs(expr):
if not expr.args:
return expr
newargs = tuple(set_signs(arg) for arg in expr.args)
if newargs != expr.args:
expr = expr.func(*newargs)
abs_flag = isinstance(expr, Abs)
arg_flag = isinstance(expr, arg)
sign_flag = isinstance(expr, sign)
if abs_flag or sign_flag or arg_flag:
sig = limit(expr.args[0], z, z0, dir)
if sig.is_zero:
sig = limit(1/expr.args[0], z, z0, dir)
if sig.is_extended_real:
if (sig < 0) == True:
return (-expr.args[0] if abs_flag else
S.NegativeOne if sign_flag else S.Pi)
elif (sig > 0) == True:
return (expr.args[0] if abs_flag else
S.One if sign_flag else S.Zero)
return expr
if e.has(Float):
# Convert floats like 0.5 to exact SymPy numbers like S.Half, to
# prevent rounding errors which can lead to unexpected execution
# of conditional blocks that work on comparisons
# Also see comments in https://github.com/sympy/sympy/issues/19453
from sympy.simplify.simplify import nsimplify
e = nsimplify(e)
e = set_signs(e)
if e.is_meromorphic(z, z0):
if z0 is S.Infinity:
newe = e.subs(z, 1/z)
# cdir changes sign as oo- should become 0+
cdir = -cdir
else:
newe = e.subs(z, z + z0)
try:
coeff, ex = newe.leadterm(z, cdir=cdir)
except ValueError:
pass
else:
if ex > 0:
return S.Zero
elif ex == 0:
return coeff
if cdir == 1 or not(int(ex) & 1):
return S.Infinity*sign(coeff)
elif cdir == -1:
return S.NegativeInfinity*sign(coeff)
else:
return S.ComplexInfinity
if z0 is S.Infinity:
if e.is_Mul:
e = factor_terms(e)
newe = e.subs(z, 1/z)
# cdir changes sign as oo- should become 0+
cdir = -cdir
else:
newe = e.subs(z, z + z0)
try:
coeff, ex = newe.leadterm(z, cdir=cdir)
except (ValueError, NotImplementedError, PoleError):
# The NotImplementedError catching is for custom functions
from sympy.simplify.powsimp import powsimp
e = powsimp(e)
if e.is_Pow:
r = self.pow_heuristics(e)
if r is not None:
return r
try:
coeff = newe.as_leading_term(z, cdir=cdir)
if coeff != newe and (coeff.has(exp) or coeff.has(S.Exp1)):
return gruntz(coeff, z, 0, "-" if re(cdir).is_negative else "+")
except (ValueError, NotImplementedError, PoleError):
pass
else:
if isinstance(coeff, AccumBounds) and ex == S.Zero:
return coeff
if coeff.has(S.Infinity, S.NegativeInfinity, S.ComplexInfinity, S.NaN):
return self
if not coeff.has(z):
if ex.is_positive:
return S.Zero
elif ex == 0:
return coeff
elif ex.is_negative:
if cdir == 1:
return S.Infinity*sign(coeff)
elif cdir == -1:
return S.NegativeInfinity*sign(coeff)*S.NegativeOne**(S.One + ex)
else:
return S.ComplexInfinity
else:
raise NotImplementedError("Not sure of sign of %s" % ex)
# gruntz fails on factorials but works with the gamma function
# If no factorial term is present, e should remain unchanged.
# factorial is defined to be zero for negative inputs (which
# differs from gamma) so only rewrite for positive z0.
if z0.is_extended_positive:
e = e.rewrite(factorial, gamma)
l = None
try:
r = gruntz(e, z, z0, dir)
if r is S.NaN or l is S.NaN:
raise PoleError()
except (PoleError, ValueError):
if l is not None:
raise
r = heuristics(e, z, z0, dir)
if r is None:
return self
return r

View File

@ -0,0 +1,257 @@
"""Limits of sequences"""
from sympy.calculus.accumulationbounds import AccumulationBounds
from sympy.core.add import Add
from sympy.core.function import PoleError
from sympy.core.power import Pow
from sympy.core.singleton import S
from sympy.core.symbol import Dummy
from sympy.core.sympify import sympify
from sympy.functions.combinatorial.numbers import fibonacci
from sympy.functions.combinatorial.factorials import factorial, subfactorial
from sympy.functions.special.gamma_functions import gamma
from sympy.functions.elementary.complexes import Abs
from sympy.functions.elementary.miscellaneous import Max, Min
from sympy.functions.elementary.trigonometric import cos, sin
from sympy.series.limits import Limit
def difference_delta(expr, n=None, step=1):
"""Difference Operator.
Explanation
===========
Discrete analog of differential operator. Given a sequence x[n],
returns the sequence x[n + step] - x[n].
Examples
========
>>> from sympy import difference_delta as dd
>>> from sympy.abc import n
>>> dd(n*(n + 1), n)
2*n + 2
>>> dd(n*(n + 1), n, 2)
4*n + 6
References
==========
.. [1] https://reference.wolfram.com/language/ref/DifferenceDelta.html
"""
expr = sympify(expr)
if n is None:
f = expr.free_symbols
if len(f) == 1:
n = f.pop()
elif len(f) == 0:
return S.Zero
else:
raise ValueError("Since there is more than one variable in the"
" expression, a variable must be supplied to"
" take the difference of %s" % expr)
step = sympify(step)
if step.is_number is False or step.is_finite is False:
raise ValueError("Step should be a finite number.")
if hasattr(expr, '_eval_difference_delta'):
result = expr._eval_difference_delta(n, step)
if result:
return result
return expr.subs(n, n + step) - expr
def dominant(expr, n):
"""Finds the dominant term in a sum, that is a term that dominates
every other term.
Explanation
===========
If limit(a/b, n, oo) is oo then a dominates b.
If limit(a/b, n, oo) is 0 then b dominates a.
Otherwise, a and b are comparable.
If there is no unique dominant term, then returns ``None``.
Examples
========
>>> from sympy import Sum
>>> from sympy.series.limitseq import dominant
>>> from sympy.abc import n, k
>>> dominant(5*n**3 + 4*n**2 + n + 1, n)
5*n**3
>>> dominant(2**n + Sum(k, (k, 0, n)), n)
2**n
See Also
========
sympy.series.limitseq.dominant
"""
terms = Add.make_args(expr.expand(func=True))
term0 = terms[-1]
comp = [term0] # comparable terms
for t in terms[:-1]:
r = term0/t
e = r.gammasimp()
if e == r:
e = r.factor()
l = limit_seq(e, n)
if l is None:
return None
elif l.is_zero:
term0 = t
comp = [term0]
elif l not in [S.Infinity, S.NegativeInfinity]:
comp.append(t)
if len(comp) > 1:
return None
return term0
def _limit_inf(expr, n):
try:
return Limit(expr, n, S.Infinity).doit(deep=False)
except (NotImplementedError, PoleError):
return None
def _limit_seq(expr, n, trials):
from sympy.concrete.summations import Sum
for i in range(trials):
if not expr.has(Sum):
result = _limit_inf(expr, n)
if result is not None:
return result
num, den = expr.as_numer_denom()
if not den.has(n) or not num.has(n):
result = _limit_inf(expr.doit(), n)
if result is not None:
return result
return None
num, den = (difference_delta(t.expand(), n) for t in [num, den])
expr = (num / den).gammasimp()
if not expr.has(Sum):
result = _limit_inf(expr, n)
if result is not None:
return result
num, den = expr.as_numer_denom()
num = dominant(num, n)
if num is None:
return None
den = dominant(den, n)
if den is None:
return None
expr = (num / den).gammasimp()
def limit_seq(expr, n=None, trials=5):
"""Finds the limit of a sequence as index ``n`` tends to infinity.
Parameters
==========
expr : Expr
SymPy expression for the ``n-th`` term of the sequence
n : Symbol, optional
The index of the sequence, an integer that tends to positive
infinity. If None, inferred from the expression unless it has
multiple symbols.
trials: int, optional
The algorithm is highly recursive. ``trials`` is a safeguard from
infinite recursion in case the limit is not easily computed by the
algorithm. Try increasing ``trials`` if the algorithm returns ``None``.
Admissible Terms
================
The algorithm is designed for sequences built from rational functions,
indefinite sums, and indefinite products over an indeterminate n. Terms of
alternating sign are also allowed, but more complex oscillatory behavior is
not supported.
Examples
========
>>> from sympy import limit_seq, Sum, binomial
>>> from sympy.abc import n, k, m
>>> limit_seq((5*n**3 + 3*n**2 + 4) / (3*n**3 + 4*n - 5), n)
5/3
>>> limit_seq(binomial(2*n, n) / Sum(binomial(2*k, k), (k, 1, n)), n)
3/4
>>> limit_seq(Sum(k**2 * Sum(2**m/m, (m, 1, k)), (k, 1, n)) / (2**n*n), n)
4
See Also
========
sympy.series.limitseq.dominant
References
==========
.. [1] Computing Limits of Sequences - Manuel Kauers
"""
from sympy.concrete.summations import Sum
if n is None:
free = expr.free_symbols
if len(free) == 1:
n = free.pop()
elif not free:
return expr
else:
raise ValueError("Expression has more than one variable. "
"Please specify a variable.")
elif n not in expr.free_symbols:
return expr
expr = expr.rewrite(fibonacci, S.GoldenRatio)
expr = expr.rewrite(factorial, subfactorial, gamma)
n_ = Dummy("n", integer=True, positive=True)
n1 = Dummy("n", odd=True, positive=True)
n2 = Dummy("n", even=True, positive=True)
# If there is a negative term raised to a power involving n, or a
# trigonometric function, then consider even and odd n separately.
powers = (p.as_base_exp() for p in expr.atoms(Pow))
if (any(b.is_negative and e.has(n) for b, e in powers) or
expr.has(cos, sin)):
L1 = _limit_seq(expr.xreplace({n: n1}), n1, trials)
if L1 is not None:
L2 = _limit_seq(expr.xreplace({n: n2}), n2, trials)
if L1 != L2:
if L1.is_comparable and L2.is_comparable:
return AccumulationBounds(Min(L1, L2), Max(L1, L2))
else:
return None
else:
L1 = _limit_seq(expr.xreplace({n: n_}), n_, trials)
if L1 is not None:
return L1
else:
if expr.is_Add:
limits = [limit_seq(term, n, trials) for term in expr.args]
if any(result is None for result in limits):
return None
else:
return Add(*limits)
# Maybe the absolute value is easier to deal with (though not if
# it has a Sum). If it tends to 0, the limit is 0.
elif not expr.has(Sum):
lim = _limit_seq(Abs(expr.xreplace({n: n_})), n_, trials)
if lim is not None and lim.is_zero:
return S.Zero

View File

@ -0,0 +1,517 @@
from sympy.core import S, sympify, Expr, Dummy, Add, Mul
from sympy.core.cache import cacheit
from sympy.core.containers import Tuple
from sympy.core.function import Function, PoleError, expand_power_base, expand_log
from sympy.core.sorting import default_sort_key
from sympy.functions.elementary.exponential import exp, log
from sympy.sets.sets import Complement
from sympy.utilities.iterables import uniq, is_sequence
class Order(Expr):
r""" Represents the limiting behavior of some function.
Explanation
===========
The order of a function characterizes the function based on the limiting
behavior of the function as it goes to some limit. Only taking the limit
point to be a number is currently supported. This is expressed in
big O notation [1]_.
The formal definition for the order of a function `g(x)` about a point `a`
is such that `g(x) = O(f(x))` as `x \rightarrow a` if and only if there
exists a `\delta > 0` and an `M > 0` such that `|g(x)| \leq M|f(x)|` for
`|x-a| < \delta`. This is equivalent to `\limsup_{x \rightarrow a}
|g(x)/f(x)| < \infty`.
Let's illustrate it on the following example by taking the expansion of
`\sin(x)` about 0:
.. math ::
\sin(x) = x - x^3/3! + O(x^5)
where in this case `O(x^5) = x^5/5! - x^7/7! + \cdots`. By the definition
of `O`, there is a `\delta > 0` and an `M` such that:
.. math ::
|x^5/5! - x^7/7! + ....| <= M|x^5| \text{ for } |x| < \delta
or by the alternate definition:
.. math ::
\lim_{x \rightarrow 0} | (x^5/5! - x^7/7! + ....) / x^5| < \infty
which surely is true, because
.. math ::
\lim_{x \rightarrow 0} | (x^5/5! - x^7/7! + ....) / x^5| = 1/5!
As it is usually used, the order of a function can be intuitively thought
of representing all terms of powers greater than the one specified. For
example, `O(x^3)` corresponds to any terms proportional to `x^3,
x^4,\ldots` and any higher power. For a polynomial, this leaves terms
proportional to `x^2`, `x` and constants.
Examples
========
>>> from sympy import O, oo, cos, pi
>>> from sympy.abc import x, y
>>> O(x + x**2)
O(x)
>>> O(x + x**2, (x, 0))
O(x)
>>> O(x + x**2, (x, oo))
O(x**2, (x, oo))
>>> O(1 + x*y)
O(1, x, y)
>>> O(1 + x*y, (x, 0), (y, 0))
O(1, x, y)
>>> O(1 + x*y, (x, oo), (y, oo))
O(x*y, (x, oo), (y, oo))
>>> O(1) in O(1, x)
True
>>> O(1, x) in O(1)
False
>>> O(x) in O(1, x)
True
>>> O(x**2) in O(x)
True
>>> O(x)*x
O(x**2)
>>> O(x) - O(x)
O(x)
>>> O(cos(x))
O(1)
>>> O(cos(x), (x, pi/2))
O(x - pi/2, (x, pi/2))
References
==========
.. [1] `Big O notation <https://en.wikipedia.org/wiki/Big_O_notation>`_
Notes
=====
In ``O(f(x), x)`` the expression ``f(x)`` is assumed to have a leading
term. ``O(f(x), x)`` is automatically transformed to
``O(f(x).as_leading_term(x),x)``.
``O(expr*f(x), x)`` is ``O(f(x), x)``
``O(expr, x)`` is ``O(1)``
``O(0, x)`` is 0.
Multivariate O is also supported:
``O(f(x, y), x, y)`` is transformed to
``O(f(x, y).as_leading_term(x,y).as_leading_term(y), x, y)``
In the multivariate case, it is assumed the limits w.r.t. the various
symbols commute.
If no symbols are passed then all symbols in the expression are used
and the limit point is assumed to be zero.
"""
is_Order = True
__slots__ = ()
@cacheit
def __new__(cls, expr, *args, **kwargs):
expr = sympify(expr)
if not args:
if expr.is_Order:
variables = expr.variables
point = expr.point
else:
variables = list(expr.free_symbols)
point = [S.Zero]*len(variables)
else:
args = list(args if is_sequence(args) else [args])
variables, point = [], []
if is_sequence(args[0]):
for a in args:
v, p = list(map(sympify, a))
variables.append(v)
point.append(p)
else:
variables = list(map(sympify, args))
point = [S.Zero]*len(variables)
if not all(v.is_symbol for v in variables):
raise TypeError('Variables are not symbols, got %s' % variables)
if len(list(uniq(variables))) != len(variables):
raise ValueError('Variables are supposed to be unique symbols, got %s' % variables)
if expr.is_Order:
expr_vp = dict(expr.args[1:])
new_vp = dict(expr_vp)
vp = dict(zip(variables, point))
for v, p in vp.items():
if v in new_vp.keys():
if p != new_vp[v]:
raise NotImplementedError(
"Mixing Order at different points is not supported.")
else:
new_vp[v] = p
if set(expr_vp.keys()) == set(new_vp.keys()):
return expr
else:
variables = list(new_vp.keys())
point = [new_vp[v] for v in variables]
if expr is S.NaN:
return S.NaN
if any(x in p.free_symbols for x in variables for p in point):
raise ValueError('Got %s as a point.' % point)
if variables:
if any(p != point[0] for p in point):
raise NotImplementedError(
"Multivariable orders at different points are not supported.")
if point[0] in (S.Infinity, S.Infinity*S.ImaginaryUnit):
s = {k: 1/Dummy() for k in variables}
rs = {1/v: 1/k for k, v in s.items()}
ps = [S.Zero for p in point]
elif point[0] in (S.NegativeInfinity, S.NegativeInfinity*S.ImaginaryUnit):
s = {k: -1/Dummy() for k in variables}
rs = {-1/v: -1/k for k, v in s.items()}
ps = [S.Zero for p in point]
elif point[0] is not S.Zero:
s = {k: Dummy() + point[0] for k in variables}
rs = {(v - point[0]).together(): k - point[0] for k, v in s.items()}
ps = [S.Zero for p in point]
else:
s = ()
rs = ()
ps = list(point)
expr = expr.subs(s)
if expr.is_Add:
expr = expr.factor()
if s:
args = tuple([r[0] for r in rs.items()])
else:
args = tuple(variables)
if len(variables) > 1:
# XXX: better way? We need this expand() to
# workaround e.g: expr = x*(x + y).
# (x*(x + y)).as_leading_term(x, y) currently returns
# x*y (wrong order term!). That's why we want to deal with
# expand()'ed expr (handled in "if expr.is_Add" branch below).
expr = expr.expand()
old_expr = None
while old_expr != expr:
old_expr = expr
if expr.is_Add:
lst = expr.extract_leading_order(args)
expr = Add(*[f.expr for (e, f) in lst])
elif expr:
try:
expr = expr.as_leading_term(*args)
except PoleError:
if isinstance(expr, Function) or\
all(isinstance(arg, Function) for arg in expr.args):
# It is not possible to simplify an expression
# containing only functions (which raise error on
# call to leading term) further
pass
else:
orders = []
pts = tuple(zip(args, ps))
for arg in expr.args:
try:
lt = arg.as_leading_term(*args)
except PoleError:
lt = arg
if lt not in args:
order = Order(lt)
else:
order = Order(lt, *pts)
orders.append(order)
if expr.is_Add:
new_expr = Order(Add(*orders), *pts)
if new_expr.is_Add:
new_expr = Order(Add(*[a.expr for a in new_expr.args]), *pts)
expr = new_expr.expr
elif expr.is_Mul:
expr = Mul(*[a.expr for a in orders])
elif expr.is_Pow:
e = expr.exp
b = expr.base
expr = exp(e * log(b))
# It would probably be better to handle this somewhere
# else. This is needed for a testcase in which there is a
# symbol with the assumptions zero=True.
if expr.is_zero:
expr = S.Zero
else:
expr = expr.as_independent(*args, as_Add=False)[1]
expr = expand_power_base(expr)
expr = expand_log(expr)
if len(args) == 1:
# The definition of O(f(x)) symbol explicitly stated that
# the argument of f(x) is irrelevant. That's why we can
# combine some power exponents (only "on top" of the
# expression tree for f(x)), e.g.:
# x**p * (-x)**q -> x**(p+q) for real p, q.
x = args[0]
margs = list(Mul.make_args(
expr.as_independent(x, as_Add=False)[1]))
for i, t in enumerate(margs):
if t.is_Pow:
b, q = t.args
if b in (x, -x) and q.is_real and not q.has(x):
margs[i] = x**q
elif b.is_Pow and not b.exp.has(x):
b, r = b.args
if b in (x, -x) and r.is_real:
margs[i] = x**(r*q)
elif b.is_Mul and b.args[0] is S.NegativeOne:
b = -b
if b.is_Pow and not b.exp.has(x):
b, r = b.args
if b in (x, -x) and r.is_real:
margs[i] = x**(r*q)
expr = Mul(*margs)
expr = expr.subs(rs)
if expr.is_Order:
expr = expr.expr
if not expr.has(*variables) and not expr.is_zero:
expr = S.One
# create Order instance:
vp = dict(zip(variables, point))
variables.sort(key=default_sort_key)
point = [vp[v] for v in variables]
args = (expr,) + Tuple(*zip(variables, point))
obj = Expr.__new__(cls, *args)
return obj
def _eval_nseries(self, x, n, logx, cdir=0):
return self
@property
def expr(self):
return self.args[0]
@property
def variables(self):
if self.args[1:]:
return tuple(x[0] for x in self.args[1:])
else:
return ()
@property
def point(self):
if self.args[1:]:
return tuple(x[1] for x in self.args[1:])
else:
return ()
@property
def free_symbols(self):
return self.expr.free_symbols | set(self.variables)
def _eval_power(b, e):
if e.is_Number and e.is_nonnegative:
return b.func(b.expr ** e, *b.args[1:])
if e == O(1):
return b
return
def as_expr_variables(self, order_symbols):
if order_symbols is None:
order_symbols = self.args[1:]
else:
if (not all(o[1] == order_symbols[0][1] for o in order_symbols) and
not all(p == self.point[0] for p in self.point)): # pragma: no cover
raise NotImplementedError('Order at points other than 0 '
'or oo not supported, got %s as a point.' % self.point)
if order_symbols and order_symbols[0][1] != self.point[0]:
raise NotImplementedError(
"Multiplying Order at different points is not supported.")
order_symbols = dict(order_symbols)
for s, p in dict(self.args[1:]).items():
if s not in order_symbols.keys():
order_symbols[s] = p
order_symbols = sorted(order_symbols.items(), key=lambda x: default_sort_key(x[0]))
return self.expr, tuple(order_symbols)
def removeO(self):
return S.Zero
def getO(self):
return self
@cacheit
def contains(self, expr):
r"""
Return True if expr belongs to Order(self.expr, \*self.variables).
Return False if self belongs to expr.
Return None if the inclusion relation cannot be determined
(e.g. when self and expr have different symbols).
"""
expr = sympify(expr)
if expr.is_zero:
return True
if expr is S.NaN:
return False
point = self.point[0] if self.point else S.Zero
if expr.is_Order:
if (any(p != point for p in expr.point) or
any(p != point for p in self.point)):
return None
if expr.expr == self.expr:
# O(1) + O(1), O(1) + O(1, x), etc.
return all(x in self.args[1:] for x in expr.args[1:])
if expr.expr.is_Add:
return all(self.contains(x) for x in expr.expr.args)
if self.expr.is_Add and point.is_zero:
return any(self.func(x, *self.args[1:]).contains(expr)
for x in self.expr.args)
if self.variables and expr.variables:
common_symbols = tuple(
[s for s in self.variables if s in expr.variables])
elif self.variables:
common_symbols = self.variables
else:
common_symbols = expr.variables
if not common_symbols:
return None
if (self.expr.is_Pow and len(self.variables) == 1
and self.variables == expr.variables):
symbol = self.variables[0]
other = expr.expr.as_independent(symbol, as_Add=False)[1]
if (other.is_Pow and other.base == symbol and
self.expr.base == symbol):
if point.is_zero:
rv = (self.expr.exp - other.exp).is_nonpositive
if point.is_infinite:
rv = (self.expr.exp - other.exp).is_nonnegative
if rv is not None:
return rv
from sympy.simplify.powsimp import powsimp
r = None
ratio = self.expr/expr.expr
ratio = powsimp(ratio, deep=True, combine='exp')
for s in common_symbols:
from sympy.series.limits import Limit
l = Limit(ratio, s, point).doit(heuristics=False)
if not isinstance(l, Limit):
l = l != 0
else:
l = None
if r is None:
r = l
else:
if r != l:
return
return r
if self.expr.is_Pow and len(self.variables) == 1:
symbol = self.variables[0]
other = expr.as_independent(symbol, as_Add=False)[1]
if (other.is_Pow and other.base == symbol and
self.expr.base == symbol):
if point.is_zero:
rv = (self.expr.exp - other.exp).is_nonpositive
if point.is_infinite:
rv = (self.expr.exp - other.exp).is_nonnegative
if rv is not None:
return rv
obj = self.func(expr, *self.args[1:])
return self.contains(obj)
def __contains__(self, other):
result = self.contains(other)
if result is None:
raise TypeError('contains did not evaluate to a bool')
return result
def _eval_subs(self, old, new):
if old in self.variables:
newexpr = self.expr.subs(old, new)
i = self.variables.index(old)
newvars = list(self.variables)
newpt = list(self.point)
if new.is_symbol:
newvars[i] = new
else:
syms = new.free_symbols
if len(syms) == 1 or old in syms:
if old in syms:
var = self.variables[i]
else:
var = syms.pop()
# First, try to substitute self.point in the "new"
# expr to see if this is a fixed point.
# E.g. O(y).subs(y, sin(x))
point = new.subs(var, self.point[i])
if point != self.point[i]:
from sympy.solvers.solveset import solveset
d = Dummy()
sol = solveset(old - new.subs(var, d), d)
if isinstance(sol, Complement):
e1 = sol.args[0]
e2 = sol.args[1]
sol = set(e1) - set(e2)
res = [dict(zip((d, ), sol))]
point = d.subs(res[0]).limit(old, self.point[i])
newvars[i] = var
newpt[i] = point
elif old not in syms:
del newvars[i], newpt[i]
if not syms and new == self.point[i]:
newvars.extend(syms)
newpt.extend([S.Zero]*len(syms))
else:
return
return Order(newexpr, *zip(newvars, newpt))
def _eval_conjugate(self):
expr = self.expr._eval_conjugate()
if expr is not None:
return self.func(expr, *self.args[1:])
def _eval_derivative(self, x):
return self.func(self.expr.diff(x), *self.args[1:]) or self
def _eval_transpose(self):
expr = self.expr._eval_transpose()
if expr is not None:
return self.func(expr, *self.args[1:])
def __neg__(self):
return self
O = Order

View File

@ -0,0 +1,73 @@
"""
This module implements the Residue function and related tools for working
with residues.
"""
from sympy.core.mul import Mul
from sympy.core.singleton import S
from sympy.core.sympify import sympify
from sympy.utilities.timeutils import timethis
@timethis('residue')
def residue(expr, x, x0):
"""
Finds the residue of ``expr`` at the point x=x0.
The residue is defined as the coefficient of ``1/(x-x0)`` in the power series
expansion about ``x=x0``.
Examples
========
>>> from sympy import Symbol, residue, sin
>>> x = Symbol("x")
>>> residue(1/x, x, 0)
1
>>> residue(1/x**2, x, 0)
0
>>> residue(2/sin(x), x, 0)
2
This function is essential for the Residue Theorem [1].
References
==========
.. [1] https://en.wikipedia.org/wiki/Residue_theorem
"""
# The current implementation uses series expansion to
# calculate it. A more general implementation is explained in
# the section 5.6 of the Bronstein's book {M. Bronstein:
# Symbolic Integration I, Springer Verlag (2005)}. For purely
# rational functions, the algorithm is much easier. See
# sections 2.4, 2.5, and 2.7 (this section actually gives an
# algorithm for computing any Laurent series coefficient for
# a rational function). The theory in section 2.4 will help to
# understand why the resultant works in the general algorithm.
# For the definition of a resultant, see section 1.4 (and any
# previous sections for more review).
from sympy.series.order import Order
from sympy.simplify.radsimp import collect
expr = sympify(expr)
if x0 != 0:
expr = expr.subs(x, x + x0)
for n in (0, 1, 2, 4, 8, 16, 32):
s = expr.nseries(x, n=n)
if not s.has(Order) or s.getn() >= 0:
break
s = collect(s.removeO(), x)
if s.is_Add:
args = s.args
else:
args = [s]
res = S.Zero
for arg in args:
c, m = arg.as_coeff_mul(x)
m = Mul(*m)
if not (m in (S.One, x) or (m.is_Pow and m.exp.is_Integer)):
raise NotImplementedError('term of unexpected form: %s' % m)
if m == 1/x:
res += c
return res

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,63 @@
from sympy.core.sympify import sympify
def series(expr, x=None, x0=0, n=6, dir="+"):
"""Series expansion of expr around point `x = x0`.
Parameters
==========
expr : Expression
The expression whose series is to be expanded.
x : Symbol
It is the variable of the expression to be calculated.
x0 : Value
The value around which ``x`` is calculated. Can be any value
from ``-oo`` to ``oo``.
n : Value
The number of terms upto which the series is to be expanded.
dir : String, optional
The series-expansion can be bi-directional. If ``dir="+"``,
then (x->x0+). If ``dir="-"``, then (x->x0-). For infinite
``x0`` (``oo`` or ``-oo``), the ``dir`` argument is determined
from the direction of the infinity (i.e., ``dir="-"`` for
``oo``).
Examples
========
>>> from sympy import series, tan, oo
>>> from sympy.abc import x
>>> f = tan(x)
>>> series(f, x, 2, 6, "+")
tan(2) + (1 + tan(2)**2)*(x - 2) + (x - 2)**2*(tan(2)**3 + tan(2)) +
(x - 2)**3*(1/3 + 4*tan(2)**2/3 + tan(2)**4) + (x - 2)**4*(tan(2)**5 +
5*tan(2)**3/3 + 2*tan(2)/3) + (x - 2)**5*(2/15 + 17*tan(2)**2/15 +
2*tan(2)**4 + tan(2)**6) + O((x - 2)**6, (x, 2))
>>> series(f, x, 2, 3, "-")
tan(2) + (2 - x)*(-tan(2)**2 - 1) + (2 - x)**2*(tan(2)**3 + tan(2))
+ O((x - 2)**3, (x, 2))
>>> series(f, x, 2, oo, "+")
Traceback (most recent call last):
...
TypeError: 'Infinity' object cannot be interpreted as an integer
Returns
=======
Expr
Series expansion of the expression about x0
See Also
========
sympy.core.expr.Expr.series: See the docstring of Expr.series() for complete details of this wrapper.
"""
expr = sympify(expr)
return expr.series(x, x0, n, dir)

View File

@ -0,0 +1,99 @@
"""
Contains the base class for series
Made using sequences in mind
"""
from sympy.core.expr import Expr
from sympy.core.singleton import S
from sympy.core.cache import cacheit
class SeriesBase(Expr):
"""Base Class for series"""
@property
def interval(self):
"""The interval on which the series is defined"""
raise NotImplementedError("(%s).interval" % self)
@property
def start(self):
"""The starting point of the series. This point is included"""
raise NotImplementedError("(%s).start" % self)
@property
def stop(self):
"""The ending point of the series. This point is included"""
raise NotImplementedError("(%s).stop" % self)
@property
def length(self):
"""Length of the series expansion"""
raise NotImplementedError("(%s).length" % self)
@property
def variables(self):
"""Returns a tuple of variables that are bounded"""
return ()
@property
def free_symbols(self):
"""
This method returns the symbols in the object, excluding those
that take on a specific value (i.e. the dummy symbols).
"""
return ({j for i in self.args for j in i.free_symbols}
.difference(self.variables))
@cacheit
def term(self, pt):
"""Term at point pt of a series"""
if pt < self.start or pt > self.stop:
raise IndexError("Index %s out of bounds %s" % (pt, self.interval))
return self._eval_term(pt)
def _eval_term(self, pt):
raise NotImplementedError("The _eval_term method should be added to"
"%s to return series term so it is available"
"when 'term' calls it."
% self.func)
def _ith_point(self, i):
"""
Returns the i'th point of a series
If start point is negative infinity, point is returned from the end.
Assumes the first point to be indexed zero.
Examples
========
TODO
"""
if self.start is S.NegativeInfinity:
initial = self.stop
step = -1
else:
initial = self.start
step = 1
return initial + i*step
def __iter__(self):
i = 0
while i < self.length:
pt = self._ith_point(i)
yield self.term(pt)
i += 1
def __getitem__(self, index):
if isinstance(index, int):
index = self._ith_point(index)
return self.term(index)
elif isinstance(index, slice):
start, stop = index.start, index.stop
if start is None:
start = 0
if stop is None:
stop = self.length
return [self.term(self._ith_point(i)) for i in
range(start, stop, index.step or 1)]

View File

@ -0,0 +1,23 @@
from sympy.series import approximants
from sympy.core.symbol import symbols
from sympy.functions.combinatorial.factorials import binomial
from sympy.functions.combinatorial.numbers import (fibonacci, lucas)
def test_approximants():
x, t = symbols("x,t")
g = [lucas(k) for k in range(16)]
assert list(approximants(g)) == (
[2, -4/(x - 2), (5*x - 2)/(3*x - 1), (x - 2)/(x**2 + x - 1)] )
g = [lucas(k)+fibonacci(k+2) for k in range(16)]
assert list(approximants(g)) == (
[3, -3/(x - 1), (3*x - 3)/(2*x - 1), -3/(x**2 + x - 1)] )
g = [lucas(k)**2 for k in range(16)]
assert list(approximants(g)) == (
[4, -16/(x - 4), (35*x - 4)/(9*x - 1), (37*x - 28)/(13*x**2 + 11*x - 7),
(50*x**2 + 63*x - 52)/(37*x**2 + 19*x - 13),
(-x**2 - 7*x + 4)/(x**3 - 2*x**2 - 2*x + 1)] )
p = [sum(binomial(k,i)*x**i for i in range(k+1)) for k in range(16)]
y = approximants(p, t, simplify=True)
assert next(y) == 1
assert next(y) == -1/(t*(x + 1) - 1)

View File

@ -0,0 +1,56 @@
from sympy.core.function import PoleError
from sympy.core.numbers import oo
from sympy.core.singleton import S
from sympy.core.symbol import Symbol
from sympy.functions.elementary.exponential import (exp, log)
from sympy.functions.elementary.miscellaneous import sqrt
from sympy.functions.elementary.trigonometric import (cos, sin)
from sympy.series.order import O
from sympy.abc import x
from sympy.testing.pytest import raises
def test_simple():
# Gruntz' theses pp. 91 to 96
# 6.6
e = sin(1/x + exp(-x)) - sin(1/x)
assert e.aseries(x) == (1/(24*x**4) - 1/(2*x**2) + 1 + O(x**(-6), (x, oo)))*exp(-x)
e = exp(x) * (exp(1/x + exp(-x)) - exp(1/x))
assert e.aseries(x, n=4) == 1/(6*x**3) + 1/(2*x**2) + 1/x + 1 + O(x**(-4), (x, oo))
e = exp(exp(x) / (1 - 1/x))
assert e.aseries(x) == exp(exp(x) / (1 - 1/x))
# The implementation of bound in aseries is incorrect currently. This test
# should be commented out when that is fixed.
# assert e.aseries(x, bound=3) == exp(exp(x) / x**2)*exp(exp(x) / x)*exp(-exp(x) + exp(x)/(1 - 1/x) - \
# exp(x) / x - exp(x) / x**2) * exp(exp(x))
e = exp(sin(1/x + exp(-exp(x)))) - exp(sin(1/x))
assert e.aseries(x, n=4) == (-1/(2*x**3) + 1/x + 1 + O(x**(-4), (x, oo)))*exp(-exp(x))
e3 = lambda x:exp(exp(exp(x)))
e = e3(x)/e3(x - 1/e3(x))
assert e.aseries(x, n=3) == 1 + exp(x + exp(x))*exp(-exp(exp(x)))\
+ ((-exp(x)/2 - S.Half)*exp(x + exp(x))\
+ exp(2*x + 2*exp(x))/2)*exp(-2*exp(exp(x))) + O(exp(-3*exp(exp(x))), (x, oo))
e = exp(exp(x)) * (exp(sin(1/x + 1/exp(exp(x)))) - exp(sin(1/x)))
assert e.aseries(x, n=4) == -1/(2*x**3) + 1/x + 1 + O(x**(-4), (x, oo))
n = Symbol('n', integer=True)
e = (sqrt(n)*log(n)**2*exp(sqrt(log(n))*log(log(n))**2*exp(sqrt(log(log(n)))*log(log(log(n)))**3)))/n
assert e.aseries(n) == \
exp(exp(sqrt(log(log(n)))*log(log(log(n)))**3)*sqrt(log(n))*log(log(n))**2)*log(n)**2/sqrt(n)
def test_hierarchical():
e = sin(1/x + exp(-x))
assert e.aseries(x, n=3, hir=True) == -exp(-2*x)*sin(1/x)/2 + \
exp(-x)*cos(1/x) + sin(1/x) + O(exp(-3*x), (x, oo))
e = sin(x) * cos(exp(-x))
assert e.aseries(x, hir=True) == exp(-4*x)*sin(x)/24 - \
exp(-2*x)*sin(x)/2 + sin(x) + O(exp(-6*x), (x, oo))
raises(PoleError, lambda: e.aseries(x))

View File

@ -0,0 +1,143 @@
from sympy.core.numbers import (Rational, oo, pi)
from sympy.core.singleton import S
from sympy.core.symbol import Symbol
from sympy.functions.elementary.exponential import (exp, log)
from sympy.functions.elementary.miscellaneous import (root, sqrt)
from sympy.functions.elementary.trigonometric import (asin, cos, sin, tan)
from sympy.polys.rationaltools import together
from sympy.series.limits import limit
# Numbers listed with the tests refer to problem numbers in the book
# "Anti-demidovich, problemas resueltos, Ed. URSS"
x = Symbol("x")
def test_leadterm():
assert (3 + 2*x**(log(3)/log(2) - 1)).leadterm(x) == (3, 0)
def root3(x):
return root(x, 3)
def root4(x):
return root(x, 4)
def test_Limits_simple_0():
assert limit((2**(x + 1) + 3**(x + 1))/(2**x + 3**x), x, oo) == 3 # 175
def test_Limits_simple_1():
assert limit((x + 1)*(x + 2)*(x + 3)/x**3, x, oo) == 1 # 172
assert limit(sqrt(x + 1) - sqrt(x), x, oo) == 0 # 179
assert limit((2*x - 3)*(3*x + 5)*(4*x - 6)/(3*x**3 + x - 1), x, oo) == 8 # Primjer 1
assert limit(x/root3(x**3 + 10), x, oo) == 1 # Primjer 2
assert limit((x + 1)**2/(x**2 + 1), x, oo) == 1 # 181
def test_Limits_simple_2():
assert limit(1000*x/(x**2 - 1), x, oo) == 0 # 182
assert limit((x**2 - 5*x + 1)/(3*x + 7), x, oo) is oo # 183
assert limit((2*x**2 - x + 3)/(x**3 - 8*x + 5), x, oo) == 0 # 184
assert limit((2*x**2 - 3*x - 4)/sqrt(x**4 + 1), x, oo) == 2 # 186
assert limit((2*x + 3)/(x + root3(x)), x, oo) == 2 # 187
assert limit(x**2/(10 + x*sqrt(x)), x, oo) is oo # 188
assert limit(root3(x**2 + 1)/(x + 1), x, oo) == 0 # 189
assert limit(sqrt(x)/sqrt(x + sqrt(x + sqrt(x))), x, oo) == 1 # 190
def test_Limits_simple_3a():
a = Symbol('a')
#issue 3513
assert together(limit((x**2 - (a + 1)*x + a)/(x**3 - a**3), x, a)) == \
(a - 1)/(3*a**2) # 196
def test_Limits_simple_3b():
h = Symbol("h")
assert limit(((x + h)**3 - x**3)/h, h, 0) == 3*x**2 # 197
assert limit((1/(1 - x) - 3/(1 - x**3)), x, 1) == -1 # 198
assert limit((sqrt(1 + x) - 1)/(root3(1 + x) - 1), x, 0) == Rational(3)/2 # Primer 4
assert limit((sqrt(x) - 1)/(x - 1), x, 1) == Rational(1)/2 # 199
assert limit((sqrt(x) - 8)/(root3(x) - 4), x, 64) == 3 # 200
assert limit((root3(x) - 1)/(root4(x) - 1), x, 1) == Rational(4)/3 # 201
assert limit(
(root3(x**2) - 2*root3(x) + 1)/(x - 1)**2, x, 1) == Rational(1)/9 # 202
def test_Limits_simple_4a():
a = Symbol('a')
assert limit((sqrt(x) - sqrt(a))/(x - a), x, a) == 1/(2*sqrt(a)) # Primer 5
assert limit((sqrt(x) - 1)/(root3(x) - 1), x, 1) == Rational(3, 2) # 205
assert limit((sqrt(1 + x) - sqrt(1 - x))/x, x, 0) == 1 # 207
assert limit(sqrt(x**2 - 5*x + 6) - x, x, oo) == Rational(-5, 2) # 213
def test_limits_simple_4aa():
assert limit(x*(sqrt(x**2 + 1) - x), x, oo) == Rational(1)/2 # 214
def test_Limits_simple_4b():
#issue 3511
assert limit(x - root3(x**3 - 1), x, oo) == 0 # 215
def test_Limits_simple_4c():
assert limit(log(1 + exp(x))/x, x, -oo) == 0 # 267a
assert limit(log(1 + exp(x))/x, x, oo) == 1 # 267b
def test_bounded():
assert limit(sin(x)/x, x, oo) == 0 # 216b
assert limit(x*sin(1/x), x, 0) == 0 # 227a
def test_f1a():
#issue 3508:
assert limit((sin(2*x)/x)**(1 + x), x, 0) == 2 # Primer 7
def test_f1a2():
#issue 3509:
assert limit(((x - 1)/(x + 1))**x, x, oo) == exp(-2) # Primer 9
def test_f1b():
m = Symbol("m")
n = Symbol("n")
h = Symbol("h")
a = Symbol("a")
assert limit(sin(x)/x, x, 2) == sin(2)/2 # 216a
assert limit(sin(3*x)/x, x, 0) == 3 # 217
assert limit(sin(5*x)/sin(2*x), x, 0) == Rational(5, 2) # 218
assert limit(sin(pi*x)/sin(3*pi*x), x, 0) == Rational(1, 3) # 219
assert limit(x*sin(pi/x), x, oo) == pi # 220
assert limit((1 - cos(x))/x**2, x, 0) == S.Half # 221
assert limit(x*sin(1/x), x, oo) == 1 # 227b
assert limit((cos(m*x) - cos(n*x))/x**2, x, 0) == -m**2/2 + n**2/2 # 232
assert limit((tan(x) - sin(x))/x**3, x, 0) == S.Half # 233
assert limit((x - sin(2*x))/(x + sin(3*x)), x, 0) == -Rational(1, 4) # 237
assert limit((1 - sqrt(cos(x)))/x**2, x, 0) == Rational(1, 4) # 239
assert limit((sqrt(1 + sin(x)) - sqrt(1 - sin(x)))/x, x, 0) == 1 # 240
assert limit((1 + h/x)**x, x, oo) == exp(h) # Primer 9
assert limit((sin(x) - sin(a))/(x - a), x, a) == cos(a) # 222, *176
assert limit((cos(x) - cos(a))/(x - a), x, a) == -sin(a) # 223
assert limit((sin(x + h) - sin(x))/h, h, 0) == cos(x) # 225
def test_f2a():
assert limit(((x + 1)/(2*x + 1))**(x**2), x, oo) == 0 # Primer 8
def test_f2():
assert limit((sqrt(
cos(x)) - root3(cos(x)))/(sin(x)**2), x, 0) == -Rational(1, 12) # *184
def test_f3():
a = Symbol('a')
#issue 3504
assert limit(asin(a*x)/x, x, 0) == a

View File

@ -0,0 +1,618 @@
from sympy.concrete.summations import Sum
from sympy.core.add import Add
from sympy.core.function import (Derivative, Function)
from sympy.core.mul import Mul
from sympy.core.numbers import (I, Rational, oo, pi)
from sympy.core.singleton import S
from sympy.core.symbol import symbols
from sympy.functions.combinatorial.factorials import factorial
from sympy.functions.elementary.exponential import (exp, log)
from sympy.functions.elementary.hyperbolic import (acosh, asech)
from sympy.functions.elementary.miscellaneous import sqrt
from sympy.functions.elementary.trigonometric import (acos, asin, atan, cos, sin)
from sympy.functions.special.bessel import airyai
from sympy.functions.special.error_functions import erf
from sympy.functions.special.gamma_functions import gamma
from sympy.integrals.integrals import integrate
from sympy.series.formal import fps
from sympy.series.order import O
from sympy.series.formal import (rational_algorithm, FormalPowerSeries,
FormalPowerSeriesProduct, FormalPowerSeriesCompose,
FormalPowerSeriesInverse, simpleDE,
rational_independent, exp_re, hyper_re)
from sympy.testing.pytest import raises, XFAIL, slow
x, y, z = symbols('x y z')
n, m, k = symbols('n m k', integer=True)
f, r = Function('f'), Function('r')
def test_rational_algorithm():
f = 1 / ((x - 1)**2 * (x - 2))
assert rational_algorithm(f, x, k) == \
(-2**(-k - 1) + 1 - (factorial(k + 1) / factorial(k)), 0, 0)
f = (1 + x + x**2 + x**3) / ((x - 1) * (x - 2))
assert rational_algorithm(f, x, k) == \
(-15*2**(-k - 1) + 4, x + 4, 0)
f = z / (y*m - m*x - y*x + x**2)
assert rational_algorithm(f, x, k) == \
(((-y**(-k - 1)*z) / (y - m)) + ((m**(-k - 1)*z) / (y - m)), 0, 0)
f = x / (1 - x - x**2)
assert rational_algorithm(f, x, k) is None
assert rational_algorithm(f, x, k, full=True) == \
(((Rational(-1, 2) + sqrt(5)/2)**(-k - 1) *
(-sqrt(5)/10 + S.Half)) +
((-sqrt(5)/2 - S.Half)**(-k - 1) *
(sqrt(5)/10 + S.Half)), 0, 0)
f = 1 / (x**2 + 2*x + 2)
assert rational_algorithm(f, x, k) is None
assert rational_algorithm(f, x, k, full=True) == \
((I*(-1 + I)**(-k - 1)) / 2 - (I*(-1 - I)**(-k - 1)) / 2, 0, 0)
f = log(1 + x)
assert rational_algorithm(f, x, k) == \
(-(-1)**(-k) / k, 0, 1)
f = atan(x)
assert rational_algorithm(f, x, k) is None
assert rational_algorithm(f, x, k, full=True) == \
(((I*I**(-k)) / 2 - (I*(-I)**(-k)) / 2) / k, 0, 1)
f = x*atan(x) - log(1 + x**2) / 2
assert rational_algorithm(f, x, k) is None
assert rational_algorithm(f, x, k, full=True) == \
(((I*I**(-k + 1)) / 2 - (I*(-I)**(-k + 1)) / 2) /
(k*(k - 1)), 0, 2)
f = log((1 + x) / (1 - x)) / 2 - atan(x)
assert rational_algorithm(f, x, k) is None
assert rational_algorithm(f, x, k, full=True) == \
((-(-1)**(-k) / 2 - (I*I**(-k)) / 2 + (I*(-I)**(-k)) / 2 +
S.Half) / k, 0, 1)
assert rational_algorithm(cos(x), x, k) is None
def test_rational_independent():
ri = rational_independent
assert ri([], x) == []
assert ri([cos(x), sin(x)], x) == [cos(x), sin(x)]
assert ri([x**2, sin(x), x*sin(x), x**3], x) == \
[x**3 + x**2, x*sin(x) + sin(x)]
assert ri([S.One, x*log(x), log(x), sin(x)/x, cos(x), sin(x), x], x) == \
[x + 1, x*log(x) + log(x), sin(x)/x + sin(x), cos(x)]
def test_simpleDE():
# Tests just the first valid DE
for DE in simpleDE(exp(x), x, f):
assert DE == (-f(x) + Derivative(f(x), x), 1)
break
for DE in simpleDE(sin(x), x, f):
assert DE == (f(x) + Derivative(f(x), x, x), 2)
break
for DE in simpleDE(log(1 + x), x, f):
assert DE == ((x + 1)*Derivative(f(x), x, 2) + Derivative(f(x), x), 2)
break
for DE in simpleDE(asin(x), x, f):
assert DE == (x*Derivative(f(x), x) + (x**2 - 1)*Derivative(f(x), x, x),
2)
break
for DE in simpleDE(exp(x)*sin(x), x, f):
assert DE == (2*f(x) - 2*Derivative(f(x)) + Derivative(f(x), x, x), 2)
break
for DE in simpleDE(((1 + x)/(1 - x))**n, x, f):
assert DE == (2*n*f(x) + (x**2 - 1)*Derivative(f(x), x), 1)
break
for DE in simpleDE(airyai(x), x, f):
assert DE == (-x*f(x) + Derivative(f(x), x, x), 2)
break
def test_exp_re():
d = -f(x) + Derivative(f(x), x)
assert exp_re(d, r, k) == -r(k) + r(k + 1)
d = f(x) + Derivative(f(x), x, x)
assert exp_re(d, r, k) == r(k) + r(k + 2)
d = f(x) + Derivative(f(x), x) + Derivative(f(x), x, x)
assert exp_re(d, r, k) == r(k) + r(k + 1) + r(k + 2)
d = Derivative(f(x), x) + Derivative(f(x), x, x)
assert exp_re(d, r, k) == r(k) + r(k + 1)
d = Derivative(f(x), x, 3) + Derivative(f(x), x, 4) + Derivative(f(x))
assert exp_re(d, r, k) == r(k) + r(k + 2) + r(k + 3)
def test_hyper_re():
d = f(x) + Derivative(f(x), x, x)
assert hyper_re(d, r, k) == r(k) + (k+1)*(k+2)*r(k + 2)
d = -x*f(x) + Derivative(f(x), x, x)
assert hyper_re(d, r, k) == (k + 2)*(k + 3)*r(k + 3) - r(k)
d = 2*f(x) - 2*Derivative(f(x), x) + Derivative(f(x), x, x)
assert hyper_re(d, r, k) == \
(-2*k - 2)*r(k + 1) + (k + 1)*(k + 2)*r(k + 2) + 2*r(k)
d = 2*n*f(x) + (x**2 - 1)*Derivative(f(x), x)
assert hyper_re(d, r, k) == \
k*r(k) + 2*n*r(k + 1) + (-k - 2)*r(k + 2)
d = (x**10 + 4)*Derivative(f(x), x) + x*(x**10 - 1)*Derivative(f(x), x, x)
assert hyper_re(d, r, k) == \
(k*(k - 1) + k)*r(k) + (4*k - (k + 9)*(k + 10) + 40)*r(k + 10)
d = ((x**2 - 1)*Derivative(f(x), x, 3) + 3*x*Derivative(f(x), x, x) +
Derivative(f(x), x))
assert hyper_re(d, r, k) == \
((k*(k - 2)*(k - 1) + 3*k*(k - 1) + k)*r(k) +
(-k*(k + 1)*(k + 2))*r(k + 2))
def test_fps():
assert fps(1) == 1
assert fps(2, x) == 2
assert fps(2, x, dir='+') == 2
assert fps(2, x, dir='-') == 2
assert fps(1/x + 1/x**2) == 1/x + 1/x**2
assert fps(log(1 + x), hyper=False, rational=False) == log(1 + x)
f = fps(x**2 + x + 1)
assert isinstance(f, FormalPowerSeries)
assert f.function == x**2 + x + 1
assert f[0] == 1
assert f[2] == x**2
assert f.truncate(4) == x**2 + x + 1 + O(x**4)
assert f.polynomial() == x**2 + x + 1
f = fps(log(1 + x))
assert isinstance(f, FormalPowerSeries)
assert f.function == log(1 + x)
assert f.subs(x, y) == f
assert f[:5] == [0, x, -x**2/2, x**3/3, -x**4/4]
assert f.as_leading_term(x) == x
assert f.polynomial(6) == x - x**2/2 + x**3/3 - x**4/4 + x**5/5
k = f.ak.variables[0]
assert f.infinite == Sum((-(-1)**(-k)*x**k)/k, (k, 1, oo))
ft, s = f.truncate(n=None), f[:5]
for i, t in enumerate(ft):
if i == 5:
break
assert s[i] == t
f = sin(x).fps(x)
assert isinstance(f, FormalPowerSeries)
assert f.truncate() == x - x**3/6 + x**5/120 + O(x**6)
raises(NotImplementedError, lambda: fps(y*x))
raises(ValueError, lambda: fps(x, dir=0))
@slow
def test_fps__rational():
assert fps(1/x) == (1/x)
assert fps((x**2 + x + 1) / x**3, dir=-1) == (x**2 + x + 1) / x**3
f = 1 / ((x - 1)**2 * (x - 2))
assert fps(f, x).truncate() == \
(Rational(-1, 2) - x*Rational(5, 4) - 17*x**2/8 - 49*x**3/16 - 129*x**4/32 -
321*x**5/64 + O(x**6))
f = (1 + x + x**2 + x**3) / ((x - 1) * (x - 2))
assert fps(f, x).truncate() == \
(S.Half + x*Rational(5, 4) + 17*x**2/8 + 49*x**3/16 + 113*x**4/32 +
241*x**5/64 + O(x**6))
f = x / (1 - x - x**2)
assert fps(f, x, full=True).truncate() == \
x + x**2 + 2*x**3 + 3*x**4 + 5*x**5 + O(x**6)
f = 1 / (x**2 + 2*x + 2)
assert fps(f, x, full=True).truncate() == \
S.Half - x/2 + x**2/4 - x**4/8 + x**5/8 + O(x**6)
f = log(1 + x)
assert fps(f, x).truncate() == \
x - x**2/2 + x**3/3 - x**4/4 + x**5/5 + O(x**6)
assert fps(f, x, dir=1).truncate() == fps(f, x, dir=-1).truncate()
assert fps(f, x, 2).truncate() == \
(log(3) - Rational(2, 3) - (x - 2)**2/18 + (x - 2)**3/81 -
(x - 2)**4/324 + (x - 2)**5/1215 + x/3 + O((x - 2)**6, (x, 2)))
assert fps(f, x, 2, dir=-1).truncate() == \
(log(3) - Rational(2, 3) - (-x + 2)**2/18 - (-x + 2)**3/81 -
(-x + 2)**4/324 - (-x + 2)**5/1215 + x/3 + O((x - 2)**6, (x, 2)))
f = atan(x)
assert fps(f, x, full=True).truncate() == x - x**3/3 + x**5/5 + O(x**6)
assert fps(f, x, full=True, dir=1).truncate() == \
fps(f, x, full=True, dir=-1).truncate()
assert fps(f, x, 2, full=True).truncate() == \
(atan(2) - Rational(2, 5) - 2*(x - 2)**2/25 + 11*(x - 2)**3/375 -
6*(x - 2)**4/625 + 41*(x - 2)**5/15625 + x/5 + O((x - 2)**6, (x, 2)))
assert fps(f, x, 2, full=True, dir=-1).truncate() == \
(atan(2) - Rational(2, 5) - 2*(-x + 2)**2/25 - 11*(-x + 2)**3/375 -
6*(-x + 2)**4/625 - 41*(-x + 2)**5/15625 + x/5 + O((x - 2)**6, (x, 2)))
f = x*atan(x) - log(1 + x**2) / 2
assert fps(f, x, full=True).truncate() == x**2/2 - x**4/12 + O(x**6)
f = log((1 + x) / (1 - x)) / 2 - atan(x)
assert fps(f, x, full=True).truncate(n=10) == 2*x**3/3 + 2*x**7/7 + O(x**10)
@slow
def test_fps__hyper():
f = sin(x)
assert fps(f, x).truncate() == x - x**3/6 + x**5/120 + O(x**6)
f = cos(x)
assert fps(f, x).truncate() == 1 - x**2/2 + x**4/24 + O(x**6)
f = exp(x)
assert fps(f, x).truncate() == \
1 + x + x**2/2 + x**3/6 + x**4/24 + x**5/120 + O(x**6)
f = atan(x)
assert fps(f, x).truncate() == x - x**3/3 + x**5/5 + O(x**6)
f = exp(acos(x))
assert fps(f, x).truncate() == \
(exp(pi/2) - x*exp(pi/2) + x**2*exp(pi/2)/2 - x**3*exp(pi/2)/3 +
5*x**4*exp(pi/2)/24 - x**5*exp(pi/2)/6 + O(x**6))
f = exp(acosh(x))
assert fps(f, x).truncate() == I + x - I*x**2/2 - I*x**4/8 + O(x**6)
f = atan(1/x)
assert fps(f, x).truncate() == pi/2 - x + x**3/3 - x**5/5 + O(x**6)
f = x*atan(x) - log(1 + x**2) / 2
assert fps(f, x, rational=False).truncate() == x**2/2 - x**4/12 + O(x**6)
f = log(1 + x)
assert fps(f, x, rational=False).truncate() == \
x - x**2/2 + x**3/3 - x**4/4 + x**5/5 + O(x**6)
f = airyai(x**2)
assert fps(f, x).truncate() == \
(3**Rational(5, 6)*gamma(Rational(1, 3))/(6*pi) -
3**Rational(2, 3)*x**2/(3*gamma(Rational(1, 3))) + O(x**6))
f = exp(x)*sin(x)
assert fps(f, x).truncate() == x + x**2 + x**3/3 - x**5/30 + O(x**6)
f = exp(x)*sin(x)/x
assert fps(f, x).truncate() == 1 + x + x**2/3 - x**4/30 - x**5/90 + O(x**6)
f = sin(x) * cos(x)
assert fps(f, x).truncate() == x - 2*x**3/3 + 2*x**5/15 + O(x**6)
def test_fps_shift():
f = x**-5*sin(x)
assert fps(f, x).truncate() == \
1/x**4 - 1/(6*x**2) + Rational(1, 120) - x**2/5040 + x**4/362880 + O(x**6)
f = x**2*atan(x)
assert fps(f, x, rational=False).truncate() == \
x**3 - x**5/3 + O(x**6)
f = cos(sqrt(x))*x
assert fps(f, x).truncate() == \
x - x**2/2 + x**3/24 - x**4/720 + x**5/40320 + O(x**6)
f = x**2*cos(sqrt(x))
assert fps(f, x).truncate() == \
x**2 - x**3/2 + x**4/24 - x**5/720 + O(x**6)
def test_fps__Add_expr():
f = x*atan(x) - log(1 + x**2) / 2
assert fps(f, x).truncate() == x**2/2 - x**4/12 + O(x**6)
f = sin(x) + cos(x) - exp(x) + log(1 + x)
assert fps(f, x).truncate() == x - 3*x**2/2 - x**4/4 + x**5/5 + O(x**6)
f = 1/x + sin(x)
assert fps(f, x).truncate() == 1/x + x - x**3/6 + x**5/120 + O(x**6)
f = sin(x) - cos(x) + 1/(x - 1)
assert fps(f, x).truncate() == \
-2 - x**2/2 - 7*x**3/6 - 25*x**4/24 - 119*x**5/120 + O(x**6)
def test_fps__asymptotic():
f = exp(x)
assert fps(f, x, oo) == f
assert fps(f, x, -oo).truncate() == O(1/x**6, (x, oo))
f = erf(x)
assert fps(f, x, oo).truncate() == 1 + O(1/x**6, (x, oo))
assert fps(f, x, -oo).truncate() == -1 + O(1/x**6, (x, oo))
f = atan(x)
assert fps(f, x, oo, full=True).truncate() == \
-1/(5*x**5) + 1/(3*x**3) - 1/x + pi/2 + O(1/x**6, (x, oo))
assert fps(f, x, -oo, full=True).truncate() == \
-1/(5*x**5) + 1/(3*x**3) - 1/x - pi/2 + O(1/x**6, (x, oo))
f = log(1 + x)
assert fps(f, x, oo) != \
(-1/(5*x**5) - 1/(4*x**4) + 1/(3*x**3) - 1/(2*x**2) + 1/x - log(1/x) +
O(1/x**6, (x, oo)))
assert fps(f, x, -oo) != \
(-1/(5*x**5) - 1/(4*x**4) + 1/(3*x**3) - 1/(2*x**2) + 1/x + I*pi -
log(-1/x) + O(1/x**6, (x, oo)))
def test_fps__fractional():
f = sin(sqrt(x)) / x
assert fps(f, x).truncate() == \
(1/sqrt(x) - sqrt(x)/6 + x**Rational(3, 2)/120 -
x**Rational(5, 2)/5040 + x**Rational(7, 2)/362880 -
x**Rational(9, 2)/39916800 + x**Rational(11, 2)/6227020800 + O(x**6))
f = sin(sqrt(x)) * x
assert fps(f, x).truncate() == \
(x**Rational(3, 2) - x**Rational(5, 2)/6 + x**Rational(7, 2)/120 -
x**Rational(9, 2)/5040 + x**Rational(11, 2)/362880 + O(x**6))
f = atan(sqrt(x)) / x**2
assert fps(f, x).truncate() == \
(x**Rational(-3, 2) - x**Rational(-1, 2)/3 + x**S.Half/5 -
x**Rational(3, 2)/7 + x**Rational(5, 2)/9 - x**Rational(7, 2)/11 +
x**Rational(9, 2)/13 - x**Rational(11, 2)/15 + O(x**6))
f = exp(sqrt(x))
assert fps(f, x).truncate().expand() == \
(1 + x/2 + x**2/24 + x**3/720 + x**4/40320 + x**5/3628800 + sqrt(x) +
x**Rational(3, 2)/6 + x**Rational(5, 2)/120 + x**Rational(7, 2)/5040 +
x**Rational(9, 2)/362880 + x**Rational(11, 2)/39916800 + O(x**6))
f = exp(sqrt(x))*x
assert fps(f, x).truncate().expand() == \
(x + x**2/2 + x**3/24 + x**4/720 + x**5/40320 + x**Rational(3, 2) +
x**Rational(5, 2)/6 + x**Rational(7, 2)/120 + x**Rational(9, 2)/5040 +
x**Rational(11, 2)/362880 + O(x**6))
def test_fps__logarithmic_singularity():
f = log(1 + 1/x)
assert fps(f, x) != \
-log(x) + x - x**2/2 + x**3/3 - x**4/4 + x**5/5 + O(x**6)
assert fps(f, x, rational=False) != \
-log(x) + x - x**2/2 + x**3/3 - x**4/4 + x**5/5 + O(x**6)
@XFAIL
def test_fps__logarithmic_singularity_fail():
f = asech(x) # Algorithms for computing limits probably needs improvemnts
assert fps(f, x) == log(2) - log(x) - x**2/4 - 3*x**4/64 + O(x**6)
def test_fps_symbolic():
f = x**n*sin(x**2)
assert fps(f, x).truncate(8) == x**(n + 2) - x**(n + 6)/6 + O(x**(n + 8), x)
f = x**n*log(1 + x)
fp = fps(f, x)
k = fp.ak.variables[0]
assert fp.infinite == \
Sum((-(-1)**(-k)*x**(k + n))/k, (k, 1, oo))
f = (x - 2)**n*log(1 + x)
assert fps(f, x, 2).truncate() == \
((x - 2)**n*log(3) + (x - 2)**(n + 1)/3 - (x - 2)**(n + 2)/18 + (x - 2)**(n + 3)/81 -
(x - 2)**(n + 4)/324 + (x - 2)**(n + 5)/1215 + O((x - 2)**(n + 6), (x, 2)))
f = x**(n - 2)*cos(x)
assert fps(f, x).truncate() == \
(x**(n - 2) - x**n/2 + x**(n + 2)/24 + O(x**(n + 4), x))
f = x**(n - 2)*sin(x) + x**n*exp(x)
assert fps(f, x).truncate() == \
(x**(n - 1) + x**(n + 1) + x**(n + 2)/2 + x**n +
x**(n + 4)/24 + x**(n + 5)/60 + O(x**(n + 6), x))
f = x**n*atan(x)
assert fps(f, x, oo).truncate() == \
(-x**(n - 5)/5 + x**(n - 3)/3 + x**n*(pi/2 - 1/x) +
O((1/x)**(-n)/x**6, (x, oo)))
f = x**(n/2)*cos(x)
assert fps(f, x).truncate() == \
x**(n/2) - x**(n/2 + 2)/2 + x**(n/2 + 4)/24 + O(x**(n/2 + 6), x)
f = x**(n + m)*sin(x)
assert fps(f, x).truncate() == \
x**(m + n + 1) - x**(m + n + 3)/6 + x**(m + n + 5)/120 + O(x**(m + n + 6), x)
def test_fps__slow():
f = x*exp(x)*sin(2*x) # TODO: rsolve needs improvement
assert fps(f, x).truncate() == 2*x**2 + 2*x**3 - x**4/3 - x**5 + O(x**6)
def test_fps__operations():
f1, f2 = fps(sin(x)), fps(cos(x))
fsum = f1 + f2
assert fsum.function == sin(x) + cos(x)
assert fsum.truncate() == \
1 + x - x**2/2 - x**3/6 + x**4/24 + x**5/120 + O(x**6)
fsum = f1 + 1
assert fsum.function == sin(x) + 1
assert fsum.truncate() == 1 + x - x**3/6 + x**5/120 + O(x**6)
fsum = 1 + f2
assert fsum.function == cos(x) + 1
assert fsum.truncate() == 2 - x**2/2 + x**4/24 + O(x**6)
assert (f1 + x) == Add(f1, x)
assert -f2.truncate() == -1 + x**2/2 - x**4/24 + O(x**6)
assert (f1 - f1) is S.Zero
fsub = f1 - f2
assert fsub.function == sin(x) - cos(x)
assert fsub.truncate() == \
-1 + x + x**2/2 - x**3/6 - x**4/24 + x**5/120 + O(x**6)
fsub = f1 - 1
assert fsub.function == sin(x) - 1
assert fsub.truncate() == -1 + x - x**3/6 + x**5/120 + O(x**6)
fsub = 1 - f2
assert fsub.function == -cos(x) + 1
assert fsub.truncate() == x**2/2 - x**4/24 + O(x**6)
raises(ValueError, lambda: f1 + fps(exp(x), dir=-1))
raises(ValueError, lambda: f1 + fps(exp(x), x0=1))
fm = f1 * 3
assert fm.function == 3*sin(x)
assert fm.truncate() == 3*x - x**3/2 + x**5/40 + O(x**6)
fm = 3 * f2
assert fm.function == 3*cos(x)
assert fm.truncate() == 3 - 3*x**2/2 + x**4/8 + O(x**6)
assert (f1 * f2) == Mul(f1, f2)
assert (f1 * x) == Mul(f1, x)
fd = f1.diff()
assert fd.function == cos(x)
assert fd.truncate() == 1 - x**2/2 + x**4/24 + O(x**6)
fd = f2.diff()
assert fd.function == -sin(x)
assert fd.truncate() == -x + x**3/6 - x**5/120 + O(x**6)
fd = f2.diff().diff()
assert fd.function == -cos(x)
assert fd.truncate() == -1 + x**2/2 - x**4/24 + O(x**6)
f3 = fps(exp(sqrt(x)))
fd = f3.diff()
assert fd.truncate().expand() == \
(1/(2*sqrt(x)) + S.Half + x/12 + x**2/240 + x**3/10080 + x**4/725760 +
x**5/79833600 + sqrt(x)/4 + x**Rational(3, 2)/48 + x**Rational(5, 2)/1440 +
x**Rational(7, 2)/80640 + x**Rational(9, 2)/7257600 + x**Rational(11, 2)/958003200 +
O(x**6))
assert f1.integrate((x, 0, 1)) == -cos(1) + 1
assert integrate(f1, (x, 0, 1)) == -cos(1) + 1
fi = integrate(f1, x)
assert fi.function == -cos(x)
assert fi.truncate() == -1 + x**2/2 - x**4/24 + O(x**6)
fi = f2.integrate(x)
assert fi.function == sin(x)
assert fi.truncate() == x - x**3/6 + x**5/120 + O(x**6)
def test_fps__product():
f1, f2, f3 = fps(sin(x)), fps(exp(x)), fps(cos(x))
raises(ValueError, lambda: f1.product(exp(x), x))
raises(ValueError, lambda: f1.product(fps(exp(x), dir=-1), x, 4))
raises(ValueError, lambda: f1.product(fps(exp(x), x0=1), x, 4))
raises(ValueError, lambda: f1.product(fps(exp(y)), x, 4))
fprod = f1.product(f2, x)
assert isinstance(fprod, FormalPowerSeriesProduct)
assert isinstance(fprod.ffps, FormalPowerSeries)
assert isinstance(fprod.gfps, FormalPowerSeries)
assert fprod.f == sin(x)
assert fprod.g == exp(x)
assert fprod.function == sin(x) * exp(x)
assert fprod._eval_terms(4) == x + x**2 + x**3/3
assert fprod.truncate(4) == x + x**2 + x**3/3 + O(x**4)
assert fprod.polynomial(4) == x + x**2 + x**3/3
raises(NotImplementedError, lambda: fprod._eval_term(5))
raises(NotImplementedError, lambda: fprod.infinite)
raises(NotImplementedError, lambda: fprod._eval_derivative(x))
raises(NotImplementedError, lambda: fprod.integrate(x))
assert f1.product(f3, x)._eval_terms(4) == x - 2*x**3/3
assert f1.product(f3, x).truncate(4) == x - 2*x**3/3 + O(x**4)
def test_fps__compose():
f1, f2, f3 = fps(exp(x)), fps(sin(x)), fps(cos(x))
raises(ValueError, lambda: f1.compose(sin(x), x))
raises(ValueError, lambda: f1.compose(fps(sin(x), dir=-1), x, 4))
raises(ValueError, lambda: f1.compose(fps(sin(x), x0=1), x, 4))
raises(ValueError, lambda: f1.compose(fps(sin(y)), x, 4))
raises(ValueError, lambda: f1.compose(f3, x))
raises(ValueError, lambda: f2.compose(f3, x))
fcomp = f1.compose(f2, x)
assert isinstance(fcomp, FormalPowerSeriesCompose)
assert isinstance(fcomp.ffps, FormalPowerSeries)
assert isinstance(fcomp.gfps, FormalPowerSeries)
assert fcomp.f == exp(x)
assert fcomp.g == sin(x)
assert fcomp.function == exp(sin(x))
assert fcomp._eval_terms(6) == 1 + x + x**2/2 - x**4/8 - x**5/15
assert fcomp.truncate() == 1 + x + x**2/2 - x**4/8 - x**5/15 + O(x**6)
assert fcomp.truncate(5) == 1 + x + x**2/2 - x**4/8 + O(x**5)
raises(NotImplementedError, lambda: fcomp._eval_term(5))
raises(NotImplementedError, lambda: fcomp.infinite)
raises(NotImplementedError, lambda: fcomp._eval_derivative(x))
raises(NotImplementedError, lambda: fcomp.integrate(x))
assert f1.compose(f2, x).truncate(4) == 1 + x + x**2/2 + O(x**4)
assert f1.compose(f2, x).truncate(8) == \
1 + x + x**2/2 - x**4/8 - x**5/15 - x**6/240 + x**7/90 + O(x**8)
assert f1.compose(f2, x).truncate(6) == \
1 + x + x**2/2 - x**4/8 - x**5/15 + O(x**6)
assert f2.compose(f2, x).truncate(4) == x - x**3/3 + O(x**4)
assert f2.compose(f2, x).truncate(8) == x - x**3/3 + x**5/10 - 8*x**7/315 + O(x**8)
assert f2.compose(f2, x).truncate(6) == x - x**3/3 + x**5/10 + O(x**6)
def test_fps__inverse():
f1, f2, f3 = fps(sin(x)), fps(exp(x)), fps(cos(x))
raises(ValueError, lambda: f1.inverse(x))
finv = f2.inverse(x)
assert isinstance(finv, FormalPowerSeriesInverse)
assert isinstance(finv.ffps, FormalPowerSeries)
raises(ValueError, lambda: finv.gfps)
assert finv.f == exp(x)
assert finv.function == exp(-x)
assert finv._eval_terms(5) == 1 - x + x**2/2 - x**3/6 + x**4/24
assert finv.truncate() == 1 - x + x**2/2 - x**3/6 + x**4/24 - x**5/120 + O(x**6)
assert finv.truncate(5) == 1 - x + x**2/2 - x**3/6 + x**4/24 + O(x**5)
raises(NotImplementedError, lambda: finv._eval_term(5))
raises(ValueError, lambda: finv.g)
raises(NotImplementedError, lambda: finv.infinite)
raises(NotImplementedError, lambda: finv._eval_derivative(x))
raises(NotImplementedError, lambda: finv.integrate(x))
assert f2.inverse(x).truncate(8) == \
1 - x + x**2/2 - x**3/6 + x**4/24 - x**5/120 + x**6/720 - x**7/5040 + O(x**8)
assert f3.inverse(x).truncate() == 1 + x**2/2 + 5*x**4/24 + O(x**6)
assert f3.inverse(x).truncate(8) == 1 + x**2/2 + 5*x**4/24 + 61*x**6/720 + O(x**8)

View File

@ -0,0 +1,165 @@
from sympy.core.add import Add
from sympy.core.numbers import (Rational, oo, pi)
from sympy.core.singleton import S
from sympy.core.symbol import symbols
from sympy.functions.elementary.exponential import (exp, log)
from sympy.functions.elementary.piecewise import Piecewise
from sympy.functions.elementary.trigonometric import (cos, sin, sinc, tan)
from sympy.series.fourier import fourier_series
from sympy.series.fourier import FourierSeries
from sympy.testing.pytest import raises
from functools import lru_cache
x, y, z = symbols('x y z')
# Don't declare these during import because they are slow
@lru_cache()
def _get_examples():
fo = fourier_series(x, (x, -pi, pi))
fe = fourier_series(x**2, (-pi, pi))
fp = fourier_series(Piecewise((0, x < 0), (pi, True)), (x, -pi, pi))
return fo, fe, fp
def test_FourierSeries():
fo, fe, fp = _get_examples()
assert fourier_series(1, (-pi, pi)) == 1
assert (Piecewise((0, x < 0), (pi, True)).
fourier_series((x, -pi, pi)).truncate()) == fp.truncate()
assert isinstance(fo, FourierSeries)
assert fo.function == x
assert fo.x == x
assert fo.period == (-pi, pi)
assert fo.term(3) == 2*sin(3*x) / 3
assert fe.term(3) == -4*cos(3*x) / 9
assert fp.term(3) == 2*sin(3*x) / 3
assert fo.as_leading_term(x) == 2*sin(x)
assert fe.as_leading_term(x) == pi**2 / 3
assert fp.as_leading_term(x) == pi / 2
assert fo.truncate() == 2*sin(x) - sin(2*x) + (2*sin(3*x) / 3)
assert fe.truncate() == -4*cos(x) + cos(2*x) + pi**2 / 3
assert fp.truncate() == 2*sin(x) + (2*sin(3*x) / 3) + pi / 2
fot = fo.truncate(n=None)
s = [0, 2*sin(x), -sin(2*x)]
for i, t in enumerate(fot):
if i == 3:
break
assert s[i] == t
def _check_iter(f, i):
for ind, t in enumerate(f):
assert t == f[ind]
if ind == i:
break
_check_iter(fo, 3)
_check_iter(fe, 3)
_check_iter(fp, 3)
assert fo.subs(x, x**2) == fo
raises(ValueError, lambda: fourier_series(x, (0, 1, 2)))
raises(ValueError, lambda: fourier_series(x, (x, 0, oo)))
raises(ValueError, lambda: fourier_series(x*y, (0, oo)))
def test_FourierSeries_2():
p = Piecewise((0, x < 0), (x, True))
f = fourier_series(p, (x, -2, 2))
assert f.term(3) == (2*sin(3*pi*x / 2) / (3*pi) -
4*cos(3*pi*x / 2) / (9*pi**2))
assert f.truncate() == (2*sin(pi*x / 2) / pi - sin(pi*x) / pi -
4*cos(pi*x / 2) / pi**2 + S.Half)
def test_square_wave():
"""Test if fourier_series approximates discontinuous function correctly."""
square_wave = Piecewise((1, x < pi), (-1, True))
s = fourier_series(square_wave, (x, 0, 2*pi))
assert s.truncate(3) == 4 / pi * sin(x) + 4 / (3 * pi) * sin(3 * x) + \
4 / (5 * pi) * sin(5 * x)
assert s.sigma_approximation(4) == 4 / pi * sin(x) * sinc(pi / 4) + \
4 / (3 * pi) * sin(3 * x) * sinc(3 * pi / 4)
def test_sawtooth_wave():
s = fourier_series(x, (x, 0, pi))
assert s.truncate(4) == \
pi/2 - sin(2*x) - sin(4*x)/2 - sin(6*x)/3
s = fourier_series(x, (x, 0, 1))
assert s.truncate(4) == \
S.Half - sin(2*pi*x)/pi - sin(4*pi*x)/(2*pi) - sin(6*pi*x)/(3*pi)
def test_FourierSeries__operations():
fo, fe, fp = _get_examples()
fes = fe.scale(-1).shift(pi**2)
assert fes.truncate() == 4*cos(x) - cos(2*x) + 2*pi**2 / 3
assert fp.shift(-pi/2).truncate() == (2*sin(x) + (2*sin(3*x) / 3) +
(2*sin(5*x) / 5))
fos = fo.scale(3)
assert fos.truncate() == 6*sin(x) - 3*sin(2*x) + 2*sin(3*x)
fx = fe.scalex(2).shiftx(1)
assert fx.truncate() == -4*cos(2*x + 2) + cos(4*x + 4) + pi**2 / 3
fl = fe.scalex(3).shift(-pi).scalex(2).shiftx(1).scale(4)
assert fl.truncate() == (-16*cos(6*x + 6) + 4*cos(12*x + 12) -
4*pi + 4*pi**2 / 3)
raises(ValueError, lambda: fo.shift(x))
raises(ValueError, lambda: fo.shiftx(sin(x)))
raises(ValueError, lambda: fo.scale(x*y))
raises(ValueError, lambda: fo.scalex(x**2))
def test_FourierSeries__neg():
fo, fe, fp = _get_examples()
assert (-fo).truncate() == -2*sin(x) + sin(2*x) - (2*sin(3*x) / 3)
assert (-fe).truncate() == +4*cos(x) - cos(2*x) - pi**2 / 3
def test_FourierSeries__add__sub():
fo, fe, fp = _get_examples()
assert fo + fo == fo.scale(2)
assert fo - fo == 0
assert -fe - fe == fe.scale(-2)
assert (fo + fe).truncate() == 2*sin(x) - sin(2*x) - 4*cos(x) + cos(2*x) \
+ pi**2 / 3
assert (fo - fe).truncate() == 2*sin(x) - sin(2*x) + 4*cos(x) - cos(2*x) \
- pi**2 / 3
assert isinstance(fo + 1, Add)
raises(ValueError, lambda: fo + fourier_series(x, (x, 0, 2)))
def test_FourierSeries_finite():
assert fourier_series(sin(x)).truncate(1) == sin(x)
# assert type(fourier_series(sin(x)*log(x))).truncate() == FourierSeries
# assert type(fourier_series(sin(x**2+6))).truncate() == FourierSeries
assert fourier_series(sin(x)*log(y)*exp(z),(x,pi,-pi)).truncate() == sin(x)*log(y)*exp(z)
assert fourier_series(sin(x)**6).truncate(oo) == -15*cos(2*x)/32 + 3*cos(4*x)/16 - cos(6*x)/32 \
+ Rational(5, 16)
assert fourier_series(sin(x) ** 6).truncate() == -15 * cos(2 * x) / 32 + 3 * cos(4 * x) / 16 \
+ Rational(5, 16)
assert fourier_series(sin(4*x+3) + cos(3*x+4)).truncate(oo) == -sin(4)*sin(3*x) + sin(4*x)*cos(3) \
+ cos(4)*cos(3*x) + sin(3)*cos(4*x)
assert fourier_series(sin(x)+cos(x)*tan(x)).truncate(oo) == 2*sin(x)
assert fourier_series(cos(pi*x), (x, -1, 1)).truncate(oo) == cos(pi*x)
assert fourier_series(cos(3*pi*x + 4) - sin(4*pi*x)*log(pi*y), (x, -1, 1)).truncate(oo) == -log(pi*y)*sin(4*pi*x)\
- sin(4)*sin(3*pi*x) + cos(4)*cos(3*pi*x)

View File

@ -0,0 +1,482 @@
from sympy.core import EulerGamma
from sympy.core.numbers import (E, I, Integer, Rational, oo, pi)
from sympy.core.singleton import S
from sympy.core.symbol import Symbol
from sympy.functions.elementary.exponential import (exp, log)
from sympy.functions.elementary.miscellaneous import sqrt
from sympy.functions.elementary.trigonometric import (acot, atan, cos, sin)
from sympy.functions.elementary.complexes import sign as _sign
from sympy.functions.special.error_functions import (Ei, erf)
from sympy.functions.special.gamma_functions import (digamma, gamma, loggamma)
from sympy.functions.special.zeta_functions import zeta
from sympy.polys.polytools import cancel
from sympy.functions.elementary.hyperbolic import cosh, coth, sinh, tanh
from sympy.series.gruntz import compare, mrv, rewrite, mrv_leadterm, gruntz, \
sign
from sympy.testing.pytest import XFAIL, skip, slow
"""
This test suite is testing the limit algorithm using the bottom up approach.
See the documentation in limits2.py. The algorithm itself is highly recursive
by nature, so "compare" is logically the lowest part of the algorithm, yet in
some sense it's the most complex part, because it needs to calculate a limit
to return the result.
Nevertheless, the rest of the algorithm depends on compare working correctly.
"""
x = Symbol('x', real=True)
m = Symbol('m', real=True)
runslow = False
def _sskip():
if not runslow:
skip("slow")
@slow
def test_gruntz_evaluation():
# Gruntz' thesis pp. 122 to 123
# 8.1
assert gruntz(exp(x)*(exp(1/x - exp(-x)) - exp(1/x)), x, oo) == -1
# 8.2
assert gruntz(exp(x)*(exp(1/x + exp(-x) + exp(-x**2))
- exp(1/x - exp(-exp(x)))), x, oo) == 1
# 8.3
assert gruntz(exp(exp(x - exp(-x))/(1 - 1/x)) - exp(exp(x)), x, oo) is oo
# 8.5
assert gruntz(exp(exp(exp(x + exp(-x)))) / exp(exp(exp(x))), x, oo) is oo
# 8.6
assert gruntz(exp(exp(exp(x))) / exp(exp(exp(x - exp(-exp(x))))),
x, oo) is oo
# 8.7
assert gruntz(exp(exp(exp(x))) / exp(exp(exp(x - exp(-exp(exp(x)))))),
x, oo) == 1
# 8.8
assert gruntz(exp(exp(x)) / exp(exp(x - exp(-exp(exp(x))))), x, oo) == 1
# 8.9
assert gruntz(log(x)**2 * exp(sqrt(log(x))*(log(log(x)))**2
* exp(sqrt(log(log(x))) * (log(log(log(x))))**3)) / sqrt(x),
x, oo) == 0
# 8.10
assert gruntz((x*log(x)*(log(x*exp(x) - x**2))**2)
/ (log(log(x**2 + 2*exp(exp(3*x**3*log(x)))))), x, oo) == Rational(1, 3)
# 8.11
assert gruntz((exp(x*exp(-x)/(exp(-x) + exp(-2*x**2/(x + 1)))) - exp(x))/x,
x, oo) == -exp(2)
# 8.12
assert gruntz((3**x + 5**x)**(1/x), x, oo) == 5
# 8.13
assert gruntz(x/log(x**(log(x**(log(2)/log(x))))), x, oo) is oo
# 8.14
assert gruntz(exp(exp(2*log(x**5 + x)*log(log(x))))
/ exp(exp(10*log(x)*log(log(x)))), x, oo) is oo
# 8.15
assert gruntz(exp(exp(Rational(5, 2)*x**Rational(-5, 7) + Rational(21, 8)*x**Rational(6, 11)
+ 2*x**(-8) + Rational(54, 17)*x**Rational(49, 45)))**8
/ log(log(-log(Rational(4, 3)*x**Rational(-5, 14))))**Rational(7, 6), x, oo) is oo
# 8.16
assert gruntz((exp(4*x*exp(-x)/(1/exp(x) + 1/exp(2*x**2/(x + 1)))) - exp(x))
/ exp(x)**4, x, oo) == 1
# 8.17
assert gruntz(exp(x*exp(-x)/(exp(-x) + exp(-2*x**2/(x + 1))))/exp(x), x, oo) \
== 1
# 8.19
assert gruntz(log(x)*(log(log(x) + log(log(x))) - log(log(x)))
/ (log(log(x) + log(log(log(x))))), x, oo) == 1
# 8.20
assert gruntz(exp((log(log(x + exp(log(x)*log(log(x))))))
/ (log(log(log(exp(x) + x + log(x)))))), x, oo) == E
# Another
assert gruntz(exp(exp(exp(x + exp(-x)))) / exp(exp(x)), x, oo) is oo
def test_gruntz_evaluation_slow():
_sskip()
# 8.4
assert gruntz(exp(exp(exp(x)/(1 - 1/x)))
- exp(exp(exp(x)/(1 - 1/x - log(x)**(-log(x))))), x, oo) is -oo
# 8.18
assert gruntz((exp(exp(-x/(1 + exp(-x))))*exp(-x/(1 + exp(-x/(1 + exp(-x)))))
*exp(exp(-x + exp(-x/(1 + exp(-x))))))
/ (exp(-x/(1 + exp(-x))))**2 - exp(x) + x, x, oo) == 2
@slow
def test_gruntz_eval_special():
# Gruntz, p. 126
assert gruntz(exp(x)*(sin(1/x + exp(-x)) - sin(1/x + exp(-x**2))), x, oo) == 1
assert gruntz((erf(x - exp(-exp(x))) - erf(x)) * exp(exp(x)) * exp(x**2),
x, oo) == -2/sqrt(pi)
assert gruntz(exp(exp(x)) * (exp(sin(1/x + exp(-exp(x)))) - exp(sin(1/x))),
x, oo) == 1
assert gruntz(exp(x)*(gamma(x + exp(-x)) - gamma(x)), x, oo) is oo
assert gruntz(exp(exp(digamma(digamma(x))))/x, x, oo) == exp(Rational(-1, 2))
assert gruntz(exp(exp(digamma(log(x))))/x, x, oo) == exp(Rational(-1, 2))
assert gruntz(digamma(digamma(digamma(x))), x, oo) is oo
assert gruntz(loggamma(loggamma(x)), x, oo) is oo
assert gruntz(((gamma(x + 1/gamma(x)) - gamma(x))/log(x) - cos(1/x))
* x*log(x), x, oo) == Rational(-1, 2)
assert gruntz(x * (gamma(x - 1/gamma(x)) - gamma(x) + log(x)), x, oo) \
== S.Half
assert gruntz((gamma(x + 1/gamma(x)) - gamma(x)) / log(x), x, oo) == 1
def test_gruntz_eval_special_slow():
_sskip()
assert gruntz(gamma(x + 1)/sqrt(2*pi)
- exp(-x)*(x**(x + S.Half) + x**(x - S.Half)/12), x, oo) is oo
assert gruntz(exp(exp(exp(digamma(digamma(digamma(x))))))/x, x, oo) == 0
@XFAIL
def test_grunts_eval_special_slow_sometimes_fail():
_sskip()
# XXX This sometimes fails!!!
assert gruntz(exp(gamma(x - exp(-x))*exp(1/x)) - exp(gamma(x)), x, oo) is oo
def test_gruntz_Ei():
assert gruntz((Ei(x - exp(-exp(x))) - Ei(x)) *exp(-x)*exp(exp(x))*x, x, oo) == -1
@XFAIL
def test_gruntz_eval_special_fail():
# TODO zeta function series
assert gruntz(
exp((log(2) + 1)*x) * (zeta(x + exp(-x)) - zeta(x)), x, oo) == -log(2)
# TODO 8.35 - 8.37 (bessel, max-min)
def test_gruntz_hyperbolic():
assert gruntz(cosh(x), x, oo) is oo
assert gruntz(cosh(x), x, -oo) is oo
assert gruntz(sinh(x), x, oo) is oo
assert gruntz(sinh(x), x, -oo) is -oo
assert gruntz(2*cosh(x)*exp(x), x, oo) is oo
assert gruntz(2*cosh(x)*exp(x), x, -oo) == 1
assert gruntz(2*sinh(x)*exp(x), x, oo) is oo
assert gruntz(2*sinh(x)*exp(x), x, -oo) == -1
assert gruntz(tanh(x), x, oo) == 1
assert gruntz(tanh(x), x, -oo) == -1
assert gruntz(coth(x), x, oo) == 1
assert gruntz(coth(x), x, -oo) == -1
def test_compare1():
assert compare(2, x, x) == "<"
assert compare(x, exp(x), x) == "<"
assert compare(exp(x), exp(x**2), x) == "<"
assert compare(exp(x**2), exp(exp(x)), x) == "<"
assert compare(1, exp(exp(x)), x) == "<"
assert compare(x, 2, x) == ">"
assert compare(exp(x), x, x) == ">"
assert compare(exp(x**2), exp(x), x) == ">"
assert compare(exp(exp(x)), exp(x**2), x) == ">"
assert compare(exp(exp(x)), 1, x) == ">"
assert compare(2, 3, x) == "="
assert compare(3, -5, x) == "="
assert compare(2, -5, x) == "="
assert compare(x, x**2, x) == "="
assert compare(x**2, x**3, x) == "="
assert compare(x**3, 1/x, x) == "="
assert compare(1/x, x**m, x) == "="
assert compare(x**m, -x, x) == "="
assert compare(exp(x), exp(-x), x) == "="
assert compare(exp(-x), exp(2*x), x) == "="
assert compare(exp(2*x), exp(x)**2, x) == "="
assert compare(exp(x)**2, exp(x + exp(-x)), x) == "="
assert compare(exp(x), exp(x + exp(-x)), x) == "="
assert compare(exp(x**2), 1/exp(x**2), x) == "="
def test_compare2():
assert compare(exp(x), x**5, x) == ">"
assert compare(exp(x**2), exp(x)**2, x) == ">"
assert compare(exp(x), exp(x + exp(-x)), x) == "="
assert compare(exp(x + exp(-x)), exp(x), x) == "="
assert compare(exp(x + exp(-x)), exp(-x), x) == "="
assert compare(exp(-x), x, x) == ">"
assert compare(x, exp(-x), x) == "<"
assert compare(exp(x + 1/x), x, x) == ">"
assert compare(exp(-exp(x)), exp(x), x) == ">"
assert compare(exp(exp(-exp(x)) + x), exp(-exp(x)), x) == "<"
def test_compare3():
assert compare(exp(exp(x)), exp(x + exp(-exp(x))), x) == ">"
def test_sign1():
assert sign(Rational(0), x) == 0
assert sign(Rational(3), x) == 1
assert sign(Rational(-5), x) == -1
assert sign(log(x), x) == 1
assert sign(exp(-x), x) == 1
assert sign(exp(x), x) == 1
assert sign(-exp(x), x) == -1
assert sign(3 - 1/x, x) == 1
assert sign(-3 - 1/x, x) == -1
assert sign(sin(1/x), x) == 1
assert sign((x**Integer(2)), x) == 1
assert sign(x**2, x) == 1
assert sign(x**5, x) == 1
def test_sign2():
assert sign(x, x) == 1
assert sign(-x, x) == -1
y = Symbol("y", positive=True)
assert sign(y, x) == 1
assert sign(-y, x) == -1
assert sign(y*x, x) == 1
assert sign(-y*x, x) == -1
def mmrv(a, b):
return set(mrv(a, b)[0].keys())
def test_mrv1():
assert mmrv(x, x) == {x}
assert mmrv(x + 1/x, x) == {x}
assert mmrv(x**2, x) == {x}
assert mmrv(log(x), x) == {x}
assert mmrv(exp(x), x) == {exp(x)}
assert mmrv(exp(-x), x) == {exp(-x)}
assert mmrv(exp(x**2), x) == {exp(x**2)}
assert mmrv(-exp(1/x), x) == {x}
assert mmrv(exp(x + 1/x), x) == {exp(x + 1/x)}
def test_mrv2a():
assert mmrv(exp(x + exp(-exp(x))), x) == {exp(-exp(x))}
assert mmrv(exp(x + exp(-x)), x) == {exp(x + exp(-x)), exp(-x)}
assert mmrv(exp(1/x + exp(-x)), x) == {exp(-x)}
#sometimes infinite recursion due to log(exp(x**2)) not simplifying
def test_mrv2b():
assert mmrv(exp(x + exp(-x**2)), x) == {exp(-x**2)}
#sometimes infinite recursion due to log(exp(x**2)) not simplifying
def test_mrv2c():
assert mmrv(
exp(-x + 1/x**2) - exp(x + 1/x), x) == {exp(x + 1/x), exp(1/x**2 - x)}
#sometimes infinite recursion due to log(exp(x**2)) not simplifying
def test_mrv3():
assert mmrv(exp(x**2) + x*exp(x) + log(x)**x/x, x) == {exp(x**2)}
assert mmrv(
exp(x)*(exp(1/x + exp(-x)) - exp(1/x)), x) == {exp(x), exp(-x)}
assert mmrv(log(
x**2 + 2*exp(exp(3*x**3*log(x)))), x) == {exp(exp(3*x**3*log(x)))}
assert mmrv(log(x - log(x))/log(x), x) == {x}
assert mmrv(
(exp(1/x - exp(-x)) - exp(1/x))*exp(x), x) == {exp(x), exp(-x)}
assert mmrv(
1/exp(-x + exp(-x)) - exp(x), x) == {exp(x), exp(-x), exp(x - exp(-x))}
assert mmrv(log(log(x*exp(x*exp(x)) + 1)), x) == {exp(x*exp(x))}
assert mmrv(exp(exp(log(log(x) + 1/x))), x) == {x}
def test_mrv4():
ln = log
assert mmrv((ln(ln(x) + ln(ln(x))) - ln(ln(x)))/ln(ln(x) + ln(ln(ln(x))))*ln(x),
x) == {x}
assert mmrv(log(log(x*exp(x*exp(x)) + 1)) - exp(exp(log(log(x) + 1/x))), x) == \
{exp(x*exp(x))}
def mrewrite(a, b, c):
return rewrite(a[1], a[0], b, c)
def test_rewrite1():
e = exp(x)
assert mrewrite(mrv(e, x), x, m) == (1/m, -x)
e = exp(x**2)
assert mrewrite(mrv(e, x), x, m) == (1/m, -x**2)
e = exp(x + 1/x)
assert mrewrite(mrv(e, x), x, m) == (1/m, -x - 1/x)
e = 1/exp(-x + exp(-x)) - exp(x)
assert mrewrite(mrv(e, x), x, m) == (1/(m*exp(m)) - 1/m, -x)
def test_rewrite2():
e = exp(x)*log(log(exp(x)))
assert mmrv(e, x) == {exp(x)}
assert mrewrite(mrv(e, x), x, m) == (1/m*log(x), -x)
#sometimes infinite recursion due to log(exp(x**2)) not simplifying
def test_rewrite3():
e = exp(-x + 1/x**2) - exp(x + 1/x)
#both of these are correct and should be equivalent:
assert mrewrite(mrv(e, x), x, m) in [(-1/m + m*exp(
1/x + 1/x**2), -x - 1/x), (m - 1/m*exp(1/x + x**(-2)), x**(-2) - x)]
def test_mrv_leadterm1():
assert mrv_leadterm(-exp(1/x), x) == (-1, 0)
assert mrv_leadterm(1/exp(-x + exp(-x)) - exp(x), x) == (-1, 0)
assert mrv_leadterm(
(exp(1/x - exp(-x)) - exp(1/x))*exp(x), x) == (-exp(1/x), 0)
def test_mrv_leadterm2():
#Gruntz: p51, 3.25
assert mrv_leadterm((log(exp(x) + x) - x)/log(exp(x) + log(x))*exp(x), x) == \
(1, 0)
def test_mrv_leadterm3():
#Gruntz: p56, 3.27
assert mmrv(exp(-x + exp(-x)*exp(-x*log(x))), x) == {exp(-x - x*log(x))}
assert mrv_leadterm(exp(-x + exp(-x)*exp(-x*log(x))), x) == (exp(-x), 0)
def test_limit1():
assert gruntz(x, x, oo) is oo
assert gruntz(x, x, -oo) is -oo
assert gruntz(-x, x, oo) is -oo
assert gruntz(x**2, x, -oo) is oo
assert gruntz(-x**2, x, oo) is -oo
assert gruntz(x*log(x), x, 0, dir="+") == 0
assert gruntz(1/x, x, oo) == 0
assert gruntz(exp(x), x, oo) is oo
assert gruntz(-exp(x), x, oo) is -oo
assert gruntz(exp(x)/x, x, oo) is oo
assert gruntz(1/x - exp(-x), x, oo) == 0
assert gruntz(x + 1/x, x, oo) is oo
def test_limit2():
assert gruntz(x**x, x, 0, dir="+") == 1
assert gruntz((exp(x) - 1)/x, x, 0) == 1
assert gruntz(1 + 1/x, x, oo) == 1
assert gruntz(-exp(1/x), x, oo) == -1
assert gruntz(x + exp(-x), x, oo) is oo
assert gruntz(x + exp(-x**2), x, oo) is oo
assert gruntz(x + exp(-exp(x)), x, oo) is oo
assert gruntz(13 + 1/x - exp(-x), x, oo) == 13
def test_limit3():
a = Symbol('a')
assert gruntz(x - log(1 + exp(x)), x, oo) == 0
assert gruntz(x - log(a + exp(x)), x, oo) == 0
assert gruntz(exp(x)/(1 + exp(x)), x, oo) == 1
assert gruntz(exp(x)/(a + exp(x)), x, oo) == 1
def test_limit4():
#issue 3463
assert gruntz((3**x + 5**x)**(1/x), x, oo) == 5
#issue 3463
assert gruntz((3**(1/x) + 5**(1/x))**x, x, 0) == 5
@XFAIL
def test_MrvTestCase_page47_ex3_21():
h = exp(-x/(1 + exp(-x)))
expr = exp(h)*exp(-x/(1 + h))*exp(exp(-x + h))/h**2 - exp(x) + x
assert mmrv(expr, x) == {1/h, exp(-x), exp(x), exp(x - h), exp(x/(1 + h))}
def test_gruntz_I():
y = Symbol("y")
assert gruntz(I*x, x, oo) == I*oo
assert gruntz(y*I*x, x, oo) == y*I*oo
assert gruntz(y*3*I*x, x, oo) == y*I*oo
assert gruntz(y*3*sin(I)*x, x, oo).simplify().rewrite(_sign) == _sign(y)*I*oo
def test_issue_4814():
assert gruntz((x + 1)**(1/log(x + 1)), x, oo) == E
def test_intractable():
assert gruntz(1/gamma(x), x, oo) == 0
assert gruntz(1/loggamma(x), x, oo) == 0
assert gruntz(gamma(x)/loggamma(x), x, oo) is oo
assert gruntz(exp(gamma(x))/gamma(x), x, oo) is oo
assert gruntz(gamma(x), x, 3) == 2
assert gruntz(gamma(Rational(1, 7) + 1/x), x, oo) == gamma(Rational(1, 7))
assert gruntz(log(x**x)/log(gamma(x)), x, oo) == 1
assert gruntz(log(gamma(gamma(x)))/exp(x), x, oo) is oo
def test_aseries_trig():
assert cancel(gruntz(1/log(atan(x)), x, oo)
- 1/(log(pi) + log(S.Half))) == 0
assert gruntz(1/acot(x), x, -oo) is -oo
def test_exp_log_series():
assert gruntz(x/log(log(x*exp(x))), x, oo) is oo
def test_issue_3644():
assert gruntz(((x**7 + x + 1)/(2**x + x**2))**(-1/x), x, oo) == 2
def test_issue_6843():
n = Symbol('n', integer=True, positive=True)
r = (n + 1)*x**(n + 1)/(x**(n + 1) - 1) - x/(x - 1)
assert gruntz(r, x, 1).simplify() == n/2
def test_issue_4190():
assert gruntz(x - gamma(1/x), x, oo) == S.EulerGamma
@XFAIL
def test_issue_5172():
n = Symbol('n')
r = Symbol('r', positive=True)
c = Symbol('c')
p = Symbol('p', positive=True)
m = Symbol('m', negative=True)
expr = ((2*n*(n - r + 1)/(n + r*(n - r + 1)))**c + \
(r - 1)*(n*(n - r + 2)/(n + r*(n - r + 1)))**c - n)/(n**c - n)
expr = expr.subs(c, c + 1)
assert gruntz(expr.subs(c, m), n, oo) == 1
# fail:
assert gruntz(expr.subs(c, p), n, oo).simplify() == \
(2**(p + 1) + r - 1)/(r + 1)**(p + 1)
def test_issue_4109():
assert gruntz(1/gamma(x), x, 0) == 0
assert gruntz(x*gamma(x), x, 0) == 1
def test_issue_6682():
assert gruntz(exp(2*Ei(-x))/x**2, x, 0) == exp(2*EulerGamma)
def test_issue_7096():
from sympy.functions import sign
assert gruntz(x**-pi, x, 0, dir='-') == oo*sign((-1)**(-pi))
def test_issue_24210_25885():
eq = exp(x)/(1+1/x)**x**2
ans = sqrt(E)
assert gruntz(eq, x, oo) == ans
assert gruntz(1/eq, x, oo) == 1/ans

View File

@ -0,0 +1,23 @@
from sympy.series.kauers import finite_diff
from sympy.series.kauers import finite_diff_kauers
from sympy.abc import x, y, z, m, n, w
from sympy.core.numbers import pi
from sympy.functions.elementary.trigonometric import (cos, sin)
from sympy.concrete.summations import Sum
def test_finite_diff():
assert finite_diff(x**2 + 2*x + 1, x) == 2*x + 3
assert finite_diff(y**3 + 2*y**2 + 3*y + 5, y) == 3*y**2 + 7*y + 6
assert finite_diff(z**2 - 2*z + 3, z) == 2*z - 1
assert finite_diff(w**2 + 3*w - 2, w) == 2*w + 4
assert finite_diff(sin(x), x, pi/6) == -sin(x) + sin(x + pi/6)
assert finite_diff(cos(y), y, pi/3) == -cos(y) + cos(y + pi/3)
assert finite_diff(x**2 - 2*x + 3, x, 2) == 4*x
assert finite_diff(n**2 - 2*n + 3, n, 3) == 6*n + 3
def test_finite_diff_kauers():
assert finite_diff_kauers(Sum(x**2, (x, 1, n))) == (n + 1)**2
assert finite_diff_kauers(Sum(y, (y, 1, m))) == (m + 1)
assert finite_diff_kauers(Sum((x*y), (x, 1, m), (y, 1, n))) == (m + 1)*(n + 1)
assert finite_diff_kauers(Sum((x*y**2), (x, 1, m), (y, 1, n))) == (n + 1)**2*(m + 1)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,177 @@
from sympy.concrete.summations import Sum
from sympy.core.add import Add
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 (binomial, factorial, subfactorial)
from sympy.functions.combinatorial.numbers import (fibonacci, harmonic)
from sympy.functions.elementary.exponential import (exp, log)
from sympy.functions.elementary.miscellaneous import sqrt
from sympy.functions.elementary.trigonometric import (cos, sin)
from sympy.functions.special.gamma_functions import gamma
from sympy.series.limitseq import limit_seq
from sympy.series.limitseq import difference_delta as dd
from sympy.testing.pytest import raises, XFAIL
from sympy.calculus.accumulationbounds import AccumulationBounds
n, m, k = symbols('n m k', integer=True)
def test_difference_delta():
e = n*(n + 1)
e2 = e * k
assert dd(e) == 2*n + 2
assert dd(e2, n, 2) == k*(4*n + 6)
raises(ValueError, lambda: dd(e2))
raises(ValueError, lambda: dd(e2, n, oo))
def test_difference_delta__Sum():
e = Sum(1/k, (k, 1, n))
assert dd(e, n) == 1/(n + 1)
assert dd(e, n, 5) == Add(*[1/(i + n + 1) for i in range(5)])
e = Sum(1/k, (k, 1, 3*n))
assert dd(e, n) == Add(*[1/(i + 3*n + 1) for i in range(3)])
e = n * Sum(1/k, (k, 1, n))
assert dd(e, n) == 1 + Sum(1/k, (k, 1, n))
e = Sum(1/k, (k, 1, n), (m, 1, n))
assert dd(e, n) == harmonic(n)
def test_difference_delta__Add():
e = n + n*(n + 1)
assert dd(e, n) == 2*n + 3
assert dd(e, n, 2) == 4*n + 8
e = n + Sum(1/k, (k, 1, n))
assert dd(e, n) == 1 + 1/(n + 1)
assert dd(e, n, 5) == 5 + Add(*[1/(i + n + 1) for i in range(5)])
def test_difference_delta__Pow():
e = 4**n
assert dd(e, n) == 3*4**n
assert dd(e, n, 2) == 15*4**n
e = 4**(2*n)
assert dd(e, n) == 15*4**(2*n)
assert dd(e, n, 2) == 255*4**(2*n)
e = n**4
assert dd(e, n) == (n + 1)**4 - n**4
e = n**n
assert dd(e, n) == (n + 1)**(n + 1) - n**n
def test_limit_seq():
e = binomial(2*n, n) / Sum(binomial(2*k, k), (k, 1, n))
assert limit_seq(e) == S(3) / 4
assert limit_seq(e, m) == e
e = (5*n**3 + 3*n**2 + 4) / (3*n**3 + 4*n - 5)
assert limit_seq(e, n) == S(5) / 3
e = (harmonic(n) * Sum(harmonic(k), (k, 1, n))) / (n * harmonic(2*n)**2)
assert limit_seq(e, n) == 1
e = Sum(k**2 * Sum(2**m/m, (m, 1, k)), (k, 1, n)) / (2**n*n)
assert limit_seq(e, n) == 4
e = (Sum(binomial(3*k, k) * binomial(5*k, k), (k, 1, n)) /
(binomial(3*n, n) * binomial(5*n, n)))
assert limit_seq(e, n) == S(84375) / 83351
e = Sum(harmonic(k)**2/k, (k, 1, 2*n)) / harmonic(n)**3
assert limit_seq(e, n) == S.One / 3
raises(ValueError, lambda: limit_seq(e * m))
def test_alternating_sign():
assert limit_seq((-1)**n/n**2, n) == 0
assert limit_seq((-2)**(n+1)/(n + 3**n), n) == 0
assert limit_seq((2*n + (-1)**n)/(n + 1), n) == 2
assert limit_seq(sin(pi*n), n) == 0
assert limit_seq(cos(2*pi*n), n) == 1
assert limit_seq((S.NegativeOne/5)**n, n) == 0
assert limit_seq((Rational(-1, 5))**n, n) == 0
assert limit_seq((I/3)**n, n) == 0
assert limit_seq(sqrt(n)*(I/2)**n, n) == 0
assert limit_seq(n**7*(I/3)**n, n) == 0
assert limit_seq(n/(n + 1) + (I/2)**n, n) == 1
def test_accum_bounds():
assert limit_seq((-1)**n, n) == AccumulationBounds(-1, 1)
assert limit_seq(cos(pi*n), n) == AccumulationBounds(-1, 1)
assert limit_seq(sin(pi*n/2)**2, n) == AccumulationBounds(0, 1)
assert limit_seq(2*(-3)**n/(n + 3**n), n) == AccumulationBounds(-2, 2)
assert limit_seq(3*n/(n + 1) + 2*(-1)**n, n) == AccumulationBounds(1, 5)
def test_limitseq_sum():
from sympy.abc import x, y, z
assert limit_seq(Sum(1/x, (x, 1, y)) - log(y), y) == S.EulerGamma
assert limit_seq(Sum(1/x, (x, 1, y)) - 1/y, y) is S.Infinity
assert (limit_seq(binomial(2*x, x) / Sum(binomial(2*y, y), (y, 1, x)), x) ==
S(3) / 4)
assert (limit_seq(Sum(y**2 * Sum(2**z/z, (z, 1, y)), (y, 1, x)) /
(2**x*x), x) == 4)
def test_issue_9308():
assert limit_seq(subfactorial(n)/factorial(n), n) == exp(-1)
def test_issue_10382():
n = Symbol('n', integer=True)
assert limit_seq(fibonacci(n+1)/fibonacci(n), n).together() == S.GoldenRatio
def test_issue_11672():
assert limit_seq(Rational(-1, 2)**n, n) == 0
def test_issue_14196():
k, n = symbols('k, n', positive=True)
m = Symbol('m')
assert limit_seq(Sum(m**k, (m, 1, n)).doit()/(n**(k + 1)), n) == 1/(k + 1)
def test_issue_16735():
assert limit_seq(5**n/factorial(n), n) == 0
def test_issue_19868():
assert limit_seq(1/gamma(n + S.One/2), n) == 0
@XFAIL
def test_limit_seq_fail():
# improve Summation algorithm or add ad-hoc criteria
e = (harmonic(n)**3 * Sum(1/harmonic(k), (k, 1, n)) /
(n * Sum(harmonic(k)/k, (k, 1, n))))
assert limit_seq(e, n) == 2
# No unique dominant term
e = (Sum(2**k * binomial(2*k, k) / k**2, (k, 1, n)) /
(Sum(2**k/k*2, (k, 1, n)) * Sum(binomial(2*k, k), (k, 1, n))))
assert limit_seq(e, n) == S(3) / 7
# Simplifications of summations needs to be improved.
e = n**3*Sum(2**k/k**2, (k, 1, n))**2 / (2**n * Sum(2**k/k, (k, 1, n)))
assert limit_seq(e, n) == 2
e = (harmonic(n) * Sum(2**k/k, (k, 1, n)) /
(n * Sum(2**k*harmonic(k)/k**2, (k, 1, n))))
assert limit_seq(e, n) == 1
e = (Sum(2**k*factorial(k) / k**2, (k, 1, 2*n)) /
(Sum(4**k/k**2, (k, 1, n)) * Sum(factorial(k), (k, 1, 2*n))))
assert limit_seq(e, n) == S(3) / 16

View File

@ -0,0 +1,65 @@
from sympy.core.numbers import E
from sympy.core.singleton import S
from sympy.functions.elementary.exponential import exp
from sympy.functions.elementary.hyperbolic import tanh
from sympy.functions.elementary.trigonometric import (cos, sin)
from sympy.series.order import Order
from sympy.abc import x, y
def test_sin():
e = sin(x).lseries(x)
assert next(e) == x
assert next(e) == -x**3/6
assert next(e) == x**5/120
def test_cos():
e = cos(x).lseries(x)
assert next(e) == 1
assert next(e) == -x**2/2
assert next(e) == x**4/24
def test_exp():
e = exp(x).lseries(x)
assert next(e) == 1
assert next(e) == x
assert next(e) == x**2/2
assert next(e) == x**3/6
def test_exp2():
e = exp(cos(x)).lseries(x)
assert next(e) == E
assert next(e) == -E*x**2/2
assert next(e) == E*x**4/6
assert next(e) == -31*E*x**6/720
def test_simple():
assert list(x.lseries()) == [x]
assert list(S.One.lseries(x)) == [1]
assert not next((x/(x + y)).lseries(y)).has(Order)
def test_issue_5183():
s = (x + 1/x).lseries()
assert list(s) == [1/x, x]
assert next((x + x**2).lseries()) == x
assert next(((1 + x)**7).lseries(x)) == 1
assert next((sin(x + y)).series(x, n=3).lseries(y)) == x
# it would be nice if all terms were grouped, but in the
# following case that would mean that all the terms would have
# to be known since, for example, every term has a constant in it.
s = ((1 + x)**7).series(x, 1, n=None)
assert [next(s) for i in range(2)] == [128, -448 + 448*x]
def test_issue_6999():
s = tanh(x).lseries(x, 1)
assert next(s) == tanh(1)
assert next(s) == x - (x - 1)*tanh(1)**2 - 1
assert next(s) == -(x - 1)**2*tanh(1) + (x - 1)**2*tanh(1)**3
assert next(s) == -(x - 1)**3*tanh(1)**4 - (x - 1)**3/3 + \
4*(x - 1)**3*tanh(1)**2/3

View File

@ -0,0 +1,557 @@
from sympy.calculus.util import AccumBounds
from sympy.core.function import (Derivative, PoleError)
from sympy.core.numbers import (E, I, Integer, Rational, pi)
from sympy.core.singleton import S
from sympy.core.symbol import (Symbol, symbols)
from sympy.functions.elementary.complexes import sign
from sympy.functions.elementary.exponential import (exp, log)
from sympy.functions.elementary.hyperbolic import (acosh, acoth, asinh, atanh, cosh, coth, sinh, tanh)
from sympy.functions.elementary.integers import (ceiling, floor, frac)
from sympy.functions.elementary.miscellaneous import (cbrt, sqrt)
from sympy.functions.elementary.trigonometric import (asin, cos, cot, sin, tan)
from sympy.series.limits import limit
from sympy.series.order import O
from sympy.abc import x, y, z
from sympy.testing.pytest import raises, XFAIL
def test_simple_1():
assert x.nseries(x, n=5) == x
assert y.nseries(x, n=5) == y
assert (1/(x*y)).nseries(y, n=5) == 1/(x*y)
assert Rational(3, 4).nseries(x, n=5) == Rational(3, 4)
assert x.nseries() == x
def test_mul_0():
assert (x*log(x)).nseries(x, n=5) == x*log(x)
def test_mul_1():
assert (x*log(2 + x)).nseries(x, n=5) == x*log(2) + x**2/2 - x**3/8 + \
x**4/24 + O(x**5)
assert (x*log(1 + x)).nseries(
x, n=5) == x**2 - x**3/2 + x**4/3 + O(x**5)
def test_pow_0():
assert (x**2).nseries(x, n=5) == x**2
assert (1/x).nseries(x, n=5) == 1/x
assert (1/x**2).nseries(x, n=5) == 1/x**2
assert (x**Rational(2, 3)).nseries(x, n=5) == (x**Rational(2, 3))
assert (sqrt(x)**3).nseries(x, n=5) == (sqrt(x)**3)
def test_pow_1():
assert ((1 + x)**2).nseries(x, n=5) == x**2 + 2*x + 1
# https://github.com/sympy/sympy/issues/21075
assert ((sqrt(x) + 1)**2).nseries(x) == 2*sqrt(x) + x + 1
assert ((sqrt(x) + cbrt(x))**2).nseries(x) == 2*x**Rational(5, 6)\
+ x**Rational(2, 3) + x
def test_geometric_1():
assert (1/(1 - x)).nseries(x, n=5) == 1 + x + x**2 + x**3 + x**4 + O(x**5)
assert (x/(1 - x)).nseries(x, n=6) == x + x**2 + x**3 + x**4 + x**5 + O(x**6)
assert (x**3/(1 - x)).nseries(x, n=8) == x**3 + x**4 + x**5 + x**6 + \
x**7 + O(x**8)
def test_sqrt_1():
assert sqrt(1 + x).nseries(x, n=5) == 1 + x/2 - x**2/8 + x**3/16 - 5*x**4/128 + O(x**5)
def test_exp_1():
assert exp(x).nseries(x, n=5) == 1 + x + x**2/2 + x**3/6 + x**4/24 + O(x**5)
assert exp(x).nseries(x, n=12) == 1 + x + x**2/2 + x**3/6 + x**4/24 + x**5/120 + \
x**6/720 + x**7/5040 + x**8/40320 + x**9/362880 + x**10/3628800 + \
x**11/39916800 + O(x**12)
assert exp(1/x).nseries(x, n=5) == exp(1/x)
assert exp(1/(1 + x)).nseries(x, n=4) == \
(E*(1 - x - 13*x**3/6 + 3*x**2/2)).expand() + O(x**4)
assert exp(2 + x).nseries(x, n=5) == \
(exp(2)*(1 + x + x**2/2 + x**3/6 + x**4/24)).expand() + O(x**5)
def test_exp_sqrt_1():
assert exp(1 + sqrt(x)).nseries(x, n=3) == \
(exp(1)*(1 + sqrt(x) + x/2 + sqrt(x)*x/6)).expand() + O(sqrt(x)**3)
def test_power_x_x1():
assert (exp(x*log(x))).nseries(x, n=4) == \
1 + x*log(x) + x**2*log(x)**2/2 + x**3*log(x)**3/6 + O(x**4*log(x)**4)
def test_power_x_x2():
assert (x**x).nseries(x, n=4) == \
1 + x*log(x) + x**2*log(x)**2/2 + x**3*log(x)**3/6 + O(x**4*log(x)**4)
def test_log_singular1():
assert log(1 + 1/x).nseries(x, n=5) == x - log(x) - x**2/2 + x**3/3 - \
x**4/4 + O(x**5)
def test_log_power1():
e = 1 / (1/x + x ** (log(3)/log(2)))
assert e.nseries(x, n=5) == -x**(log(3)/log(2) + 2) + x + O(x**5)
def test_log_series():
l = Symbol('l')
e = 1/(1 - log(x))
assert e.nseries(x, n=5, logx=l) == 1/(1 - l)
def test_log2():
e = log(-1/x)
assert e.nseries(x, n=5) == -log(x) + log(-1)
def test_log3():
l = Symbol('l')
e = 1/log(-1/x)
assert e.nseries(x, n=4, logx=l) == 1/(-l + log(-1))
def test_series1():
e = sin(x)
assert e.nseries(x, 0, 0) != 0
assert e.nseries(x, 0, 0) == O(1, x)
assert e.nseries(x, 0, 1) == O(x, x)
assert e.nseries(x, 0, 2) == x + O(x**2, x)
assert e.nseries(x, 0, 3) == x + O(x**3, x)
assert e.nseries(x, 0, 4) == x - x**3/6 + O(x**4, x)
e = (exp(x) - 1)/x
assert e.nseries(x, 0, 3) == 1 + x/2 + x**2/6 + O(x**3)
assert x.nseries(x, 0, 2) == x
@XFAIL
def test_series1_failing():
assert x.nseries(x, 0, 0) == O(1, x)
assert x.nseries(x, 0, 1) == O(x, x)
def test_seriesbug1():
assert (1/x).nseries(x, 0, 3) == 1/x
assert (x + 1/x).nseries(x, 0, 3) == x + 1/x
def test_series2x():
assert ((x + 1)**(-2)).nseries(x, 0, 4) == 1 - 2*x + 3*x**2 - 4*x**3 + O(x**4, x)
assert ((x + 1)**(-1)).nseries(x, 0, 4) == 1 - x + x**2 - x**3 + O(x**4, x)
assert ((x + 1)**0).nseries(x, 0, 3) == 1
assert ((x + 1)**1).nseries(x, 0, 3) == 1 + x
assert ((x + 1)**2).nseries(x, 0, 3) == x**2 + 2*x + 1
assert ((x + 1)**3).nseries(x, 0, 3) == 1 + 3*x + 3*x**2 + O(x**3)
assert (1/(1 + x)).nseries(x, 0, 4) == 1 - x + x**2 - x**3 + O(x**4, x)
assert (x + 3/(1 + 2*x)).nseries(x, 0, 4) == 3 - 5*x + 12*x**2 - 24*x**3 + O(x**4, x)
assert ((1/x + 1)**3).nseries(x, 0, 3) == 1 + 3/x + 3/x**2 + x**(-3)
assert (1/(1 + 1/x)).nseries(x, 0, 4) == x - x**2 + x**3 - O(x**4, x)
assert (1/(1 + 1/x**2)).nseries(x, 0, 6) == x**2 - x**4 + O(x**6, x)
def test_bug2(): # 1/log(0)*log(0) problem
w = Symbol("w")
e = (w**(-1) + w**(
-log(3)*log(2)**(-1)))**(-1)*(3*w**(-log(3)*log(2)**(-1)) + 2*w**(-1))
e = e.expand()
assert e.nseries(w, 0, 4).subs(w, 0) == 3
def test_exp():
e = (1 + x)**(1/x)
assert e.nseries(x, n=3) == exp(1) - x*exp(1)/2 + 11*exp(1)*x**2/24 + O(x**3)
def test_exp2():
w = Symbol("w")
e = w**(1 - log(x)/(log(2) + log(x)))
logw = Symbol("logw")
assert e.nseries(
w, 0, 1, logx=logw) == exp(logw*log(2)/(log(x) + log(2)))
def test_bug3():
e = (2/x + 3/x**2)/(1/x + 1/x**2)
assert e.nseries(x, n=3) == 3 - x + x**2 + O(x**3)
def test_generalexponent():
p = 2
e = (2/x + 3/x**p)/(1/x + 1/x**p)
assert e.nseries(x, 0, 3) == 3 - x + x**2 + O(x**3)
p = S.Half
e = (2/x + 3/x**p)/(1/x + 1/x**p)
assert e.nseries(x, 0, 2) == 2 - x + sqrt(x) + x**(S(3)/2) + O(x**2)
e = 1 + sqrt(x)
assert e.nseries(x, 0, 4) == 1 + sqrt(x)
# more complicated example
def test_genexp_x():
e = 1/(1 + sqrt(x))
assert e.nseries(x, 0, 2) == \
1 + x - sqrt(x) - sqrt(x)**3 + O(x**2, x)
# more complicated example
def test_genexp_x2():
p = Rational(3, 2)
e = (2/x + 3/x**p)/(1/x + 1/x**p)
assert e.nseries(x, 0, 3) == 3 + x + x**2 - sqrt(x) - x**(S(3)/2) - x**(S(5)/2) + O(x**3)
def test_seriesbug2():
w = Symbol("w")
#simple case (1):
e = ((2*w)/w)**(1 + w)
assert e.nseries(w, 0, 1) == 2 + O(w, w)
assert e.nseries(w, 0, 1).subs(w, 0) == 2
def test_seriesbug2b():
w = Symbol("w")
#test sin
e = sin(2*w)/w
assert e.nseries(w, 0, 3) == 2 - 4*w**2/3 + O(w**3)
def test_seriesbug2d():
w = Symbol("w", real=True)
e = log(sin(2*w)/w)
assert e.series(w, n=5) == log(2) - 2*w**2/3 - 4*w**4/45 + O(w**5)
def test_seriesbug2c():
w = Symbol("w", real=True)
#more complicated case, but sin(x)~x, so the result is the same as in (1)
e = (sin(2*w)/w)**(1 + w)
assert e.series(w, 0, 1) == 2 + O(w)
assert e.series(w, 0, 3) == 2 + 2*w*log(2) + \
w**2*(Rational(-4, 3) + log(2)**2) + O(w**3)
assert e.series(w, 0, 2).subs(w, 0) == 2
def test_expbug4():
x = Symbol("x", real=True)
assert (log(
sin(2*x)/x)*(1 + x)).series(x, 0, 2) == log(2) + x*log(2) + O(x**2, x)
assert exp(
log(sin(2*x)/x)*(1 + x)).series(x, 0, 2) == 2 + 2*x*log(2) + O(x**2)
assert exp(log(2) + O(x)).nseries(x, 0, 2) == 2 + O(x)
assert ((2 + O(x))**(1 + x)).nseries(x, 0, 2) == 2 + O(x)
def test_logbug4():
assert log(2 + O(x)).nseries(x, 0, 2) == log(2) + O(x, x)
def test_expbug5():
assert exp(log(1 + x)/x).nseries(x, n=3) == exp(1) + -exp(1)*x/2 + 11*exp(1)*x**2/24 + O(x**3)
assert exp(O(x)).nseries(x, 0, 2) == 1 + O(x)
def test_sinsinbug():
assert sin(sin(x)).nseries(x, 0, 8) == x - x**3/3 + x**5/10 - 8*x**7/315 + O(x**8)
def test_issue_3258():
a = x/(exp(x) - 1)
assert a.nseries(x, 0, 5) == 1 - x/2 - x**4/720 + x**2/12 + O(x**5)
def test_issue_3204():
x = Symbol("x", nonnegative=True)
f = sin(x**3)**Rational(1, 3)
assert f.nseries(x, 0, 17) == x - x**7/18 - x**13/3240 + O(x**17)
def test_issue_3224():
f = sqrt(1 - sqrt(y))
assert f.nseries(y, 0, 2) == 1 - sqrt(y)/2 - y/8 - sqrt(y)**3/16 + O(y**2)
def test_issue_3463():
w, i = symbols('w,i')
r = log(5)/log(3)
p = w**(-1 + r)
e = 1/x*(-log(w**(1 + r)) + log(w + w**r))
e_ser = -r*log(w)/x + p/x - p**2/(2*x) + O(w)
assert e.nseries(w, n=1) == e_ser
def test_sin():
assert sin(8*x).nseries(x, n=4) == 8*x - 256*x**3/3 + O(x**4)
assert sin(x + y).nseries(x, n=1) == sin(y) + O(x)
assert sin(x + y).nseries(x, n=2) == sin(y) + cos(y)*x + O(x**2)
assert sin(x + y).nseries(x, n=5) == sin(y) + cos(y)*x - sin(y)*x**2/2 - \
cos(y)*x**3/6 + sin(y)*x**4/24 + O(x**5)
def test_issue_3515():
e = sin(8*x)/x
assert e.nseries(x, n=6) == 8 - 256*x**2/3 + 4096*x**4/15 + O(x**6)
def test_issue_3505():
e = sin(x)**(-4)*(sqrt(cos(x))*sin(x)**2 -
cos(x)**Rational(1, 3)*sin(x)**2)
assert e.nseries(x, n=9) == Rational(-1, 12) - 7*x**2/288 - \
43*x**4/10368 - 1123*x**6/2488320 + 377*x**8/29859840 + O(x**9)
def test_issue_3501():
a = Symbol("a")
e = x**(-2)*(x*sin(a + x) - x*sin(a))
assert e.nseries(x, n=6) == cos(a) - sin(a)*x/2 - cos(a)*x**2/6 + \
x**3*sin(a)/24 + x**4*cos(a)/120 - x**5*sin(a)/720 + O(x**6)
e = x**(-2)*(x*cos(a + x) - x*cos(a))
assert e.nseries(x, n=6) == -sin(a) - cos(a)*x/2 + sin(a)*x**2/6 + \
cos(a)*x**3/24 - x**4*sin(a)/120 - x**5*cos(a)/720 + O(x**6)
def test_issue_3502():
e = sin(5*x)/sin(2*x)
assert e.nseries(x, n=2) == Rational(5, 2) + O(x**2)
assert e.nseries(x, n=6) == \
Rational(5, 2) - 35*x**2/4 + 329*x**4/48 + O(x**6)
def test_issue_3503():
e = sin(2 + x)/(2 + x)
assert e.nseries(x, n=2) == sin(2)/2 + x*cos(2)/2 - x*sin(2)/4 + O(x**2)
def test_issue_3506():
e = (x + sin(3*x))**(-2)*(x*(x + sin(3*x)) - (x + sin(3*x))*sin(2*x))
assert e.nseries(x, n=7) == \
Rational(-1, 4) + 5*x**2/96 + 91*x**4/768 + 11117*x**6/129024 + O(x**7)
def test_issue_3508():
x = Symbol("x", real=True)
assert log(sin(x)).series(x, n=5) == log(x) - x**2/6 - x**4/180 + O(x**5)
e = -log(x) + x*(-log(x) + log(sin(2*x))) + log(sin(2*x))
assert e.series(x, n=5) == \
log(2) + log(2)*x - 2*x**2/3 - 2*x**3/3 - 4*x**4/45 + O(x**5)
def test_issue_3507():
e = x**(-4)*(x**2 - x**2*sqrt(cos(x)))
assert e.nseries(x, n=9) == \
Rational(1, 4) + x**2/96 + 19*x**4/5760 + 559*x**6/645120 + 29161*x**8/116121600 + O(x**9)
def test_issue_3639():
assert sin(cos(x)).nseries(x, n=5) == \
sin(1) - x**2*cos(1)/2 - x**4*sin(1)/8 + x**4*cos(1)/24 + O(x**5)
def test_hyperbolic():
assert sinh(x).nseries(x, n=6) == x + x**3/6 + x**5/120 + O(x**6)
assert cosh(x).nseries(x, n=5) == 1 + x**2/2 + x**4/24 + O(x**5)
assert tanh(x).nseries(x, n=6) == x - x**3/3 + 2*x**5/15 + O(x**6)
assert coth(x).nseries(x, n=6) == \
1/x - x**3/45 + x/3 + 2*x**5/945 + O(x**6)
assert asinh(x).nseries(x, n=6) == x - x**3/6 + 3*x**5/40 + O(x**6)
assert acosh(x).nseries(x, n=6) == \
pi*I/2 - I*x - 3*I*x**5/40 - I*x**3/6 + O(x**6)
assert atanh(x).nseries(x, n=6) == x + x**3/3 + x**5/5 + O(x**6)
assert acoth(x).nseries(x, n=6) == -I*pi/2 + x + x**3/3 + x**5/5 + O(x**6)
def test_series2():
w = Symbol("w", real=True)
x = Symbol("x", real=True)
e = w**(-2)*(w*exp(1/x - w) - w*exp(1/x))
assert e.nseries(w, n=4) == -exp(1/x) + w*exp(1/x)/2 - w**2*exp(1/x)/6 + w**3*exp(1/x)/24 + O(w**4)
def test_series3():
w = Symbol("w", real=True)
e = w**(-6)*(w**3*tan(w) - w**3*sin(w))
assert e.nseries(w, n=8) == Integer(1)/2 + w**2/8 + 13*w**4/240 + 529*w**6/24192 + O(w**8)
def test_bug4():
w = Symbol("w")
e = x/(w**4 + x**2*w**4 + 2*x*w**4)*w**4
assert e.nseries(w, n=2).removeO().expand() in [x/(1 + 2*x + x**2),
1/(1 + x/2 + 1/x/2)/2, 1/x/(1 + 2/x + x**(-2))]
def test_bug5():
w = Symbol("w")
l = Symbol('l')
e = (-log(w) + log(1 + w*log(x)))**(-2)*w**(-2)*((-log(w) +
log(1 + x*w))*(-log(w) + log(1 + w*log(x)))*w - x*(-log(w) +
log(1 + w*log(x)))*w)
assert e.nseries(w, n=0, logx=l) == x/w/l + 1/w + O(1, w)
assert e.nseries(w, n=1, logx=l) == x/w/l + 1/w - x/l + 1/l*log(x) \
+ x*log(x)/l**2 + O(w)
def test_issue_4115():
assert (sin(x)/(1 - cos(x))).nseries(x, n=1) == 2/x + O(x)
assert (sin(x)**2/(1 - cos(x))).nseries(x, n=1) == 2 + O(x)
def test_pole():
raises(PoleError, lambda: sin(1/x).series(x, 0, 5))
raises(PoleError, lambda: sin(1 + 1/x).series(x, 0, 5))
raises(PoleError, lambda: (x*sin(1/x)).series(x, 0, 5))
def test_expsinbug():
assert exp(sin(x)).series(x, 0, 0) == O(1, x)
assert exp(sin(x)).series(x, 0, 1) == 1 + O(x)
assert exp(sin(x)).series(x, 0, 2) == 1 + x + O(x**2)
assert exp(sin(x)).series(x, 0, 3) == 1 + x + x**2/2 + O(x**3)
assert exp(sin(x)).series(x, 0, 4) == 1 + x + x**2/2 + O(x**4)
assert exp(sin(x)).series(x, 0, 5) == 1 + x + x**2/2 - x**4/8 + O(x**5)
def test_floor():
x = Symbol('x')
assert floor(x).series(x) == 0
assert floor(-x).series(x) == -1
assert floor(sin(x)).series(x) == 0
assert floor(sin(-x)).series(x) == -1
assert floor(x**3).series(x) == 0
assert floor(-x**3).series(x) == -1
assert floor(cos(x)).series(x) == 0
assert floor(cos(-x)).series(x) == 0
assert floor(5 + sin(x)).series(x) == 5
assert floor(5 + sin(-x)).series(x) == 4
assert floor(x).series(x, 2) == 2
assert floor(-x).series(x, 2) == -3
x = Symbol('x', negative=True)
assert floor(x + 1.5).series(x) == 1
def test_frac():
assert frac(x).series(x, cdir=1) == x
assert frac(x).series(x, cdir=-1) == 1 + x
assert frac(2*x + 1).series(x, cdir=1) == 2*x
assert frac(2*x + 1).series(x, cdir=-1) == 1 + 2*x
assert frac(x**2).series(x, cdir=1) == x**2
assert frac(x**2).series(x, cdir=-1) == x**2
assert frac(sin(x) + 5).series(x, cdir=1) == x - x**3/6 + x**5/120 + O(x**6)
assert frac(sin(x) + 5).series(x, cdir=-1) == 1 + x - x**3/6 + x**5/120 + O(x**6)
assert frac(sin(x) + S.Half).series(x) == S.Half + x - x**3/6 + x**5/120 + O(x**6)
assert frac(x**8).series(x, cdir=1) == O(x**6)
assert frac(1/x).series(x) == AccumBounds(0, 1) + O(x**6)
def test_ceiling():
assert ceiling(x).series(x) == 1
assert ceiling(-x).series(x) == 0
assert ceiling(sin(x)).series(x) == 1
assert ceiling(sin(-x)).series(x) == 0
assert ceiling(1 - cos(x)).series(x) == 1
assert ceiling(1 - cos(-x)).series(x) == 1
assert ceiling(x).series(x, 2) == 3
assert ceiling(-x).series(x, 2) == -2
def test_abs():
a = Symbol('a')
assert abs(x).nseries(x, n=4) == x
assert abs(-x).nseries(x, n=4) == x
assert abs(x + 1).nseries(x, n=4) == x + 1
assert abs(sin(x)).nseries(x, n=4) == x - Rational(1, 6)*x**3 + O(x**4)
assert abs(sin(-x)).nseries(x, n=4) == x - Rational(1, 6)*x**3 + O(x**4)
assert abs(x - a).nseries(x, 1) == -a*sign(1 - a) + (x - 1)*sign(1 - a) + sign(1 - a)
def test_dir():
assert abs(x).series(x, 0, dir="+") == x
assert abs(x).series(x, 0, dir="-") == -x
assert floor(x + 2).series(x, 0, dir='+') == 2
assert floor(x + 2).series(x, 0, dir='-') == 1
assert floor(x + 2.2).series(x, 0, dir='-') == 2
assert ceiling(x + 2.2).series(x, 0, dir='-') == 3
assert sin(x + y).series(x, 0, dir='-') == sin(x + y).series(x, 0, dir='+')
def test_cdir():
assert abs(x).series(x, 0, cdir=1) == x
assert abs(x).series(x, 0, cdir=-1) == -x
assert floor(x + 2).series(x, 0, cdir=1) == 2
assert floor(x + 2).series(x, 0, cdir=-1) == 1
assert floor(x + 2.2).series(x, 0, cdir=1) == 2
assert ceiling(x + 2.2).series(x, 0, cdir=-1) == 3
assert sin(x + y).series(x, 0, cdir=-1) == sin(x + y).series(x, 0, cdir=1)
def test_issue_3504():
a = Symbol("a")
e = asin(a*x)/x
assert e.series(x, 4, n=2).removeO() == \
(x - 4)*(a/(4*sqrt(-16*a**2 + 1)) - asin(4*a)/16) + asin(4*a)/4
def test_issue_4441():
a, b = symbols('a,b')
f = 1/(1 + a*x)
assert f.series(x, 0, 5) == 1 - a*x + a**2*x**2 - a**3*x**3 + \
a**4*x**4 + O(x**5)
f = 1/(1 + (a + b)*x)
assert f.series(x, 0, 3) == 1 + x*(-a - b)\
+ x**2*(a + b)**2 + O(x**3)
def test_issue_4329():
assert tan(x).series(x, pi/2, n=3).removeO() == \
-pi/6 + x/3 - 1/(x - pi/2)
assert cot(x).series(x, pi, n=3).removeO() == \
-x/3 + pi/3 + 1/(x - pi)
assert limit(tan(x)**tan(2*x), x, pi/4) == exp(-1)
def test_issue_5183():
assert abs(x + x**2).series(n=1) == O(x)
assert abs(x + x**2).series(n=2) == x + O(x**2)
assert ((1 + x)**2).series(x, n=6) == x**2 + 2*x + 1
assert (1 + 1/x).series() == 1 + 1/x
assert Derivative(exp(x).series(), x).doit() == \
1 + x + x**2/2 + x**3/6 + x**4/24 + O(x**5)
def test_issue_5654():
a = Symbol('a')
assert (1/(x**2+a**2)**2).nseries(x, x0=I*a, n=0) == \
-I/(4*a**3*(-I*a + x)) - 1/(4*a**2*(-I*a + x)**2) + O(1, (x, I*a))
assert (1/(x**2+a**2)**2).nseries(x, x0=I*a, n=1) == 3/(16*a**4) \
-I/(4*a**3*(-I*a + x)) - 1/(4*a**2*(-I*a + x)**2) + O(-I*a + x, (x, I*a))
def test_issue_5925():
sx = sqrt(x + z).series(z, 0, 1)
sxy = sqrt(x + y + z).series(z, 0, 1)
s1, s2 = sx.subs(x, x + y), sxy
assert (s1 - s2).expand().removeO().simplify() == 0
sx = sqrt(x + z).series(z, 0, 1)
sxy = sqrt(x + y + z).series(z, 0, 1)
assert sxy.subs({x:1, y:2}) == sx.subs(x, 3)
def test_exp_2():
assert exp(x**3).nseries(x, 0, 14) == 1 + x**3 + x**6/2 + x**9/6 + x**12/24 + O(x**14)

View File

@ -0,0 +1,477 @@
from sympy.core.add import Add
from sympy.core.function import (Function, expand)
from sympy.core.numbers import (I, Rational, nan, oo, pi)
from sympy.core.singleton import S
from sympy.core.symbol import (Symbol, symbols)
from sympy.functions.elementary.complexes import (conjugate, transpose)
from sympy.functions.elementary.exponential import (exp, log)
from sympy.functions.elementary.miscellaneous import sqrt
from sympy.functions.elementary.trigonometric import (cos, sin)
from sympy.integrals.integrals import Integral
from sympy.series.order import O, Order
from sympy.core.expr import unchanged
from sympy.testing.pytest import raises
from sympy.abc import w, x, y, z
def test_caching_bug():
#needs to be a first test, so that all caches are clean
#cache it
O(w)
#and test that this won't raise an exception
O(w**(-1/x/log(3)*log(5)), w)
def test_free_symbols():
assert Order(1).free_symbols == set()
assert Order(x).free_symbols == {x}
assert Order(1, x).free_symbols == {x}
assert Order(x*y).free_symbols == {x, y}
assert Order(x, x, y).free_symbols == {x, y}
def test_simple_1():
o = Rational(0)
assert Order(2*x) == Order(x)
assert Order(x)*3 == Order(x)
assert -28*Order(x) == Order(x)
assert Order(Order(x)) == Order(x)
assert Order(Order(x), y) == Order(Order(x), x, y)
assert Order(-23) == Order(1)
assert Order(exp(x)) == Order(1, x)
assert Order(exp(1/x)).expr == exp(1/x)
assert Order(x*exp(1/x)).expr == x*exp(1/x)
assert Order(x**(o/3)).expr == x**(o/3)
assert Order(x**(o*Rational(5, 3))).expr == x**(o*Rational(5, 3))
assert Order(x**2 + x + y, x) == O(1, x)
assert Order(x**2 + x + y, y) == O(1, y)
raises(ValueError, lambda: Order(exp(x), x, x))
raises(TypeError, lambda: Order(x, 2 - x))
def test_simple_2():
assert Order(2*x)*x == Order(x**2)
assert Order(2*x)/x == Order(1, x)
assert Order(2*x)*x*exp(1/x) == Order(x**2*exp(1/x))
assert (Order(2*x)*x*exp(1/x)/log(x)**3).expr == x**2*exp(1/x)*log(x)**-3
def test_simple_3():
assert Order(x) + x == Order(x)
assert Order(x) + 2 == 2 + Order(x)
assert Order(x) + x**2 == Order(x)
assert Order(x) + 1/x == 1/x + Order(x)
assert Order(1/x) + 1/x**2 == 1/x**2 + Order(1/x)
assert Order(x) + exp(1/x) == Order(x) + exp(1/x)
def test_simple_4():
assert Order(x)**2 == Order(x**2)
def test_simple_5():
assert Order(x) + Order(x**2) == Order(x)
assert Order(x) + Order(x**-2) == Order(x**-2)
assert Order(x) + Order(1/x) == Order(1/x)
def test_simple_6():
assert Order(x) - Order(x) == Order(x)
assert Order(x) + Order(1) == Order(1)
assert Order(x) + Order(x**2) == Order(x)
assert Order(1/x) + Order(1) == Order(1/x)
assert Order(x) + Order(exp(1/x)) == Order(exp(1/x))
assert Order(x**3) + Order(exp(2/x)) == Order(exp(2/x))
assert Order(x**-3) + Order(exp(2/x)) == Order(exp(2/x))
def test_simple_7():
assert 1 + O(1) == O(1)
assert 2 + O(1) == O(1)
assert x + O(1) == O(1)
assert 1/x + O(1) == 1/x + O(1)
def test_simple_8():
assert O(sqrt(-x)) == O(sqrt(x))
assert O(x**2*sqrt(x)) == O(x**Rational(5, 2))
assert O(x**3*sqrt(-(-x)**3)) == O(x**Rational(9, 2))
assert O(x**Rational(3, 2)*sqrt((-x)**3)) == O(x**3)
assert O(x*(-2*x)**(I/2)) == O(x*(-x)**(I/2))
def test_as_expr_variables():
assert Order(x).as_expr_variables(None) == (x, ((x, 0),))
assert Order(x).as_expr_variables(((x, 0),)) == (x, ((x, 0),))
assert Order(y).as_expr_variables(((x, 0),)) == (y, ((x, 0), (y, 0)))
assert Order(y).as_expr_variables(((x, 0), (y, 0))) == (y, ((x, 0), (y, 0)))
def test_contains_0():
assert Order(1, x).contains(Order(1, x))
assert Order(1, x).contains(Order(1))
assert Order(1).contains(Order(1, x)) is False
def test_contains_1():
assert Order(x).contains(Order(x))
assert Order(x).contains(Order(x**2))
assert not Order(x**2).contains(Order(x))
assert not Order(x).contains(Order(1/x))
assert not Order(1/x).contains(Order(exp(1/x)))
assert not Order(x).contains(Order(exp(1/x)))
assert Order(1/x).contains(Order(x))
assert Order(exp(1/x)).contains(Order(x))
assert Order(exp(1/x)).contains(Order(1/x))
assert Order(exp(1/x)).contains(Order(exp(1/x)))
assert Order(exp(2/x)).contains(Order(exp(1/x)))
assert not Order(exp(1/x)).contains(Order(exp(2/x)))
def test_contains_2():
assert Order(x).contains(Order(y)) is None
assert Order(x).contains(Order(y*x))
assert Order(y*x).contains(Order(x))
assert Order(y).contains(Order(x*y))
assert Order(x).contains(Order(y**2*x))
def test_contains_3():
assert Order(x*y**2).contains(Order(x**2*y)) is None
assert Order(x**2*y).contains(Order(x*y**2)) is None
def test_contains_4():
assert Order(sin(1/x**2)).contains(Order(cos(1/x**2))) is True
assert Order(cos(1/x**2)).contains(Order(sin(1/x**2))) is True
def test_contains():
assert Order(1, x) not in Order(1)
assert Order(1) in Order(1, x)
raises(TypeError, lambda: Order(x*y**2) in Order(x**2*y))
def test_add_1():
assert Order(x + x) == Order(x)
assert Order(3*x - 2*x**2) == Order(x)
assert Order(1 + x) == Order(1, x)
assert Order(1 + 1/x) == Order(1/x)
# TODO : A better output for Order(log(x) + 1/log(x))
# could be Order(log(x)). Currently Order for expressions
# where all arguments would involve a log term would fall
# in this category and outputs for these should be improved.
assert Order(log(x) + 1/log(x)) == Order((log(x)**2 + 1)/log(x))
assert Order(exp(1/x) + x) == Order(exp(1/x))
assert Order(exp(1/x) + 1/x**20) == Order(exp(1/x))
def test_ln_args():
assert O(log(x)) + O(log(2*x)) == O(log(x))
assert O(log(x)) + O(log(x**3)) == O(log(x))
assert O(log(x*y)) + O(log(x) + log(y)) == O(log(x) + log(y), x, y)
def test_multivar_0():
assert Order(x*y).expr == x*y
assert Order(x*y**2).expr == x*y**2
assert Order(x*y, x).expr == x
assert Order(x*y**2, y).expr == y**2
assert Order(x*y*z).expr == x*y*z
assert Order(x/y).expr == x/y
assert Order(x*exp(1/y)).expr == x*exp(1/y)
assert Order(exp(x)*exp(1/y)).expr == exp(x)*exp(1/y)
def test_multivar_0a():
assert Order(exp(1/x)*exp(1/y)).expr == exp(1/x)*exp(1/y)
def test_multivar_1():
assert Order(x + y).expr == x + y
assert Order(x + 2*y).expr == x + y
assert (Order(x + y) + x).expr == (x + y)
assert (Order(x + y) + x**2) == Order(x + y)
assert (Order(x + y) + 1/x) == 1/x + Order(x + y)
assert Order(x**2 + y*x).expr == x**2 + y*x
def test_multivar_2():
assert Order(x**2*y + y**2*x, x, y).expr == x**2*y + y**2*x
def test_multivar_mul_1():
assert Order(x + y)*x == Order(x**2 + y*x, x, y)
def test_multivar_3():
assert (Order(x) + Order(y)).args in [
(Order(x), Order(y)),
(Order(y), Order(x))]
assert Order(x) + Order(y) + Order(x + y) == Order(x + y)
assert (Order(x**2*y) + Order(y**2*x)).args in [
(Order(x*y**2), Order(y*x**2)),
(Order(y*x**2), Order(x*y**2))]
assert (Order(x**2*y) + Order(y*x)) == Order(x*y)
def test_issue_3468():
y = Symbol('y', negative=True)
z = Symbol('z', complex=True)
# check that Order does not modify assumptions about symbols
Order(x)
Order(y)
Order(z)
assert x.is_positive is None
assert y.is_positive is False
assert z.is_positive is None
def test_leading_order():
assert (x + 1 + 1/x**5).extract_leading_order(x) == ((1/x**5, O(1/x**5)),)
assert (1 + 1/x).extract_leading_order(x) == ((1/x, O(1/x)),)
assert (1 + x).extract_leading_order(x) == ((1, O(1, x)),)
assert (1 + x**2).extract_leading_order(x) == ((1, O(1, x)),)
assert (2 + x**2).extract_leading_order(x) == ((2, O(1, x)),)
assert (x + x**2).extract_leading_order(x) == ((x, O(x)),)
def test_leading_order2():
assert set((2 + pi + x**2).extract_leading_order(x)) == {(pi, O(1, x)),
(S(2), O(1, x))}
assert set((2*x + pi*x + x**2).extract_leading_order(x)) == {(2*x, O(x)),
(x*pi, O(x))}
def test_order_leadterm():
assert O(x**2)._eval_as_leading_term(x) == O(x**2)
def test_order_symbols():
e = x*y*sin(x)*Integral(x, (x, 1, 2))
assert O(e) == O(x**2*y, x, y)
assert O(e, x) == O(x**2)
def test_nan():
assert O(nan) is nan
assert not O(x).contains(nan)
def test_O1():
assert O(1, x) * x == O(x)
assert O(1, y) * x == O(1, y)
def test_getn():
# other lines are tested incidentally by the suite
assert O(x).getn() == 1
assert O(x/log(x)).getn() == 1
assert O(x**2/log(x)**2).getn() == 2
assert O(x*log(x)).getn() == 1
raises(NotImplementedError, lambda: (O(x) + O(y)).getn())
def test_diff():
assert O(x**2).diff(x) == O(x)
def test_getO():
assert (x).getO() is None
assert (x).removeO() == x
assert (O(x)).getO() == O(x)
assert (O(x)).removeO() == 0
assert (z + O(x) + O(y)).getO() == O(x) + O(y)
assert (z + O(x) + O(y)).removeO() == z
raises(NotImplementedError, lambda: (O(x) + O(y)).getn())
def test_leading_term():
from sympy.functions.special.gamma_functions import digamma
assert O(1/digamma(1/x)) == O(1/log(x))
def test_eval():
assert Order(x).subs(Order(x), 1) == 1
assert Order(x).subs(x, y) == Order(y)
assert Order(x).subs(y, x) == Order(x)
assert Order(x).subs(x, x + y) == Order(x + y, (x, -y))
assert (O(1)**x).is_Pow
def test_issue_4279():
a, b = symbols('a b')
assert O(a, a, b) + O(1, a, b) == O(1, a, b)
assert O(b, a, b) + O(1, a, b) == O(1, a, b)
assert O(a + b, a, b) + O(1, a, b) == O(1, a, b)
assert O(1, a, b) + O(a, a, b) == O(1, a, b)
assert O(1, a, b) + O(b, a, b) == O(1, a, b)
assert O(1, a, b) + O(a + b, a, b) == O(1, a, b)
def test_issue_4855():
assert 1/O(1) != O(1)
assert 1/O(x) != O(1/x)
assert 1/O(x, (x, oo)) != O(1/x, (x, oo))
f = Function('f')
assert 1/O(f(x)) != O(1/x)
def test_order_conjugate_transpose():
x = Symbol('x', real=True)
y = Symbol('y', imaginary=True)
assert conjugate(Order(x)) == Order(conjugate(x))
assert conjugate(Order(y)) == Order(conjugate(y))
assert conjugate(Order(x**2)) == Order(conjugate(x)**2)
assert conjugate(Order(y**2)) == Order(conjugate(y)**2)
assert transpose(Order(x)) == Order(transpose(x))
assert transpose(Order(y)) == Order(transpose(y))
assert transpose(Order(x**2)) == Order(transpose(x)**2)
assert transpose(Order(y**2)) == Order(transpose(y)**2)
def test_order_noncommutative():
A = Symbol('A', commutative=False)
assert Order(A + A*x, x) == Order(1, x)
assert (A + A*x)*Order(x) == Order(x)
assert (A*x)*Order(x) == Order(x**2, x)
assert expand((1 + Order(x))*A*A*x) == A*A*x + Order(x**2, x)
assert expand((A*A + Order(x))*x) == A*A*x + Order(x**2, x)
assert expand((A + Order(x))*A*x) == A*A*x + Order(x**2, x)
def test_issue_6753():
assert (1 + x**2)**10000*O(x) == O(x)
def test_order_at_infinity():
assert Order(1 + x, (x, oo)) == Order(x, (x, oo))
assert Order(3*x, (x, oo)) == Order(x, (x, oo))
assert Order(x, (x, oo))*3 == Order(x, (x, oo))
assert -28*Order(x, (x, oo)) == Order(x, (x, oo))
assert Order(Order(x, (x, oo)), (x, oo)) == Order(x, (x, oo))
assert Order(Order(x, (x, oo)), (y, oo)) == Order(x, (x, oo), (y, oo))
assert Order(3, (x, oo)) == Order(1, (x, oo))
assert Order(x**2 + x + y, (x, oo)) == O(x**2, (x, oo))
assert Order(x**2 + x + y, (y, oo)) == O(y, (y, oo))
assert Order(2*x, (x, oo))*x == Order(x**2, (x, oo))
assert Order(2*x, (x, oo))/x == Order(1, (x, oo))
assert Order(2*x, (x, oo))*x*exp(1/x) == Order(x**2*exp(1/x), (x, oo))
assert Order(2*x, (x, oo))*x*exp(1/x)/log(x)**3 == Order(x**2*exp(1/x)*log(x)**-3, (x, oo))
assert Order(x, (x, oo)) + 1/x == 1/x + Order(x, (x, oo)) == Order(x, (x, oo))
assert Order(x, (x, oo)) + 1 == 1 + Order(x, (x, oo)) == Order(x, (x, oo))
assert Order(x, (x, oo)) + x == x + Order(x, (x, oo)) == Order(x, (x, oo))
assert Order(x, (x, oo)) + x**2 == x**2 + Order(x, (x, oo))
assert Order(1/x, (x, oo)) + 1/x**2 == 1/x**2 + Order(1/x, (x, oo)) == Order(1/x, (x, oo))
assert Order(x, (x, oo)) + exp(1/x) == exp(1/x) + Order(x, (x, oo))
assert Order(x, (x, oo))**2 == Order(x**2, (x, oo))
assert Order(x, (x, oo)) + Order(x**2, (x, oo)) == Order(x**2, (x, oo))
assert Order(x, (x, oo)) + Order(x**-2, (x, oo)) == Order(x, (x, oo))
assert Order(x, (x, oo)) + Order(1/x, (x, oo)) == Order(x, (x, oo))
assert Order(x, (x, oo)) - Order(x, (x, oo)) == Order(x, (x, oo))
assert Order(x, (x, oo)) + Order(1, (x, oo)) == Order(x, (x, oo))
assert Order(x, (x, oo)) + Order(x**2, (x, oo)) == Order(x**2, (x, oo))
assert Order(1/x, (x, oo)) + Order(1, (x, oo)) == Order(1, (x, oo))
assert Order(x, (x, oo)) + Order(exp(1/x), (x, oo)) == Order(x, (x, oo))
assert Order(x**3, (x, oo)) + Order(exp(2/x), (x, oo)) == Order(x**3, (x, oo))
assert Order(x**-3, (x, oo)) + Order(exp(2/x), (x, oo)) == Order(exp(2/x), (x, oo))
# issue 7207
assert Order(exp(x), (x, oo)).expr == Order(2*exp(x), (x, oo)).expr == exp(x)
assert Order(y**x, (x, oo)).expr == Order(2*y**x, (x, oo)).expr == exp(x*log(y))
# issue 19545
assert Order(1/x - 3/(3*x + 2), (x, oo)).expr == x**(-2)
def test_mixing_order_at_zero_and_infinity():
assert (Order(x, (x, 0)) + Order(x, (x, oo))).is_Add
assert Order(x, (x, 0)) + Order(x, (x, oo)) == Order(x, (x, oo)) + Order(x, (x, 0))
assert Order(Order(x, (x, oo))) == Order(x, (x, oo))
# not supported (yet)
raises(NotImplementedError, lambda: Order(x, (x, 0))*Order(x, (x, oo)))
raises(NotImplementedError, lambda: Order(x, (x, oo))*Order(x, (x, 0)))
raises(NotImplementedError, lambda: Order(Order(x, (x, oo)), y))
raises(NotImplementedError, lambda: Order(Order(x), (x, oo)))
def test_order_at_some_point():
assert Order(x, (x, 1)) == Order(1, (x, 1))
assert Order(2*x - 2, (x, 1)) == Order(x - 1, (x, 1))
assert Order(-x + 1, (x, 1)) == Order(x - 1, (x, 1))
assert Order(x - 1, (x, 1))**2 == Order((x - 1)**2, (x, 1))
assert Order(x - 2, (x, 2)) - O(x - 2, (x, 2)) == Order(x - 2, (x, 2))
def test_order_subs_limits():
# issue 3333
assert (1 + Order(x)).subs(x, 1/x) == 1 + Order(1/x, (x, oo))
assert (1 + Order(x)).limit(x, 0) == 1
# issue 5769
assert ((x + Order(x**2))/x).limit(x, 0) == 1
assert Order(x**2).subs(x, y - 1) == Order((y - 1)**2, (y, 1))
assert Order(10*x**2, (x, 2)).subs(x, y - 1) == Order(1, (y, 3))
def test_issue_9351():
assert exp(x).series(x, 10, 1) == exp(10) + Order(x - 10, (x, 10))
def test_issue_9192():
assert O(1)*O(1) == O(1)
assert O(1)**O(1) == O(1)
def test_issue_9910():
assert O(x*log(x) + sin(x), (x, oo)) == O(x*log(x), (x, oo))
def test_performance_of_adding_order():
l = [x**i for i in range(1000)]
l.append(O(x**1001))
assert Add(*l).subs(x,1) == O(1)
def test_issue_14622():
assert (x**(-4) + x**(-3) + x**(-1) + O(x**(-6), (x, oo))).as_numer_denom() == (
x**4 + x**5 + x**7 + O(x**2, (x, oo)), x**8)
assert (x**3 + O(x**2, (x, oo))).is_Add
assert O(x**2, (x, oo)).contains(x**3) is False
assert O(x, (x, oo)).contains(O(x, (x, 0))) is None
assert O(x, (x, 0)).contains(O(x, (x, oo))) is None
raises(NotImplementedError, lambda: O(x**3).contains(x**w))
def test_issue_15539():
assert O(1/x**2 + 1/x**4, (x, -oo)) == O(1/x**2, (x, -oo))
assert O(1/x**4 + exp(x), (x, -oo)) == O(1/x**4, (x, -oo))
assert O(1/x**4 + exp(-x), (x, -oo)) == O(exp(-x), (x, -oo))
assert O(1/x, (x, oo)).subs(x, -x) == O(-1/x, (x, -oo))
def test_issue_18606():
assert unchanged(Order, 0)
def test_issue_22165():
assert O(log(x)).contains(2)
def test_issue_23231():
# This test checks Order for expressions having
# arguments containing variables in exponents/powers.
assert O(x**x + 2**x, (x, oo)) == O(exp(x*log(x)), (x, oo))
assert O(x**x + x**2, (x, oo)) == O(exp(x*log(x)), (x, oo))
assert O(x**x + 1/x**2, (x, oo)) == O(exp(x*log(x)), (x, oo))
assert O(2**x + 3**x , (x, oo)) == O(exp(x*log(3)), (x, oo))
def test_issue_9917():
assert O(x*sin(x) + 1, (x, oo)) == O(x, (x, oo))

View File

@ -0,0 +1,101 @@
from sympy.core.function import Function
from sympy.core.numbers import (I, Rational, pi)
from sympy.core.singleton import S
from sympy.core.symbol import Symbol
from sympy.functions.combinatorial.factorials import factorial
from sympy.functions.elementary.exponential import (exp, log)
from sympy.functions.elementary.hyperbolic import tanh
from sympy.functions.elementary.miscellaneous import sqrt
from sympy.functions.elementary.trigonometric import (cot, sin, tan)
from sympy.series.residues import residue
from sympy.testing.pytest import XFAIL, raises
from sympy.abc import x, z, a, s, k
def test_basic1():
assert residue(1/x, x, 0) == 1
assert residue(-2/x, x, 0) == -2
assert residue(81/x, x, 0) == 81
assert residue(1/x**2, x, 0) == 0
assert residue(0, x, 0) == 0
assert residue(5, x, 0) == 0
assert residue(x, x, 0) == 0
assert residue(x**2, x, 0) == 0
def test_basic2():
assert residue(1/x, x, 1) == 0
assert residue(-2/x, x, 1) == 0
assert residue(81/x, x, -1) == 0
assert residue(1/x**2, x, 1) == 0
assert residue(0, x, 1) == 0
assert residue(5, x, 1) == 0
assert residue(x, x, 1) == 0
assert residue(x**2, x, 5) == 0
def test_f():
f = Function("f")
assert residue(f(x)/x**5, x, 0) == f(x).diff(x, 4).subs(x, 0)/24
def test_functions():
assert residue(1/sin(x), x, 0) == 1
assert residue(2/sin(x), x, 0) == 2
assert residue(1/sin(x)**2, x, 0) == 0
assert residue(1/sin(x)**5, x, 0) == Rational(3, 8)
def test_expressions():
assert residue(1/(x + 1), x, 0) == 0
assert residue(1/(x + 1), x, -1) == 1
assert residue(1/(x**2 + 1), x, -1) == 0
assert residue(1/(x**2 + 1), x, I) == -I/2
assert residue(1/(x**2 + 1), x, -I) == I/2
assert residue(1/(x**4 + 1), x, 0) == 0
assert residue(1/(x**4 + 1), x, exp(I*pi/4)).equals(-(Rational(1, 4) + I/4)/sqrt(2))
assert residue(1/(x**2 + a**2)**2, x, a*I) == -I/4/a**3
@XFAIL
def test_expressions_failing():
n = Symbol('n', integer=True, positive=True)
assert residue(exp(z)/(z - pi*I/4*a)**n, z, I*pi*a) == \
exp(I*pi*a/4)/factorial(n - 1)
def test_NotImplemented():
raises(NotImplementedError, lambda: residue(exp(1/z), z, 0))
def test_bug():
assert residue(2**(z)*(s + z)*(1 - s - z)/z**2, z, 0) == \
1 + s*log(2) - s**2*log(2) - 2*s
def test_issue_5654():
assert residue(1/(x**2 + a**2)**2, x, a*I) == -I/(4*a**3)
assert residue(1/s*1/(z - exp(s)), s, 0) == 1/(z - 1)
assert residue((1 + k)/s*1/(z - exp(s)), s, 0) == k/(z - 1) + 1/(z - 1)
def test_issue_6499():
assert residue(1/(exp(z) - 1), z, 0) == 1
def test_issue_14037():
assert residue(sin(x**50)/x**51, x, 0) == 1
def test_issue_21176():
f = x**2*cot(pi*x)/(x**4 + 1)
assert residue(f, x, -sqrt(2)/2 - sqrt(2)*I/2).cancel().together(deep=True)\
== sqrt(2)*(1 - I)/(8*tan(sqrt(2)*pi*(1 + I)/2))
def test_issue_21177():
r = -sqrt(3)*tanh(sqrt(3)*pi/2)/3
a = residue(cot(pi*x)/((x - 1)*(x - 2) + 1), x, S(3)/2 - sqrt(3)*I/2)
b = residue(cot(pi*x)/(x**2 - 3*x + 3), x, S(3)/2 - sqrt(3)*I/2)
assert a == r
assert (b - a).cancel() == 0

View File

@ -0,0 +1,312 @@
from sympy.core.containers import Tuple
from sympy.core.function import Function
from sympy.core.numbers import oo, Rational
from sympy.core.singleton import S
from sympy.core.symbol import symbols, Symbol
from sympy.functions.combinatorial.numbers import tribonacci, fibonacci
from sympy.functions.elementary.exponential import exp
from sympy.functions.elementary.miscellaneous import sqrt
from sympy.functions.elementary.trigonometric import cos, sin
from sympy.series import EmptySequence
from sympy.series.sequences import (SeqMul, SeqAdd, SeqPer, SeqFormula,
sequence)
from sympy.sets.sets import Interval
from sympy.tensor.indexed import Indexed, Idx
from sympy.series.sequences import SeqExpr, SeqExprOp, RecursiveSeq
from sympy.testing.pytest import raises, slow
x, y, z = symbols('x y z')
n, m = symbols('n m')
def test_EmptySequence():
assert S.EmptySequence is EmptySequence
assert S.EmptySequence.interval is S.EmptySet
assert S.EmptySequence.length is S.Zero
assert list(S.EmptySequence) == []
def test_SeqExpr():
#SeqExpr is a baseclass and does not take care of
#ensuring all arguments are Basics hence the use of
#Tuple(...) here.
s = SeqExpr(Tuple(1, n, y), Tuple(x, 0, 10))
assert isinstance(s, SeqExpr)
assert s.gen == (1, n, y)
assert s.interval == Interval(0, 10)
assert s.start == 0
assert s.stop == 10
assert s.length == 11
assert s.variables == (x,)
assert SeqExpr(Tuple(1, 2, 3), Tuple(x, 0, oo)).length is oo
def test_SeqPer():
s = SeqPer((1, n, 3), (x, 0, 5))
assert isinstance(s, SeqPer)
assert s.periodical == Tuple(1, n, 3)
assert s.period == 3
assert s.coeff(3) == 1
assert s.free_symbols == {n}
assert list(s) == [1, n, 3, 1, n, 3]
assert s[:] == [1, n, 3, 1, n, 3]
assert SeqPer((1, n, 3), (x, -oo, 0))[0:6] == [1, n, 3, 1, n, 3]
raises(ValueError, lambda: SeqPer((1, 2, 3), (0, 1, 2)))
raises(ValueError, lambda: SeqPer((1, 2, 3), (x, -oo, oo)))
raises(ValueError, lambda: SeqPer(n**2, (0, oo)))
assert SeqPer((n, n**2, n**3), (m, 0, oo))[:6] == \
[n, n**2, n**3, n, n**2, n**3]
assert SeqPer((n, n**2, n**3), (n, 0, oo))[:6] == [0, 1, 8, 3, 16, 125]
assert SeqPer((n, m), (n, 0, oo))[:6] == [0, m, 2, m, 4, m]
def test_SeqFormula():
s = SeqFormula(n**2, (n, 0, 5))
assert isinstance(s, SeqFormula)
assert s.formula == n**2
assert s.coeff(3) == 9
assert list(s) == [i**2 for i in range(6)]
assert s[:] == [i**2 for i in range(6)]
assert SeqFormula(n**2, (n, -oo, 0))[0:6] == [i**2 for i in range(6)]
assert SeqFormula(n**2, (0, oo)) == SeqFormula(n**2, (n, 0, oo))
assert SeqFormula(n**2, (0, m)).subs(m, x) == SeqFormula(n**2, (0, x))
assert SeqFormula(m*n**2, (n, 0, oo)).subs(m, x) == \
SeqFormula(x*n**2, (n, 0, oo))
raises(ValueError, lambda: SeqFormula(n**2, (0, 1, 2)))
raises(ValueError, lambda: SeqFormula(n**2, (n, -oo, oo)))
raises(ValueError, lambda: SeqFormula(m*n**2, (0, oo)))
seq = SeqFormula(x*(y**2 + z), (z, 1, 100))
assert seq.expand() == SeqFormula(x*y**2 + x*z, (z, 1, 100))
seq = SeqFormula(sin(x*(y**2 + z)),(z, 1, 100))
assert seq.expand(trig=True) == SeqFormula(sin(x*y**2)*cos(x*z) + sin(x*z)*cos(x*y**2), (z, 1, 100))
assert seq.expand() == SeqFormula(sin(x*y**2 + x*z), (z, 1, 100))
assert seq.expand(trig=False) == SeqFormula(sin(x*y**2 + x*z), (z, 1, 100))
seq = SeqFormula(exp(x*(y**2 + z)), (z, 1, 100))
assert seq.expand() == SeqFormula(exp(x*y**2)*exp(x*z), (z, 1, 100))
assert seq.expand(power_exp=False) == SeqFormula(exp(x*y**2 + x*z), (z, 1, 100))
assert seq.expand(mul=False, power_exp=False) == SeqFormula(exp(x*(y**2 + z)), (z, 1, 100))
def test_sequence():
form = SeqFormula(n**2, (n, 0, 5))
per = SeqPer((1, 2, 3), (n, 0, 5))
inter = SeqFormula(n**2)
assert sequence(n**2, (n, 0, 5)) == form
assert sequence((1, 2, 3), (n, 0, 5)) == per
assert sequence(n**2) == inter
def test_SeqExprOp():
form = SeqFormula(n**2, (n, 0, 10))
per = SeqPer((1, 2, 3), (m, 5, 10))
s = SeqExprOp(form, per)
assert s.gen == (n**2, (1, 2, 3))
assert s.interval == Interval(5, 10)
assert s.start == 5
assert s.stop == 10
assert s.length == 6
assert s.variables == (n, m)
def test_SeqAdd():
per = SeqPer((1, 2, 3), (n, 0, oo))
form = SeqFormula(n**2)
per_bou = SeqPer((1, 2), (n, 1, 5))
form_bou = SeqFormula(n**2, (6, 10))
form_bou2 = SeqFormula(n**2, (1, 5))
assert SeqAdd() == S.EmptySequence
assert SeqAdd(S.EmptySequence) == S.EmptySequence
assert SeqAdd(per) == per
assert SeqAdd(per, S.EmptySequence) == per
assert SeqAdd(per_bou, form_bou) == S.EmptySequence
s = SeqAdd(per_bou, form_bou2, evaluate=False)
assert s.args == (form_bou2, per_bou)
assert s[:] == [2, 6, 10, 18, 26]
assert list(s) == [2, 6, 10, 18, 26]
assert isinstance(SeqAdd(per, per_bou, evaluate=False), SeqAdd)
s1 = SeqAdd(per, per_bou)
assert isinstance(s1, SeqPer)
assert s1 == SeqPer((2, 4, 4, 3, 3, 5), (n, 1, 5))
s2 = SeqAdd(form, form_bou)
assert isinstance(s2, SeqFormula)
assert s2 == SeqFormula(2*n**2, (6, 10))
assert SeqAdd(form, form_bou, per) == \
SeqAdd(per, SeqFormula(2*n**2, (6, 10)))
assert SeqAdd(form, SeqAdd(form_bou, per)) == \
SeqAdd(per, SeqFormula(2*n**2, (6, 10)))
assert SeqAdd(per, SeqAdd(form, form_bou), evaluate=False) == \
SeqAdd(per, SeqFormula(2*n**2, (6, 10)))
assert SeqAdd(SeqPer((1, 2), (n, 0, oo)), SeqPer((1, 2), (m, 0, oo))) == \
SeqPer((2, 4), (n, 0, oo))
def test_SeqMul():
per = SeqPer((1, 2, 3), (n, 0, oo))
form = SeqFormula(n**2)
per_bou = SeqPer((1, 2), (n, 1, 5))
form_bou = SeqFormula(n**2, (n, 6, 10))
form_bou2 = SeqFormula(n**2, (1, 5))
assert SeqMul() == S.EmptySequence
assert SeqMul(S.EmptySequence) == S.EmptySequence
assert SeqMul(per) == per
assert SeqMul(per, S.EmptySequence) == S.EmptySequence
assert SeqMul(per_bou, form_bou) == S.EmptySequence
s = SeqMul(per_bou, form_bou2, evaluate=False)
assert s.args == (form_bou2, per_bou)
assert s[:] == [1, 8, 9, 32, 25]
assert list(s) == [1, 8, 9, 32, 25]
assert isinstance(SeqMul(per, per_bou, evaluate=False), SeqMul)
s1 = SeqMul(per, per_bou)
assert isinstance(s1, SeqPer)
assert s1 == SeqPer((1, 4, 3, 2, 2, 6), (n, 1, 5))
s2 = SeqMul(form, form_bou)
assert isinstance(s2, SeqFormula)
assert s2 == SeqFormula(n**4, (6, 10))
assert SeqMul(form, form_bou, per) == \
SeqMul(per, SeqFormula(n**4, (6, 10)))
assert SeqMul(form, SeqMul(form_bou, per)) == \
SeqMul(per, SeqFormula(n**4, (6, 10)))
assert SeqMul(per, SeqMul(form, form_bou2,
evaluate=False), evaluate=False) == \
SeqMul(form, per, form_bou2, evaluate=False)
assert SeqMul(SeqPer((1, 2), (n, 0, oo)), SeqPer((1, 2), (n, 0, oo))) == \
SeqPer((1, 4), (n, 0, oo))
def test_add():
per = SeqPer((1, 2), (n, 0, oo))
form = SeqFormula(n**2)
assert per + (SeqPer((2, 3))) == SeqPer((3, 5), (n, 0, oo))
assert form + SeqFormula(n**3) == SeqFormula(n**2 + n**3)
assert per + form == SeqAdd(per, form)
raises(TypeError, lambda: per + n)
raises(TypeError, lambda: n + per)
def test_sub():
per = SeqPer((1, 2), (n, 0, oo))
form = SeqFormula(n**2)
assert per - (SeqPer((2, 3))) == SeqPer((-1, -1), (n, 0, oo))
assert form - (SeqFormula(n**3)) == SeqFormula(n**2 - n**3)
assert per - form == SeqAdd(per, -form)
raises(TypeError, lambda: per - n)
raises(TypeError, lambda: n - per)
def test_mul__coeff_mul():
assert SeqPer((1, 2), (n, 0, oo)).coeff_mul(2) == SeqPer((2, 4), (n, 0, oo))
assert SeqFormula(n**2).coeff_mul(2) == SeqFormula(2*n**2)
assert S.EmptySequence.coeff_mul(100) == S.EmptySequence
assert SeqPer((1, 2), (n, 0, oo)) * (SeqPer((2, 3))) == \
SeqPer((2, 6), (n, 0, oo))
assert SeqFormula(n**2) * SeqFormula(n**3) == SeqFormula(n**5)
assert S.EmptySequence * SeqFormula(n**2) == S.EmptySequence
assert SeqFormula(n**2) * S.EmptySequence == S.EmptySequence
raises(TypeError, lambda: sequence(n**2) * n)
raises(TypeError, lambda: n * sequence(n**2))
def test_neg():
assert -SeqPer((1, -2), (n, 0, oo)) == SeqPer((-1, 2), (n, 0, oo))
assert -SeqFormula(n**2) == SeqFormula(-n**2)
def test_operations():
per = SeqPer((1, 2), (n, 0, oo))
per2 = SeqPer((2, 4), (n, 0, oo))
form = SeqFormula(n**2)
form2 = SeqFormula(n**3)
assert per + form + form2 == SeqAdd(per, form, form2)
assert per + form - form2 == SeqAdd(per, form, -form2)
assert per + form - S.EmptySequence == SeqAdd(per, form)
assert per + per2 + form == SeqAdd(SeqPer((3, 6), (n, 0, oo)), form)
assert S.EmptySequence - per == -per
assert form + form == SeqFormula(2*n**2)
assert per * form * form2 == SeqMul(per, form, form2)
assert form * form == SeqFormula(n**4)
assert form * -form == SeqFormula(-n**4)
assert form * (per + form2) == SeqMul(form, SeqAdd(per, form2))
assert form * (per + per) == SeqMul(form, per2)
assert form.coeff_mul(m) == SeqFormula(m*n**2, (n, 0, oo))
assert per.coeff_mul(m) == SeqPer((m, 2*m), (n, 0, oo))
def test_Idx_limits():
i = symbols('i', cls=Idx)
r = Indexed('r', i)
assert SeqFormula(r, (i, 0, 5))[:] == [r.subs(i, j) for j in range(6)]
assert SeqPer((1, 2), (i, 0, 5))[:] == [1, 2, 1, 2, 1, 2]
@slow
def test_find_linear_recurrence():
assert sequence((0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55), \
(n, 0, 10)).find_linear_recurrence(11) == [1, 1]
assert sequence((1, 2, 4, 7, 28, 128, 582, 2745, 13021, 61699, 292521, \
1387138), (n, 0, 11)).find_linear_recurrence(12) == [5, -2, 6, -11]
assert sequence(x*n**3+y*n, (n, 0, oo)).find_linear_recurrence(10) \
== [4, -6, 4, -1]
assert sequence(x**n, (n,0,20)).find_linear_recurrence(21) == [x]
assert sequence((1,2,3)).find_linear_recurrence(10, 5) == [0, 0, 1]
assert sequence(((1 + sqrt(5))/2)**n + \
(-(1 + sqrt(5))/2)**(-n)).find_linear_recurrence(10) == [1, 1]
assert sequence(x*((1 + sqrt(5))/2)**n + y*(-(1 + sqrt(5))/2)**(-n), \
(n,0,oo)).find_linear_recurrence(10) == [1, 1]
assert sequence((1,2,3,4,6),(n, 0, 4)).find_linear_recurrence(5) == []
assert sequence((2,3,4,5,6,79),(n, 0, 5)).find_linear_recurrence(6,gfvar=x) \
== ([], None)
assert sequence((2,3,4,5,8,30),(n, 0, 5)).find_linear_recurrence(6,gfvar=x) \
== ([Rational(19, 2), -20, Rational(27, 2)], (-31*x**2 + 32*x - 4)/(27*x**3 - 40*x**2 + 19*x -2))
assert sequence(fibonacci(n)).find_linear_recurrence(30,gfvar=x) \
== ([1, 1], -x/(x**2 + x - 1))
assert sequence(tribonacci(n)).find_linear_recurrence(30,gfvar=x) \
== ([1, 1, 1], -x/(x**3 + x**2 + x - 1))
def test_RecursiveSeq():
y = Function('y')
n = Symbol('n')
fib = RecursiveSeq(y(n - 1) + y(n - 2), y(n), n, [0, 1])
assert fib.coeff(3) == 2

View File

@ -0,0 +1,404 @@
from sympy.core.evalf import N
from sympy.core.function import (Derivative, Function, PoleError, Subs)
from sympy.core.numbers import (E, Float, Rational, oo, pi, I)
from sympy.core.singleton import S
from sympy.core.symbol import (Symbol, symbols)
from sympy.functions.elementary.exponential import (LambertW, exp, log)
from sympy.functions.elementary.miscellaneous import sqrt
from sympy.functions.elementary.trigonometric import (atan, cos, sin)
from sympy.functions.special.gamma_functions import gamma
from sympy.integrals.integrals import Integral, integrate
from sympy.series.order import O
from sympy.series.series import series
from sympy.abc import x, y, n, k
from sympy.testing.pytest import raises
from sympy.core import EulerGamma
def test_sin():
e1 = sin(x).series(x, 0)
e2 = series(sin(x), x, 0)
assert e1 == e2
def test_cos():
e1 = cos(x).series(x, 0)
e2 = series(cos(x), x, 0)
assert e1 == e2
def test_exp():
e1 = exp(x).series(x, 0)
e2 = series(exp(x), x, 0)
assert e1 == e2
def test_exp2():
e1 = exp(cos(x)).series(x, 0)
e2 = series(exp(cos(x)), x, 0)
assert e1 == e2
def test_issue_5223():
assert series(1, x) == 1
assert next(S.Zero.lseries(x)) == 0
assert cos(x).series() == cos(x).series(x)
raises(ValueError, lambda: cos(x + y).series())
raises(ValueError, lambda: x.series(dir=""))
assert (cos(x).series(x, 1) -
cos(x + 1).series(x).subs(x, x - 1)).removeO() == 0
e = cos(x).series(x, 1, n=None)
assert [next(e) for i in range(2)] == [cos(1), -((x - 1)*sin(1))]
e = cos(x).series(x, 1, n=None, dir='-')
assert [next(e) for i in range(2)] == [cos(1), (1 - x)*sin(1)]
# the following test is exact so no need for x -> x - 1 replacement
assert abs(x).series(x, 1, dir='-') == x
assert exp(x).series(x, 1, dir='-', n=3).removeO() == \
E - E*(-x + 1) + E*(-x + 1)**2/2
D = Derivative
assert D(x**2 + x**3*y**2, x, 2, y, 1).series(x).doit() == 12*x*y
assert next(D(cos(x), x).lseries()) == D(1, x)
assert D(
exp(x), x).series(n=3) == D(1, x) + D(x, x) + D(x**2/2, x) + D(x**3/6, x) + O(x**3)
assert Integral(x, (x, 1, 3), (y, 1, x)).series(x) == -4 + 4*x
assert (1 + x + O(x**2)).getn() == 2
assert (1 + x).getn() is None
raises(PoleError, lambda: ((1/sin(x))**oo).series())
logx = Symbol('logx')
assert ((sin(x))**y).nseries(x, n=1, logx=logx) == \
exp(y*logx) + O(x*exp(y*logx), x)
assert sin(1/x).series(x, oo, n=5) == 1/x - 1/(6*x**3) + O(x**(-5), (x, oo))
assert abs(x).series(x, oo, n=5, dir='+') == x
assert abs(x).series(x, -oo, n=5, dir='-') == -x
assert abs(-x).series(x, oo, n=5, dir='+') == x
assert abs(-x).series(x, -oo, n=5, dir='-') == -x
assert exp(x*log(x)).series(n=3) == \
1 + x*log(x) + x**2*log(x)**2/2 + O(x**3*log(x)**3)
# XXX is this right? If not, fix "ngot > n" handling in expr.
p = Symbol('p', positive=True)
assert exp(sqrt(p)**3*log(p)).series(n=3) == \
1 + p**S('3/2')*log(p) + O(p**3*log(p)**3)
assert exp(sin(x)*log(x)).series(n=2) == 1 + x*log(x) + O(x**2*log(x)**2)
def test_issue_6350():
expr = integrate(exp(k*(y**3 - 3*y)), (y, 0, oo), conds='none')
assert expr.series(k, 0, 3) == -(-1)**(S(2)/3)*sqrt(3)*gamma(S(1)/3)**2*gamma(S(2)/3)/(6*pi*k**(S(1)/3)) - \
sqrt(3)*k*gamma(-S(2)/3)*gamma(-S(1)/3)/(6*pi) - \
(-1)**(S(1)/3)*sqrt(3)*k**(S(1)/3)*gamma(-S(1)/3)*gamma(S(1)/3)*gamma(S(2)/3)/(6*pi) - \
(-1)**(S(2)/3)*sqrt(3)*k**(S(5)/3)*gamma(S(1)/3)**2*gamma(S(2)/3)/(4*pi) - \
(-1)**(S(1)/3)*sqrt(3)*k**(S(7)/3)*gamma(-S(1)/3)*gamma(S(1)/3)*gamma(S(2)/3)/(8*pi) + O(k**3)
def test_issue_11313():
assert Integral(cos(x), x).series(x) == sin(x).series(x)
assert Derivative(sin(x), x).series(x, n=3).doit() == cos(x).series(x, n=3)
assert Derivative(x**3, x).as_leading_term(x) == 3*x**2
assert Derivative(x**3, y).as_leading_term(x) == 0
assert Derivative(sin(x), x).as_leading_term(x) == 1
assert Derivative(cos(x), x).as_leading_term(x) == -x
# This result is equivalent to zero, zero is not return because
# `Expr.series` doesn't currently detect an `x` in its `free_symbol`s.
assert Derivative(1, x).as_leading_term(x) == Derivative(1, x)
assert Derivative(exp(x), x).series(x).doit() == exp(x).series(x)
assert 1 + Integral(exp(x), x).series(x) == exp(x).series(x)
assert Derivative(log(x), x).series(x).doit() == (1/x).series(x)
assert Integral(log(x), x).series(x) == Integral(log(x), x).doit().series(x).removeO()
def test_series_of_Subs():
from sympy.abc import z
subs1 = Subs(sin(x), x, y)
subs2 = Subs(sin(x) * cos(z), x, y)
subs3 = Subs(sin(x * z), (x, z), (y, x))
assert subs1.series(x) == subs1
subs1_series = (Subs(x, x, y) + Subs(-x**3/6, x, y) +
Subs(x**5/120, x, y) + O(y**6))
assert subs1.series() == subs1_series
assert subs1.series(y) == subs1_series
assert subs1.series(z) == subs1
assert subs2.series(z) == (Subs(z**4*sin(x)/24, x, y) +
Subs(-z**2*sin(x)/2, x, y) + Subs(sin(x), x, y) + O(z**6))
assert subs3.series(x).doit() == subs3.doit().series(x)
assert subs3.series(z).doit() == sin(x*y)
raises(ValueError, lambda: Subs(x + 2*y, y, z).series())
assert Subs(x + y, y, z).series(x).doit() == x + z
def test_issue_3978():
f = Function('f')
assert f(x).series(x, 0, 3, dir='-') == \
f(0) + x*Subs(Derivative(f(x), x), x, 0) + \
x**2*Subs(Derivative(f(x), x, x), x, 0)/2 + O(x**3)
assert f(x).series(x, 0, 3) == \
f(0) + x*Subs(Derivative(f(x), x), x, 0) + \
x**2*Subs(Derivative(f(x), x, x), x, 0)/2 + O(x**3)
assert f(x**2).series(x, 0, 3) == \
f(0) + x**2*Subs(Derivative(f(x), x), x, 0) + O(x**3)
assert f(x**2+1).series(x, 0, 3) == \
f(1) + x**2*Subs(Derivative(f(x), x), x, 1) + O(x**3)
class TestF(Function):
pass
assert TestF(x).series(x, 0, 3) == TestF(0) + \
x*Subs(Derivative(TestF(x), x), x, 0) + \
x**2*Subs(Derivative(TestF(x), x, x), x, 0)/2 + O(x**3)
from sympy.series.acceleration import richardson, shanks
from sympy.concrete.summations import Sum
from sympy.core.numbers import Integer
def test_acceleration():
e = (1 + 1/n)**n
assert round(richardson(e, n, 10, 20).evalf(), 10) == round(E.evalf(), 10)
A = Sum(Integer(-1)**(k + 1) / k, (k, 1, n))
assert round(shanks(A, n, 25).evalf(), 4) == round(log(2).evalf(), 4)
assert round(shanks(A, n, 25, 5).evalf(), 10) == round(log(2).evalf(), 10)
def test_issue_5852():
assert series(1/cos(x/log(x)), x, 0) == 1 + x**2/(2*log(x)**2) + \
5*x**4/(24*log(x)**4) + O(x**6)
def test_issue_4583():
assert cos(1 + x + x**2).series(x, 0, 5) == cos(1) - x*sin(1) + \
x**2*(-sin(1) - cos(1)/2) + x**3*(-cos(1) + sin(1)/6) + \
x**4*(-11*cos(1)/24 + sin(1)/2) + O(x**5)
def test_issue_6318():
eq = (1/x)**Rational(2, 3)
assert (eq + 1).as_leading_term(x) == eq
def test_x_is_base_detection():
eq = (x**2)**Rational(2, 3)
assert eq.series() == x**Rational(4, 3)
def test_issue_7203():
assert series(cos(x), x, pi, 3) == \
-1 + (x - pi)**2/2 + O((x - pi)**3, (x, pi))
def test_exp_product_positive_factors():
a, b = symbols('a, b', positive=True)
x = a * b
assert series(exp(x), x, n=8) == 1 + a*b + a**2*b**2/2 + \
a**3*b**3/6 + a**4*b**4/24 + a**5*b**5/120 + a**6*b**6/720 + \
a**7*b**7/5040 + O(a**8*b**8, a, b)
def test_issue_8805():
assert series(1, n=8) == 1
def test_issue_9549():
y = (x**2 + x + 1) / (x**3 + x**2)
assert series(y, x, oo) == x**(-5) - 1/x**4 + x**(-3) + 1/x + O(x**(-6), (x, oo))
def test_issue_10761():
assert series(1/(x**-2 + x**-3), x, 0) == x**3 - x**4 + x**5 + O(x**6)
def test_issue_12578():
y = (1 - 1/(x/2 - 1/(2*x))**4)**(S(1)/8)
assert y.series(x, 0, n=17) == 1 - 2*x**4 - 8*x**6 - 34*x**8 - 152*x**10 - 714*x**12 - \
3472*x**14 - 17318*x**16 + O(x**17)
def test_issue_12791():
beta = symbols('beta', positive=True)
theta, varphi = symbols('theta varphi', real=True)
expr = (-beta**2*varphi*sin(theta) + beta**2*cos(theta) + \
beta*varphi*sin(theta) - beta*cos(theta) - beta + 1)/(beta*cos(theta) - 1)**2
sol = (0.5/(0.5*cos(theta) - 1.0)**2 - 0.25*cos(theta)/(0.5*cos(theta) - 1.0)**2
+ (beta - 0.5)*(-0.25*varphi*sin(2*theta) - 1.5*cos(theta)
+ 0.25*cos(2*theta) + 1.25)/((0.5*cos(theta) - 1.0)**2*(0.5*cos(theta) - 1.0))
+ 0.25*varphi*sin(theta)/(0.5*cos(theta) - 1.0)**2
+ O((beta - S.Half)**2, (beta, S.Half)))
assert expr.series(beta, 0.5, 2).trigsimp() == sol
def test_issue_14384():
x, a = symbols('x a')
assert series(x**a, x) == x**a
assert series(x**(-2*a), x) == x**(-2*a)
assert series(exp(a*log(x)), x) == exp(a*log(x))
raises(PoleError, lambda: series(x**I, x))
raises(PoleError, lambda: series(x**(I + 1), x))
raises(PoleError, lambda: series(exp(I*log(x)), x))
def test_issue_14885():
assert series(x**Rational(-3, 2)*exp(x), x, 0) == (x**Rational(-3, 2) + 1/sqrt(x) +
sqrt(x)/2 + x**Rational(3, 2)/6 + x**Rational(5, 2)/24 + x**Rational(7, 2)/120 +
x**Rational(9, 2)/720 + x**Rational(11, 2)/5040 + O(x**6))
def test_issue_15539():
assert series(atan(x), x, -oo) == (-1/(5*x**5) + 1/(3*x**3) - 1/x - pi/2
+ O(x**(-6), (x, -oo)))
assert series(atan(x), x, oo) == (-1/(5*x**5) + 1/(3*x**3) - 1/x + pi/2
+ O(x**(-6), (x, oo)))
def test_issue_7259():
assert series(LambertW(x), x) == x - x**2 + 3*x**3/2 - 8*x**4/3 + 125*x**5/24 + O(x**6)
assert series(LambertW(x**2), x, n=8) == x**2 - x**4 + 3*x**6/2 + O(x**8)
assert series(LambertW(sin(x)), x, n=4) == x - x**2 + 4*x**3/3 + O(x**4)
def test_issue_11884():
assert cos(x).series(x, 1, n=1) == cos(1) + O(x - 1, (x, 1))
def test_issue_18008():
y = x*(1 + x*(1 - x))/((1 + x*(1 - x)) - (1 - x)*(1 - x))
assert y.series(x, oo, n=4) == -9/(32*x**3) - 3/(16*x**2) - 1/(8*x) + S(1)/4 + x/2 + \
O(x**(-4), (x, oo))
def test_issue_18842():
f = log(x/(1 - x))
assert f.series(x, 0.491, n=1).removeO().nsimplify() == \
-S(180019443780011)/5000000000000000
def test_issue_19534():
dt = symbols('dt', real=True)
expr = 16*dt*(0.125*dt*(2.0*dt + 1.0) + 0.875*dt + 1.0)/45 + \
49*dt*(-0.049335189898860408029*dt*(2.0*dt + 1.0) + \
0.29601113939316244817*dt*(0.125*dt*(2.0*dt + 1.0) + 0.875*dt + 1.0) - \
0.12564355335492979587*dt*(0.074074074074074074074*dt*(2.0*dt + 1.0) + \
0.2962962962962962963*dt*(0.125*dt*(2.0*dt + 1.0) + 0.875*dt + 1.0) + \
0.96296296296296296296*dt + 1.0) + 0.051640768506639183825*dt + \
dt*(1/2 - sqrt(21)/14) + 1.0)/180 + 49*dt*(-0.23637909581542530626*dt*(2.0*dt + 1.0) - \
0.74817562366625959291*dt*(0.125*dt*(2.0*dt + 1.0) + 0.875*dt + 1.0) + \
0.88085458023927036857*dt*(0.074074074074074074074*dt*(2.0*dt + 1.0) + \
0.2962962962962962963*dt*(0.125*dt*(2.0*dt + 1.0) + 0.875*dt + 1.0) + \
0.96296296296296296296*dt + 1.0) + \
2.1165151389911680013*dt*(-0.049335189898860408029*dt*(2.0*dt + 1.0) + \
0.29601113939316244817*dt*(0.125*dt*(2.0*dt + 1.0) + 0.875*dt + 1.0) - \
0.12564355335492979587*dt*(0.074074074074074074074*dt*(2.0*dt + 1.0) + \
0.2962962962962962963*dt*(0.125*dt*(2.0*dt + 1.0) + 0.875*dt + 1.0) + \
0.96296296296296296296*dt + 1.0) + 0.22431393315265061193*dt + 1.0) - \
1.1854881643947648988*dt + dt*(sqrt(21)/14 + 1/2) + 1.0)/180 + \
dt*(0.66666666666666666667*dt*(2.0*dt + 1.0) + \
6.0173399699313066769*dt*(0.125*dt*(2.0*dt + 1.0) + 0.875*dt + 1.0) - \
4.1117044797036320069*dt*(0.074074074074074074074*dt*(2.0*dt + 1.0) + \
0.2962962962962962963*dt*(0.125*dt*(2.0*dt + 1.0) + 0.875*dt + 1.0) + \
0.96296296296296296296*dt + 1.0) - \
7.0189140975801991157*dt*(-0.049335189898860408029*dt*(2.0*dt + 1.0) + \
0.29601113939316244817*dt*(0.125*dt*(2.0*dt + 1.0) + 0.875*dt + 1.0) - \
0.12564355335492979587*dt*(0.074074074074074074074*dt*(2.0*dt + 1.0) + \
0.2962962962962962963*dt*(0.125*dt*(2.0*dt + 1.0) + 0.875*dt + 1.0) + \
0.96296296296296296296*dt + 1.0) + 0.22431393315265061193*dt + 1.0) + \
0.94010945196161777522*dt*(-0.23637909581542530626*dt*(2.0*dt + 1.0) - \
0.74817562366625959291*dt*(0.125*dt*(2.0*dt + 1.0) + 0.875*dt + 1.0) + \
0.88085458023927036857*dt*(0.074074074074074074074*dt*(2.0*dt + 1.0) + \
0.2962962962962962963*dt*(0.125*dt*(2.0*dt + 1.0) + 0.875*dt + 1.0) + \
0.96296296296296296296*dt + 1.0) + \
2.1165151389911680013*dt*(-0.049335189898860408029*dt*(2.0*dt + 1.0) + \
0.29601113939316244817*dt*(0.125*dt*(2.0*dt + 1.0) + 0.875*dt + 1.0) - \
0.12564355335492979587*dt*(0.074074074074074074074*dt*(2.0*dt + 1.0) + \
0.2962962962962962963*dt*(0.125*dt*(2.0*dt + 1.0) + 0.875*dt + 1.0) + \
0.96296296296296296296*dt + 1.0) + 0.22431393315265061193*dt + 1.0) - \
0.35816132904077632692*dt + 1.0) + 5.5065024887242400038*dt + 1.0)/20 + dt/20 + 1
assert N(expr.series(dt, 0, 8), 20) == (
- Float('0.00092592592592592596126289', precision=70) * dt**7
+ Float('0.0027777777777777783174695', precision=70) * dt**6
+ Float('0.016666666666666656027029', precision=70) * dt**5
+ Float('0.083333333333333300951828', precision=70) * dt**4
+ Float('0.33333333333333337034077', precision=70) * dt**3
+ Float('1.0', precision=70) * dt**2
+ Float('1.0', precision=70) * dt
+ Float('1.0', precision=70)
)
def test_issue_11407():
a, b, c, x = symbols('a b c x')
assert series(sqrt(a + b + c*x), x, 0, 1) == sqrt(a + b) + O(x)
assert series(sqrt(a + b + c + c*x), x, 0, 1) == sqrt(a + b + c) + O(x)
def test_issue_14037():
assert (sin(x**50)/x**51).series(x, n=0) == 1/x + O(1, x)
def test_issue_20551():
expr = (exp(x)/x).series(x, n=None)
terms = [ next(expr) for i in range(3) ]
assert terms == [1/x, 1, x/2]
def test_issue_20697():
p_0, p_1, p_2, p_3, b_0, b_1, b_2 = symbols('p_0 p_1 p_2 p_3 b_0 b_1 b_2')
Q = (p_0 + (p_1 + (p_2 + p_3/y)/y)/y)/(1 + ((p_3/(b_0*y) + (b_0*p_2\
- b_1*p_3)/b_0**2)/y + (b_0**2*p_1 - b_0*b_1*p_2 - p_3*(b_0*b_2\
- b_1**2))/b_0**3)/y)
assert Q.series(y, n=3).ratsimp() == b_2*y**2 + b_1*y + b_0 + O(y**3)
def test_issue_21245():
fi = (1 + sqrt(5))/2
assert (1/(1 - x - x**2)).series(x, 1/fi, 1).factor() == \
(-4812 - 2152*sqrt(5) + 1686*x + 754*sqrt(5)*x\
+ O((x - 2/(1 + sqrt(5)))**2, (x, 2/(1 + sqrt(5)))))/((1 + sqrt(5))\
*(20 + 9*sqrt(5))**2*(x + sqrt(5)*x - 2))
def test_issue_21938():
expr = sin(1/x + exp(-x)) - sin(1/x)
assert expr.series(x, oo) == (1/(24*x**4) - 1/(2*x**2) + 1 + O(x**(-6), (x, oo)))*exp(-x)
def test_issue_23432():
expr = 1/sqrt(1 - x**2)
result = expr.series(x, 0.5)
assert result.is_Add and len(result.args) == 7
def test_issue_23727():
res = series(sqrt(1 - x**2), x, 0.1)
assert res.is_Add == True
def test_issue_24266():
#type1: exp(f(x))
assert (exp(-I*pi*(2*x+1))).series(x, 0, 3) == -1 + 2*I*pi*x + 2*pi**2*x**2 + O(x**3)
assert (exp(-I*pi*(2*x+1))*gamma(1+x)).series(x, 0, 3) == -1 + x*(EulerGamma + 2*I*pi) + \
x**2*(-EulerGamma**2/2 + 23*pi**2/12 - 2*EulerGamma*I*pi) + O(x**3)
#type2: c**f(x)
assert ((2*I)**(-I*pi*(2*x+1))).series(x, 0, 2) == exp(pi**2/2 - I*pi*log(2)) + \
x*(pi**2*exp(pi**2/2 - I*pi*log(2)) - 2*I*pi*exp(pi**2/2 - I*pi*log(2))*log(2)) + O(x**2)
assert ((2)**(-I*pi*(2*x+1))).series(x, 0, 2) == exp(-I*pi*log(2)) - 2*I*pi*x*exp(-I*pi*log(2))*log(2) + O(x**2)
#type3: f(y)**g(x)
assert ((y)**(I*pi*(2*x+1))).series(x, 0, 2) == exp(I*pi*log(y)) + 2*I*pi*x*exp(I*pi*log(y))*log(y) + O(x**2)
assert ((I*y)**(I*pi*(2*x+1))).series(x, 0, 2) == exp(I*pi*log(I*y)) + 2*I*pi*x*exp(I*pi*log(I*y))*log(I*y) + O(x**2)