Skip to content
Browse files

3267: limit watches for difficult Add terms

In cases as noted in the code, try see if the rational
form of the terms gives a result, and if so continue with the limit algorithm.
  • Loading branch information...
1 parent 5c33969 commit 626b5c9d7ab9dfbaa74210dc15b14e00531d489c @smichr smichr committed May 23, 2012
Showing with 96 additions and 36 deletions.
  1. +3 −4 sympy/integrals/tests/test_integrals.py
  2. +81 −31 sympy/series/limits.py
  3. +12 −1 sympy/series/tests/test_limits.py
View
7 sympy/integrals/tests/test_integrals.py
@@ -2,7 +2,7 @@
Function, Rational, log, sin, cos, pi, E, I, Poly, LambertW, diff, Matrix,
sympify, sqrt, atan, asin, acos, asinh, acosh, DiracDelta, Heaviside,
Lambda, sstr, Add, Tuple, Interval, Sum, factor, trigsimp, simplify, O,
- terms_gcd)
+ terms_gcd, EulerGamma, Ci)
from sympy.utilities.pytest import XFAIL, raises
from sympy.physics.units import m, s
@@ -684,10 +684,9 @@ def test_atom_bug():
assert heurisch(meijerg([], [], [1], [], x), x) is None
def test_limit_bug():
- # NOTE this used to raise NotImplementedError because of a limit problem.
- # actually gruntz() can do this limit, see issue 2079
assert integrate(sin(x*y*z), (x, 0, pi), (y, 0, pi)) == \
- Integral(-cos(pi*y*z)/(y*z) + 1/(y*z), (y, 0, pi))
+ -((-log(pi*z) + log(pi**2*z**2)/2 + Ci(pi**2*z)
+ )/z) + log(z**2)/(2*z) + EulerGamma/z + 2*log(pi)/z
# The following tests work using meijerint.
def test_issue841():
View
112 sympy/series/limits.py
@@ -161,42 +161,92 @@ def limit(e, z, z0, dir="+"):
# this is a case like limit(x*y+x*z, z, 2) == x*y+2*x
# but we need to make sure, that the general gruntz() algorithm is
# executed for a case like "limit(sqrt(x+1)-sqrt(x),x,oo)==0"
- unbounded = []; unbounded_result=[]
- finite = []; unknown = []
- ok = True
- for term in e.args:
- if not term.has(z) and not term.is_unbounded:
- finite.append(term)
- continue
- result = term.subs(z, z0)
- bounded = result.is_bounded
- if bounded is False or result is S.NaN:
- if unknown:
- ok = False
- break
- unbounded.append(term)
- if result != S.NaN:
- # take result from direction given
- result = limit(term, z, z0, dir)
- unbounded_result.append(result)
- elif bounded:
- finite.append(result)
+
+ unbounded = []
+ unbounded_result = []
+ unbounded_const = []
+ unknown = []
+ unknown_result = []
+ finite = []
+ zero = []
+ def _sift(term):
+ if z not in term.free_symbols:
+ if term.is_unbounded:
+ unbounded_const.append(term)
+ else:
+ finite.append(term)
else:
- if unbounded:
- ok = False
- break
- unknown.append(result)
- if not ok:
+ result = term.subs(z, z0)
+ bounded = result.is_bounded
+ if bounded is False or result is S.NaN:
+ unbounded.append(term)
+ if result != S.NaN:
+ # take result from direction given
+ result = limit(term, z, z0, dir)
+ unbounded_result.append(result)
+ elif bounded:
+ if result:
+ finite.append(result)
+ else:
+ zero.append(term)
+ else:
+ unknown.append(term)
+ unknown_result.append(result)
+
+ for term in e.args:
+ _sift(term)
+
+ bad = bool(unknown and unbounded)
+ if bad or len(unknown) > 1 or len(unbounded) > 1 and not zero:
+ uu = unknown + unbounded
# we won't be able to resolve this with unbounded
# terms, e.g. Sum(1/k, (k, 1, n)) - log(n) as n -> oo:
# since the Sum is unevaluated it's boundedness is
# unknown and the log(n) is oo so you get Sum - oo
- # which is unsatisfactory.
- raise NotImplementedError('unknown boundedness for %s' %
- (unknown or result))
- u = Add(*unknown)
- if unbounded:
- inf_limit = Add(*unbounded_result)
+ # which is unsatisfactory. BUT...if there are both
+ # unknown and unbounded terms (condition 'bad') or
+ # there are multiple terms that are unknown, or
+ # there are multiple symbolic unbounded terms they may
+ # respond better if they are made into a rational
+ # function, so give them a chance to do so before
+ # reporting failure.
+ u = Add(*uu)
+ f = u.normal()
+ if f != u:
+ unknown = []
+ unbounded = []
+ unbounded_result = []
+ unknown_result = []
+ _sift(limit(f, z, z0, dir))
+
+ # We came in with a) unknown and unbounded terms or b) had multiple
+ # unknown terms
+
+ # At this point we've done one of 3 things.
+ # (1) We did nothing with f so we now report the error
+ # showing the troublesome terms which are now in uu. OR
+
+ # (2) We did something with f but the result came back as unknown.
+ # Normally this wouldn't be a problem,
+ # but we had either multiple terms that were troublesome (unk and
+ # unbounded or multiple unknown terms) so if we
+ # weren't able to resolve the boundedness by now, that indicates a
+ # problem so we report the error showing the troublesome terms which are
+ # now in uu.
+ if unknown:
+ if bad:
+ msg = 'unknown and unbounded terms present in %s'
+ elif unknown:
+ msg = 'multiple terms with unknown boundedness in %s'
+ raise NotImplementedError(msg % uu)
+ # OR
+ # (3) the troublesome terms have been identified as finite or unbounded
+ # and we proceed with the non-error code since the lists have been updated.
+
+ u = Add(*unknown_result)
+ if unbounded_result or unbounded_const:
+ unbounded.extend(zero)
+ inf_limit = Add(*(unbounded_result + unbounded_const))
if inf_limit is not S.NaN:
return inf_limit + u
if finite:
View
13 sympy/series/tests/test_limits.py
@@ -294,9 +294,12 @@ def test_extended_real_line():
assert limit(oo - x, x, -oo) == oo
assert limit(x**2/(x-5) - oo, x, oo) == -oo
assert limit(1/(x+sin(x)) - oo, x, 0) == -oo
+ assert limit(oo/x, x, oo) == oo
+
+@XFAIL
+def test_extended_real_line_fail():
assert limit(x - oo + 1/x, x, oo) == -oo
assert limit(x - oo + 1/x, x, 0) == -oo
- assert limit(oo/x, x, oo) == oo
@XFAIL
def test_order_oo():
@@ -316,3 +319,11 @@ def test_Limit_dir():
def test_polynomial():
assert limit((x + 1)**1000/((x + 1)**1000 + 1), x, oo) == 1
assert limit((x + 1)**1000/((x + 1)**1000 + 1), x, -oo) == 1
+
+def test_issue_2641():
+ assert limit(log(x)/z - log(2*x)/z, x, 0) == -log(2)/z
+
+def test_issue_3267():
+ n = Symbol('n', integer=True, positive=True)
+ r = (n + 1)*x**(n + 1)/(x**(n + 1) - 1) - x/(x - 1)
+ assert limit(r, x, 1) == n/2

0 comments on commit 626b5c9

Please sign in to comment.
Something went wrong with that request. Please try again.