elif not e.has(x):
f= e.evalf()
if f > 0:
return 1
else:
return -1
Which obviously utterly fails if "e == Symbol('y')", because then "f == y" and
"f > 0" just compares hashes, that changed in python2.6. The solution is to use
"e.is_positive" instead and everything works just fine.
Thorough tests for this issue committed.
---
sympy/series/gruntz.py | 3 +--
sympy/series/tests/test_gruntz.py | 9 +++++++++
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/sympy/series/gruntz.py b/sympy/series/gruntz.py
index 556b540..e386f9f 100644
--- a/sympy/series/gruntz.py
+++ b/sympy/series/gruntz.py
@@ -276,8 +276,7 @@ def sign(e, x):
else:
return -1
elif not e.has(x):
- f= e.evalf()
- if f > 0:
+ if e.is_positive:
return 1
else:
return -1
diff --git a/sympy/series/tests/test_gruntz.py b/sympy/series/tests/test_gruntz.py
index f8ab654..f7df2b6 100644
--- a/sympy/series/tests/test_gruntz.py
+++ b/sympy/series/tests/test_gruntz.py
@@ -75,6 +75,15 @@ def test_sign1():
assert sign(3-1/x, x) == 1
assert sign(-3-1/x, 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 test_mrv1():
assert mrv(x, x) == set([x])
assert mrv(x+1/x, x) == set([x])
--
1.5.6.5
diff --git a/sympy/utilities/tests/test_pytest.py b/sympy/utilities/tests/test_pytest.py
new file mode 100644
index 0000000..92ac477
--- /dev/null
+++ b/sympy/utilities/tests/test_pytest.py
@@ -0,0 +1,18 @@
+from sympy.utilities.pytest import raises
+
+def test_raises():
+ class My(Exception):
+ pass
+ raises(My, "raise My()")
+
+ try:
+ raises(My, "1+1")
+ assert False
+ except Exception, e:
+ assert e.message == "DID NOT RAISE"
+
+ try:
+ raises(My, "raise Exception('my text123')")
+ assert False
+ except Exception, e:
+ assert e.message == "my text123"
--
1.5.6.5
limit(exp(y*x), x, oo) == oo
but this is only true if y is positive, so y was made positive.
---
sympy/series/tests/test_limits.py | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/sympy/series/tests/test_limits.py b/sympy/series/tests/test_limits.py
index 4386df3..1079b4e 100644
--- a/sympy/series/tests/test_limits.py
+++ b/sympy/series/tests/test_limits.py
@@ -119,6 +119,7 @@ def test_heuristic():
assert limit(log(2+sqrt(atan(x)*sin(1/x))), x, 0) == log(2)
def test_issue772():
+ z = Symbol("z", positive=True)
f = -1/z*exp(-z*x)
assert limit(f, x, oo) == 0
assert f.limit(x, oo) == 0
--
1.5.6.5
diff --git a/sympy/core/tests/test_basic.py b/sympy/core/tests/test_basic.py
index 5826c8f..693e936 100644
--- a/sympy/core/tests/test_basic.py
+++ b/sympy/core/tests/test_basic.py
@@ -151,6 +151,16 @@ def test_leadterm():
assert (x+x**2).leadterm(x)[1] == 1
assert (x**2).leadterm(x)[1] == 2
+def test_as_leading_term():
+ assert (3+2*x**(log(3)/log(2)-1)).as_leading_term(x) == 3
+ assert (1/x**2+1+x+x**2).as_leading_term(x) == 1/x**2
+ assert (1/x+1+x+x**2).as_leading_term(x) == 1/x
+ assert (x**2+1/x).as_leading_term(x) == 1/x
+ assert (1+x**2).as_leading_term(x) == 1
+ assert (x+1).as_leading_term(x) == 1
+ assert (x+x**2).as_leading_term(x) == x
+ assert (x**2).as_leading_term(x) == x**2
+
def test_atoms():
assert sorted(list(x.atoms())) == [x]
assert sorted(list((1+x).atoms())) == sorted([1, x])
--
1.5.6.5
diff --git a/sympy/series/gruntz.py b/sympy/series/gruntz.py
index e386f9f..eb9c2cc 100644
--- a/sympy/series/gruntz.py
+++ b/sympy/series/gruntz.py
@@ -87,6 +87,42 @@ 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
+applying the following patch:
+
+@@ -101,7 +108,7 @@ def debug(func):
+ It will print a nice execution tree with arguments and results
+ of all decorated functions.
+ ""
+- if 1:
++ if 0:
+ #normal mode - do nothing
+ return func
+
+Then start isympy and type the failing limit. For example:
+
+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 sympy.core import Basic, S, Add, Mul, Pow, Function, oo, Symbol, \
--
1.5.6.5
diff --git a/sympy/series/tests/test_limits.py b/sympy/series/tests/test_limits.py
index f44b863..2dfd83c 100644
--- a/sympy/series/tests/test_limits.py
+++ b/sympy/series/tests/test_limits.py
@@ -1,5 +1,5 @@
from sympy import limit, exp, oo, log, sqrt, Limit, sin, floor, cos, ceiling, \
- atan, Symbol
+ atan, Symbol, S
from sympy.abc import x, y, z
from sympy.utilities.pytest import XFAIL
@@ -138,3 +138,8 @@ def test_exponential2():
def test_bug693a():
assert sin(sin(x+1)+1).limit(x,0) == sin(sin(1)+1)
+
+def test_issue693():
+ assert limit( (1-cos(x))/x**2, x, S(1)/2) == 4 - 4*cos(S(1)/2)
+ assert limit(sin(sin(x+1)+1), x, 0) == sin(1 + sin(1))
+ assert limit(abs(sin(x+1)+1), x, 0) == 1 + sin(1)
--
1.5.6.5
diff --git a/sympy/series/tests/test_limits.py b/sympy/series/tests/test_limits.py
index 1079b4e..f44b863 100644
--- a/sympy/series/tests/test_limits.py
+++ b/sympy/series/tests/test_limits.py
@@ -135,3 +135,6 @@ def test_exponential():
def test_exponential2():
n = Symbol('n')
assert limit((1+x/(n+sin(n)))**n,n,oo) == exp(x)
+
+def test_bug693a():
+ assert sin(sin(x+1)+1).limit(x,0) == sin(sin(1)+1)
--
1.5.6.5
Then there was a problem that some advanced series tests started to hang after
this patch. As it turned out, sometimes Order(..., x) returns O(2) instead of
O(1). So we fixed that by applying this patch (at 2 different places):
- if o.expr==1:
+ if o.expr.is_number:
And the final problem was, that by fixing the as_leading_term(), we had to call
collect in Pow._eval_nseries() -- previously the wrong as_leading_term() was
effectively achieving the same thing, but that was just a sheer luck.
---
sympy/core/add.py | 4 ++--
sympy/core/power.py | 7 +++++--
sympy/functions/elementary/exponential.py | 2 +-
3 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/sympy/core/add.py b/sympy/core/add.py
index 0a86dbb..7e3c9cb 100644
--- a/sympy/core/add.py
+++ b/sympy/core/add.py
@@ -325,14 +325,14 @@ class Add(AssocOp):
seq = [(f, C.Order(f, *symbols)) for f in self.args]
for ef,of in seq:
for e,o in lst:
- if o.contains(of):
+ if o.contains(of) and o != of:
of = None
break
if of is None:
continue
new_lst = [(ef,of)]
for e,o in lst:
- if of.contains(o):
+ if of.contains(o) and o != of:
continue
new_lst.append((e,o))
lst = new_lst
diff --git a/sympy/core/power.py b/sympy/core/power.py
index ebd9824..81768bc 100644
--- a/sympy/core/power.py
+++ b/sympy/core/power.py
@@ -502,7 +502,10 @@ class Pow(Basic):
# express "rest" as: rest = 1 + k*x**l + ... + O(x**n)
rest = ((base-prefactor)/prefactor).expand()
if rest == 0:
- return 1/prefactor
+ # if prefactor == w**4 + x**2*w**4 + 2*x*w**4, we need to
+ # factor the w**4 out using collect:
+ from sympy import collect
+ return 1/collect(prefactor, x)
if rest.is_Order:
return ((1+rest)/prefactor).expand()
if not rest.has(x):
@@ -580,7 +583,7 @@ class Pow(Basic):
if o is S.Zero:
r = (1+z)
else:
- if o.expr==1:
+ if o.expr.is_number:
e2 = ln(o2.expr*x)/ln(x)
else:
e2 = ln(o2.expr)/ln(o.expr)
diff --git a/sympy/functions/elementary/exponential.py b/sympy/functions/elementary/exponential.py
index 370a455..bbea266 100644
--- a/sympy/functions/elementary/exponential.py
+++ b/sympy/functions/elementary/exponential.py
@@ -401,7 +401,7 @@ class log(Function):
o = C.Order(z, x)
if o is S.Zero:
return ln(1+z)+ ln(arg0)
- if o.expr==1:
+ if o.expr.is_number:
e = ln(order.expr*x)/ln(x)
else:
e = ln(order.expr)/ln(o.expr)
--
1.5.6.5
diff --git a/sympy/series/tests/test_limits.py b/sympy/series/tests/test_limits.py
index 2dfd83c..19afb37 100644
--- a/sympy/series/tests/test_limits.py
+++ b/sympy/series/tests/test_limits.py
@@ -1,5 +1,5 @@
from sympy import limit, exp, oo, log, sqrt, Limit, sin, floor, cos, ceiling, \
- atan, Symbol, S
+ atan, Symbol, S, pi
from sympy.abc import x, y, z
from sympy.utilities.pytest import XFAIL
@@ -143,3 +143,9 @@ def test_issue693():
assert limit( (1-cos(x))/x**2, x, S(1)/2) == 4 - 4*cos(S(1)/2)
assert limit(sin(sin(x+1)+1), x, 0) == sin(1 + sin(1))
assert limit(abs(sin(x+1)+1), x, 0) == 1 + sin(1)
+
+def test_issue991():
+ assert limit(1/(x+3), x, 2) == S(1)/5
+ assert limit(1/(x+pi), x, 2) == S(1)/(2+pi)
+ assert limit(log(x)/(x**2+3), x, 2) == log(2)/7
+ assert limit(log(x)/(x**2+pi), x, 2) == log(2)/(4+pi)
--
1.5.6.5
diff --git a/sympy/series/order.py b/sympy/series/order.py
index 5de6e87..5c37f11 100644
--- a/sympy/series/order.py
+++ b/sympy/series/order.py
@@ -82,7 +82,7 @@ class Order(Basic):
@cacheit
def __new__(cls, expr, *symbols, **assumptions):
- expr = sympify(expr).expand(trig=True)
+ expr = sympify(expr).expand()
if expr is S.NaN:
return S.NaN
--
1.5.6.5
The bug #991 is not fixed, but things like the following now work:
(x*cos(1)*cos(1 + sin(1)) + sin(1 + sin(1))).as_leading_term(x) == \
sin(1 + sin(1))
Tests written.
---
sympy/core/basic.py | 3 +--
sympy/core/tests/test_basic.py | 8 ++++++++
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/sympy/core/basic.py b/sympy/core/basic.py
index 275a4ae..95c81eb 100644
--- a/sympy/core/basic.py
+++ b/sympy/core/basic.py
@@ -2105,8 +2105,7 @@ class Basic(AssumeMeths):
assert x.is_Symbol, `x`
if not self.has(x):
return self
- expr = self.expand(trig=True)
- obj = expr._eval_as_leading_term(x)
+ obj = self._eval_as_leading_term(x)
if obj is not None:
return obj
raise NotImplementedError('as_leading_term(%s, %s)' % (self, x))
diff --git a/sympy/core/tests/test_basic.py b/sympy/core/tests/test_basic.py
index 693e936..b21f649 100644
--- a/sympy/core/tests/test_basic.py
+++ b/sympy/core/tests/test_basic.py
@@ -161,6 +161,14 @@ def test_as_leading_term():
assert (x+x**2).as_leading_term(x) == x
assert (x**2).as_leading_term(x) == x**2
+def test_leadterm2():
+ assert (x*cos(1)*cos(1 + sin(1)) + sin(1 + sin(1))).leadterm(x) == \
+ (sin(1 + sin(1)), 0)
+
+def test_as_leading_term2():
+ assert (x*cos(1)*cos(1 + sin(1)) + sin(1 + sin(1))).as_leading_term(x) == \
+ sin(1 + sin(1))
diff --git a/sympy/series/tests/test_demidovich.py b/sympy/series/tests/test_demidovich.py
index c2fef30..dfa9de5 100644
--- a/sympy/series/tests/test_demidovich.py
+++ b/sympy/series/tests/test_demidovich.py
@@ -1,6 +1,5 @@
from sympy import limit, Symbol, oo, sqrt, Rational, log, exp, cos, sin, tan, \
- pi, asin
-from sympy.utilities.pytest import XFAIL
+ pi, asin, together
"""
(*) in problem number means that the number is relative to the book "Anti-demidovich,
@@ -39,11 +38,11 @@ def test_Limits_simple_2():
assert limit(sqrt3(x**2+1)/(x+1),x,oo)==0 #189
assert limit(sqrt(x)/sqrt(x+sqrt(x+sqrt(x))),x,oo)==1 #190
-@XFAIL
def test_Limits_simple_3a():
a = Symbol('a', real=True)
#issue 414
- assert limit((x**2-(a+1)*x+a)/(x**3-a**3),x,a)==(a-1)/(3*a**2) #196
+ 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")
--
1.5.6.5
diff --git a/sympy/core/tests/test_basic.py b/sympy/core/tests/test_basic.py
index a48e0a1..0b8eeb1 100644
--- a/sympy/core/tests/test_basic.py
+++ b/sympy/core/tests/test_basic.py
@@ -165,6 +165,9 @@ def test_leadterm2():
assert (x*cos(1)*cos(1 + sin(1)) + sin(1 + sin(1))).leadterm(x) == \
(sin(1 + sin(1)), 0)
+def test_leadterm3():
+ assert (y+z+x).leadterm(x) == (y+z, 0)
+
def test_as_leading_term2():
assert (x*cos(1)*cos(1 + sin(1)) + sin(1 + sin(1))).as_leading_term(x) == \
sin(1 + sin(1))
--
1.5.6.5
diff --git a/sympy/core/basic.py b/sympy/core/basic.py
index d5e4262..275a4ae 100644
--- a/sympy/core/basic.py
+++ b/sympy/core/basic.py
@@ -2078,6 +2078,22 @@ class Basic(AssumeMeths):
@cacheit
def as_leading_term(self, *symbols):
+ """
+ Returns the leading term.
+
+ Example:
+
+ >>> x = Symbol("x")
+ >>> (1+x+x**2).as_leading_term(x)
+ 1
+ >>> (1/x**2+x+x**2).as_leading_term(x)
+ 1/x**2
+
+ Note:
+
+ self is assumed to be the result returned by Basic.series().
+ """
+
if len(symbols)>1:
c = self
for x in symbols:
@@ -2113,6 +2129,22 @@ class Basic(AssumeMeths):
return self, S.Zero
def leadterm(self, x):
+ """
+ Returns the leading term a*x**b as a tuple (a, b).
+
+ Example:
+
+ >>> x = Symbol("x")
+ >>> (1+x+x**2).leadterm(x)
+ (1, 0)
+ >>> (1/x**2+x+x**2).leadterm(x)
+ (1, -2)
+
+ Note:
+
+ self is assumed to be the result returned by Basic.series().
+ """
+
x = sympify(x)
c,e = self.as_leading_term(x).as_coeff_exponent(x)
if not c.has(x):
--
1.5.6.5
diff --git a/sympy/core/tests/test_basic.py b/sympy/core/tests/test_basic.py
index b21f649..a48e0a1 100644
--- a/sympy/core/tests/test_basic.py
+++ b/sympy/core/tests/test_basic.py
@@ -169,6 +169,10 @@ def test_as_leading_term2():
assert (x*cos(1)*cos(1 + sin(1)) + sin(1 + sin(1))).as_leading_term(x) == \
sin(1 + sin(1))
+def test_as_leading_term3():
+ assert (2+pi+x).as_leading_term(x) == 2 + pi
+ assert (2*x+pi*x+x**2).as_leading_term(x) == 2*x + pi*x
+
def test_atoms():
assert sorted(list(x.atoms())) == [x]
assert sorted(list((1+x).atoms())) == sorted([1, x])
diff --git a/sympy/series/tests/test_order.py b/sympy/series/tests/test_order.py
index a28c32d..468fad5 100644
--- a/sympy/series/tests/test_order.py
+++ b/sympy/series/tests/test_order.py
@@ -1,4 +1,4 @@
-from sympy import Symbol, Rational, Order, C, exp, ln, log, O, var, nan
+from sympy import Symbol, Rational, Order, C, exp, ln, log, O, var, nan, pi
from sympy.utilities.pytest import XFAIL
from sympy.abc import w, x, y, z
@@ -167,6 +167,11 @@ def test_leading_order():
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 (2+pi+x**2).extract_leading_order(x) == ((pi, O(1, x)), (2, O(1, x)))
+ assert (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)
--
1.5.6.5
I noticed here the redundancy ---- so I suggest to remove the
test_bug693a() completely.
Ondrej
wouldn't it be more elegant to have a variable settings.DEBUG
somewhere (like django does) that turns
on / off global debugging messages ( or an argument for the function,
like mymethod(args, debug=True) ?
I think the overhead for this should be minimal and it would be nice
to turn on/off debug messages on all functions
just changing one line in a settings.py file.
--------------------
Fabian Seoane
http://fseoane.net
Yes, I think it would. The overhead will be zero, as this will be
decided at import time. I think we can just use environment variable
SYMPY_DEBUG to turn on debugging. But I suggest to implement this
later. In this patch I was just documenting the current system.
Ondrej
ok, i made an issue for this
>
>
> Ondrej
It's +1 for me (the whole set of patches)
--------------------
Fabian Seoane
http://fseoane.net
Thanks for review, so I am pushing all patches in.
Ondrej