Beispiel #1
0
 def __new__(cls, sym, condition, base_set=S.UniversalSet):
     # nonlinsolve uses ConditionSet to return an unsolved system
     # of equations (see _return_conditionset in solveset) so until
     # that is changed we do minimal checking of the args
     if isinstance(sym, (Tuple, tuple)):  # unsolved eqns syntax
         sym = Tuple(*sym)
         condition = FiniteSet(*condition)
         return Basic.__new__(cls, sym, condition, base_set)
     condition = as_Boolean(condition)
     if isinstance(base_set, set):
         base_set = FiniteSet(*base_set)
     elif not isinstance(base_set, Set):
         raise TypeError('expecting set for base_set')
     if condition is S.false:
         return S.EmptySet
     if condition is S.true:
         return base_set
     if isinstance(base_set, EmptySet):
         return base_set
     know = None
     if isinstance(base_set, FiniteSet):
         sifted = sift(
             base_set, lambda _: fuzzy_bool(
                 condition.subs(sym, _)))
         if sifted[None]:
             know = FiniteSet(*sifted[True])
             base_set = FiniteSet(*sifted[None])
         else:
             return FiniteSet(*sifted[True])
     if isinstance(base_set, cls):
         s, c, base_set = base_set.args
         if sym == s:
             condition = And(condition, c)
         elif sym not in c.free_symbols:
             condition = And(condition, c.xreplace({s: sym}))
         elif s not in condition.free_symbols:
             condition = And(condition.xreplace({sym: s}), c)
             sym = s
         else:
             # user will have to use cls.sym to get symbol
             dum = Symbol('lambda')
             if dum in condition.free_symbols or \
                     dum in c.free_symbols:
                 dum = Dummy(str(dum))
             condition = And(
                 condition.xreplace({sym: dum}),
                 c.xreplace({s: dum}))
             sym = dum
     if not isinstance(sym, Symbol):
         s = Dummy('lambda')
         if s not in condition.xreplace({sym: s}).free_symbols:
             raise ValueError(
                 'non-symbol dummy not recognized in condition')
     rv = Basic.__new__(cls, sym, condition, base_set)
     return rv if know is None else Union(know, rv)
Beispiel #2
0
    def __new__(cls, sets, polar=False):
        from sympy import sin, cos

        x, y, r, theta = symbols('x, y, r, theta', cls=Dummy)
        I = S.ImaginaryUnit
        polar = sympify(polar)

        # Rectangular Form
        if polar == False:
            if all(_a.is_FiniteSet for _a in sets.args) and (len(sets.args) == 2):

                # ** ProductSet of FiniteSets in the Complex Plane. **
                # For Cases like ComplexRegion({2, 4}*{3}), It
                # would return {2 + 3*I, 4 + 3*I}
                complex_num = []
                for x in sets.args[0]:
                    for y in sets.args[1]:
                        complex_num.append(x + I*y)
                obj = FiniteSet(*complex_num)
            else:
                obj = ImageSet.__new__(cls, Lambda((x, y), x + I*y), sets)
            obj._variables = (x, y)
            obj._expr = x + I*y

        # Polar Form
        elif polar == True:
            new_sets = []
            # sets is Union of ProductSets
            if not sets.is_ProductSet:
                for k in sets.args:
                    new_sets.append(k)
            # sets is ProductSets
            else:
                new_sets.append(sets)
            # Normalize input theta
            for k, v in enumerate(new_sets):
                from sympy.sets import ProductSet
                new_sets[k] = ProductSet(v.args[0],
                                         normalize_theta_set(v.args[1]))
            sets = Union(*new_sets)
            obj = ImageSet.__new__(cls, Lambda((r, theta),
                                   r*(cos(theta) + I*sin(theta))),
                                   sets)
            obj._variables = (r, theta)
            obj._expr = r*(cos(theta) + I*sin(theta))

        else:
            raise ValueError("polar should be either True or False")

        obj._sets = sets
        obj._polar = polar
        return obj
Beispiel #3
0
    def __new__(cls, *partition):
        """
        Generates a new partition object.

        This method also verifies if the arguments passed are
        valid and raises a ValueError if they are not.

        Examples
        ========

        >>> from sympy.combinatorics.partitions import Partition
        >>> a = Partition([1, 2], [3])
        >>> a
        {{3}, {1, 2}}
        >>> a.partition
        [[1, 2], [3]]
        >>> len(a)
        2
        >>> a.members
        (1, 2, 3)

        """
        args = partition
        if not all(isinstance(part, (list, FiniteSet)) for part in args):
            raise ValueError(
                "Each argument to Partition should be a list or a FiniteSet")

        # sort so we have a canonical reference for RGS
        partition = sorted(sum(partition, []), key=default_sort_key)
        if has_dups(partition):
            raise ValueError("Partition contained duplicated elements.")

        obj = FiniteSet.__new__(cls, *[FiniteSet(*x) for x in args])
        obj.members = tuple(partition)
        obj.size = len(partition)
        return obj
Beispiel #4
0
def test_ImageSet():
    raises(ValueError, lambda: ImageSet(x, S.Integers))
    assert ImageSet(Lambda(x, 1), S.Integers) == FiniteSet(1)
    assert ImageSet(Lambda(x, y), S.Integers) == {y}
    assert ImageSet(Lambda(x, 1), S.EmptySet) == S.EmptySet
    empty = Intersection(FiniteSet(log(2) / pi), S.Integers)
    assert unchanged(ImageSet, Lambda(x, 1), empty)  # issue #17471
    squares = ImageSet(Lambda(x, x**2), S.Naturals)
    assert 4 in squares
    assert 5 not in squares
    assert FiniteSet(*range(10)).intersect(squares) == FiniteSet(1, 4, 9)

    assert 16 not in squares.intersect(Interval(0, 10))

    si = iter(squares)
    a, b, c, d = next(si), next(si), next(si), next(si)
    assert (a, b, c, d) == (1, 4, 9, 16)

    harmonics = ImageSet(Lambda(x, 1 / x), S.Naturals)
    assert Rational(1, 5) in harmonics
    assert Rational(.25) in harmonics
    assert 0.25 not in harmonics
    assert Rational(.3) not in harmonics
    assert (1, 2) not in harmonics

    assert harmonics.is_iterable

    assert imageset(x, -x, Interval(0, 1)) == Interval(-1, 0)

    assert ImageSet(Lambda(x, x**2), Interval(0, 2)).doit() == Interval(0, 4)
    assert ImageSet(Lambda((x, y), 2 * x), {4}, {3}).doit() == FiniteSet(8)
    assert (ImageSet(Lambda((x, y), x + y), {1, 2, 3},
                     {10, 20, 30}).doit() == FiniteSet(11, 12, 13, 21, 22, 23,
                                                       31, 32, 33))

    c = Interval(1, 3) * Interval(1, 3)
    assert Tuple(2, 6) in ImageSet(Lambda(((x, y), ), (x, 2 * y)), c)
    assert Tuple(2, S.Half) in ImageSet(Lambda(((x, y), ), (x, 1 / y)), c)
    assert Tuple(2, -2) not in ImageSet(Lambda(((x, y), ), (x, y**2)), c)
    assert Tuple(2, -2) in ImageSet(Lambda(((x, y), ), (x, -2)), c)
    c3 = ProductSet(Interval(3, 7), Interval(8, 11), Interval(5, 9))
    assert Tuple(8, 3, 9) in ImageSet(Lambda(((t, y, x), ), (y, t, x)), c3)
    assert Tuple(Rational(1, 8), 3,
                 9) in ImageSet(Lambda(((t, y, x), ), (1 / y, t, x)), c3)
    assert 2 / pi not in ImageSet(Lambda(((x, y), ), 2 / x), c)
    assert 2 / S(100) not in ImageSet(Lambda(((x, y), ), 2 / x), c)
    assert Rational(2, 3) in ImageSet(Lambda(((x, y), ), 2 / x), c)

    S1 = imageset(lambda x, y: x + y, S.Integers, S.Naturals)
    assert S1.base_pset == ProductSet(S.Integers, S.Naturals)
    assert S1.base_sets == (S.Integers, S.Naturals)

    # Passing a set instead of a FiniteSet shouldn't raise
    assert unchanged(ImageSet, Lambda(x, x**2), {1, 2, 3})

    S2 = ImageSet(Lambda(((x, y), ), x + y), {(1, 2), (3, 4)})
    assert 3 in S2.doit()
    # FIXME: This doesn't yet work:
    #assert 3 in S2
    assert S2._contains(3) is None

    raises(TypeError, lambda: ImageSet(Lambda(x, x**2), 1))
Beispiel #5
0
 def elements(self):
     return FiniteSet(*[frozenset(((self.symbol, elem), )) for elem in self.set])
Beispiel #6
0
 def _density(self):
     return dict((FiniteSet((self.symbol, val)), prob)
                 for val, prob in self.distribution.dict.items())
Beispiel #7
0
 def spaces(self):
     return FiniteSet(*self.args)
Beispiel #8
0
 def __new__(cls, symbols, *args):
     symbols = FiniteSet(*symbols)
     return Basic.__new__(cls, symbols, *args)
Beispiel #9
0
def test_Lambda():
    e = Lambda(x, x**2)
    assert e(4) == 16
    assert e(x) == x**2
    assert e(y) == y**2

    assert Lambda((), 42)() == 42
    assert unchanged(Lambda, (), 42)
    assert Lambda((), 42) != Lambda((), 43)
    assert Lambda((), f(x))() == f(x)
    assert Lambda((), 42).nargs == FiniteSet(0)

    assert unchanged(Lambda, (x,), x**2)
    assert Lambda(x, x**2) == Lambda((x,), x**2)
    assert Lambda(x, x**2) != Lambda(x, x**2 + 1)
    assert Lambda((x, y), x**y) != Lambda((y, x), y**x)
    assert Lambda((x, y), x**y) != Lambda((x, y), y**x)

    assert Lambda((x, y), x**y)(x, y) == x**y
    assert Lambda((x, y), x**y)(3, 3) == 3**3
    assert Lambda((x, y), x**y)(x, 3) == x**3
    assert Lambda((x, y), x**y)(3, y) == 3**y
    assert Lambda(x, f(x))(x) == f(x)
    assert Lambda(x, x**2)(e(x)) == x**4
    assert e(e(x)) == x**4

    x1, x2 = (Indexed('x', i) for i in (1, 2))
    assert Lambda((x1, x2), x1 + x2)(x, y) == x + y

    assert Lambda((x, y), x + y).nargs == FiniteSet(2)

    p = x, y, z, t
    assert Lambda(p, t*(x + y + z))(*p) == t * (x + y + z)

    eq = Lambda(x, 2*x) + Lambda(y, 2*y)
    assert eq != 2*Lambda(x, 2*x)
    assert eq.as_dummy() == 2*Lambda(x, 2*x).as_dummy()
    assert Lambda(x, 2*x) not in [ Lambda(x, x) ]
    raises(BadSignatureError, lambda: Lambda(1, x))
    assert Lambda(x, 1)(1) is S.One

    raises(BadSignatureError, lambda: Lambda((x, x), x + 2))
    raises(BadSignatureError, lambda: Lambda(((x, x), y), x))
    raises(BadSignatureError, lambda: Lambda(((y, x), x), x))
    raises(BadSignatureError, lambda: Lambda(((y, 1), 2), x))

    with warns_deprecated_sympy():
        assert Lambda([x, y], x+y) == Lambda((x, y), x+y)

    flam = Lambda(((x, y),), x + y)
    assert flam((2, 3)) == 5
    flam = Lambda(((x, y), z), x + y + z)
    assert flam((2, 3), 1) == 6
    flam = Lambda((((x, y), z),), x + y + z)
    assert flam(((2, 3), 1)) == 6
    raises(BadArgumentsError, lambda: flam(1, 2, 3))
    flam = Lambda( (x,), (x, x))
    assert flam(1,) == (1, 1)
    assert flam((1,)) == ((1,), (1,))
    flam = Lambda( ((x,),), (x, x))
    raises(BadArgumentsError, lambda: flam(1))
    assert flam((1,)) == (1, 1)

    # Previously TypeError was raised so this is potentially needed for
    # backwards compatibility.
    assert issubclass(BadSignatureError, TypeError)
    assert issubclass(BadArgumentsError, TypeError)

    # These are tested to see they don't raise:
    hash(Lambda(x, 2*x))
    hash(Lambda(x, x))  # IdentityFunction subclass
Beispiel #10
0
def normalize_theta_set(theta):
    """
    Normalize a Real Set `theta` in the Interval [0, 2*pi). It returns
    a normalized value of theta in the Set. For Interval, a maximum of
    one cycle [0, 2*pi], is returned i.e. for theta equal to [0, 10*pi],
    returned normalized value would be [0, 2*pi). As of now intervals
    with end points as non-multiples of `pi` is not supported.

    Raises
    ======

    NotImplementedError
        The algorithms for Normalizing theta Set are not yet
        implemented.
    ValueError
        The input is not valid, i.e. the input is not a real set.
    RuntimeError
        It is a bug, please report to the github issue tracker.

    Examples
    ========

    >>> from sympy.sets.fancysets import normalize_theta_set
    >>> from sympy import Interval, FiniteSet, pi
    >>> normalize_theta_set(Interval(9*pi/2, 5*pi))
    Interval(pi/2, pi)
    >>> normalize_theta_set(Interval(-3*pi/2, pi/2))
    Interval.Ropen(0, 2*pi)
    >>> normalize_theta_set(Interval(-pi/2, pi/2))
    Union(Interval(0, pi/2), Interval.Ropen(3*pi/2, 2*pi))
    >>> normalize_theta_set(Interval(-4*pi, 3*pi))
    Interval.Ropen(0, 2*pi)
    >>> normalize_theta_set(Interval(-3*pi/2, -pi/2))
    Interval(pi/2, 3*pi/2)
    >>> normalize_theta_set(FiniteSet(0, pi, 3*pi))
    {0, pi}

    """
    from sympy.functions.elementary.trigonometric import _pi_coeff as coeff

    if theta.is_Interval:
        interval_len = theta.measure
        # one complete circle
        if interval_len >= 2 * S.Pi:
            if interval_len == 2 * S.Pi and theta.left_open and theta.right_open:
                k = coeff(theta.start)
                return Union(Interval(0, k * S.Pi, False, True),
                             Interval(k * S.Pi, 2 * S.Pi, True, True))
            return Interval(0, 2 * S.Pi, False, True)

        k_start, k_end = coeff(theta.start), coeff(theta.end)

        if k_start is None or k_end is None:
            raise NotImplementedError(
                "Normalizing theta without pi as coefficient is "
                "not yet implemented")
        new_start = k_start * S.Pi
        new_end = k_end * S.Pi

        if new_start > new_end:
            return Union(Interval(S.Zero, new_end, False, theta.right_open),
                         Interval(new_start, 2 * S.Pi, theta.left_open, True))
        else:
            return Interval(new_start, new_end, theta.left_open,
                            theta.right_open)

    elif theta.is_FiniteSet:
        new_theta = []
        for element in theta:
            k = coeff(element)
            if k is None:
                raise NotImplementedError('Normalizing theta without pi as '
                                          'coefficient, is not Implemented.')
            else:
                new_theta.append(k * S.Pi)
        return FiniteSet(*new_theta)

    elif theta.is_Union:
        return Union(
            *[normalize_theta_set(interval) for interval in theta.args])

    elif theta.is_subset(S.Reals):
        raise NotImplementedError(
            "Normalizing theta when, it is of type %s is not "
            "implemented" % type(theta))
    else:
        raise ValueError(" %s is not a real set" % (theta))
Beispiel #11
0
    def __new__(cls, *partition):
        """
        Generates a new partition object.

        This method also verifies if the arguments passed are
        valid and raises a ValueError if they are not.

        Examples
        ========

        Creating Partition from Python lists:

        >>> from sympy.combinatorics.partitions import Partition
        >>> a = Partition([1, 2], [3])
        >>> a
        Partition(FiniteSet(1, 2), FiniteSet(3))
        >>> a.partition
        [[1, 2], [3]]
        >>> len(a)
        2
        >>> a.members
        (1, 2, 3)

        Creating Partition from Python sets:

        >>> Partition({1, 2, 3}, {4, 5})
        Partition(FiniteSet(1, 2, 3), FiniteSet(4, 5))

        Creating Partition from SymPy finite sets:

        >>> from sympy.sets.sets import FiniteSet
        >>> a = FiniteSet(1, 2, 3)
        >>> b = FiniteSet(4, 5)
        >>> Partition(a, b)
        Partition(FiniteSet(1, 2, 3), FiniteSet(4, 5))
        """
        args = []
        dups = False
        for arg in partition:
            if isinstance(arg, list):
                as_set = set(arg)
                if len(as_set) < len(arg):
                    dups = True
                    break  # error below
                arg = as_set
            args.append(_sympify(arg))

        if not all(isinstance(part, FiniteSet) for part in args):
            raise ValueError(
                "Each argument to Partition should be " \
                "a list, set, or a FiniteSet")

        # sort so we have a canonical reference for RGS
        U = Union(*args)
        if dups or len(U) < sum(len(arg) for arg in args):
            raise ValueError("Partition contained duplicate elements.")

        obj = FiniteSet.__new__(cls, *args)
        obj.members = tuple(U)
        obj.size = len(U)
        return obj
def test_normalize_theta_set():

    # Interval
    assert normalize_theta_set(Interval(pi, 2*pi)) == \
        Union(FiniteSet(0), Interval.Ropen(pi, 2*pi))
    assert normalize_theta_set(Interval(9 * pi / 2,
                                        5 * pi)) == Interval(pi / 2, pi)
    assert normalize_theta_set(Interval(-3 * pi / 2,
                                        pi / 2)) == Interval.Ropen(0, 2 * pi)
    assert normalize_theta_set(Interval.open(-3*pi/2, pi/2)) == \
        Union(Interval.Ropen(0, pi/2), Interval.open(pi/2, 2*pi))
    assert normalize_theta_set(Interval.open(-7*pi/2, -3*pi/2)) == \
        Union(Interval.Ropen(0, pi/2), Interval.open(pi/2, 2*pi))
    assert normalize_theta_set(Interval(-pi/2, pi/2)) == \
        Union(Interval(0, pi/2), Interval.Ropen(3*pi/2, 2*pi))
    assert normalize_theta_set(Interval.open(-pi/2, pi/2)) == \
        Union(Interval.Ropen(0, pi/2), Interval.open(3*pi/2, 2*pi))
    assert normalize_theta_set(Interval(-4 * pi,
                                        3 * pi)) == Interval.Ropen(0, 2 * pi)
    assert normalize_theta_set(Interval(-3 * pi / 2, -pi / 2)) == Interval(
        pi / 2, 3 * pi / 2)
    assert normalize_theta_set(Interval.open(0, 2 * pi)) == Interval.open(
        0, 2 * pi)
    assert normalize_theta_set(Interval.Ropen(-pi/2, pi/2)) == \
        Union(Interval.Ropen(0, pi/2), Interval.Ropen(3*pi/2, 2*pi))
    assert normalize_theta_set(Interval.Lopen(-pi/2, pi/2)) == \
        Union(Interval(0, pi/2), Interval.open(3*pi/2, 2*pi))
    assert normalize_theta_set(Interval(-pi/2, pi/2)) == \
        Union(Interval(0, pi/2), Interval.Ropen(3*pi/2, 2*pi))
    assert normalize_theta_set(Interval.open(4 * pi,
                                             9 * pi / 2)) == Interval.open(
                                                 0, pi / 2)
    assert normalize_theta_set(Interval.Lopen(4 * pi,
                                              9 * pi / 2)) == Interval.Lopen(
                                                  0, pi / 2)
    assert normalize_theta_set(Interval.Ropen(4 * pi,
                                              9 * pi / 2)) == Interval.Ropen(
                                                  0, pi / 2)
    assert normalize_theta_set(Interval.open(3*pi, 5*pi)) == \
        Union(Interval.Ropen(0, pi), Interval.open(pi, 2*pi))

    # FiniteSet
    assert normalize_theta_set(FiniteSet(0, pi, 3 * pi)) == FiniteSet(0, pi)
    assert normalize_theta_set(FiniteSet(0, pi / 2, pi,
                                         2 * pi)) == FiniteSet(0, pi / 2, pi)
    assert normalize_theta_set(FiniteSet(0, -pi / 2, -pi,
                                         -2 * pi)) == FiniteSet(
                                             0, pi, 3 * pi / 2)
    assert normalize_theta_set(FiniteSet(-3*pi/2, pi/2)) == \
        FiniteSet(pi/2)
    assert normalize_theta_set(FiniteSet(2 * pi)) == FiniteSet(0)

    # Unions
    assert normalize_theta_set(Union(Interval(0, pi/3), Interval(pi/2, pi))) == \
        Union(Interval(0, pi/3), Interval(pi/2, pi))
    assert normalize_theta_set(Union(Interval(0, pi), Interval(2*pi, 7*pi/3))) == \
        Interval(0, pi)

    # ValueError for non-real sets
    raises(ValueError, lambda: normalize_theta_set(S.Complexes))
Beispiel #13
0
    def __pow__(self, other):
        from sympy.functions.elementary.miscellaneous import real_root
        if isinstance(other, Expr):
            if other is S.Infinity:
                if self.min.is_nonnegative:
                    if self.max < 1:
                        return S.Zero
                    if self.min > 1:
                        return S.Infinity
                    return AccumBounds(0, oo)
                elif self.max.is_negative:
                    if self.min > -1:
                        return S.Zero
                    if self.max < -1:
                        return FiniteSet(-oo, oo)
                    return AccumBounds(-oo, oo)
                else:
                    if self.min > -1:
                        if self.max < 1:
                            return S.Zero
                        return AccumBounds(0, oo)
                    return AccumBounds(-oo, oo)

            if other is S.NegativeInfinity:
                return (1 / self)**oo

            if other.is_real and other.is_number:
                if other.is_zero:
                    return S.One

                if other.is_Integer:
                    if self.min.is_positive:
                        return AccumBounds(
                            Min(self.min**other, self.max**other),
                            Max(self.min**other, self.max**other))
                    elif self.max.is_negative:
                        return AccumBounds(
                            Min(self.max**other, self.min**other),
                            Max(self.max**other, self.min**other))

                    if other % 2 == 0:
                        if other.is_negative:
                            if self.min.is_zero:
                                return AccumBounds(self.max**other, oo)
                            if self.max.is_zero:
                                return AccumBounds(self.min**other, oo)
                            return AccumBounds(0, oo)
                        return AccumBounds(
                            S.Zero, Max(self.min**other, self.max**other))
                    else:
                        if other.is_negative:
                            if self.min.is_zero:
                                return AccumBounds(self.max**other, oo)
                            if self.max.is_zero:
                                return AccumBounds(-oo, self.min**other)
                            return AccumBounds(-oo, oo)
                        return AccumBounds(self.min**other, self.max**other)

                num, den = other.as_numer_denom()
                if num == S(1):
                    if den % 2 == 0:
                        if S.Zero in self:
                            if self.min.is_negative:
                                return AccumBounds(0, real_root(self.max, den))
                    return AccumBounds(real_root(self.min, den),
                                       real_root(self.max, den))
                num_pow = self**num
                return num_pow**(1 / den)
            return Pow(self, other, evaluate=False)

        return NotImplemented
Beispiel #14
0
def function_range(f, symbol, domain):
    """
    Finds the range of a function in a given domain.
    This method is limited by the ability to determine the singularities and
    determine limits.

    Examples
    ========

    >>> from sympy import Symbol, S, exp, log, pi, sqrt, sin, tan
    >>> from sympy.sets import Interval
    >>> from sympy.calculus.util import function_range
    >>> x = Symbol('x')
    >>> function_range(sin(x), x, Interval(0, 2*pi))
    [-1, 1]
    >>> function_range(tan(x), x, Interval(-pi/2, pi/2))
    (-oo, oo)
    >>> function_range(1/x, x, S.Reals)
    (-oo, oo)
    >>> function_range(exp(x), x, S.Reals)
    (0, oo)
    >>> function_range(log(x), x, S.Reals)
    (-oo, oo)
    >>> function_range(sqrt(x), x , Interval(-5, 9))
    [0, 3]

    """
    from sympy.solvers.solveset import solveset

    vals = S.EmptySet
    intervals = continuous_domain(f, symbol, domain)
    range_int = S.EmptySet
    if isinstance(intervals, Interval):
        interval_iter = (intervals, )

    else:
        interval_iter = intervals.args

    for interval in interval_iter:
        critical_points = S.EmptySet
        critical_values = S.EmptySet
        bounds = ((interval.left_open, interval.inf, '+'),
                  (interval.right_open, interval.sup, '-'))

        for is_open, limit_point, direction in bounds:
            if is_open:
                critical_values += FiniteSet(
                    limit(f, symbol, limit_point, direction))
                vals += critical_values

            else:
                vals += FiniteSet(f.subs(symbol, limit_point))

        critical_points += solveset(f.diff(symbol), symbol, domain)

        for critical_point in critical_points:
            vals += FiniteSet(f.subs(symbol, critical_point))

        left_open, right_open = False, False

        if critical_values is not S.EmptySet:
            if critical_values.inf == vals.inf:
                left_open = True

            if critical_values.sup == vals.sup:
                right_open = True

        range_int += Interval(vals.inf, vals.sup, left_open, right_open)

    return range_int
Beispiel #15
0
 def __new__(cls, symbol, set):
     if not isinstance(set, FiniteSet) and \
         not isinstance(set, Intersection):
         set = FiniteSet(*set)
     return Basic.__new__(cls, symbol, set)
Beispiel #16
0
 def dict(self):
     return FiniteSet(*[Dict(dict(el)) for el in self.elements])
Beispiel #17
0
 def symbols(self):
     return FiniteSet(sym for sym, val in self.elements)
Beispiel #18
0
def test_ComplexRegion_from_real():
    c1 = ComplexRegion(Interval(0, 1) * Interval(0, 2 * S.Pi), polar=True)

    raises(ValueError, lambda: c1.from_real(c1))
    assert c1.from_real(Interval(-1, 1)) == ComplexRegion(
        Interval(-1, 1) * FiniteSet(0), False)
Beispiel #19
0
def test_not_empty_in():
    from sympy.abc import x
    a = Symbol('a', real=True)
    assert not_empty_in(FiniteSet(x, 2*x).intersect(Interval(1, 2, True, False)), x) == \
        Interval(S(1)/2, 2, True, False)
    assert not_empty_in(FiniteSet(x, x**2).intersect(Interval(1, 2)), x) == \
        Union(Interval(-sqrt(2), -1), Interval(1, 2))
    assert not_empty_in(FiniteSet(x**2 + x, x).intersect(Interval(2, 4)), x) == \
        Union(Interval(-sqrt(17)/2 - S(1)/2, -2), Interval(1, -S(1)/2 + sqrt(17)/2), Interval(2, 4))
    assert not_empty_in(FiniteSet(x/(x - 1)).intersect(S.Reals), x) == Complement(S.Reals, FiniteSet(1))
    assert not_empty_in(FiniteSet(a/(a - 1)).intersect(S.Reals), a) == Complement(S.Reals, FiniteSet(1))
    assert not_empty_in(FiniteSet((x**2 - 3*x + 2)/(x - 1)).intersect(S.Reals), x) == \
        Complement(S.Reals, FiniteSet(1))
    assert not_empty_in(FiniteSet(3, 4, x/(x - 1)).intersect(Interval(2, 3)), x) == \
        Union(Interval(S(3)/2, 2), FiniteSet(3))
    assert not_empty_in(FiniteSet(x/(x**2 - 1)).intersect(S.Reals), x) == \
        Complement(S.Reals, FiniteSet(-1, 1))
    assert not_empty_in(FiniteSet(x, x**2).intersect(Union(Interval(1, 3, True, True), Interval(4, 5))), x) == \
        Union(Interval(-sqrt(5), -2), Interval(-sqrt(3), -1, True, True), Interval(1, 3, True, True), Interval(4, 5))
    assert not_empty_in(FiniteSet(1).intersect(Interval(3, 4)), x) == S.EmptySet
    assert not_empty_in(FiniteSet(x**2/(x + 2)).intersect(Interval(1, oo)), x) == \
        Union(Interval(-2, -1, True, False), Interval(2, oo))
Beispiel #20
0
def test_normalize_theta_set():
    # Interval
    assert normalize_theta_set(Interval(pi, 2*pi)) == \
        Union(FiniteSet(0), Interval.Ropen(pi, 2*pi))
    assert normalize_theta_set(Interval(pi * Rational(9, 2),
                                        5 * pi)) == Interval(pi / 2, pi)
    assert normalize_theta_set(Interval(pi * Rational(-3, 2),
                                        pi / 2)) == Interval.Ropen(0, 2 * pi)
    assert normalize_theta_set(Interval.open(pi*Rational(-3, 2), pi/2)) == \
        Union(Interval.Ropen(0, pi/2), Interval.open(pi/2, 2*pi))
    assert normalize_theta_set(Interval.open(pi*Rational(-7, 2), pi*Rational(-3, 2))) == \
        Union(Interval.Ropen(0, pi/2), Interval.open(pi/2, 2*pi))
    assert normalize_theta_set(Interval(-pi/2, pi/2)) == \
        Union(Interval(0, pi/2), Interval.Ropen(pi*Rational(3, 2), 2*pi))
    assert normalize_theta_set(Interval.open(-pi/2, pi/2)) == \
        Union(Interval.Ropen(0, pi/2), Interval.open(pi*Rational(3, 2), 2*pi))
    assert normalize_theta_set(Interval(-4 * pi,
                                        3 * pi)) == Interval.Ropen(0, 2 * pi)
    assert normalize_theta_set(Interval(pi * Rational(-3, 2),
                                        -pi / 2)) == Interval(
                                            pi / 2, pi * Rational(3, 2))
    assert normalize_theta_set(Interval.open(0, 2 * pi)) == Interval.open(
        0, 2 * pi)
    assert normalize_theta_set(Interval.Ropen(-pi/2, pi/2)) == \
        Union(Interval.Ropen(0, pi/2), Interval.Ropen(pi*Rational(3, 2), 2*pi))
    assert normalize_theta_set(Interval.Lopen(-pi/2, pi/2)) == \
        Union(Interval(0, pi/2), Interval.open(pi*Rational(3, 2), 2*pi))
    assert normalize_theta_set(Interval(-pi/2, pi/2)) == \
        Union(Interval(0, pi/2), Interval.Ropen(pi*Rational(3, 2), 2*pi))
    assert normalize_theta_set(Interval.open(
        4 * pi, pi * Rational(9, 2))) == Interval.open(0, pi / 2)
    assert normalize_theta_set(Interval.Lopen(
        4 * pi, pi * Rational(9, 2))) == Interval.Lopen(0, pi / 2)
    assert normalize_theta_set(Interval.Ropen(
        4 * pi, pi * Rational(9, 2))) == Interval.Ropen(0, pi / 2)
    assert normalize_theta_set(Interval.open(3*pi, 5*pi)) == \
        Union(Interval.Ropen(0, pi), Interval.open(pi, 2*pi))

    # FiniteSet
    assert normalize_theta_set(FiniteSet(0, pi, 3 * pi)) == FiniteSet(0, pi)
    assert normalize_theta_set(FiniteSet(0, pi / 2, pi,
                                         2 * pi)) == FiniteSet(0, pi / 2, pi)
    assert normalize_theta_set(FiniteSet(0, -pi / 2, -pi,
                                         -2 * pi)) == FiniteSet(
                                             0, pi, pi * Rational(3, 2))
    assert normalize_theta_set(FiniteSet(pi*Rational(-3, 2), pi/2)) == \
        FiniteSet(pi/2)
    assert normalize_theta_set(FiniteSet(2 * pi)) == FiniteSet(0)

    # Unions
    assert normalize_theta_set(Union(Interval(0, pi/3), Interval(pi/2, pi))) == \
        Union(Interval(0, pi/3), Interval(pi/2, pi))
    assert normalize_theta_set(Union(Interval(0, pi), Interval(2*pi, pi*Rational(7, 3)))) == \
        Interval(0, pi)

    # ValueError for non-real sets
    raises(ValueError, lambda: normalize_theta_set(S.Complexes))

    # NotImplementedError for subset of reals
    raises(NotImplementedError, lambda: normalize_theta_set(Interval(0, 1)))

    # NotImplementedError without pi as coefficient
    raises(NotImplementedError,
           lambda: normalize_theta_set(Interval(1, 2 * pi)))
    raises(NotImplementedError,
           lambda: normalize_theta_set(Interval(2 * pi, 10)))
    raises(NotImplementedError,
           lambda: normalize_theta_set(FiniteSet(0, 3, 3 * pi)))
Beispiel #21
0
def test_codomain():
    x = Symbol('x', real=True)
    assert codomain(x, Interval(-1, 1), x) == Interval(-1, 1)
    assert codomain(x, Interval(0, 1, True, True), x) == \
            Interval(0, 1, True, True)
    assert codomain(x, Interval(1, 2, True, False), x) == Interval(1, 2, True, False)
    assert codomain(x, Interval(1, 2, False, True), x) == Interval(1, 2, False, True)
    assert codomain(x**2, Interval(-1, 1), x) == Interval(0, 1)
    assert codomain(x**3, Interval(0, 1), x) == Interval(0, 1)
    assert codomain(x/(x**2 - 4), Interval(3, 4), x) == Interval(S(1)/3, S(3)/5)
    assert codomain(1, Interval(-1, 4), x) == FiniteSet(1)
    assert codomain(x, Interval(-oo, oo), x) == S.Reals

    assert codomain(1/x**2, FiniteSet(1, 2, -1, 0), x) == FiniteSet(1, S(1)/4)
    assert codomain(x, FiniteSet(1, -1, 3, 5), x) == FiniteSet(-1, 1, 3, 5)
    assert codomain(x**2 - x, FiniteSet(1, -1, 3, 5, -oo), x) == \
            FiniteSet(0, 2, 6, 20, oo)
    assert codomain(x**2/(x - 4), FiniteSet(4), x) == S.EmptySet
    assert codomain(x**2 - x, FiniteSet(S(1)/2, -oo, oo, 2), x) == \
            FiniteSet(S(-1)/4, 2, oo)

    assert codomain(x**2, Interval(-1, 1, True, True), x) == Interval(0, 1, False, True)
    assert codomain(x**2, Interval(-1, 1, False, True), x) == Interval(0, 1)
    assert codomain(x**2, Interval(-1, 1, True, False), x) == Interval(0, 1)

    assert codomain(1/x, Interval(0, 1), x) == Interval(1, oo)
    assert codomain(1/x, Interval(-1, 1), x) == Union(Interval(-oo, -1), Interval(1, oo))
    assert codomain(1/x**2, Interval(-1, 1), x) == Interval(1, oo)
    assert codomain(1/x**2, Interval(-1, 1, True, False), x) == Interval(1, oo)
    assert codomain(1/x**2, Interval(-1, 1, True, True), x) == \
            Interval(1, oo, True, True)
    assert codomain(1/x**2, Interval(-1, 1, False, True), x) == Interval(1, oo)
    assert codomain(1/x, Interval(1, 2), x) == Interval(S(1)/2, 1)
    assert codomain(1/x**2, Interval(-2, -1, True, True), x) == \
            Interval(S(1)/4, 1, True, True)
    assert codomain(x**2/(x - 4), Interval(-oo, oo), x) == \
            Complement(S.Reals, Interval(0, 16, True, True))
    assert codomain(x**2/(x - 4), Interval(3, 4), x) == Interval(-oo, -9)
    assert codomain(-x**2/(x - 4), Interval(3, 4), x) == Interval(9, oo)
    assert codomain((x**2 - x)/(x**3 - 1), S.Reals, x) == Interval(-1, S(1)/3, False, True)
    assert codomain(-x**2 + 1/x, S.Reals, x) == S.Reals
    assert codomain(x**2 - 1/x, S.Reals, x) == S.Reals

    assert codomain(x**2, Union(Interval(1, 2), FiniteSet(3)), x) == \
            Union(Interval(1, 4), FiniteSet(9))
    assert codomain(x/(x**2 - 4), Union(Interval(-oo, 1), Interval(0, oo)), x) == S.Reals
    assert codomain(x, Union(Interval(-1, 1), FiniteSet(-oo)), x) == \
            Union(Interval(-1, 1), FiniteSet(-oo))
    assert codomain(x**2 - x, Interval(1, oo), x) == Interval(0, oo)
    raises(ValueError, lambda: codomain(sqrt(x), Interval(-1, 2), x))
Beispiel #22
0
def _set_pow(x, z):  # noqa:F811
    return FiniteSet(S.One)
Beispiel #23
0
def test_issue_16871():
    assert ImageSet(Lambda(x, x), FiniteSet(1)) == {1}
    assert ImageSet(Lambda(x, x - 3), S.Integers).intersection(
        S.Integers) is S.Integers
Beispiel #24
0
 def symbols(self):
     return FiniteSet(*[val.symbol for val in self.rs_space_dict.keys()])
Beispiel #25
0
def solve_univariate_inequality(expr,
                                gen,
                                relational=True,
                                domain=S.Reals,
                                continuous=False):
    """Solves a real univariate inequality.

    Parameters
    ==========

    expr : Relational
        The target inequality
    gen : Symbol
        The variable for which the inequality is solved
    relational : bool
        A Relational type output is expected or not
    domain : Set
        The domain over which the equation is solved
    continuous: bool
        True if expr is known to be continuous over the given domain
        (and so continuous_domain() doesn't need to be called on it)

    Raises
    ======

    NotImplementedError
        The solution of the inequality cannot be determined due to limitation
        in :func:`sympy.solvers.solveset.solvify`.

    Notes
    =====

    Currently, we cannot solve all the inequalities due to limitations in
    :func:`sympy.solvers.solveset.solvify`. Also, the solution returned for trigonometric inequalities
    are restricted in its periodic interval.

    See Also
    ========

    sympy.solvers.solveset.solvify: solver returning solveset solutions with solve's output API

    Examples
    ========

    >>> from sympy.solvers.inequalities import solve_univariate_inequality
    >>> from sympy import Symbol, sin, Interval, S
    >>> x = Symbol('x')

    >>> solve_univariate_inequality(x**2 >= 4, x)
    ((2 <= x) & (x < oo)) | ((x <= -2) & (-oo < x))

    >>> solve_univariate_inequality(x**2 >= 4, x, relational=False)
    Union(Interval(-oo, -2), Interval(2, oo))

    >>> domain = Interval(0, S.Infinity)
    >>> solve_univariate_inequality(x**2 >= 4, x, False, domain)
    Interval(2, oo)

    >>> solve_univariate_inequality(sin(x) > 0, x, relational=False)
    Interval.open(0, pi)

    """
    from sympy import im
    from sympy.calculus.util import continuous_domain, periodicity, function_range
    from sympy.solvers.solvers import denoms
    from sympy.solvers.solveset import solvify, solveset

    # This keeps the function independent of the assumptions about `gen`.
    # `solveset` makes sure this function is called only when the domain is
    # real.
    _gen = gen
    _domain = domain
    if gen.is_extended_real is False:
        rv = S.EmptySet
        return rv if not relational else rv.as_relational(_gen)
    elif gen.is_extended_real is None:
        gen = Dummy("gen", extended_real=True)
        try:
            expr = expr.xreplace({_gen: gen})
        except TypeError:
            raise TypeError(
                filldedent("""
                When gen is real, the relational has a complex part
                which leads to an invalid comparison like I < 0.
                """))

    rv = None

    if expr is S.true:
        rv = domain

    elif expr is S.false:
        rv = S.EmptySet

    else:
        e = expr.lhs - expr.rhs
        period = periodicity(e, gen)
        if period == S.Zero:
            e = expand_mul(e)
            const = expr.func(e, 0)
            if const is S.true:
                rv = domain
            elif const is S.false:
                rv = S.EmptySet
        elif period is not None:
            frange = function_range(e, gen, domain)

            rel = expr.rel_op
            if rel == "<" or rel == "<=":
                if expr.func(frange.sup, 0):
                    rv = domain
                elif not expr.func(frange.inf, 0):
                    rv = S.EmptySet

            elif rel == ">" or rel == ">=":
                if expr.func(frange.inf, 0):
                    rv = domain
                elif not expr.func(frange.sup, 0):
                    rv = S.EmptySet

            inf, sup = domain.inf, domain.sup
            if sup - inf is S.Infinity:
                domain = Interval(0, period, False, True)

        if rv is None:
            n, d = e.as_numer_denom()
            try:
                if gen not in n.free_symbols and len(e.free_symbols) > 1:
                    raise ValueError
                # this might raise ValueError on its own
                # or it might give None...
                solns = solvify(e, gen, domain)
                if solns is None:
                    # in which case we raise ValueError
                    raise ValueError
            except (ValueError, NotImplementedError):
                # replace gen with generic x since it's
                # univariate anyway
                raise NotImplementedError(
                    filldedent("""
                    The inequality, %s, cannot be solved using
                    solve_univariate_inequality.
                    """ % expr.subs(gen, Symbol("x"))))

            expanded_e = expand_mul(e)

            def valid(x):
                # this is used to see if gen=x satisfies the
                # relational by substituting it into the
                # expanded form and testing against 0, e.g.
                # if expr = x*(x + 1) < 2 then e = x*(x + 1) - 2
                # and expanded_e = x**2 + x - 2; the test is
                # whether a given value of x satisfies
                # x**2 + x - 2 < 0
                #
                # expanded_e, expr and gen used from enclosing scope
                v = expanded_e.subs(gen, expand_mul(x))
                try:
                    r = expr.func(v, 0)
                except TypeError:
                    r = S.false
                if r in (S.true, S.false):
                    return r
                if v.is_extended_real is False:
                    return S.false
                else:
                    v = v.n(2)
                    if v.is_comparable:
                        return expr.func(v, 0)
                    # not comparable or couldn't be evaluated
                    raise NotImplementedError(
                        "relationship did not evaluate: %s" % r)

            singularities = []
            for d in denoms(expr, gen):
                singularities.extend(solvify(d, gen, domain))
            if not continuous:
                domain = continuous_domain(expanded_e, gen, domain)

            include_x = "=" in expr.rel_op and expr.rel_op != "!="

            try:
                discontinuities = set(domain.boundary -
                                      FiniteSet(domain.inf, domain.sup))
                # remove points that are not between inf and sup of domain
                critical_points = FiniteSet(
                    *(solns + singularities +
                      list(discontinuities))).intersection(
                          Interval(
                              domain.inf,
                              domain.sup,
                              domain.inf not in domain,
                              domain.sup not in domain,
                          ))
                if all(r.is_number for r in critical_points):
                    reals = _nsort(critical_points, separated=True)[0]
                else:
                    sifted = sift(critical_points,
                                  lambda x: x.is_extended_real)
                    if sifted[None]:
                        # there were some roots that weren't known
                        # to be real
                        raise NotImplementedError
                    try:
                        reals = sifted[True]
                        if len(reals) > 1:
                            reals = list(sorted(reals))
                    except TypeError:
                        raise NotImplementedError
            except NotImplementedError:
                raise NotImplementedError(
                    "sorting of these roots is not supported")

            # If expr contains imaginary coefficients, only take real
            # values of x for which the imaginary part is 0
            make_real = S.Reals
            if im(expanded_e) != S.Zero:
                check = True
                im_sol = FiniteSet()
                try:
                    a = solveset(im(expanded_e), gen, domain)
                    if not isinstance(a, Interval):
                        for z in a:
                            if (z not in singularities and valid(z)
                                    and z.is_extended_real):
                                im_sol += FiniteSet(z)
                    else:
                        start, end = a.inf, a.sup
                        for z in _nsort(critical_points + FiniteSet(end)):
                            valid_start = valid(start)
                            if start != end:
                                valid_z = valid(z)
                                pt = _pt(start, z)
                                if (pt not in singularities
                                        and pt.is_extended_real and valid(pt)):
                                    if valid_start and valid_z:
                                        im_sol += Interval(start, z)
                                    elif valid_start:
                                        im_sol += Interval.Ropen(start, z)
                                    elif valid_z:
                                        im_sol += Interval.Lopen(start, z)
                                    else:
                                        im_sol += Interval.open(start, z)
                            start = z
                        for s in singularities:
                            im_sol -= FiniteSet(s)
                except (TypeError):
                    im_sol = S.Reals
                    check = False

                if isinstance(im_sol, EmptySet):
                    raise ValueError(
                        filldedent("""
                        %s contains imaginary parts which cannot be
                        made 0 for any value of %s satisfying the
                        inequality, leading to relations like I < 0.
                        """ % (expr.subs(gen, _gen), _gen)))

                make_real = make_real.intersect(im_sol)

            sol_sets = [S.EmptySet]

            start = domain.inf
            if valid(start) and start.is_finite:
                sol_sets.append(FiniteSet(start))

            for x in reals:
                end = x

                if valid(_pt(start, end)):
                    sol_sets.append(Interval(start, end, True, True))

                if x in singularities:
                    singularities.remove(x)
                else:
                    if x in discontinuities:
                        discontinuities.remove(x)
                        _valid = valid(x)
                    else:  # it's a solution
                        _valid = include_x
                    if _valid:
                        sol_sets.append(FiniteSet(x))

                start = end

            end = domain.sup
            if valid(end) and end.is_finite:
                sol_sets.append(FiniteSet(end))

            if valid(_pt(start, end)):
                sol_sets.append(Interval.open(start, end))

            if im(expanded_e) != S.Zero and check:
                rv = (make_real).intersect(_domain)
            else:
                rv = Intersection((Union(*sol_sets)), make_real,
                                  _domain).subs(gen, _gen)

    return rv if not relational else rv.as_relational(_gen)
Beispiel #26
0
 def symbols(self):
     return FiniteSet(
         *[sym for domain in self.domains for sym in domain.symbols])
Beispiel #27
0
    def _intersect(self, other):
        from sympy.solvers.diophantine import diophantine
        if self.base_set is S.Integers:
            g = None
            if isinstance(other, ImageSet) and other.base_set is S.Integers:
                g = other.lamda.expr
                m = other.lamda.variables[0]
            elif other is S.Integers:
                m = g = Dummy('x')
            if g is not None:
                f = self.lamda.expr
                n = self.lamda.variables[0]
                # Diophantine sorts the solutions according to the alphabetic
                # order of the variable names, since the result should not depend
                # on the variable name, they are replaced by the dummy variables
                # below
                a, b = Dummy('a'), Dummy('b')
                f, g = f.subs(n, a), g.subs(m, b)
                solns_set = diophantine(f - g)
                if solns_set == set():
                    return EmptySet()
                solns = list(diophantine(f - g))

                if len(solns) != 1:
                    return

                # since 'a' < 'b', select soln for n
                nsol = solns[0][0]
                t = nsol.free_symbols.pop()
                return imageset(Lambda(n, f.subs(a, nsol.subs(t, n))),
                                S.Integers)

        if other == S.Reals:
            from sympy.solvers.solveset import solveset_real
            from sympy.core.function import expand_complex
            if len(self.lamda.variables) > 1:
                return None

            f = self.lamda.expr
            n = self.lamda.variables[0]

            n_ = Dummy(n.name, real=True)
            f_ = f.subs(n, n_)

            re, im = f_.as_real_imag()
            im = expand_complex(im)

            return imageset(Lambda(n_, re),
                            self.base_set.intersect(solveset_real(im, n_)))

        elif isinstance(other, Interval):
            from sympy.solvers.solveset import (invert_real, invert_complex,
                                                solveset)

            f = self.lamda.expr
            n = self.lamda.variables[0]
            base_set = self.base_set
            new_inf, new_sup = None, None

            if f.is_real:
                inverter = invert_real
            else:
                inverter = invert_complex

            g1, h1 = inverter(f, other.inf, n)
            g2, h2 = inverter(f, other.sup, n)

            if all(isinstance(i, FiniteSet) for i in (h1, h2)):
                if g1 == n:
                    if len(h1) == 1:
                        new_inf = h1.args[0]
                if g2 == n:
                    if len(h2) == 1:
                        new_sup = h2.args[0]
                # TODO: Design a technique to handle multiple-inverse
                # functions

                # Any of the new boundary values cannot be determined
                if any(i is None for i in (new_sup, new_inf)):
                    return

                range_set = S.EmptySet

                if all(i.is_real for i in (new_sup, new_inf)):
                    new_interval = Interval(new_inf, new_sup)
                    range_set = base_set._intersect(new_interval)
                else:
                    if other.is_subset(S.Reals):
                        solutions = solveset(f, n, S.Reals)
                        if not isinstance(range_set, (ImageSet, ConditionSet)):
                            range_set = solutions._intersect(other)
                        else:
                            return

                if range_set is S.EmptySet:
                    return S.EmptySet
                elif isinstance(range_set,
                                Range) and range_set.size is not S.Infinity:
                    range_set = FiniteSet(*list(range_set))

                if range_set is not None:
                    return imageset(Lambda(n, f), range_set)
                return
            else:
                return
Beispiel #28
0
 def symbols(self):
     return FiniteSet(self.symbol)
Beispiel #29
0
def test_fun():
    assert (FiniteSet(
        *ImageSet(Lambda(x, sin(pi * x / 4)), Range(-10, 11))) == FiniteSet(
            -1, -sqrt(2) / 2, 0,
            sqrt(2) / 2, 1))
Beispiel #30
0
def test_Range_set():
    empty = Range(0)

    assert Range(5) == Range(0, 5) == Range(0, 5, 1)

    r = Range(10, 20, 2)
    assert 12 in r
    assert 8 not in r
    assert 11 not in r
    assert 30 not in r

    assert list(Range(0, 5)) == list(range(5))
    assert list(Range(5, 0, -1)) == list(range(5, 0, -1))

    assert Range(5, 15).sup == 14
    assert Range(5, 15).inf == 5
    assert Range(15, 5, -1).sup == 15
    assert Range(15, 5, -1).inf == 6
    assert Range(10, 67, 10).sup == 60
    assert Range(60, 7, -10).inf == 10

    assert len(Range(10, 38, 10)) == 3

    assert Range(0, 0, 5) == empty
    assert Range(oo, oo, 1) == empty
    assert Range(oo, 1, 1) == empty
    assert Range(-oo, 1, -1) == empty
    assert Range(1, oo, -1) == empty
    assert Range(1, -oo, 1) == empty
    assert Range(1, -4, oo) == empty
    assert Range(1, -4, -oo) == Range(1, 2)
    assert Range(1, 4, oo) == Range(1, 2)
    assert Range(-oo, oo).size == oo
    assert Range(oo, -oo, -1).size == oo
    raises(ValueError, lambda: Range(-oo, oo, 2))
    raises(ValueError, lambda: Range(x, pi, y))
    raises(ValueError, lambda: Range(x, y, 0))

    assert 5 in Range(0, oo, 5)
    assert -5 in Range(-oo, 0, 5)
    assert oo not in Range(0, oo)
    ni = symbols('ni', integer=False)
    assert ni not in Range(oo)
    u = symbols('u', integer=None)
    assert Range(oo).contains(u) is not False
    inf = symbols('inf', infinite=True)
    assert inf not in Range(-oo, oo)
    raises(ValueError, lambda: Range(0, oo, 2)[-1])
    raises(ValueError, lambda: Range(0, -oo, -2)[-1])
    assert Range(-oo, 1, 1)[-1] is S.Zero
    assert Range(oo, 1, -1)[-1] == 2
    assert inf not in Range(oo)
    inf = symbols('inf', infinite=True)
    assert inf not in Range(oo)
    assert Range(-oo, 1, 1)[-1] is S.Zero
    assert Range(oo, 1, -1)[-1] == 2
    assert Range(1, 10, 1)[-1] == 9
    assert all(i.is_Integer for i in Range(0, -1, 1))

    it = iter(Range(-oo, 0, 2))
    raises(TypeError, lambda: next(it))

    assert empty.intersect(S.Integers) == empty
    assert Range(-1, 10, 1).intersect(S.Integers) == Range(-1, 10, 1)
    assert Range(-1, 10, 1).intersect(S.Naturals) == Range(1, 10, 1)
    assert Range(-1, 10, 1).intersect(S.Naturals0) == Range(0, 10, 1)

    # test slicing
    assert Range(1, 10, 1)[5] == 6
    assert Range(1, 12, 2)[5] == 11
    assert Range(1, 10, 1)[-1] == 9
    assert Range(1, 10, 3)[-1] == 7
    raises(ValueError, lambda: Range(oo, 0, -1)[1:3:0])
    raises(ValueError, lambda: Range(oo, 0, -1)[:1])
    raises(ValueError, lambda: Range(1, oo)[-2])
    raises(ValueError, lambda: Range(-oo, 1)[2])
    raises(IndexError, lambda: Range(10)[-20])
    raises(IndexError, lambda: Range(10)[20])
    raises(ValueError, lambda: Range(2, -oo, -2)[2:2:0])
    assert Range(2, -oo, -2)[2:2:2] == empty
    assert Range(2, -oo, -2)[:2:2] == Range(2, -2, -4)
    raises(ValueError, lambda: Range(-oo, 4, 2)[:2:2])
    assert Range(-oo, 4, 2)[::-2] == Range(2, -oo, -4)
    raises(ValueError, lambda: Range(-oo, 4, 2)[::2])
    assert Range(oo, 2, -2)[::] == Range(oo, 2, -2)
    assert Range(-oo, 4, 2)[:-2:-2] == Range(2, 0, -4)
    assert Range(-oo, 4, 2)[:-2:2] == Range(-oo, 0, 4)
    raises(ValueError, lambda: Range(-oo, 4, 2)[:0:-2])
    raises(ValueError, lambda: Range(-oo, 4, 2)[:2:-2])
    assert Range(-oo, 4, 2)[-2::-2] == Range(0, -oo, -4)
    raises(ValueError, lambda: Range(-oo, 4, 2)[-2:0:-2])
    raises(ValueError, lambda: Range(-oo, 4, 2)[0::2])
    assert Range(oo, 2, -2)[0::] == Range(oo, 2, -2)
    raises(ValueError, lambda: Range(-oo, 4, 2)[0:-2:2])
    assert Range(oo, 2, -2)[0:-2:] == Range(oo, 6, -2)
    raises(ValueError, lambda: Range(oo, 2, -2)[0:2:])
    raises(ValueError, lambda: Range(-oo, 4, 2)[2::-1])
    assert Range(-oo, 4, 2)[-2::2] == Range(0, 4, 4)
    assert Range(oo, 0, -2)[-10:0:2] == empty
    raises(ValueError, lambda: Range(oo, 0, -2)[-10:10:2])
    raises(ValueError, lambda: Range(oo, 0, -2)[0::-2])
    assert Range(oo, 0, -2)[0:-4:-2] == empty
    assert Range(oo, 0, -2)[:0:2] == empty
    raises(ValueError, lambda: Range(oo, 0, -2)[:1:-1])

    # test empty Range
    assert Range(x, x, y) == empty
    assert empty.reversed == empty
    assert 0 not in empty
    assert list(empty) == []
    assert len(empty) == 0
    assert empty.size is S.Zero
    assert empty.intersect(FiniteSet(0)) is S.EmptySet
    assert bool(empty) is False
    raises(IndexError, lambda: empty[0])
    assert empty[:0] == empty
    raises(NotImplementedError, lambda: empty.inf)
    raises(NotImplementedError, lambda: empty.sup)

    AB = [None] + list(range(12))
    for R in [
            Range(1, 10),
            Range(1, 10, 2),
    ]:
        r = list(R)
        for a, b, c in cartes(AB, AB, [-3, -1, None, 1, 3]):
            for reverse in range(2):
                r = list(reversed(r))
                R = R.reversed
                result = list(R[a:b:c])
                ans = r[a:b:c]
                txt = ('\n%s[%s:%s:%s] = %s -> %s' % (R, a, b, c, result, ans))
                check = ans == result
                assert check, txt

    assert Range(1, 10, 1).boundary == Range(1, 10, 1)

    for r in (Range(1, 10, 2), Range(1, oo, 2)):
        rev = r.reversed
        assert r.inf == rev.inf and r.sup == rev.sup
        assert r.step == -rev.step

    builtin_range = range

    raises(TypeError, lambda: Range(builtin_range(1)))
    assert S(builtin_range(10)) == Range(10)
    assert S(builtin_range(1000000000000)) == Range(1000000000000)

    # test Range.as_relational
    assert Range(1,
                 4).as_relational(x) == (x >= 1) & (x <= 3) & Eq(x, floor(x))
    assert Range(oo, 1,
                 -2).as_relational(x) == (x >= 3) & (x < oo) & Eq(x, floor(x))
Beispiel #31
0
 def elements(self):
     return FiniteSet(*self)
Beispiel #32
0
def test_Range_symbolic():
    # symbolic Range
    sr = Range(x, y, t)
    i = Symbol('i', integer=True)
    ip = Symbol('i', integer=True, positive=True)
    ir = Range(i, i + 20, 2)
    inf = symbols('inf', infinite=True)
    # args
    assert sr.args == (x, y, t)
    assert ir.args == (i, i + 20, 2)
    # reversed
    raises(ValueError, lambda: sr.reversed)
    assert ir.reversed == Range(i + 18, i - 2, -2)
    # contains
    assert inf not in sr
    assert inf not in ir
    assert .1 not in sr
    assert .1 not in ir
    assert i + 1 not in ir
    assert i + 2 in ir
    raises(TypeError,
           lambda: 1 in sr)  # XXX is this what contains is supposed to do?
    # iter
    raises(ValueError, lambda: next(iter(sr)))
    assert next(iter(ir)) == i
    assert sr.intersect(S.Integers) == sr
    assert sr.intersect(FiniteSet(x)) == Intersection({x}, sr)
    raises(ValueError, lambda: sr[:2])
    raises(ValueError, lambda: sr[0])
    raises(ValueError, lambda: sr.as_relational(x))
    # len
    assert len(ir) == ir.size == 10
    raises(ValueError, lambda: len(sr))
    raises(ValueError, lambda: sr.size)
    # bool
    assert bool(ir) == bool(sr) == True
    # getitem
    raises(ValueError, lambda: sr[0])
    raises(ValueError, lambda: sr[-1])
    raises(ValueError, lambda: sr[:2])
    assert ir[:2] == Range(i, i + 4, 2)
    assert ir[0] == i
    assert ir[-2] == i + 16
    assert ir[-1] == i + 18
    raises(ValueError, lambda: Range(i)[-1])
    assert Range(ip)[-1] == ip - 1
    assert ir.inf == i
    assert ir.sup == i + 18
    assert Range(ip).inf == 0
    assert Range(ip).sup == ip - 1
    raises(ValueError, lambda: Range(i).inf)
    # as_relational
    raises(ValueError, lambda: sr.as_relational(x))
    assert ir.as_relational(x) == (x >= i) & Eq(x, floor(x)) & (x <= i + 18)
    assert Range(i, i + 1).as_relational(x) == Eq(x, i)
    # contains() for symbolic values (issue #18146)
    e = Symbol('e', integer=True, even=True)
    o = Symbol('o', integer=True, odd=True)
    assert Range(5).contains(i) == And(i >= 0, i <= 4)
    assert Range(1).contains(i) == Eq(i, 0)
    assert Range(-oo, 5, 1).contains(i) == (i <= 4)
    assert Range(-oo, oo).contains(i) == True
    assert Range(0, 8, 2).contains(i) == Contains(i, Range(0, 8, 2))
    assert Range(0, 8, 2).contains(e) == And(e >= 0, e <= 6)
    assert Range(0, 8, 2).contains(2 * i) == And(2 * i >= 0, 2 * i <= 6)
    assert Range(0, 8, 2).contains(o) == False
    assert Range(1, 9, 2).contains(e) == False
    assert Range(1, 9, 2).contains(o) == And(o >= 1, o <= 7)
    assert Range(8, 0, -2).contains(o) == False
    assert Range(9, 1, -2).contains(o) == And(o >= 3, o <= 9)
    assert Range(-oo, 8, 2).contains(i) == Contains(i, Range(-oo, 8, 2))
Beispiel #33
0
def test_DiagramGrid():
    # Set up some objects and morphisms.
    A = Object("A")
    B = Object("B")
    C = Object("C")
    D = Object("D")
    E = Object("E")

    f = NamedMorphism(A, B, "f")
    g = NamedMorphism(B, C, "g")
    h = NamedMorphism(D, A, "h")
    k = NamedMorphism(D, B, "k")

    # A one-morphism diagram.
    d = Diagram([f])
    grid = DiagramGrid(d)

    assert grid.width == 2
    assert grid.height == 1
    assert grid[0, 0] == A
    assert grid[0, 1] == B
    assert grid.morphisms == {f: FiniteSet()}

    # A triangle.
    d = Diagram([f, g], {g * f: "unique"})
    grid = DiagramGrid(d)

    assert grid.width == 2
    assert grid.height == 2
    assert grid[0, 0] == A
    assert grid[0, 1] == B
    assert grid[1, 0] == C
    assert grid[1, 1] is None
    assert grid.morphisms == {f: FiniteSet(), g: FiniteSet(),
                              g * f: FiniteSet("unique")}

    # A triangle with a "loop" morphism.
    l_A = NamedMorphism(A, A, "l_A")
    d = Diagram([f, g, l_A])
    grid = DiagramGrid(d)

    assert grid.width == 2
    assert grid.height == 2
    assert grid[0, 0] == A
    assert grid[0, 1] == B
    assert grid[1, 0] is None
    assert grid[1, 1] == C
    assert grid.morphisms == {f: FiniteSet(), g: FiniteSet(), l_A: FiniteSet()}

    # A simple diagram.
    d = Diagram([f, g, h, k])
    grid = DiagramGrid(d)

    assert grid.width == 3
    assert grid.height == 2
    assert grid[0, 0] == A
    assert grid[0, 1] == B
    assert grid[0, 2] == D
    assert grid[1, 0] is None
    assert grid[1, 1] == C
    assert grid[1, 2] is None
    assert grid.morphisms == {f: FiniteSet(), g: FiniteSet(), h: FiniteSet(),
                              k: FiniteSet()}

    assert str(grid) == '[[Object("A"), Object("B"), Object("D")], ' \
        '[None, Object("C"), None]]'

    # A chain of morphisms.
    f = NamedMorphism(A, B, "f")
    g = NamedMorphism(B, C, "g")
    h = NamedMorphism(C, D, "h")
    k = NamedMorphism(D, E, "k")
    d = Diagram([f, g, h, k])
    grid = DiagramGrid(d)

    assert grid.width == 3
    assert grid.height == 3
    assert grid[0, 0] == A
    assert grid[0, 1] == B
    assert grid[0, 2] is None
    assert grid[1, 0] is None
    assert grid[1, 1] == C
    assert grid[1, 2] == D
    assert grid[2, 0] is None
    assert grid[2, 1] is None
    assert grid[2, 2] == E
    assert grid.morphisms == {f: FiniteSet(), g: FiniteSet(), h: FiniteSet(),
                              k: FiniteSet()}

    # A square.
    f = NamedMorphism(A, B, "f")
    g = NamedMorphism(B, D, "g")
    h = NamedMorphism(A, C, "h")
    k = NamedMorphism(C, D, "k")
    d = Diagram([f, g, h, k])
    grid = DiagramGrid(d)

    assert grid.width == 2
    assert grid.height == 2
    assert grid[0, 0] == A
    assert grid[0, 1] == B
    assert grid[1, 0] == C
    assert grid[1, 1] == D
    assert grid.morphisms == {f: FiniteSet(), g: FiniteSet(), h: FiniteSet(),
                              k: FiniteSet()}

    # A strange diagram which resulted from a typo when creating a
    # test for five lemma, but which allowed to stop one extra problem
    # in the algorithm.
    A = Object("A")
    B = Object("B")
    C = Object("C")
    D = Object("D")
    E = Object("E")
    A_ = Object("A'")
    B_ = Object("B'")
    C_ = Object("C'")
    D_ = Object("D'")
    E_ = Object("E'")

    f = NamedMorphism(A, B, "f")
    g = NamedMorphism(B, C, "g")
    h = NamedMorphism(C, D, "h")
    i = NamedMorphism(D, E, "i")

    # These 4 morphisms should be between primed objects.
    j = NamedMorphism(A, B, "j")
    k = NamedMorphism(B, C, "k")
    l = NamedMorphism(C, D, "l")
    m = NamedMorphism(D, E, "m")

    o = NamedMorphism(A, A_, "o")
    p = NamedMorphism(B, B_, "p")
    q = NamedMorphism(C, C_, "q")
    r = NamedMorphism(D, D_, "r")
    s = NamedMorphism(E, E_, "s")

    d = Diagram([f, g, h, i, j, k, l, m, o, p, q, r, s])
    grid = DiagramGrid(d)

    assert grid.width == 3
    assert grid.height == 4
    assert grid[0, 0] is None
    assert grid[0, 1] == A
    assert grid[0, 2] == A_
    assert grid[1, 0] == C
    assert grid[1, 1] == B
    assert grid[1, 2] == B_
    assert grid[2, 0] == C_
    assert grid[2, 1] == D
    assert grid[2, 2] == D_
    assert grid[3, 0] is None
    assert grid[3, 1] == E
    assert grid[3, 2] == E_

    morphisms = {}
    for m in [f, g, h, i, j, k, l, m, o, p, q, r, s]:
        morphisms[m] = FiniteSet()
    assert grid.morphisms == morphisms

    # A cube.
    A1 = Object("A1")
    A2 = Object("A2")
    A3 = Object("A3")
    A4 = Object("A4")
    A5 = Object("A5")
    A6 = Object("A6")
    A7 = Object("A7")
    A8 = Object("A8")

    # The top face of the cube.
    f1 = NamedMorphism(A1, A2, "f1")
    f2 = NamedMorphism(A1, A3, "f2")
    f3 = NamedMorphism(A2, A4, "f3")
    f4 = NamedMorphism(A3, A4, "f3")

    # The bottom face of the cube.
    f5 = NamedMorphism(A5, A6, "f5")
    f6 = NamedMorphism(A5, A7, "f6")
    f7 = NamedMorphism(A6, A8, "f7")
    f8 = NamedMorphism(A7, A8, "f8")

    # The remaining morphisms.
    f9 = NamedMorphism(A1, A5, "f9")
    f10 = NamedMorphism(A2, A6, "f10")
    f11 = NamedMorphism(A3, A7, "f11")
    f12 = NamedMorphism(A4, A8, "f11")

    d = Diagram([f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12])
    grid = DiagramGrid(d)

    assert grid.width == 4
    assert grid.height == 3
    assert grid[0, 0] is None
    assert grid[0, 1] == A5
    assert grid[0, 2] == A6
    assert grid[0, 3] is None
    assert grid[1, 0] is None
    assert grid[1, 1] == A1
    assert grid[1, 2] == A2
    assert grid[1, 3] is None
    assert grid[2, 0] == A7
    assert grid[2, 1] == A3
    assert grid[2, 2] == A4
    assert grid[2, 3] == A8

    morphisms = {}
    for m in [f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12]:
        morphisms[m] = FiniteSet()
    assert grid.morphisms == morphisms

    # A line diagram.
    A = Object("A")
    B = Object("B")
    C = Object("C")
    D = Object("D")
    E = Object("E")

    f = NamedMorphism(A, B, "f")
    g = NamedMorphism(B, C, "g")
    h = NamedMorphism(C, D, "h")
    i = NamedMorphism(D, E, "i")
    d = Diagram([f, g, h, i])
    grid = DiagramGrid(d, layout="sequential")

    assert grid.width == 5
    assert grid.height == 1
    assert grid[0, 0] == A
    assert grid[0, 1] == B
    assert grid[0, 2] == C
    assert grid[0, 3] == D
    assert grid[0, 4] == E
    assert grid.morphisms == {f: FiniteSet(), g: FiniteSet(), h: FiniteSet(),
                              i: FiniteSet()}

    # Test the transposed version.
    grid = DiagramGrid(d, layout="sequential", transpose=True)

    assert grid.width == 1
    assert grid.height == 5
    assert grid[0, 0] == A
    assert grid[1, 0] == B
    assert grid[2, 0] == C
    assert grid[3, 0] == D
    assert grid[4, 0] == E
    assert grid.morphisms == {f: FiniteSet(), g: FiniteSet(), h: FiniteSet(),
                              i: FiniteSet()}

    # A pullback.
    m1 = NamedMorphism(A, B, "m1")
    m2 = NamedMorphism(A, C, "m2")
    s1 = NamedMorphism(B, D, "s1")
    s2 = NamedMorphism(C, D, "s2")
    f1 = NamedMorphism(E, B, "f1")
    f2 = NamedMorphism(E, C, "f2")
    g = NamedMorphism(E, A, "g")

    d = Diagram([m1, m2, s1, s2, f1, f2], {g: "unique"})
    grid = DiagramGrid(d)

    assert grid.width == 3
    assert grid.height == 2
    assert grid[0, 0] == A
    assert grid[0, 1] == B
    assert grid[0, 2] == E
    assert grid[1, 0] == C
    assert grid[1, 1] == D
    assert grid[1, 2] is None

    morphisms = {g: FiniteSet("unique")}
    for m in [m1, m2, s1, s2, f1, f2]:
        morphisms[m] = FiniteSet()
    assert grid.morphisms == morphisms

    # Test the pullback with sequential layout, just for stress
    # testing.
    grid = DiagramGrid(d, layout="sequential")

    assert grid.width == 5
    assert grid.height == 1
    assert grid[0, 0] == D
    assert grid[0, 1] == B
    assert grid[0, 2] == A
    assert grid[0, 3] == C
    assert grid[0, 4] == E
    assert grid.morphisms == morphisms

    # Test a pullback with object grouping.
    grid = DiagramGrid(d, groups=FiniteSet(E, FiniteSet(A, B, C, D)))

    assert grid.width == 3
    assert grid.height == 2
    assert grid[0, 0] == E
    assert grid[0, 1] == A
    assert grid[0, 2] == B
    assert grid[1, 0] is None
    assert grid[1, 1] == C
    assert grid[1, 2] == D
    assert grid.morphisms == morphisms

    # Five lemma, actually.
    A = Object("A")
    B = Object("B")
    C = Object("C")
    D = Object("D")
    E = Object("E")
    A_ = Object("A'")
    B_ = Object("B'")
    C_ = Object("C'")
    D_ = Object("D'")
    E_ = Object("E'")

    f = NamedMorphism(A, B, "f")
    g = NamedMorphism(B, C, "g")
    h = NamedMorphism(C, D, "h")
    i = NamedMorphism(D, E, "i")

    j = NamedMorphism(A_, B_, "j")
    k = NamedMorphism(B_, C_, "k")
    l = NamedMorphism(C_, D_, "l")
    m = NamedMorphism(D_, E_, "m")

    o = NamedMorphism(A, A_, "o")
    p = NamedMorphism(B, B_, "p")
    q = NamedMorphism(C, C_, "q")
    r = NamedMorphism(D, D_, "r")
    s = NamedMorphism(E, E_, "s")

    d = Diagram([f, g, h, i, j, k, l, m, o, p, q, r, s])
    grid = DiagramGrid(d)

    assert grid.width == 5
    assert grid.height == 3
    assert grid[0, 0] is None
    assert grid[0, 1] == A
    assert grid[0, 2] == A_
    assert grid[0, 3] is None
    assert grid[0, 4] is None
    assert grid[1, 0] == C
    assert grid[1, 1] == B
    assert grid[1, 2] == B_
    assert grid[1, 3] == C_
    assert grid[1, 4] is None
    assert grid[2, 0] == D
    assert grid[2, 1] == E
    assert grid[2, 2] is None
    assert grid[2, 3] == D_
    assert grid[2, 4] == E_

    morphisms = {}
    for m in [f, g, h, i, j, k, l, m, o, p, q, r, s]:
        morphisms[m] = FiniteSet()
    assert grid.morphisms == morphisms

    # Test the five lemma with object grouping.
    grid = DiagramGrid(d, FiniteSet(
        FiniteSet(A, B, C, D, E), FiniteSet(A_, B_, C_, D_, E_)))

    assert grid.width == 6
    assert grid.height == 3
    assert grid[0, 0] == A
    assert grid[0, 1] == B
    assert grid[0, 2] is None
    assert grid[0, 3] == A_
    assert grid[0, 4] == B_
    assert grid[0, 5] is None
    assert grid[1, 0] is None
    assert grid[1, 1] == C
    assert grid[1, 2] == D
    assert grid[1, 3] is None
    assert grid[1, 4] == C_
    assert grid[1, 5] == D_
    assert grid[2, 0] is None
    assert grid[2, 1] is None
    assert grid[2, 2] == E
    assert grid[2, 3] is None
    assert grid[2, 4] is None
    assert grid[2, 5] == E_
    assert grid.morphisms == morphisms

    # Test the five lemma with object grouping, but mixing containers
    # to represent groups.
    grid = DiagramGrid(d, [(A, B, C, D, E), {A_, B_, C_, D_, E_}])

    assert grid.width == 6
    assert grid.height == 3
    assert grid[0, 0] == A
    assert grid[0, 1] == B
    assert grid[0, 2] is None
    assert grid[0, 3] == A_
    assert grid[0, 4] == B_
    assert grid[0, 5] is None
    assert grid[1, 0] is None
    assert grid[1, 1] == C
    assert grid[1, 2] == D
    assert grid[1, 3] is None
    assert grid[1, 4] == C_
    assert grid[1, 5] == D_
    assert grid[2, 0] is None
    assert grid[2, 1] is None
    assert grid[2, 2] == E
    assert grid[2, 3] is None
    assert grid[2, 4] is None
    assert grid[2, 5] == E_
    assert grid.morphisms == morphisms

    # Test the five lemma with object grouping and hints.
    grid = DiagramGrid(d, {
        FiniteSet(A, B, C, D, E): {"layout": "sequential",
                                   "transpose": True},
        FiniteSet(A_, B_, C_, D_, E_): {"layout": "sequential",
                                        "transpose": True}},
        transpose=True)

    assert grid.width == 5
    assert grid.height == 2
    assert grid[0, 0] == A
    assert grid[0, 1] == B
    assert grid[0, 2] == C
    assert grid[0, 3] == D
    assert grid[0, 4] == E
    assert grid[1, 0] == A_
    assert grid[1, 1] == B_
    assert grid[1, 2] == C_
    assert grid[1, 3] == D_
    assert grid[1, 4] == E_
    assert grid.morphisms == morphisms

    # A two-triangle disconnected diagram.
    f = NamedMorphism(A, B, "f")
    g = NamedMorphism(B, C, "g")
    f_ = NamedMorphism(A_, B_, "f")
    g_ = NamedMorphism(B_, C_, "g")
    d = Diagram([f, g, f_, g_], {g * f: "unique", g_ * f_: "unique"})
    grid = DiagramGrid(d)

    assert grid.width == 4
    assert grid.height == 2
    assert grid[0, 0] == A
    assert grid[0, 1] == B
    assert grid[0, 2] == A_
    assert grid[0, 3] == B_
    assert grid[1, 0] == C
    assert grid[1, 1] is None
    assert grid[1, 2] == C_
    assert grid[1, 3] is None
    assert grid.morphisms == {f: FiniteSet(), g: FiniteSet(), f_: FiniteSet(),
                              g_: FiniteSet(), g * f: FiniteSet("unique"),
                              g_ * f_: FiniteSet("unique")}

    # A two-morphism disconnected diagram.
    f = NamedMorphism(A, B, "f")
    g = NamedMorphism(C, D, "g")
    d = Diagram([f, g])
    grid = DiagramGrid(d)

    assert grid.width == 4
    assert grid.height == 1
    assert grid[0, 0] == A
    assert grid[0, 1] == B
    assert grid[0, 2] == C
    assert grid[0, 3] == D
    assert grid.morphisms == {f: FiniteSet(), g: FiniteSet()}

    # Test a one-object diagram.
    f = NamedMorphism(A, A, "f")
    d = Diagram([f])
    grid = DiagramGrid(d)

    assert grid.width == 1
    assert grid.height == 1
    assert grid[0, 0] == A

    # Test a two-object disconnected diagram.
    g = NamedMorphism(B, B, "g")
    d = Diagram([f, g])
    grid = DiagramGrid(d)

    assert grid.width == 2
    assert grid.height == 1
    assert grid[0, 0] == A
    assert grid[0, 1] == B