Exemple #1
0
 def then(self, other):
     if not isinstance(other, Tensor):
         raise TypeError(messages.type_err(Tensor, other))
     if self.cod != other.dom:
         raise AxiomError(messages.does_not_compose(self, other))
     array = np.tensordot(self.array, other.array, len(self.cod))\
         if self.array.shape and other.array.shape\
         else self.array * other.array
     return Tensor(self.dom, other.cod, array)
Exemple #2
0
 def __init__(self, dom, cod, boxes, _scan=True):
     if not isinstance(dom, Ob):
         raise TypeError(messages.type_err(Ob, dom))
     if not isinstance(cod, Ob):
         raise TypeError(messages.type_err(Ob, cod))
     if _scan:
         scan = dom
         for depth, box in enumerate(boxes):
             if not isinstance(box, Arrow):
                 raise TypeError(messages.type_err(Arrow, box))
             if box.dom != scan:
                 raise AxiomError(messages.does_not_compose(
                     boxes[depth - 1] if depth else Id(dom), box))
             scan = box.cod
         if scan != cod:
             raise AxiomError(messages.does_not_compose(
                 boxes[-1] if boxes else Id(dom), Id(cod)))
     self._dom, self._cod, self._boxes = dom, cod, boxes
Exemple #3
0
 def __init__(self, left, right):
     if not isinstance(left, Over):
         raise TypeError(messages.type_err(Under, left))
     if not isinstance(right, Under):
         raise TypeError(messages.type_err(Under, right))
     if left.left != right.left:
         raise TypeError(messages.does_not_compose(left, right))
     name = "BX({}, {})".format(left, right)
     dom, cod = left @ right, right.right << left.right
     super().__init__(name, dom, cod)
Exemple #4
0
 def __init__(self, left, right):
     if not isinstance(left, Over):
         raise TypeError(messages.type_err(Over, left))
     if not isinstance(right, Under):
         raise TypeError(messages.type_err(Over, right))
     if left.right != right.right:
         raise TypeError(messages.does_not_compose(left, right))
     name = "FX({}, {})".format(left, right)
     dom, cod = left @ right, right.left >> left.left
     Box.__init__(self, name, dom, cod)
     BinaryBoxConstructor.__init__(self, left, right)
Exemple #5
0
 def then(self, *others):
     if len(others) != 1 or any(isinstance(other, Sum) for other in others):
         return monoidal.Diagram.then(self, *others)
     other, = others
     if not isinstance(other, Tensor):
         raise TypeError(messages.type_err(Tensor, other))
     if self.cod != other.dom:
         raise AxiomError(messages.does_not_compose(self, other))
     array = Tensor.np.tensordot(self.array, other.array, len(self.cod))\
         if self.array.shape and other.array.shape\
         else self.array * other.array
     return Tensor(self.dom, other.cod, array)
Exemple #6
0
    def then(self, *others):
        """
        Returns the composition of `self` with arrows `others`.

        This method is called using the binary operators `>>` and `<<`:

        >>> x, y, z = Ob('x'), Ob('y'), Ob('z')
        >>> f, g, h = Box('f', x, y), Box('g', y, z), Box('h', z, x)
        >>> assert f.then(g) == f >> g == g << f

        Parameters
        ----------
        others : cat.Arrow
            such that `self.cod == others[0].dom`
            and `all(x.cod == y.dom for x, y in zip(others, others[1:])`.

        Returns
        -------
        arrow : cat.Arrow
            such that :code:`arrow.boxes == self.boxes
            + sum(other.boxes for other in others, [])`.

        Raises
        ------
        :class:`cat.AxiomError`
            whenever `self` and `others` do not compose.

        Notes
        -----

        We can check the axioms of categories
        (i.e. composition is unital and associative):

        >>> assert f >> Id(y) == f == Id(x) >> f
        >>> assert (f >> g) >> h == f >> (g >> h)
        """
        if not others:
            return self
        if len(others) > 1:
            return self.then(others[0]).then(*others[1:])
        other, = others
        if isinstance(other, Sum):
            return self.sum([self]).then(other)
        if not isinstance(other, Arrow):
            raise TypeError(messages.type_err(Arrow, other))
        if self.cod != other.dom:
            raise AxiomError(messages.does_not_compose(self, other))
        return self.upgrade(
            Arrow(self.dom, other.cod, self.boxes + other.boxes, _scan=False))
Exemple #7
0
    def then(self, other):
        """
        Implements the sequential composition of Python functions.

        >>> copy = Function(1, 2, lambda *x: x + x)
        >>> swap = Function(2, 2, lambda x, y: (y, x))
        >>> assert (copy >> swap)(1) == copy(1)
        >>> assert (swap >> swap)(1, 2) == (1, 2)
        """
        if not isinstance(other, Function):
            raise TypeError(messages.type_err(Function, other))
        if len(self.cod) != len(other.dom):
            raise AxiomError(messages.does_not_compose(self, other))
        return Function(self.dom, other.cod,
                        lambda *vals: other(*tuplify(self(*vals))))
Exemple #8
0
    def then(self, other):
        """
        Returns the composition of `self` with an arrow `other`.

        This method is called using the binary operators `>>` and `<<`:

        >>> x, y, z = Ob('x'), Ob('y'), Ob('z')
        >>> f, g, h = Box('f', x, y), Box('g', y, z), Box('h', z, x)
        >>> assert f.then(g) == f >> g == g << f

        Parameters
        ----------
        other : cat.Arrow
            such that `self.cod == other.dom`.

        Returns
        -------
        arrow : cat.Arrow
            such that :code:`arrow.boxes == self.boxes + other.boxes`.

        Raises
        ------
        :class:`cat.AxiomError`
            whenever `self` and `other` do not compose.

        Notes
        -----

        We can check the axioms of categories
        (i.e. composition is unital and associative):

        >>> assert f >> Id(y) == f == Id(x) >> f
        >>> assert (f >> g) >> h == f >> (g >> h)
        """
        if not isinstance(other, Arrow):
            raise TypeError(messages.type_err(Arrow, other))
        if self.cod != other.dom:
            raise AxiomError(messages.does_not_compose(self, other))
        boxes = self.boxes + other.boxes
        return Arrow(self.dom, other.cod, boxes, _scan=False)