Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changed Printing of Logic Expressions #11448

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 5 additions & 2 deletions sympy/printing/str.py
Expand Up @@ -75,13 +75,16 @@ def _print_BooleanFalse(self, expr):
return "False"

def _print_And(self, expr):
return '%s(%s)' % (expr.func, ', '.join(sorted(self._print(a) for a in
return '(%s)' % (' & '.join(sorted(self._print(a) for a in
expr.args)))

def _print_Or(self, expr):
return '%s(%s)' % (expr.func, ', '.join(sorted(self._print(a) for a in
return '(%s)' % (' | '.join(sorted(self._print(a) for a in
expr.args)))

def _print_Not(self, expr):
return '%s(%s)' % ('~', self._print(expr.args[0]))

def _print_AppliedPredicate(self, expr):
return '%s(%s)' % (expr.func, expr.arg)

Expand Down
6 changes: 3 additions & 3 deletions sympy/printing/tests/test_str.py
Expand Up @@ -660,14 +660,14 @@ def test_settings():
def test_RandomDomain():
from sympy.stats import Normal, Die, Exponential, pspace, where
X = Normal('x1', 0, 1)
assert str(where(X > 0)) == "Domain: And(0 < x1, x1 < oo)"
assert str(where(X > 0)) == "Domain: (0 < x1 & x1 < oo)"

D = Die('d1', 6)
assert str(where(D > 4)) == "Domain: Or(Eq(d1, 5), Eq(d1, 6))"
assert str(where(D > 4)) == "Domain: (Eq(d1, 5) | Eq(d1, 6))"

A = Exponential('a', 1)
B = Exponential('b', 1)
assert str(pspace(Tuple(A, B)).domain) == "Domain: And(0 <= a, 0 <= b, a < oo, b < oo)"
assert str(pspace(Tuple(A, B)).domain) == "Domain: (0 <= a & 0 <= b & a < oo & b < oo)"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to be more careful about parenthesization. This is wrong (needs parentheses around the inequalities).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this output desirable?

>>> from sympy import *
>>> from sympy.abc import x,y,z
>>> print(And(Not(x), Or(y, z)))
((((y) | (z))) & (~(x)))

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO, I don't think that is desirable.
Is it possible to parenthesize only when necessary, depending on operator precedence?

I would suggest you take a look at the parethesize method of the StrPrinter class.
(https://github.com/sympy/sympy/blob/master/sympy/printing/str.py#L27)

Personally, I think this would be desirable:

>>> print(And(Not(x), Or(y, z)))
(y | z) & ~x

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am able to get the output using the parethesize method method. But I am unable to parenthesize inequalities as desired. Any tips?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume you used the precedence function, which follows this precedence table:
https://github.com/sympy/sympy/blob/master/sympy/printing/precedence.py#L8

Do we really need parentheses around the inequalities in that case? Don't relational operators have precedence over logical And? (at least from a programming language perspective)

However, this does look more appealing:

"Domain: (0 <= a) & (0 <= b) & (a < oo) & (b < oo)"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need parentheses around the inequalities in that case? Don't relational operators have precedence over logical And? (at least from a programming language perspective)

No they don't. That's why parentheses are so important.

In [71]: type(x < y & z)
Out[71]: sympy.core.relational.StrictLessThan

In [72]: x < (y & z)
Out[72]: x < y ∧ z

In [73]: (x < y) & z
Out[73]: z ∧ x < y

In [74]: (x < y & z).args
Out[74]: (x, y ∧ z)

See also https://docs.python.org/3/reference/expressions.html#operator-precedence

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly, I find the behavior in the example above odd. I would expect the following results to be equal:

>>> srepr(x < y & z)
"StrictLessThan(Symbol(′x′),And(Symbol(′y′),Symbol(′z′)))"

>>> srepr((x < y) & z)
"And(Symbol(′z′),StrictLessThan(Symbol(′x′),Symbol(′y′)))"

As for the python reference, it agrees with what I was trying to say in my previous answer.

>>> 2 > 2 and True
False

>>> (2 > 2) and True
False

>>> 2 > (2 and True)
True

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gorisaka do not confuse and and &. The former has lower precedence than the inequality operators, and can't be overridden by libraries like SymPy. & has higher precedence and can be overridden.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since | is also overridden the same problem occurs with it:

>>> str((x > 1) | (x < -1))
x > 1 | x < -1



def test_FiniteSet():
Expand Down