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

bool, relational: added as_set method #2781

Merged
merged 1 commit into from Jan 19, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
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
27 changes: 27 additions & 0 deletions sympy/core/relational.py
Expand Up @@ -227,6 +227,33 @@ def __nonzero__(self):

__bool__ = __nonzero__

def as_set(self):
"""
Rewrites univariate inequality in terms of real sets

Examples
========

>>> from sympy import Symbol, Eq
>>> x = Symbol('x', real=True)
>>> (x>0).as_set()
(0, oo)
>>> Eq(x, 0).as_set()
{0}

"""
from sympy.solvers.inequalities import solve_univariate_inequality
syms = self.free_symbols

if len(syms) == 1:
sym = syms.pop()
else:
raise NotImplementedError("Sorry, Relational.as_set procedure"
" is not yet implemented for"
" multivariate expressions")

return solve_univariate_inequality(self, sym, relational=False)


class Equality(Relational):

Expand Down
19 changes: 19 additions & 0 deletions sympy/core/tests/test_relational.py
Expand Up @@ -3,6 +3,7 @@
from sympy.core.relational import ( Relational, Equality, Unequality,
GreaterThan, LessThan, StrictGreaterThan, StrictLessThan, Rel, Eq, Lt, Le,
Gt, Ge, Ne )
from sympy.core.sets import Interval, FiniteSet

x, y, z, t = symbols('x,y,z,t')

Expand Down Expand Up @@ -282,3 +283,21 @@ def test_relational_logic_symbols():
assert isinstance((x < y) >> (z < t), Implies)
assert isinstance((x < y) << (z < t), Implies)
assert isinstance((x < y) ^ (z < t), (Or, Xor))


def test_univariate_relational_as_set():
assert (x > 0).as_set() == Interval(0, oo, True, True)
assert (x >= 0).as_set() == Interval(0, oo)
assert (x < 0).as_set() == Interval(-oo, 0, True, True)
assert (x <= 0).as_set() == Interval(-oo, 0)
assert Eq(x, 0).as_set() == FiniteSet(0)
assert Ne(x, 0).as_set() == Interval(-oo, 0, True, True) + \
Interval(0, oo, True, True)

assert (x**2 >= 4).as_set() == Interval(-oo, -2) + Interval(2, oo)


@XFAIL
def test_multivariate_relational_as_set():
assert (x*y >= 0).as_set() == Interval(0, oo)*Interval(0, oo) + \
Interval(-oo, 0)*Interval(-oo, 0)
88 changes: 87 additions & 1 deletion sympy/logic/boolalg.py
Expand Up @@ -135,6 +135,20 @@ def __nonzero__(self):
def __hash__(self):
return hash(True)

def as_set(self):
"""
Rewrite logic operators and relationals in terms of real sets.

Examples
========

>>> from sympy import true
>>> true.as_set()
UniversalSet()
"""
return S.UniversalSet


class BooleanFalse(with_metaclass(Singleton, BooleanAtom)):
"""
SymPy version of False.
Expand Down Expand Up @@ -174,6 +188,20 @@ def __nonzero__(self):
def __hash__(self):
return hash(False)

def as_set(self):
"""
Rewrite logic operators and relationals in terms of real sets.

Examples
========

>>> from sympy import false
>>> false.as_set()
EmptySet()
"""
from sympy.core.sets import EmptySet
return EmptySet()

true = BooleanTrue()
false = BooleanFalse()
# We want S.true and S.false to work, rather than S.BooleanTrue and
Expand Down Expand Up @@ -241,6 +269,26 @@ def _new_args_filter(cls, args):
newargs.append(x)
return LatticeOp._new_args_filter(newargs, And)

def as_set(self):
"""
Rewrite logic operators and relationals in terms of real sets.

Examples
========

>>> from sympy import And, Symbol
>>> x = Symbol('x', real=True)
>>> And(x<2, x>-2).as_set()
(-2, 2)
"""
from sympy.core.sets import Intersection
if len(self.free_symbols) == 1:
return Intersection(*[arg.as_set() for arg in self.args])
else:
raise NotImplementedError("Sorry, And.as_set has not yet been"
" implemented for multivariate"
" expressions")


class Or(LatticeOp, BooleanFunction):
"""
Expand Down Expand Up @@ -283,6 +331,26 @@ def _new_args_filter(cls, args):
newargs.append(x)
return LatticeOp._new_args_filter(newargs, Or)

def as_set(self):
"""
Rewrite logic operators and relationals in terms of real sets.

Examples
========

>>> from sympy import Or, Symbol
>>> x = Symbol('x', real=True)
>>> Or(x>2, x<-2).as_set()
(-oo, -2) U (2, oo)
"""
from sympy.core.sets import Union
if len(self.free_symbols) == 1:
return Union(*[arg.as_set() for arg in self.args])
else:
raise NotImplementedError("Sorry, Or.as_set has not yet been"
" implemented for multivariate"
" expressions")


class Not(BooleanFunction):
"""
Expand Down Expand Up @@ -333,7 +401,6 @@ class Not(BooleanFunction):

is_Not = True


@classmethod
def eval(cls, arg):
if isinstance(arg, Number) or arg in (True, False):
Expand All @@ -346,6 +413,25 @@ def eval(cls, arg):
if arg.func is Not:
return arg.args[0]

def as_set(self):
"""
Rewrite logic operators and relationals in terms of real sets.

Examples
========

>>> from sympy import Not, Symbol
>>> x = Symbol('x', real=True)
>>> Not(x>0).as_set()
(-oo, 0]
"""
if len(self.free_symbols) == 1:
return self.args[0].as_set().complement
else:
raise NotImplementedError("Sorry, Not.as_set has not yet been"
" implemented for mutivariate"
" expressions")


class Xor(BooleanFunction):
"""
Expand Down
27 changes: 24 additions & 3 deletions sympy/logic/tests/test_boolalg.py
@@ -1,11 +1,13 @@
from sympy import symbols, sympify, Dummy, simplify, Equality, S
from sympy import (symbols, sympify, Dummy, simplify, Equality, S, Interval,
oo, EmptySet)
from sympy.logic.boolalg import (
And, Boolean, Equivalent, ITE, Implies, Nand, Nor, Not, Or, POSform,
SOPform, Xor, conjuncts, disjuncts, distribute_or_over_and,
distribute_and_over_or, eliminate_implications, is_cnf, is_dnf,
simplify_logic, to_cnf, to_dnf, to_int_repr, bool_map, true, false, BooleanAtom
simplify_logic, to_cnf, to_dnf, to_int_repr, bool_map, true, false,
BooleanAtom
)
from sympy.utilities.pytest import raises
from sympy.utilities.pytest import raises, XFAIL
from sympy.utilities import cartes


Expand Down Expand Up @@ -543,3 +545,22 @@ def test_true_false():
assert ITE(F, T, F) is false
assert ITE(F, F, T) is true
assert ITE(F, F, F) is false


def test_bool_as_set():
x = symbols('x')

assert And(x <= 2, x >= -2).as_set() == Interval(-2, 2)
assert Or(x >= 2, x <= -2).as_set() == Interval(-oo, -2) + Interval(2, oo)
assert Not(x > 2).as_set() == Interval(-oo, 2)
assert true.as_set() == S.UniversalSet
assert false.as_set() == EmptySet()


@XFAIL
def test_multivariate_bool_as_set():
x, y = symbols('x,y')

assert And(x >= 0, y >= 0).as_set() == Interval(0, oo)*Interval(0, oo)
assert Or(x >= 0, y >= 0).as_set() == S.UniversalSet - \
Interval(-oo, 0, True, True)*Interval(-oo, 0, True, True)