from sympy.core.sympify import _sympify, sympify
from sympy.core.basic import Basic
from sympy.core.singleton import Singleton, S
from sympy.core.evalf import EvalfMixin
from sympy.core.numbers import Float
from sympy.core.compatibility import iterable
from sympy.core.decorators import deprecated

from sympy.mpmath import mpi, mpf
from sympy.assumptions import ask
from sympy.logic.boolalg import And, Or

from sympy.utilities import default_sort_key


class Set(Basic):
    """
    The base class for any kind of set.

    This is not meant to be used directly as a container of items.
    It does not behave like the builtin set; see FiniteSet for that.

    Real intervals are represented by the Interval class and unions of sets
    by the Union class. The empty set is represented by the EmptySet class
    and available as a singleton as S.EmptySet.
    """
    is_number = False
    is_iterable = False
    is_interval = False

    is_FiniteSet = False
    is_Interval = False
    is_ProductSet = False
    is_Union = False
    is_Intersection = None
    is_EmptySet = None
    is_UniversalSet = None

    def sort_key(self, order=None):
        """
        Give sort_key of infimum (if possible) else sort_key of the set.
        """
        try:
            infimum = self.inf
            if infimum.is_comparable:
                return default_sort_key(infimum, order)
        except (NotImplementedError, ValueError):
            pass
        args = tuple([default_sort_key(a, order) for a in self._sorted_args])
        return self.class_key(), (len(args), args), S.One.class_key(), S.One

    def union(self, other):
        """
        Returns the union of 'self' and 'other'.

        As a shortcut it is possible to use the '+' operator:

        >>> from sympy import Interval, FiniteSet
        >>> Interval(0, 1).union(Interval(2, 3))
        [0, 1] U [2, 3]
        >>> Interval(0, 1) + Interval(2, 3)
        [0, 1] U [2, 3]
        >>> Interval(1, 2, True, True) + FiniteSet(2, 3)