Skip to content

Commit

Permalink
Redo Add._eval_is_positive/negative handlers
Browse files Browse the repository at this point in the history
Correct also broken test test_Add_is_pos_neg (finite doesn't
imply real!).  Fixes sympy/sympy#9832.
  • Loading branch information
skirpichev committed Sep 13, 2015
1 parent 8328fb7 commit 253aa87
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 69 deletions.
106 changes: 38 additions & 68 deletions sympy/core/add.py
Expand Up @@ -508,86 +508,56 @@ def _eval_is_irrational(self):
def _eval_is_positive(self):
if self.is_number:
return super(Add, self)._eval_is_positive()
pos = nonneg = nonpos = unknown_sign = False
saw_INF = set()
args = [a for a in self.args if not a.is_zero]
if not args:
return False

if any(a.is_infinite for a in self.args):
args = [a for a in self.args if not a.is_finite]
else:
args = self.args

nonpos = nonneg = 0
for a in args:
ispos = a.is_positive
infinite = a.is_infinite
if infinite:
saw_INF.add(fuzzy_or((ispos, a.is_nonnegative)))
if True in saw_INF and False in saw_INF:
return
if ispos:
pos = True
if a.is_positive:
continue
elif a.is_nonnegative:
nonneg = True
continue
nonneg += 1
if a.is_zero:
nonpos += 1
elif a.is_nonpositive:
nonpos = True
continue

if infinite is None:
return
unknown_sign = True

if saw_INF:
if len(saw_INF) > 1:
return
return saw_INF.pop()
elif unknown_sign:
return
elif not nonpos and not nonneg and pos:
return True
elif not nonpos and pos:
return True
elif not pos and not nonneg:
return False
nonpos += 1
else:
break
else:
if not nonpos and nonneg < len(args):
return True
elif nonpos == len(args):
return False

def _eval_is_negative(self):
if self.is_number:
return super(Add, self)._eval_is_negative()
neg = nonpos = nonneg = unknown_sign = False
saw_INF = set()
args = [a for a in self.args if not a.is_zero]
if not args:
return False

if any(a.is_infinite for a in self.args):
args = [a for a in self.args if not a.is_finite]
else:
args = self.args

nonneg = nonpos = 0
for a in args:
isneg = a.is_negative
infinite = a.is_infinite
if infinite:
saw_INF.add(fuzzy_or((isneg, a.is_nonpositive)))
if True in saw_INF and False in saw_INF:
return
if isneg:
neg = True
if a.is_negative:
continue
elif a.is_nonpositive:
nonpos = True
continue
nonpos += 1
if a.is_zero:
nonneg += 1
elif a.is_nonnegative:
nonneg = True
continue

if infinite is None:
return
unknown_sign = True

if saw_INF:
if len(saw_INF) > 1:
return
return saw_INF.pop()
elif unknown_sign:
return
elif not nonneg and not nonpos and neg:
return True
elif not nonneg and neg:
return True
elif not neg and not nonpos:
return False
nonneg += 1
else:
break
else:
if not nonneg and nonpos < len(args):
return True
elif nonneg == len(args):
return False

def _eval_subs(self, old, new):
if not old.is_Add:
Expand Down
5 changes: 5 additions & 0 deletions sympy/core/tests/test_arit.py
Expand Up @@ -1874,3 +1874,8 @@ def test_issue_8247_8354():
1566)*((3*sqrt(93) + 29)**(1/3)*(-2**(2/3)*(3*sqrt(93) + 29)**(1/3) -
2) - 2*2**(1/3))**2''')
assert z.is_positive is False # it's 0 (and a single _mexpand isn't enough)


def test_issue_9832():
x = Symbol('x', extended_real=True)
assert (x**2 - oo).is_negative is None
2 changes: 1 addition & 1 deletion sympy/core/tests/test_assumptions.py
Expand Up @@ -640,7 +640,7 @@ def test_Add_is_pos_neg():
p = Symbol('p', positive=True, infinite=True)
r = Dummy(extended_real=True, finite=False)
x = Symbol('x')
xf = Symbol('xb', finite=True)
xf = Symbol('xb', finite=True, real=True)
assert (n + p).is_positive is None
assert (n + x).is_positive is None
assert (p + x).is_positive is None
Expand Down

0 comments on commit 253aa87

Please sign in to comment.