Skip to content

Commit

Permalink
Merge ce9b2d5 into 5e8d658
Browse files Browse the repository at this point in the history
  • Loading branch information
skirpichev committed May 16, 2015
2 parents 5e8d658 + ce9b2d5 commit ad14b36
Show file tree
Hide file tree
Showing 15 changed files with 133 additions and 166 deletions.
4 changes: 2 additions & 2 deletions sympy/core/add.py
Original file line number Diff line number Diff line change
Expand Up @@ -348,8 +348,8 @@ def as_coeff_Add(self):
def _eval_derivative(self, s):
return self.func(*[a.diff(s) for a in self.args])

def _eval_nseries(self, x, n, logx):
terms = [t.nseries(x, n=n, logx=logx) for t in self.args]
def _eval_nseries(self, x, n):
terms = [t.nseries(x, n=n) for t in self.args]
return self.func(*terms)

def _matches_simple(self, expr, repl_dict):
Expand Down
75 changes: 23 additions & 52 deletions sympy/core/expr.py
Original file line number Diff line number Diff line change
Expand Up @@ -2399,7 +2399,7 @@ def is_algebraic_expr(self, *syms):
##################### SERIES, LEADING TERM, LIMIT, ORDER METHODS ##################
###################################################################################

def series(self, x=None, x0=0, n=6, dir="+", logx=None):
def series(self, x=None, x0=0, n=6, dir="+"):
"""
Series expansion of "self" around ``x = x0`` yielding either terms of
the series one by one (the lazy series given when n=None), else
Expand Down Expand Up @@ -2476,7 +2476,7 @@ def series(self, x=None, x0=0, n=6, dir="+", logx=None):
rep = x + x0
rep2 = x
rep2b = -x0
s = self.subs(x, rep).series(x, x0=0, n=n, dir='+', logx=logx)
s = self.subs(x, rep).series(x, x0=0, n=n, dir='+')
if n is None: # lseries...
return (si.subs(x, rep2 + rep2b) for si in s)
return s.subs(x, rep2 + rep2b)
Expand All @@ -2486,14 +2486,14 @@ def series(self, x=None, x0=0, n=6, dir="+", logx=None):
if x.is_positive is x.is_negative is None or x.is_Symbol is not True:
# replace x with an x that has a positive assumption
xpos = Dummy('x', positive=True, finite=True)
rv = self.subs(x, xpos).series(xpos, x0, n, dir, logx=logx)
rv = self.subs(x, xpos).series(xpos, x0, n, dir)
if n is None:
return (s.subs(xpos, x) for s in rv)
else:
return rv.subs(xpos, x)

if n is not None: # nseries handling
s1 = self._eval_nseries(x, n=n, logx=logx)
s1 = self._eval_nseries(x, n=n)
o = s1.getO() or S.Zero
if o:
# make sure the requested order is returned
Expand All @@ -2511,13 +2511,13 @@ def series(self, x=None, x0=0, n=6, dir="+", logx=None):
# is different than the original order and then predict how
# many additional terms are needed
for more in range(1, 9):
s1 = self._eval_nseries(x, n=n + more, logx=logx)
s1 = self._eval_nseries(x, n=n + more)
newn = s1.getn()
if newn != ngot:
ndo = n + (n - ngot)*more/(newn - ngot)
s1 = self._eval_nseries(x, n=ndo, logx=logx)
while s1.getn() < n:
s1 = self._eval_nseries(x, n=ndo, logx=logx)
s1 = self._eval_nseries(x, n=ndo)
while s1.getn().simplify() < n:
s1 = self._eval_nseries(x, n=ndo)
ndo += 1
break
else:
Expand Down Expand Up @@ -2564,7 +2564,7 @@ def yield_lseries(s):
break
yielded += do

return yield_lseries(self.removeO()._eval_lseries(x, logx=logx))
return yield_lseries(self.removeO()._eval_lseries(x))

def taylor_term(self, n, x, *previous_terms):
"""General method for the taylor term.
Expand All @@ -2577,7 +2577,7 @@ def taylor_term(self, n, x, *previous_terms):
_x = Dummy('x')
return self.subs(x, _x).diff(_x, n).subs(_x, x).subs(x, 0) * x**n / factorial(n)

def lseries(self, x=None, x0=0, dir='+', logx=None):
def lseries(self, x=None, x0=0, dir='+'):
"""
Wrapper for series yielding an iterator of the terms of the series.
Expand All @@ -2595,16 +2595,16 @@ def lseries(self, x=None, x0=0, dir='+', logx=None):
See also nseries().
"""
return self.series(x, x0, n=None, dir=dir, logx=logx)
return self.series(x, x0, n=None, dir=dir)

def _eval_lseries(self, x, logx=None):
def _eval_lseries(self, x):
# default implementation of lseries is using nseries(), and adaptively
# increasing the "n". As you can see, it is not very efficient, because
# we are calculating the series over and over again. Subclasses should
# override this method and implement much more efficient yielding of
# terms.
n = 0
series = self._eval_nseries(x, n=n, logx=logx)
series = self._eval_nseries(x, n=n)
if not series.is_Order:
if series.is_Add:
yield series.removeO()
Expand All @@ -2614,19 +2614,19 @@ def _eval_lseries(self, x, logx=None):

while series.is_Order:
n += 1
series = self._eval_nseries(x, n=n, logx=logx)
series = self._eval_nseries(x, n=n)
e = series.removeO()
yield e
while 1:
while 1:
n += 1
series = self._eval_nseries(x, n=n, logx=logx).removeO()
series = self._eval_nseries(x, n=n).removeO()
if e != series:
break
yield series - e
e = series

def nseries(self, x=None, x0=0, n=6, dir='+', logx=None):
def nseries(self, x=None, x0=0, n=6, dir='+'):
"""
Wrapper to _eval_nseries if assumptions allow, else to series.
Expand All @@ -2635,10 +2635,6 @@ def nseries(self, x=None, x0=0, n=6, dir='+', logx=None):
then builds up the final series just by "cross-multiplying" everything
out.
The optional ``logx`` parameter can be used to replace any log(x) in the
returned series with a symbolic value to avoid evaluating log(x) at 0. A
symbol to use in place of log(x) should be provided.
Advantage -- it's fast, because we don't have to determine how many
terms we need to calculate in advance.
Expand All @@ -2661,39 +2657,15 @@ def nseries(self, x=None, x0=0, n=6, dir='+', logx=None):
x - x**3/6 + x**5/120 + O(x**6)
>>> log(x+1).nseries(x, 0, 5)
x - x**2/2 + x**3/3 - x**4/4 + O(x**5)
Handling of the ``logx`` parameter --- in the following example the
expansion fails since ``sin`` does not have an asymptotic expansion
at -oo (the limit of log(x) as x approaches 0):
>>> e = sin(log(x))
>>> e.nseries(x, 0, 6)
Traceback (most recent call last):
...
PoleError: ...
...
>>> logx = Symbol('logx')
>>> e.nseries(x, 0, 6, logx=logx)
sin(logx)
In the following example, the expansion works but gives only an Order term
unless the ``logx`` parameter is used:
>>> e = x**y
>>> e.nseries(x, 0, 2)
O(log(x)**2)
>>> e.nseries(x, 0, 2, logx=logx)
exp(logx*y)
"""
if x and not x in self.free_symbols:
return self
if x is None or x0 or dir != '+': # {see XPOS above} or (x.is_positive == x.is_negative == None):
return self.series(x, x0, n, dir)
else:
return self._eval_nseries(x, n=n, logx=logx)
return self._eval_nseries(x, n=n)

def _eval_nseries(self, x, n, logx):
def _eval_nseries(self, x, n):
"""
Return terms of series for self up to O(x**n) at x=0
from the positive direction.
Expand Down Expand Up @@ -2831,17 +2803,16 @@ def compute_leading_term(self, x, logx=None):
"""
from sympy import Dummy, log

d = logx if logx else Dummy('logx')
for t in self.lseries(x):
if logx:
t = t.subs(log(x), logx)
t = t.subs(log(1/x), -logx)

for t in self.lseries(x, logx=d):
t = t.cancel()

if t.simplify():
break

if logx is None:
t = t.subs(d, log(x))

return t.as_leading_term(x)

@cacheit
Expand Down Expand Up @@ -3274,7 +3245,7 @@ def _eval_is_rational_function(self, syms):
def _eval_is_algebraic_expr(self, syms):
return True

def _eval_nseries(self, x, n, logx):
def _eval_nseries(self, x, n):
return self


Expand Down
24 changes: 12 additions & 12 deletions sympy/core/function.py
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ def as_base_exp(self):
"""
return self, S.One

def _eval_aseries(self, n, args0, x, logx):
def _eval_aseries(self, n, args0, x):
"""
Compute an asymptotic expansion around args0, in terms of self.args.
This function is only used internally by _eval_nseries and should not
Expand All @@ -528,7 +528,7 @@ def _eval_aseries(self, n, args0, x, logx):
Asymptotic expansion of %s around %s is
not implemented.''' % (type(self), args0)))

def _eval_nseries(self, x, n, logx):
def _eval_nseries(self, x, n):
"""
This function does compute series for multivariate functions,
but the expansion is always in terms of *one* variable.
Expand Down Expand Up @@ -558,17 +558,17 @@ def _eval_nseries(self, x, n, logx):
from sympy import oo, zoo, nan
# XXX could use t.as_leading_term(x) here but it's a little
# slower
a = [t.compute_leading_term(x, logx=logx) for t in args]
a = [t.compute_leading_term(x) for t in args]
a0 = [t.limit(x, 0) for t in a]
if any([t.has(oo, -oo, zoo, nan) for t in a0]):
return self._eval_aseries(n, args0, x, logx)
return self._eval_aseries(n, args0, x)
# Careful: the argument goes to oo, but only logarithmically so. We
# are supposed to do a power series expansion "around the
# logarithmic term". e.g.
# f(1+x+log(x))
# -> f(1+logx) + x*f'(1+logx) + O(x**2)
# where 'logx' is given in the argument
a = [t._eval_nseries(x, n, logx) for t in args]
a = [t._eval_nseries(x, n) for t in args]
z = [r - r0 for (r, r0) in zip(a, a0)]
p = [Dummy() for t in z]
q = []
Expand All @@ -584,7 +584,7 @@ def _eval_nseries(self, x, n, logx):
e1 = self.func(*q)
if v is None:
return e1
s = e1._eval_nseries(v, n, logx)
s = e1._eval_nseries(v, n)
o = s.getO()
s = s.removeO()
s = s.subs(v, zi).expand() + Order(o.expr.subs(v, zi), x)
Expand Down Expand Up @@ -618,7 +618,7 @@ def _eval_nseries(self, x, n, logx):
term = term.expand()
series += term
return series + Order(x**n, x)
return e1.nseries(x, n=n, logx=logx)
return e1.nseries(x, n=n)
arg = self.args[0]
l = []
g = None
Expand All @@ -629,7 +629,7 @@ def _eval_nseries(self, x, n, logx):
nterms = int(nterms / cf)
for i in range(nterms):
g = self.taylor_term(i, arg, g)
g = g.nseries(x, n=n, logx=logx)
g = g.nseries(x, n=n)
l.append(g)
return Add(*l) + Order(x**n, x)

Expand Down Expand Up @@ -1303,13 +1303,13 @@ def _eval_subs(self, old, new):
return Derivative(new, *variables)
return Derivative(*(x._subs(old, new) for x in self.args))

def _eval_lseries(self, x, logx):
def _eval_lseries(self, x):
dx = self.args[1:]
for term in self.args[0].lseries(x, logx=logx):
for term in self.args[0].lseries(x):
yield self.func(term, *dx)

def _eval_nseries(self, x, n, logx):
arg = self.args[0].nseries(x, n=n, logx=logx)
def _eval_nseries(self, x, n):
arg = self.args[0].nseries(x, n=n)
o = arg.getO()
dx = self.args[1:]
rv = [self.func(a, *dx) for a in Add.make_args(arg.removeO())]
Expand Down
4 changes: 2 additions & 2 deletions sympy/core/mul.py
Original file line number Diff line number Diff line change
Expand Up @@ -1445,9 +1445,9 @@ def ndiv(a, b):
margs = [Pow(new, cdid)] + margs
return co_residual*self2.func(*margs)*self2.func(*nc)

def _eval_nseries(self, x, n, logx):
def _eval_nseries(self, x, n):
from sympy import Order, powsimp
terms = [t.nseries(x, n=n, logx=logx) for t in self.args]
terms = [t.nseries(x, n=n) for t in self.args]
res = powsimp(self.func(*terms).expand(), combine='exp', deep=True)
if res.has(Order):
res += Order(x**n, x)
Expand Down
20 changes: 10 additions & 10 deletions sympy/core/power.py
Original file line number Diff line number Diff line change
Expand Up @@ -1074,7 +1074,7 @@ def matches(self, expr, repl_dict={}, old=False):
return Expr.matches(self, expr, repl_dict)
return d

def _eval_nseries(self, x, n, logx):
def _eval_nseries(self, x, n):
# NOTE! This function is an important part of the gruntz algorithm
# for computing limits. It has to return a generalized power
# series with coefficients in C(log, log(x)). In more detail:
Expand All @@ -1088,8 +1088,8 @@ def _eval_nseries(self, x, n, logx):
if e > 0:
# positive integer powers are easy to expand, e.g.:
# sin(x)**4 = (x-x**3/3+...)**4 = ...
return expand_multinomial(self.func(b._eval_nseries(x, n=n,
logx=logx), e), deep=False)
return expand_multinomial(self.func(b._eval_nseries(x, n=n),
e), deep=False)
elif e is S.NegativeOne:
# this is also easy to expand using the formula:
# 1/(1 + x) = 1 - x + x**2 - x**3 ...
Expand All @@ -1111,7 +1111,7 @@ def _eval_nseries(self, x, n, logx):
b_orig, prefactor = b, O(1, x)
while prefactor.is_Order:
nuse += 1
b = b_orig._eval_nseries(x, n=nuse, logx=logx)
b = b_orig._eval_nseries(x, n=nuse)
prefactor = b.as_leading_term(x)

# express "rest" as: rest = 1 + k*x**l + ... + O(x**n)
Expand Down Expand Up @@ -1173,15 +1173,15 @@ def _eval_nseries(self, x, n, logx):
# and expand the denominator:
nuse, denominator = n, O(1, x)
while denominator.is_Order:
denominator = (b**(-e))._eval_nseries(x, n=nuse, logx=logx)
denominator = (b**(-e))._eval_nseries(x, n=nuse)
nuse += 1
if 1/denominator == self:
return self
# now we have a type 1/f(x), that we know how to expand
return (1/denominator)._eval_nseries(x, n=n, logx=logx)
return (1/denominator)._eval_nseries(x, n=n)

if e.has(Symbol):
return exp(e*log(b))._eval_nseries(x, n=n, logx=logx)
return exp(e*log(b))._eval_nseries(x, n=n)

# see if the base is as simple as possible
bx = b
Expand Down Expand Up @@ -1250,15 +1250,15 @@ def e2int(e):
except NotImplementedError:
pass

bs = b._eval_nseries(x, n=nuse, logx=logx)
bs = b._eval_nseries(x, n=nuse)
terms = bs.removeO()
if terms.is_Add:
bs = terms
lt = terms.as_leading_term(x)

# bs -> lt + rest -> lt*(1 + (bs/lt - 1))
return ((self.func(lt, e) * self.func((bs/lt).expand(), e).nseries(
x, n=nuse, logx=logx)).expand() + order)
x, n=nuse)).expand() + order)

if bs.is_Add:
from sympy import O
Expand Down Expand Up @@ -1301,7 +1301,7 @@ def e2int(e):
g = None
for i in range(n + 2):
g = self._taylor_term(i, z, g)
g = g.nseries(x, n=n, logx=logx)
g = g.nseries(x, n=n)
l.append(g)
r = Add(*l)
return expand_mul(r*b0**e) + order
Expand Down
4 changes: 2 additions & 2 deletions sympy/functions/elementary/complexes.py
Original file line number Diff line number Diff line change
Expand Up @@ -530,9 +530,9 @@ def _eval_power(self, exponent):
return self.args[0]**(exponent - 1)*self
return

def _eval_nseries(self, x, n, logx):
def _eval_nseries(self, x, n):
direction = self.args[0].as_leading_term(x).as_coeff_exponent(x)[0]
s = self.args[0]._eval_nseries(x, n=n, logx=logx)
s = self.args[0]._eval_nseries(x, n=n)
when = Eq(direction, 0)
return Piecewise(
((s.subs(direction, 0)), when),
Expand Down
Loading

0 comments on commit ad14b36

Please sign in to comment.