Skip to content

Commit

Permalink
Merge pull request #2350 from jrioux/relational
Browse files Browse the repository at this point in the history
Relational: bool(Relational) should raise

Continuation of #1646. See issue 2832.
  • Loading branch information
jrioux committed Aug 7, 2013
2 parents 3a92446 + 9138eb7 commit 0ef7411
Show file tree
Hide file tree
Showing 46 changed files with 233 additions and 225 deletions.
6 changes: 3 additions & 3 deletions doc/src/modules/polys/basics.rst
Expand Up @@ -209,11 +209,11 @@ polynomials and to solve some systems of polynomial equations::
>>> p = Symbol('p')
>>> q = Symbol('q')

>>> sorted(solve(x**2 + p*x + q, x))
>>> solve(x**2 + p*x + q, x)
__________ __________
/ 2 / 2
p \/ p - 4*q p \/ p - 4*q
[- - + -------------, - - - -------------]
[- - - -------------, - - + -------------]
2 2 2 2

>>> solve_poly_system([y - x, x - 5], x, y)
Expand All @@ -222,5 +222,5 @@ polynomials and to solve some systems of polynomial equations::
>>> solve_poly_system([y**2 - x**3 + 1, y*x], x, y)
___ ___
1 \/ 3 *I 1 \/ 3 *I
[(0, I), (0, -I), (1, 0), (- - + -------, 0), (- - - -------, 0)]
[(0, -I), (0, I), (1, 0), (- - - -------, 0), (- - + -------, 0)]
2 2 2 2
8 changes: 5 additions & 3 deletions sympy/combinatorics/partitions.py
Expand Up @@ -86,7 +86,7 @@ def sort_key(self, order=None):
else:
members = tuple(sorted(self.members,
key=lambda w: default_sort_key(w, order)))
return self.size, members, self.rank
return list(map(default_sort_key, (self.size, members, self.rank)))

@property
def partition(self):
Expand All @@ -100,7 +100,8 @@ def partition(self):
[[1], [2, 3]]
"""
if self._partition is None:
self._partition = sorted(sorted(p) for p in self.args)
self._partition = sorted([sorted(p, key=default_sort_key)
for p in self.args])
return self._partition

def __add__(self, other):
Expand Down Expand Up @@ -230,7 +231,8 @@ def RGS(self):
for i, part in enumerate(partition):
for j in part:
rgs[j] = i
return tuple([rgs[i] for i in sorted(i for p in partition for i in p)])
return tuple([rgs[i] for i in sorted(
[i for p in partition for i in p], key=default_sort_key)])

@classmethod
def from_rgs(self, rgs, elements):
Expand Down
4 changes: 2 additions & 2 deletions sympy/concrete/summations.py
Expand Up @@ -243,7 +243,7 @@ def doit(self, **hints):
for n, limit in enumerate(self.limits):
i, a, b = limit
dif = b - a
if dif.is_integer and dif < 0:
if dif.is_integer and (dif < 0) is True:
a, b = b + 1, a - 1
f = -f

Expand Down Expand Up @@ -361,7 +361,7 @@ def euler_maclaurin(self, m=0, n=0, eps=0, eval_integral=True):
f = self.function
assert len(self.limits) == 1
i, a, b = self.limits[0]
if a > b:
if (a > b) is True:
a, b = b + 1, a - 1
f = -f
s = S.Zero
Expand Down
2 changes: 1 addition & 1 deletion sympy/core/mod.py
Expand Up @@ -51,7 +51,7 @@ def doit(p, q):
else:
if type(d) is int:
rv = p - d*q
if rv*q < 0:
if (rv*q < 0) is True:
rv += q
return rv

Expand Down
2 changes: 1 addition & 1 deletion sympy/core/mul.py
Expand Up @@ -177,7 +177,7 @@ def flatten(cls, seq):
if b.is_Rational:
a, b = b, a
assert not a is S.One
if a and a.is_Rational:
if not a.is_zero and a.is_Rational:
r, b = b.as_coeff_Mul()
if b.is_Add:
if r is not S.One: # 2-arg hack
Expand Down
6 changes: 3 additions & 3 deletions sympy/core/power.py
Expand Up @@ -153,7 +153,7 @@ def _eval_power(self, other):
e.is_real is False and smallarg is False):
return -self.func(b, e*other)
if (other.is_integer or
e.is_real and (b_nneg or abs(e) < 1) or
e.is_real and (b_nneg or (abs(e) < 1) is True) or
e.is_real is False and smallarg is True or
b.is_polar):
return self.func(b, e*other)
Expand Down Expand Up @@ -693,7 +693,7 @@ def _eval_evalf(self, prec):
base = base._evalf(prec)
if not exp.is_Integer:
exp = exp._evalf(prec)
if exp < 0 and base.is_number and base.is_real is False:
if (exp < 0) is True and base.is_number and base.is_real is False:
base = base.conjugate() / (base * base.conjugate())._evalf(prec)
exp = -exp
return self.func(base, exp).expand()
Expand All @@ -706,7 +706,7 @@ def _eval_is_polynomial(self, syms):
if self.base.has(*syms):
return self.base._eval_is_polynomial(syms) and \
self.exp.is_Integer and \
self.exp >= 0
(self.exp >= 0) is True
else:
return True

Expand Down
55 changes: 15 additions & 40 deletions sympy/core/relational.py
Expand Up @@ -222,6 +222,11 @@ def _eval_simplify(self, ratio, measure):
return self.__class__(self.lhs.simplify(ratio=ratio),
self.rhs.simplify(ratio=ratio))

def __nonzero__(self):
raise TypeError("symbolic boolean expression has no truth value.")

__bool__ = __nonzero__


class Equality(Relational):

Expand All @@ -239,11 +244,6 @@ def _eval_relation(cls, lhs, rhs):
def _eval_relation_doit(cls, lhs, rhs):
return Eq(lhs, rhs)

def __nonzero__(self):
return self.lhs.compare(self.rhs) == 0

__bool__ = __nonzero__


class Unequality(Relational):

Expand All @@ -259,11 +259,6 @@ def _eval_relation(cls, lhs, rhs):
def _eval_relation_doit(cls, lhs, rhs):
return Ne(lhs, rhs)

def __nonzero__(self):
return self.lhs.compare(self.rhs) != 0

__bool__ = __nonzero__


class _Greater(Relational):
"""Not intended for general use
Expand Down Expand Up @@ -472,9 +467,10 @@ class GreaterThan(_Greater):
The other gotcha is with chained inequalities. Occasionally, one may be
tempted to write statements like:
>>> e = x < y < z # silent error! Where did ``x`` go?
>>> e #doctest: +SKIP
y < z
>>> e = x < y < z
Traceback (most recent call last):
...
TypeError: symbolic boolean expression has no truth value.
Due to an implementation detail or decision of Python [1]_, there is no way
for SymPy to reliably create that as a chained inequality. To create a
Expand Down Expand Up @@ -509,23 +505,21 @@ class GreaterThan(_Greater):
evaluated once and the comparison can short-circuit. For example, ``1
> 2 > 3`` is evaluated by Python as ``(1 > 2) and (2 > 3)``. The
``and`` operator coerces each side into a bool, returning the object
itself when it short-circuits. Currently, the bool of the --Than
operators will give True or False arbitrarily. Thus, if we were to
itself when it short-circuits. The bool of the --Than operators
will raise TypeError on purpose, because SymPy cannot determine the
mathematical ordering of symbolic expressions. Thus, if we were to
compute ``x > y > z``, with ``x``, ``y``, and ``z`` being Symbols,
Python converts the statement (roughly) into these steps:
(1) x > y > z
(2) (x > y) and (y > z)
(3) (GreaterThanObject) and (y > z)
(4) (GreaterThanObject.__nonzero__()) and (y > z)
(5) (True) and (y > z)
(6) (y > z)
(7) LessThanObject
(5) TypeError
Because of the "and" added at step 2, the statement gets turned into a
weak ternary statement. If the first object evalutes __nonzero__ as
True, then the second object, (y > z) is returned. If the first object
evaluates __nonzero__ as False (step 5), then (x > y) is returned.
weak ternary statement, and the first object's __nonzero__ method will
raise TypeError. Thus, creating a chained inequality is not possible.
In Python, there is no way to override the ``and`` operator, or to
control how it short circuits, so it is impossible to make something
Expand All @@ -550,11 +544,6 @@ class GreaterThan(_Greater):
def _eval_relation(cls, lhs, rhs):
return lhs >= rhs

def __nonzero__(self):
return self.lhs.compare( self.rhs ) >= 0

__bool__ = __nonzero__


class LessThan(_Less):
__doc__ = GreaterThan.__doc__
Expand All @@ -566,11 +555,6 @@ class LessThan(_Less):
def _eval_relation(cls, lhs, rhs):
return lhs <= rhs

def __nonzero__(self):
return self.lhs.compare( self.rhs ) <= 0

__bool__ = __nonzero__


class StrictGreaterThan(_Greater):
__doc__ = GreaterThan.__doc__
Expand All @@ -582,11 +566,6 @@ class StrictGreaterThan(_Greater):
def _eval_relation(cls, lhs, rhs):
return lhs > rhs

def __nonzero__(self):
return self.lhs.compare( self.rhs ) > 0

__bool__ = __nonzero__


class StrictLessThan(_Less):
__doc__ = GreaterThan.__doc__
Expand All @@ -598,10 +577,6 @@ class StrictLessThan(_Less):
def _eval_relation(cls, lhs, rhs):
return lhs < rhs

def __nonzero__(self):
return self.lhs.compare( self.rhs ) < 0

__bool__ = __nonzero__

# A class-specific (not object-specific) data item used for a minor speedup. It
# is defined here, rather than directly in the class, because the classes that
Expand Down
4 changes: 2 additions & 2 deletions sympy/core/tests/test_args.py
Expand Up @@ -1488,7 +1488,7 @@ def test_sympy__functions__special__polynomials__chebyshevt():

def test_sympy__functions__special__polynomials__chebyshevt_root():
from sympy.functions.special.polynomials import chebyshevt_root
assert _test_args(chebyshevt_root(x, 2))
assert _test_args(chebyshevt_root(3, 2))


def test_sympy__functions__special__polynomials__chebyshevu():
Expand All @@ -1498,7 +1498,7 @@ def test_sympy__functions__special__polynomials__chebyshevu():

def test_sympy__functions__special__polynomials__chebyshevu_root():
from sympy.functions.special.polynomials import chebyshevu_root
assert _test_args(chebyshevu_root(x, 2))
assert _test_args(chebyshevu_root(3, 2))


def test_sympy__functions__special__polynomials__hermite():
Expand Down
37 changes: 18 additions & 19 deletions sympy/core/tests/test_expr.py
Expand Up @@ -299,32 +299,31 @@ class foo(Function):


def test_atoms():
assert sorted(list(x.atoms())) == [x]
assert sorted(list((1 + x).atoms())) == sorted([1, x])
assert x.atoms() == set([x])
assert (1 + x).atoms() == set([x, S(1)])

assert sorted(list((1 + 2*cos(x)).atoms(Symbol))) == [x]
assert sorted(
list((1 + 2*cos(x)).atoms(Symbol, Number))) == sorted([1, 2, x])
assert (1 + 2*cos(x)).atoms(Symbol) == set([x])
assert (1 + 2*cos(x)).atoms(Symbol, Number) == set([S(1), S(2), x])

assert sorted(list((2*(x**(y**x))).atoms())) == sorted([2, x, y])
assert (2*(x**(y**x))).atoms() == set([S(2), x, y])

assert sorted(list(Rational(1, 2).atoms())) == [S.Half]
assert sorted(list(Rational(1, 2).atoms(Symbol))) == []
assert Rational(1, 2).atoms() == set([S.Half])
assert Rational(1, 2).atoms(Symbol) == set([])

assert sorted(list(sin(oo).atoms(oo))) == [oo]
assert sin(oo).atoms(oo) == set([oo])

assert sorted(list(Poly(0, x).atoms())) == [S.Zero]
assert sorted(list(Poly(1, x).atoms())) == [S.One]
assert Poly(0, x).atoms() == set([S.Zero])
assert Poly(1, x).atoms() == set([S.One])

assert sorted(list(Poly(x, x).atoms())) == [x]
assert sorted(list(Poly(x, x, y).atoms())) == [x]
assert sorted(list(Poly(x + y, x, y).atoms())) == sorted([x, y])
assert sorted(list(Poly(x + y, x, y, z).atoms())) == sorted([x, y])
assert sorted(list(Poly(x + y*t, x, y, z).atoms())) == sorted([t, x, y])
assert Poly(x, x).atoms() == set([x])
assert Poly(x, x, y).atoms() == set([x])
assert Poly(x + y, x, y).atoms() == set([x, y])
assert Poly(x + y, x, y, z).atoms() == set([x, y])
assert Poly(x + y*t, x, y, z).atoms() == set([t, x, y])

assert list((I*pi).atoms(NumberSymbol)) == [pi]
assert sorted((I*pi).atoms(NumberSymbol, I)) == \
sorted((I*pi).atoms(I, NumberSymbol)) == [pi, I]
assert (I*pi).atoms(NumberSymbol) == set([pi])
assert (I*pi).atoms(NumberSymbol, I) == \
(I*pi).atoms(I, NumberSymbol) == set([pi, I])

assert exp(exp(x)).atoms(exp) == set([exp(exp(x)), exp(x)])
assert (1 + x*(2 + y) + exp(3 + z)).atoms(Add) == \
Expand Down
9 changes: 6 additions & 3 deletions sympy/core/tests/test_relational.py
Expand Up @@ -261,11 +261,14 @@ def test_new_relational():
raises(ValueError, lambda: Relational(x, 1, relation_type))


@XFAIL
def test_relational_bool_output():
# XFail test for issue:
# http://code.google.com/p/sympy/issues/detail?id=2832
raises(ValueError, lambda: bool(x > 3))
raises(TypeError, lambda: bool(x > 3))
raises(TypeError, lambda: bool(x >= 3))
raises(TypeError, lambda: bool(x < 3))
raises(TypeError, lambda: bool(x <= 3))
raises(TypeError, lambda: bool(Eq(x, 3)))
raises(TypeError, lambda: bool(Ne(x, 3)))


def test_relational_logic_symbols():
Expand Down
3 changes: 2 additions & 1 deletion sympy/core/trace.py
Expand Up @@ -2,6 +2,7 @@

from sympy import Expr, Add, Mul, Matrix, Pow, sympify, Matrix, Tuple
from sympy.core.compatibility import xrange
from sympy.utilities import default_sort_key


def _is_scalar(e):
Expand Down Expand Up @@ -32,7 +33,7 @@ def _cycle_permute(l):
if len(l) == 1:
return l

min_item = min(l)
min_item = min(l, key=default_sort_key)
indices = [i for i, x in enumerate(l) if x == min_item]

le = list(l)
Expand Down
2 changes: 1 addition & 1 deletion sympy/functions/elementary/exponential.py
Expand Up @@ -114,7 +114,7 @@ def _eval_power(b, e):
if be.is_polar:
return rv
besmall = abs(be) <= S.Pi
if besmall:
if besmall is True:
return rv
elif besmall is False and e.is_Rational and e.q == 2:
return -rv
Expand Down
3 changes: 2 additions & 1 deletion sympy/functions/elementary/piecewise.py
Expand Up @@ -357,7 +357,8 @@ def _sort_expr_cond(self, sym, a, b, targetcond=None):
else:
int_expr[n][1] = Min(lower, int_expr[n][1])
elif len(int_expr[n][1].free_symbols) and \
lower < int_expr[n][0] is not True:
(lower >= int_expr[n][0]) is not True and \
(int_expr[n][1] == Min(lower, upper)) is not True:
upper = Min(upper, int_expr[n][0])
elif self.__eval_cond(upper > int_expr[n][0]) and \
self.__eval_cond(upper <= int_expr[n][1]):
Expand Down
8 changes: 4 additions & 4 deletions sympy/functions/special/gamma_functions.py
Expand Up @@ -343,11 +343,11 @@ def eval(cls, a, z):

# We extract branching information here. C/f lowergamma.
nx, n = z.extract_branch_factor()
if a.is_integer and a > 0:
if a.is_integer and (a > 0) is True:
nx = unpolarify(z)
if z != nx:
return uppergamma(a, nx)
elif a.is_integer and a <= 0:
elif a.is_integer and (a <= 0) is True:
if n != 0:
return -2*pi*I*n*(-1)**(-a)/factorial(-a) + uppergamma(a, nx)
elif n != 0:
Expand Down Expand Up @@ -428,11 +428,11 @@ def fdiff(self, argindex=2):
raise ArgumentIndexError(self, argindex)

def _eval_is_positive(self):
if self.args[1].is_positive and self.args[0] > 0:
if self.args[1].is_positive and (self.args[0] > 0) is True:
return self.args[0].is_odd

def _eval_is_negative(self):
if self.args[1].is_positive and self.args[0] > 0:
if self.args[1].is_positive and (self.args[0] > 0) is True:
return self.args[0].is_even

def _eval_is_real(self):
Expand Down

0 comments on commit 0ef7411

Please sign in to comment.