from sympy.core import S, Add, sympify, Basic, PoleError, Mul, oo, C from gruntz import gruntz def limit(e, z, z0, dir="+"): """ Compute the limit of e(z) at the point z0. 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 doesn't matter. Examples: >>> from sympy import limit, sin, Symbol >>> x = Symbol('x') >>> limit(sin(x)/x, x, 0) 1 >>> limit(1/x, x, 0, dir="+") oo >>> limit(1/x, x, 0, dir="-") -oo >>> limit(1/x, x, oo) 0 Strategy: 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). """ e = sympify(e) z = sympify(z) z0 = sympify(z0) if e == z: return z0 if e.is_Rational: return e if e.is_Pow: if e.args[0] == z: if e.args[1].is_Rational: if e.args[1] > 0: return z0**e.args[1] else: if z0 == 0: if dir == "+": return S.Infinity else: return -S.Infinity else: return z0**e.args[1] if e.args[1].is_number: if e.args[1].evalf() > 0: return S.Zero else: if dir == "+": return S.Infinity else: return -S.Infinity if e.is_Add: if e.is_polynomial() and z0.is_finite: return Add(*[limit(term, z, z0, dir) for term in e.args]) else: # 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 = [] for term in e.args: result = term.subs(z, z0) if result.is_unbounded or result is S.NaN: unbounded.append(term) unbounded_result.append(result) else: finite.append(result) if unbounded: inf_limit = Add(*unbounded_result) if inf_limit is not S.NaN: return inf_limit if finite: return Add(*finite) + limit(Add(*unbounded), z, z0, dir) else: return Add(*finite) try: r = gruntz(e, z, z0, dir) except PoleError: r = heuristics(e, z, z0, dir) return r def heuristics(e, z, z0, dir): if z0 == oo: return heuristics(e.subs(z, 1/z), z, sympify(0), "+") elif e.is_Mul: r = [] for a in e.args: if not a.is_bounded: r.append(a.limit(z, z0, dir)) if not (r is []): return Mul(*r) elif e.is_Add: r = [] for a in e.args: r.append(a.limit(z, z0, dir)) return Add(*r) elif isinstance(e, C.Function): return e.subs(e.args[0], heuristics(e.args[0], z, z0, dir)) msg = "Don't know how to calculate the limit(%s, %s, %s, dir=%s), sorry." raise PoleError(msg % (e, z, z0, dir)) class Limit(Basic): """Represents unevaluated limit. Examples: >>> from sympy import limit, sin, Symbol >>> x = Symbol('x') >>> Limit(sin(x)/x, x, 0) Limit(sin(x)/x, x, 0) >>> 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) obj = Basic.__new__(cls) obj._args = (e, z, z0, dir) return obj def doit(self): e, z, z0, dir = self.args return limit(e, z, z0, dir)