<commit_before>"""Boolean algebra module for SymPy"""
from __future__ import print_function, division

from collections import defaultdict
from itertools import product

from sympy.core.basic import Basic
from sympy.core.numbers import Number
from sympy.core.decorators import deprecated
from sympy.core.operations import LatticeOp
from sympy.core.function import Application, sympify
from sympy.core.compatibility import ordered, xrange, with_metaclass
from sympy.core.sympify import converter
from sympy.core.singleton import Singleton, S


class Boolean(Basic):
    """A boolean object is an object for which logic operations make sense."""

    __slots__ = []

    def __and__(self, other):
        """Overloading for & operator"""
        return And(self, other)

    __rand__ = __and__

    def __or__(self, other):
        """Overloading for |"""
        return Or(self, other)

    __ror__ = __or__

    def __invert__(self):
        """Overloading for ~"""
        return Not(self)

    def __rshift__(self, other):
        """Overloading for >>"""
        return Implies(self, other)

    def __lshift__(self, other):
        """Overloading for <<"""
        return Implies(other, self)

    __rrshift__ = __lshift__
    __rlshift__ = __rshift__

    def __xor__(self, other):
        return Xor(self, other)

    __rxor__ = __xor__

# Developer note: There is liable to be some confusion as to when True should
# be used and when S.true should be used in various contexts throughout SymPy.
# An important thing to remember is that sympify(True) returns S.true.  This
# means that for the most part, you can just use True and it will
# automatically be converted to S.true when necessary, similar to how you can
# generally use 1 instead of S.One.

# The rule of thumb is:

#   "If the boolean in question can be replaced by an arbitrary symbolic
#   Boolean, like Or(x, y) or x > 1, use S.true. Otherwise, use True"

# In other words, use S.true only on those contexts where the boolean is being
# used as a symbolic representation of truth.  For example, if the object ends
# up in the .args of any expression, then it must necessarily be S.true
# instead of True, as elements of .args must be Basic.  On the other hand, ==
# is not a symbolic operation in SymPy, since it always returns True or False,
# and does so in terms of structural equality rather than mathematical, so it
# should return True. The assumptions system should use True and False. Aside
# from not satisfying the above rule of thumb, the assumptions system uses a
# three-valued logic (True, False, None), whereas S.true and S.false represent
# a two-valued logic.  When it doubt, use True.

# 2. "S.true == True" is True.

# While "S.true is True" is False, "S.true == True" is True, so if there is
# any doubt over whether a function or expression will return S.true or True,
# just use "==" instead of "is" to do the comparison, and it will work in
# either case.  Finally, for boolean flags, it's better to just use "if x"
# instead of "if x is True". To quote PEP 8:

#     Don't compare boolean values to True or False using ==.

#       Yes:   if greeting:
#       No:    if greeting == True:
#       Worse: if greeting is True:

class BooleanTrue(with_metaclass(Singleton, Boolean)):
    """
    SymPy version of True.

    This is the SymPy version of True, for use in the logic module. The
    primary advantage of using true instead of True is that shorthand boolean
    operations like ~ and >> will work as expected on this class, whereas with
    True they act bitwise on 1. Functions in the logic module will return this
    class when they evaluate to true.

    The instances of this class are singletonized and can be accessed via
    S.true.

    Examples
    ========

    >>> from sympy import sympify, true, Or
    >>> sympify(True)
    true
    >>> ~true
    false
    >>> ~True
    -2
    >>> Or(True, False)
    true

    See Also
    ========
    sympy.logic.boolalg.BooleanFalse

    """
    def __nonzero__(self):
        return True

    __bool__ = __nonzero__

    def __repr__(self):
        return "true"

    __str__ = __repr__

    def __hash__(self):
        return hash(True)

class BooleanFalse(with_metaclass(Singleton, Boolean)):
    """
    SymPy version of False.

    This is the SymPy version of False, for use in the logic module. The
    primary advantage of using false instead of False is that shorthand boolean
    operations like ~ and >> will work as expected on this class, whereas with
    False they act bitwise on 0. Functions in the logic module will return this
    class when they evaluate to false.

    The instances of this class are singletonized and can be accessed via
    S.false.

    Examples
    ========

    >>> from sympy import sympify, false, Or, true
    >>> sympify(False)
    false
    >>> false >> false
    true
    >>> False >> False
    0
    >>> Or(True, False)
    true

    See Also
    ========
    sympy.logic.boolalg.BooleanTrue

    """
    def __nonzero__(self):
        return False

    __bool__ = __nonzero__

    def __repr__(self):
        return "false"

    __str__ = __repr__

    def __hash__(self):
        return hash(False)

true = BooleanTrue()
false = BooleanFalse()
# We want S.true and S.false to work, rather than S.BooleanTrue and
# S.BooleanFalse, but making the class and instance names the same causes some
# major issues (like the inability to import the class directly from this
# file).
S.true = true
S.false = false

converter[bool] = lambda x: S.true if x else S.false

class BooleanFunction(Application, Boolean):
    """Boolean function is a function that lives in a boolean space
    It is used as base class for And, Or, Not, etc.
    """
    is_Boolean = True

    def __call__(self, *args):
        return self.func(*[arg(*args) for arg in self.args])

    def _eval_simplify(self, ratio, measure):
        return simplify_logic(self)


class And(LatticeOp, BooleanFunction):
    """
    Logical AND function.

    It evaluates its arguments in order, giving False immediately
    if any of them are False, and True if they are all True.

    Examples
    ========

    >>> from sympy.core import symbols
    >>> from sympy.abc import x, y
    >>> from sympy.logic.boolalg import And
    >>> x & y
    And(x, y)

    Notes
    =====

    The ``&`` operator is provided as a convenience, but note that its use
    here is different from its normal use in Python, which is bitwise
    and. Hence, ``And(a, b)`` and ``a & b`` will return different things if
    ``a`` and ``b`` are integers.

    >>> And(x, y).subs(x, 1)
    y

    """
    zero = False
    identity = True

    @classmethod
    def _new_args_filter(cls, args):
        newargs = []
        for x in args:
            if isinstance(x, Number) or x in (0, 1):
                newargs.append(True if x else False)
            else:
                newargs.append(x)
        return LatticeOp._new_args_filter(newargs, And)


class Or(LatticeOp, BooleanFunction):
    """
    Logical OR function

    It evaluates its arguments in order, giving True immediately
    if any of them are True, and False if they are all False.

    Examples
    ========

    >>> from sympy.core import symbols
    >>> from sympy.abc import x, y
    >>> from sympy.logic.boolalg import Or
    >>> x | y
    Or(x, y)

    Notes
    =====

    The ``|`` operator is provided as a convenience, but note that its use
    here is different from its normal use in Python, which is bitwise
    or. Hence, ``Or(a, b)`` and ``a | b`` will return different things if
    ``a`` and ``b`` are integers.

    >>> Or(x, y).subs(x, 0)
    y

    """
    zero = True
    identity = False

    @classmethod
    def _new_args_filter(cls, args):
        newargs = []
        for x in args:
            if isinstance(x, Number) or x in (0, 1):
                newargs.append(True if x else False)
            else:
                newargs.append(x)
        return LatticeOp._new_args_filter(newargs, Or)


class Not(BooleanFunction):
    """
    Logical Not function (negation)


    Returns True if the statement is False
    Returns False if the statement is True

    Examples
    ========

    >>> from sympy.logic.boolalg import Not, And, Or
    >>> from sympy.abc import x
    >>> Not(True)
    false
    >>> Not(False)
    true
    >>> Not(And(True, False))
    true
    >>> Not(Or(True, False))
    false
    >>> Not(And(And(True, x), Or(x, False)))
    Not(x)
    >>> ~x
    Not(x)

    Notes
    =====

    - De Morgan rules are applied automatically.

    - The ``~`` operator is provided as a convenience, but note that its use
      here is different from its normal use in Python, which is bitwise
      not. In particular, ``~a`` and ``Not(a)`` will be different if ``a`` is
      an integer. Furthermore, since bools in Python subclass from ``int``,
      ``~True`` is the same as ``~1`` which is ``-2``, which has a boolean
      value of True.  To avoid this issue, use the SymPy boolean types
      ``true`` and ``false``.

    >>> from sympy import true
    >>> ~True
    -2
    >>> ~true
    false

    """

    is_Not = True

    @classmethod
    def eval(cls, arg):
        if isinstance(arg, Number) or arg in (0, 1, true, false):
            return false if arg else true
        # apply De Morgan Rules
        if arg.func is And:
            return Or(*[Not(a) for a in arg.args])
        if arg.func is Or:
            return And(*[Not(a) for a in arg.args])
        if arg.func is Not:
            return arg.args[0]


class Xor(BooleanFunction):
    """
    Logical XOR (exclusive OR) function.


    Returns True if an odd number of the arguments are True and the rest are
    False.

    Returns False if an even number of the arguments are True and the rest are
    False.

    Examples
    ========

    >>> from sympy.logic.boolalg import Xor
    >>> from sympy import symbols
    >>> x, y = symbols('x y')
    >>> Xor(True, False)
    true
    >>> Xor(True, True)
    false

    >>> Xor(True, False, True, True, False)
    true
    >>> Xor(True, False, True, False)
    false

    >>> x ^ y
    Or(And(Not(x), y), And(Not(y), x))

    Notes
    =====

    The ``^`` operator is provided as a convenience, but note that its use
    here is different from its normal use in Python, which is bitwise xor. In
    particular, ``a ^ b`` and ``Xor(a, b)`` will be different if ``a`` and
    ``b`` are integers.

    >>> Xor(x, y).subs(y, 0)
    x

    """
    @classmethod
    def eval(cls, *args):
        if not args:
            return false
        args = list(args)
        A = args.pop()
        while args:
            B = args.pop()
            A = Or(And(A, Not(B)), And(Not(A), B))
        return A


class Nand(BooleanFunction):
    """
    Logical NAND function.

    It evaluates its arguments in order, giving True immediately if any
    of them are False, and False if they are all True.

    Returns True if any of the arguments are False
    Returns False if all arguments are True

    Examples
    ========

    >>> from sympy.logic.boolalg import Nand
    >>> from sympy import symbols
    >>> x, y = symbols('x y')
    >>> Nand(False, True)
    true
    >>> Nand(True, True)
    false
    >>> Nand(x, y)
    Or(Not(x), Not(y))

    """
    @classmethod
    def eval(cls, *args):
        return Not(And(*args))


class Nor(BooleanFunction):
    """
    Logical NOR function.

    It evaluates its arguments in order, giving False immediately if any
    of them are True, and True if they are all False.

    Returns False if any argument is True
    Returns True if all arguments are False

    Examples
    ========

    >>> from sympy.logic.boolalg import Nor
    >>> from sympy import symbols
    >>> x, y = symbols('x y')

    >>> Nor(True, False)
    false
    >>> Nor(True, True)
    false
    >>> Nor(False, True)
    false
    >>> Nor(False, False)
    true
    >>> Nor(x, y)
    And(Not(x), Not(y))

    """
    @classmethod
    def eval(cls, *args):
        return Not(Or(*args))


class Implies(BooleanFunction):
    """
    Logical implication.

    A implies B is equivalent to !A v B

    Accepts two Boolean arguments; A and B.
    Returns False if A is True and B is False
    Returns True otherwise.

    Examples
    ========

    >>> from sympy.logic.boolalg import Implies
    >>> from sympy import symbols
    >>> x, y = symbols('x y')

    >>> Implies(True, False)
    false
    >>> Implies(False, False)
    true
    >>> Implies(True, True)
    true
    >>> Implies(False, True)
    true
    >>> x >> y
    Implies(x, y)
    >>> y << x
    Implies(x, y)

    Notes
    =====

    The ``>>`` and ``<<`` operators are provided as a convenience, but note
    that their use here is different from their normal use in Python, which is
    bit shifts. Hence, ``Implies(a, b)`` and ``a >> b`` will return different
    things if ``a`` and ``b`` are integers.  In particular, since Python
    considers ``True`` and ``False`` to be integers, ``True >> True`` will be
    the same as ``1 >> 1``, i.e., 0, which has a truth value of False.  To
    avoid this issue, use the SymPy objects ``true`` and ``false``.

    >>> from sympy import true, false
    >>> True >> False
    1
    >>> true >> false
    false

    """
    @classmethod
    def eval(cls, *args):
        try:
            newargs = []
            for x in args:
                if isinstance(x, Number) or x in (0, 1):
                    newargs.append(True if x else False)
                else:
                    newargs.append(x)
            A, B = newargs
        except ValueError:
            raise ValueError(
                "%d operand(s) used for an Implies "
                "(pairs are required): %s" % (len(args), str(args)))
        if A == True or A == False or B == True or B == False:
            return Or(Not(A), B)
        else:
            return Basic.__new__(cls, *args)


class Equivalent(BooleanFunction):
    """
    Equivalence relation.

    Equivalent(A, B) is True iff A and B are both True or both False

    Returns True if all of the arguments are logically equivalent.
    Returns False otherwise.

    Examples
    ========

    >>> from sympy.logic.boolalg import Equivalent, And
    >>> from sympy.abc import x, y
    >>> Equivalent(False, False, False)
    true
    >>> Equivalent(True, False, False)
    false
    >>> Equivalent(x, And(x, True))
    true
    """
    @classmethod
    def eval(cls, *args):
        newargs = []
        for x in args:
            if isinstance(x, Number) or x in (0, 1, true, false):
                newargs.append(True if x else False)
            else:
                newargs.append(x)
        argset = set(newargs)
        if len(argset) <= 1:
            return true
        if True in argset or true in argset:
            argset.discard(True)
            argset.discard(true)
            return And(*argset)
        if False in argset or false in argset:
            argset.discard(False)
            argset.discard(false)
            return Nor(*argset)
        return Basic.__new__(cls, *set(args))


class ITE(BooleanFunction):
    """
    If then else clause.
<commit_msg>Remove unnecessary logic<commit_after>"""Boolean algebra module for SymPy"""
from __future__ import print_function, division

from collections import defaultdict
from itertools import product

from sympy.core.basic import Basic
from sympy.core.numbers import Number
from sympy.core.decorators import deprecated
from sympy.core.operations import LatticeOp
from sympy.core.function import Application, sympify
from sympy.core.compatibility import ordered, xrange, with_metaclass
from sympy.core.sympify import converter
from sympy.core.singleton import Singleton, S


class Boolean(Basic):
    """A boolean object is an object for which logic operations make sense."""

    __slots__ = []

    def __and__(self, other):
        """Overloading for & operator"""
        return And(self, other)

    __rand__ = __and__

    def __or__(self, other):
        """Overloading for |"""
        return Or(self, other)

    __ror__ = __or__

    def __invert__(self):
        """Overloading for ~"""
        return Not(self)

    def __rshift__(self, other):
        """Overloading for >>"""
        return Implies(self, other)

    def __lshift__(self, other):
        """Overloading for <<"""
        return Implies(other, self)

    __rrshift__ = __lshift__
    __rlshift__ = __rshift__

    def __xor__(self, other):
        return Xor(self, other)

    __rxor__ = __xor__

# Developer note: There is liable to be some confusion as to when True should
# be used and when S.true should be used in various contexts throughout SymPy.
# An important thing to remember is that sympify(True) returns S.true.  This
# means that for the most part, you can just use True and it will
# automatically be converted to S.true when necessary, similar to how you can
# generally use 1 instead of S.One.

# The rule of thumb is:

#   "If the boolean in question can be replaced by an arbitrary symbolic
#   Boolean, like Or(x, y) or x > 1, use S.true. Otherwise, use True"

# In other words, use S.true only on those contexts where the boolean is being
# used as a symbolic representation of truth.  For example, if the object ends
# up in the .args of any expression, then it must necessarily be S.true
# instead of True, as elements of .args must be Basic.  On the other hand, ==
# is not a symbolic operation in SymPy, since it always returns True or False,
# and does so in terms of structural equality rather than mathematical, so it
# should return True. The assumptions system should use True and False. Aside
# from not satisfying the above rule of thumb, the assumptions system uses a
# three-valued logic (True, False, None), whereas S.true and S.false represent
# a two-valued logic.  When it doubt, use True.

# 2. "S.true == True" is True.

# While "S.true is True" is False, "S.true == True" is True, so if there is
# any doubt over whether a function or expression will return S.true or True,
# just use "==" instead of "is" to do the comparison, and it will work in
# either case.  Finally, for boolean flags, it's better to just use "if x"
# instead of "if x is True". To quote PEP 8:

#     Don't compare boolean values to True or False using ==.

#       Yes:   if greeting:
#       No:    if greeting == True:
#       Worse: if greeting is True:

class BooleanTrue(with_metaclass(Singleton, Boolean)):
    """
    SymPy version of True.

    This is the SymPy version of True, for use in the logic module. The
    primary advantage of using true instead of True is that shorthand boolean
    operations like ~ and >> will work as expected on this class, whereas with
    True they act bitwise on 1. Functions in the logic module will return this
    class when they evaluate to true.

    The instances of this class are singletonized and can be accessed via
    S.true.

    Examples
    ========

    >>> from sympy import sympify, true, Or
    >>> sympify(True)
    true
    >>> ~true
    false
    >>> ~True
    -2
    >>> Or(True, False)
    true

    See Also
    ========
    sympy.logic.boolalg.BooleanFalse

    """
    def __nonzero__(self):
        return True

    __bool__ = __nonzero__

    def __repr__(self):
        return "true"

    __str__ = __repr__

    def __hash__(self):
        return hash(True)

class BooleanFalse(with_metaclass(Singleton, Boolean)):
    """
    SymPy version of False.

    This is the SymPy version of False, for use in the logic module. The
    primary advantage of using false instead of False is that shorthand boolean
    operations like ~ and >> will work as expected on this class, whereas with
    False they act bitwise on 0. Functions in the logic module will return this
    class when they evaluate to false.

    The instances of this class are singletonized and can be accessed via
    S.false.

    Examples
    ========

    >>> from sympy import sympify, false, Or, true
    >>> sympify(False)
    false
    >>> false >> false
    true
    >>> False >> False
    0
    >>> Or(True, False)
    true

    See Also
    ========
    sympy.logic.boolalg.BooleanTrue

    """
    def __nonzero__(self):
        return False

    __bool__ = __nonzero__

    def __repr__(self):
        return "false"

    __str__ = __repr__

    def __hash__(self):
        return hash(False)

true = BooleanTrue()
false = BooleanFalse()
# We want S.true and S.false to work, rather than S.BooleanTrue and
# S.BooleanFalse, but making the class and instance names the same causes some
# major issues (like the inability to import the class directly from this
# file).
S.true = true
S.false = false

converter[bool] = lambda x: S.true if x else S.false

class BooleanFunction(Application, Boolean):
    """Boolean function is a function that lives in a boolean space
    It is used as base class for And, Or, Not, etc.
    """
    is_Boolean = True

    def __call__(self, *args):
        return self.func(*[arg(*args) for arg in self.args])

    def _eval_simplify(self, ratio, measure):
        return simplify_logic(self)


class And(LatticeOp, BooleanFunction):
    """
    Logical AND function.

    It evaluates its arguments in order, giving False immediately
    if any of them are False, and True if they are all True.

    Examples
    ========

    >>> from sympy.core import symbols
    >>> from sympy.abc import x, y
    >>> from sympy.logic.boolalg import And
    >>> x & y
    And(x, y)

    Notes
    =====

    The ``&`` operator is provided as a convenience, but note that its use
    here is different from its normal use in Python, which is bitwise
    and. Hence, ``And(a, b)`` and ``a & b`` will return different things if
    ``a`` and ``b`` are integers.

    >>> And(x, y).subs(x, 1)
    y

    """
    zero = False
    identity = True

    @classmethod
    def _new_args_filter(cls, args):
        newargs = []
        for x in args:
            if isinstance(x, Number) or x in (0, 1):
                newargs.append(True if x else False)
            else:
                newargs.append(x)
        return LatticeOp._new_args_filter(newargs, And)


class Or(LatticeOp, BooleanFunction):
    """
    Logical OR function

    It evaluates its arguments in order, giving True immediately
    if any of them are True, and False if they are all False.

    Examples
    ========

    >>> from sympy.core import symbols
    >>> from sympy.abc import x, y
    >>> from sympy.logic.boolalg import Or
    >>> x | y
    Or(x, y)

    Notes
    =====

    The ``|`` operator is provided as a convenience, but note that its use
    here is different from its normal use in Python, which is bitwise
    or. Hence, ``Or(a, b)`` and ``a | b`` will return different things if
    ``a`` and ``b`` are integers.

    >>> Or(x, y).subs(x, 0)
    y

    """
    zero = True
    identity = False

    @classmethod
    def _new_args_filter(cls, args):
        newargs = []
        for x in args:
            if isinstance(x, Number) or x in (0, 1):
                newargs.append(True if x else False)
            else:
                newargs.append(x)
        return LatticeOp._new_args_filter(newargs, Or)


class Not(BooleanFunction):
    """
    Logical Not function (negation)


    Returns True if the statement is False
    Returns False if the statement is True

    Examples
    ========

    >>> from sympy.logic.boolalg import Not, And, Or
    >>> from sympy.abc import x
    >>> Not(True)
    false
    >>> Not(False)
    true
    >>> Not(And(True, False))
    true
    >>> Not(Or(True, False))
    false
    >>> Not(And(And(True, x), Or(x, False)))
    Not(x)
    >>> ~x
    Not(x)

    Notes
    =====

    - De Morgan rules are applied automatically.

    - The ``~`` operator is provided as a convenience, but note that its use
      here is different from its normal use in Python, which is bitwise
      not. In particular, ``~a`` and ``Not(a)`` will be different if ``a`` is
      an integer. Furthermore, since bools in Python subclass from ``int``,
      ``~True`` is the same as ``~1`` which is ``-2``, which has a boolean
      value of True.  To avoid this issue, use the SymPy boolean types
      ``true`` and ``false``.

    >>> from sympy import true
    >>> ~True
    -2
    >>> ~true
    false

    """

    is_Not = True

    @classmethod
    def eval(cls, arg):
        if isinstance(arg, Number) or arg in (0, 1, true, false):
            return false if arg else true
        # apply De Morgan Rules
        if arg.func is And:
            return Or(*[Not(a) for a in arg.args])
        if arg.func is Or:
            return And(*[Not(a) for a in arg.args])
        if arg.func is Not:
            return arg.args[0]


class Xor(BooleanFunction):
    """
    Logical XOR (exclusive OR) function.


    Returns True if an odd number of the arguments are True and the rest are
    False.

    Returns False if an even number of the arguments are True and the rest are
    False.

    Examples
    ========

    >>> from sympy.logic.boolalg import Xor
    >>> from sympy import symbols
    >>> x, y = symbols('x y')
    >>> Xor(True, False)
    true
    >>> Xor(True, True)
    false

    >>> Xor(True, False, True, True, False)
    true
    >>> Xor(True, False, True, False)
    false

    >>> x ^ y
    Or(And(Not(x), y), And(Not(y), x))

    Notes
    =====

    The ``^`` operator is provided as a convenience, but note that its use
    here is different from its normal use in Python, which is bitwise xor. In
    particular, ``a ^ b`` and ``Xor(a, b)`` will be different if ``a`` and
    ``b`` are integers.

    >>> Xor(x, y).subs(y, 0)
    x

    """
    @classmethod
    def eval(cls, *args):
        if not args:
            return false
        args = list(args)
        A = args.pop()
        while args:
            B = args.pop()
            A = Or(And(A, Not(B)), And(Not(A), B))
        return A


class Nand(BooleanFunction):
    """
    Logical NAND function.

    It evaluates its arguments in order, giving True immediately if any
    of them are False, and False if they are all True.

    Returns True if any of the arguments are False
    Returns False if all arguments are True

    Examples
    ========

    >>> from sympy.logic.boolalg import Nand
    >>> from sympy import symbols
    >>> x, y = symbols('x y')
    >>> Nand(False, True)
    true
    >>> Nand(True, True)
    false
    >>> Nand(x, y)
    Or(Not(x), Not(y))

    """
    @classmethod
    def eval(cls, *args):
        return Not(And(*args))


class Nor(BooleanFunction):
    """
    Logical NOR function.

    It evaluates its arguments in order, giving False immediately if any
    of them are True, and True if they are all False.

    Returns False if any argument is True
    Returns True if all arguments are False

    Examples
    ========

    >>> from sympy.logic.boolalg import Nor
    >>> from sympy import symbols
    >>> x, y = symbols('x y')

    >>> Nor(True, False)
    false
    >>> Nor(True, True)
    false
    >>> Nor(False, True)
    false
    >>> Nor(False, False)
    true
    >>> Nor(x, y)
    And(Not(x), Not(y))

    """
    @classmethod
    def eval(cls, *args):
        return Not(Or(*args))


class Implies(BooleanFunction):
    """
    Logical implication.

    A implies B is equivalent to !A v B

    Accepts two Boolean arguments; A and B.
    Returns False if A is True and B is False
    Returns True otherwise.

    Examples
    ========

    >>> from sympy.logic.boolalg import Implies
    >>> from sympy import symbols
    >>> x, y = symbols('x y')

    >>> Implies(True, False)
    false
    >>> Implies(False, False)
    true
    >>> Implies(True, True)
    true
    >>> Implies(False, True)
    true
    >>> x >> y
    Implies(x, y)
    >>> y << x
    Implies(x, y)

    Notes
    =====

    The ``>>`` and ``<<`` operators are provided as a convenience, but note
    that their use here is different from their normal use in Python, which is
    bit shifts. Hence, ``Implies(a, b)`` and ``a >> b`` will return different
    things if ``a`` and ``b`` are integers.  In particular, since Python
    considers ``True`` and ``False`` to be integers, ``True >> True`` will be
    the same as ``1 >> 1``, i.e., 0, which has a truth value of False.  To
    avoid this issue, use the SymPy objects ``true`` and ``false``.

    >>> from sympy import true, false
    >>> True >> False
    1
    >>> true >> false
    false

    """
    @classmethod
    def eval(cls, *args):
        try:
            newargs = []
            for x in args:
                if isinstance(x, Number) or x in (0, 1):
                    newargs.append(True if x else False)
                else:
                    newargs.append(x)
            A, B = newargs
        except ValueError:
            raise ValueError(
                "%d operand(s) used for an Implies "
                "(pairs are required): %s" % (len(args), str(args)))
        if A == True or A == False or B == True or B == False:
            return Or(Not(A), B)
        else:
            return Basic.__new__(cls, *args)


class Equivalent(BooleanFunction):
    """
    Equivalence relation.

    Equivalent(A, B) is True iff A and B are both True or both False

    Returns True if all of the arguments are logically equivalent.
    Returns False otherwise.

    Examples
    ========

    >>> from sympy.logic.boolalg import Equivalent, And
    >>> from sympy.abc import x, y
    >>> Equivalent(False, False, False)
    true
    >>> Equivalent(True, False, False)
    false
    >>> Equivalent(x, And(x, True))
    true
    """
    @classmethod
    def eval(cls, *args):
        newargs = []
        for x in args:
            if isinstance(x, Number) or x in (0, 1, true, false):
                newargs.append(True if x else False)
            else:
                newargs.append(x)
        argset = set(newargs)
        if len(argset) <= 1:
            return true
        if True in argset:
            argset.discard(True)
            return And(*argset)
        if False in argset:
            argset.discard(False)
            return Nor(*argset)
        return Basic.__new__(cls, *set(args))


class ITE(BooleanFunction):
    """
    If then else clause.

{'fraction_non_alphanumeric': 0.10598516075845012, 'fraction_numerical': 0.001978565539983512, 'mean_word_length': 2.378188704466971, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 479, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4001558', 'n_tokens_mistral': 9175, 'n_tokens_neox': 8756, 'n_words': 3654}