def setUp(self):
     self.t = UnnamedOpetopicSet.Type(
         UnnamedOpetopicSet.PastingDiagram.nonDegeneratePastingDiagram(
             UnnamedOpetope.OpetopicInteger(2), {
                 UnnamedOpetope.Address.epsilon(1): "a",
                 UnnamedOpetope.Address.epsilon(0).shift(): "b"
             }), UnnamedOpetopicSet.Variable("t", UnnamedOpetope.Arrow()))
 def setUp(self):
     self.p = UnnamedOpetopicSet.Typing(
         UnnamedOpetopicSet.Variable("p", UnnamedOpetope.Point()),
         UnnamedOpetopicSet.Type(UnnamedOpetopicSet.PastingDiagram.point(),
                                 None))
     self.a = UnnamedOpetopicSet.Typing(
         UnnamedOpetopicSet.Variable("a",
                                     UnnamedOpetope.OpetopicInteger(0)),
         UnnamedOpetopicSet.Type(
             UnnamedOpetopicSet.PastingDiagram.degeneratePastingDiagram(
                 UnnamedOpetope.OpetopicInteger(0), "p"),
             UnnamedOpetopicSet.Variable("p", UnnamedOpetope.Arrow())))
     self.b = UnnamedOpetopicSet.Typing(
         UnnamedOpetopicSet.Variable("b",
                                     UnnamedOpetope.OpetopicInteger(0)),
         UnnamedOpetopicSet.Type(
             UnnamedOpetopicSet.PastingDiagram.degeneratePastingDiagram(
                 UnnamedOpetope.OpetopicInteger(0), "p"),
             UnnamedOpetopicSet.Variable("p", UnnamedOpetope.Arrow())))
     self.c = UnnamedOpetopicSet.Typing(
         UnnamedOpetopicSet.Variable("c",
                                     UnnamedOpetope.OpetopicInteger(2)),
         UnnamedOpetopicSet.Type(
             UnnamedOpetopicSet.PastingDiagram.nonDegeneratePastingDiagram(
                 UnnamedOpetope.OpetopicInteger(2), {
                     UnnamedOpetope.Address.epsilon(1): "x",
                     UnnamedOpetope.Address.epsilon(0).shift(): "y"
                 }), UnnamedOpetopicSet.Variable("z",
                                                 UnnamedOpetope.Arrow())))
     self.ctx = UnnamedOpetopicSet.Context() + self.p + self.a + self.c
 def test_graft(self):
     with self.assertRaises(DerivationError):
         UnnamedOpetopicSet.graft(
             UnnamedOpetopicSet.Sequent(),
             UnnamedOpetopicSet.PastingDiagram.degeneratePastingDiagram(
                 UnnamedOpetope.OpetopicInteger(0), "x"))
     with self.assertRaises(DerivationError):
         UnnamedOpetopicSet.graft(
             UnnamedOpetopicSet.Sequent(),
             UnnamedOpetopicSet.PastingDiagram.nonDegeneratePastingDiagram(
                 UnnamedOpetope.Arrow(),
                 {UnnamedOpetope.Address.epsilon(0): "x"}))
     # Incorrect grafting: ab on top of cd
     with self.assertRaises(DerivationError):
         UnnamedOpetopicSet.graft(
             self.seq,
             UnnamedOpetopicSet.PastingDiagram.nonDegeneratePastingDiagram(
                 UnnamedOpetope.OpetopicInteger(2), {
                     UnnamedOpetope.Address.epsilon(1): "cd",
                     UnnamedOpetope.Address.epsilon(0).shift(): "ab"
                 }))
     # Correct grafting: ab on top of bc
     UnnamedOpetopicSet.graft(
         self.seq,
         UnnamedOpetopicSet.PastingDiagram.nonDegeneratePastingDiagram(
             UnnamedOpetope.OpetopicInteger(2), {
                 UnnamedOpetope.Address.epsilon(1): "bc",
                 UnnamedOpetope.Address.epsilon(0).shift(): "ab"
             }))
Exemple #4
0
 def test___init__(self):
     with self.assertRaises(DerivationError):
         UnnamedOpetope.Preopetope(-2)
     UnnamedOpetope.Preopetope(-1)
     x = UnnamedOpetope.Preopetope(8)
     self.assertEqual(x.dimension, 8)
     self.assertFalse(x.isDegenerate)
     self.assertEqual(x.nodes, {})
 def test_shape(self):
     self.assertEqual(self.a.shape, UnnamedOpetope.Arrow().eval().source)
     self.assertEqual(self.b.shape, UnnamedOpetope.Arrow().eval().source)
     self.assertEqual(self.i1.shape,
                      UnnamedOpetope.OpetopicInteger(1).eval().source)
     self.assertEqual(self.i2.shape,
                      UnnamedOpetope.OpetopicInteger(2).eval().source)
     self.assertEqual(self.i3.shape,
                      UnnamedOpetope.OpetopicInteger(3).eval().source)
 def test___init__(self):
     UnnamedOpetopicSet.Typing(
         UnnamedOpetopicSet.Variable("x",
                                     UnnamedOpetope.OpetopicInteger(2)),
         self.t)
     with self.assertRaises(DerivationError):
         UnnamedOpetopicSet.Typing(
             UnnamedOpetopicSet.Variable("x",
                                         UnnamedOpetope.OpetopicInteger(3)),
             self.t)
 def test___init__(self):
     UnnamedOpetopicSet.Type(
         self.s, UnnamedOpetopicSet.Variable("t", UnnamedOpetope.Arrow()))
     with self.assertRaises(DerivationError):
         UnnamedOpetopicSet.Type(
             self.s, UnnamedOpetopicSet.Variable("t",
                                                 UnnamedOpetope.Point()))
     UnnamedOpetopicSet.Type(UnnamedOpetopicSet.PastingDiagram.point(),
                             None)
     with self.assertRaises(DerivationError):
         UnnamedOpetopicSet.Type(self.s, None)
Exemple #8
0
 def test___sub__(self):
     with self.assertRaises(DerivationError):
         self.b - UnnamedOpetope.Address.epsilon(1)
     with self.assertRaises(DerivationError):
         self.f - UnnamedOpetope.Address.epsilon(2)
     self.assertEqual(self.c - UnnamedOpetope.Address.epsilon(1), self.b)
     self.assertEqual(self.d - UnnamedOpetope.Address.fromList(['*'], 1),
                      self.b)
     self.assertEqual(self.e - UnnamedOpetope.Address.epsilon(2),
                      UnnamedOpetope.Context(3))
     self.assertEqual(self.f - UnnamedOpetope.Address.epsilon(1).shift(),
                      UnnamedOpetope.Context(3))
 def test___getitem__(self):
     d = UnnamedOpetopicSet.PastingDiagram.degeneratePastingDiagram(
         UnnamedOpetope.OpetopicInteger(0), "d")
     p = UnnamedOpetopicSet.PastingDiagram.nonDegeneratePastingDiagram(
         UnnamedOpetope.OpetopicInteger(2), {
             UnnamedOpetope.Address.epsilon(1): "a",
             UnnamedOpetope.Address.epsilon(0).shift(): "b"
         })
     with self.assertRaises(DerivationError):
         d[UnnamedOpetope.Address.epsilon(0)]
     self.assertEqual(p[UnnamedOpetope.Address.epsilon(1)], "a")
     self.assertEqual(p[UnnamedOpetope.Address.epsilon(0).shift()], "b")
Exemple #10
0
 def test_degen(self):
     s = UnnamedOpetope.degen(UnnamedOpetope.point())
     self.assertEqual(
         s.context,
         UnnamedOpetope.Context(2) + (UnnamedOpetope.Address.epsilon(1),
                                      UnnamedOpetope.Address.epsilon(0)))
     self.assertEqual(
         s.source,
         UnnamedOpetope.Preopetope.degenerate(
             UnnamedOpetope.Preopetope.point()))
     self.assertEqual(s.target,
                      UnnamedOpetope.shift(UnnamedOpetope.point()).source)
 def test_nonDegeneratePastingDiagram(self):
     UnnamedOpetopicSet.PastingDiagram.nonDegeneratePastingDiagram(
         UnnamedOpetope.OpetopicInteger(2), {
             UnnamedOpetope.Address.epsilon(1): "a",
             UnnamedOpetope.Address.epsilon(0).shift(): "b"
         })
     with self.assertRaises(DerivationError):
         UnnamedOpetopicSet.PastingDiagram.nonDegeneratePastingDiagram(
             UnnamedOpetope.OpetopicInteger(0), {})
     with self.assertRaises(DerivationError):
         UnnamedOpetopicSet.PastingDiagram.nonDegeneratePastingDiagram(
             UnnamedOpetope.OpetopicInteger(2),
             {UnnamedOpetope.Address.epsilon(1): "a"})
 def setUp(self):
     self.type_point = UnnamedOpetopicSet.Type(
         UnnamedOpetopicSet.PastingDiagram.point(), None)
     self.a = UnnamedOpetopicSet.Variable("a", UnnamedOpetope.Point())
     self.b = UnnamedOpetopicSet.Variable("b", UnnamedOpetope.Point())
     self.c = UnnamedOpetopicSet.Variable("c", UnnamedOpetope.Point())
     self.d = UnnamedOpetopicSet.Variable("d", UnnamedOpetope.Point())
     self.ab = UnnamedOpetopicSet.Variable("ab", UnnamedOpetope.Arrow())
     self.ac = UnnamedOpetopicSet.Variable("ac", UnnamedOpetope.Arrow())
     self.bc = UnnamedOpetopicSet.Variable("bc", UnnamedOpetope.Arrow())
     self.cd = UnnamedOpetopicSet.Variable("cd", UnnamedOpetope.Arrow())
     self.seq = UnnamedOpetopicSet.Sequent()
     self.seq.context = UnnamedOpetopicSet.Context() + \
         UnnamedOpetopicSet.Typing(self.a, self.type_point) + \
         UnnamedOpetopicSet.Typing(self.b, self.type_point) + \
         UnnamedOpetopicSet.Typing(self.c, self.type_point) + \
         UnnamedOpetopicSet.Typing(self.d, self.type_point) + \
         UnnamedOpetopicSet.Typing(
             self.ab, self.type_arrow("a", self.b)) + \
         UnnamedOpetopicSet.Typing(
             self.ac, self.type_arrow("a", self.c)) + \
         UnnamedOpetopicSet.Typing(
             self.bc, self.type_arrow("b", self.c)) + \
         UnnamedOpetopicSet.Typing(
             self.cd, self.type_arrow("c", self.d))
Exemple #13
0
 def setUp(self):
     self.a = UnnamedOpetope.Preopetope(-1)
     self.b = UnnamedOpetope.Preopetope(0)
     self.c = UnnamedOpetope.Preopetope.fromDictOfPreopetopes(
         {UnnamedOpetope.Address.epsilon(0): self.b})
     self.d = UnnamedOpetope.Preopetope.degenerate(self.b)
     self.e = UnnamedOpetope.Preopetope.fromDictOfPreopetopes(
         {UnnamedOpetope.Address.epsilon(1): self.c})
     self.f = UnnamedOpetope.Preopetope.fromDictOfPreopetopes({
         UnnamedOpetope.Address.epsilon(1):
         self.c,
         UnnamedOpetope.Address.fromList(['*'], 1):
         self.c
     })
Exemple #14
0
def point(seq: Sequent, name: Union[str, List[str]]) -> Sequent:
    """
    The :math:`\\textbf{OptSet${}^?$}` :math:`\\texttt{point}` rule.

    * If argument ``name`` is a ``str``, creates a new point with that name
      (this is just the :math:`\\texttt{point}`);
    * if it is a list of ``str``, then creates as many points.

    """
    if isinstance(name, list):
        res = seq
        for n in name:
            res = point(res, n)
        return res
    elif isinstance(name, str):
        if seq.pastingDiagram is not None:
            raise DerivationError("point rule",
                                  "Sequent cannot have a pasting diagram")
        var = Variable(name, UnnamedOpetope.Point())
        if var in seq.context:
            raise DerivationError(
                "point rule",
                "Point shaped variable {name} is already typed in context "
                "{ctx}",
                name=name,
                ctx=str(seq.context))
        res = deepcopy(seq)
        res.context = res.context + Typing(var,
                                           Type(PastingDiagram.point(), None))
        return res
    else:
        raise DerivationError(
            "point rule",
            "Argument name is expected to be a str or list of str")
Exemple #15
0
 def test_substitution(self):
     i2 = UnnamedOpetope.Preopetope.fromDictOfPreopetopes({
         UnnamedOpetope.Address.epsilon(1):
         self.c,
         UnnamedOpetope.Address.fromList(['*'], 1):
         self.c
     })
     i4 = UnnamedOpetope.Preopetope.fromDictOfPreopetopes({
         UnnamedOpetope.Address.epsilon(1):
         self.c,
         UnnamedOpetope.Address.fromList(['*'], 1):
         self.c,
         UnnamedOpetope.Address.fromList(['*', '*'], 1):
         self.c,
         UnnamedOpetope.Address.fromList(['*', '*', '*'], 1):
         self.c
     })
     i5 = UnnamedOpetope.Preopetope.fromDictOfPreopetopes({
         UnnamedOpetope.Address.epsilon(1):
         self.c,
         UnnamedOpetope.Address.fromList(['*'], 1):
         self.c,
         UnnamedOpetope.Address.fromList(['*', '*'], 1):
         self.c,
         UnnamedOpetope.Address.fromList(['*', '*', '*'], 1):
         self.c,
         UnnamedOpetope.Address.fromList(['*', '*', '*', '*'], 1):
         self.c
     })
     ctx = UnnamedOpetope.Context(2) + (UnnamedOpetope.Address.fromList(
         ['*', '*'], 1), UnnamedOpetope.Address.epsilon(0))
     self.assertEqual(
         UnnamedOpetope.Preopetope.substitution(
             i4, UnnamedOpetope.Address.fromList(['*', '*'], 1), ctx, i2),
         i5)
 def __str__(self) -> str:
     srcstr = str()
     if self.source.degeneracy is None:
         if self.source.nodes is None:
             raise RuntimeError("[Pasting diagram, to string] Both the "
                                "degeneracy and node dict of the pasting "
                                "diagram are None. In valid derivations, "
                                "this should not happen")
         if self.source.shape == UnnamedOpetope.point().source:
             srcstr = "⧫"
         else:
             lines = []  # type: List[str]
             for addr in self.source.nodes.keys():
                 if self.isSourceUniversal(addr):
                     lines += [
                         str(addr) + " ← ∀" + str(self.source.nodes[addr])
                     ]
                 else:
                     lines += [
                         str(addr) + " ← " + str(self.source.nodes[addr])
                     ]
             srcstr = "{" + ", ".join(lines) + "}"
     else:
         srcstr = "{{" + str(self.source.degeneracy) + "}}"
     if self.isTargetUniversal():
         return srcstr + " → ∀" + str(self.target)
     else:
         return srcstr + " → " + str(self.target)
 def setUp(self):
     self.a = UnnamedOpetopicSet.Variable("a", UnnamedOpetope.Arrow())
     self.b = UnnamedOpetopicSet.Variable("b", UnnamedOpetope.Arrow())
     self.i1 = UnnamedOpetopicSet.Variable(
         "i1", UnnamedOpetope.OpetopicInteger(1))
     self.i2 = UnnamedOpetopicSet.Variable(
         "i2", UnnamedOpetope.OpetopicInteger(2))
     self.i3 = UnnamedOpetopicSet.Variable(
         "i3", UnnamedOpetope.OpetopicInteger(3))
     self.c = UnnamedOpetopicSet.Variable(
         "c",
         UnnamedOpetope.Graft(
             UnnamedOpetope.Shift(UnnamedOpetope.OpetopicInteger(2)),
             UnnamedOpetope.OpetopicInteger(2),
             UnnamedOpetope.Address.fromList([['*']], 2)))
 def type_arrow(
         self, src: str,
         tgt: UnnamedOpetopicSet.Variable) -> UnnamedOpetopicSet.Type:
     """
     Convenient function to define the type of an arrow shaped cell
     """
     return UnnamedOpetopicSet.Type(
         UnnamedOpetopicSet.PastingDiagram.nonDegeneratePastingDiagram(
             UnnamedOpetope.Arrow(),
             {UnnamedOpetope.Address.epsilon(0): src}), tgt)
 def test_shift(self):
     s = UnnamedOpetopicSet.graft(
         self.seq,
         UnnamedOpetopicSet.PastingDiagram.nonDegeneratePastingDiagram(
             UnnamedOpetope.OpetopicInteger(1),
             {UnnamedOpetope.Address.epsilon(1): "ac"}))
     with self.assertRaises(DerivationError):
         UnnamedOpetopicSet.shift(s, "ab", "A")
     with self.assertRaises(DerivationError):
         UnnamedOpetopicSet.shift(s, "bc", "A")
     UnnamedOpetopicSet.shift(s, "ac", "A")
Exemple #20
0
def degen(seq: Sequent, name: str) -> Sequent:
    """
    The :math:`\\textbf{OptSet${}^?$}` :math:`\\texttt{degen}` rule.
    """
    if seq.pastingDiagram is not None:
        raise DerivationError("degen rule",
                              "Sequent cannot have a pasting diagram")
    res = deepcopy(seq)
    res.pastingDiagram = PastingDiagram.degeneratePastingDiagram(
        UnnamedOpetope.Degen(seq.context[name].variable.shapeProof), name)
    return res
Exemple #21
0
 def test_graft(self):
     i2 = UnnamedOpetope.OpetopicInteger(2).eval()
     i3 = UnnamedOpetope.OpetopicInteger(3).eval()
     s = UnnamedOpetope.shift(i3)
     s = UnnamedOpetope.graft(s, i2,
                              UnnamedOpetope.Address.fromList([['*']], 2))
     s = UnnamedOpetope.graft(
         s, i2, UnnamedOpetope.Address.fromList([['*', '*']], 2))
     r = s.context
     self.assertEqual(r(UnnamedOpetope.Address.fromList([[]], 2)),
                      UnnamedOpetope.Address.fromList([], 1))
     self.assertEqual(r(UnnamedOpetope.Address.fromList([['*'], []], 2)),
                      UnnamedOpetope.Address.fromList(['*'], 1))
     self.assertEqual(r(UnnamedOpetope.Address.fromList([['*'], ['*']], 2)),
                      UnnamedOpetope.Address.fromList(['*', '*'], 1))
     self.assertEqual(
         r(UnnamedOpetope.Address.fromList([['*', '*'], []], 2)),
         UnnamedOpetope.Address.fromList(['*', '*', '*'], 1))
     self.assertEqual(
         r(UnnamedOpetope.Address.fromList([['*', '*'], ['*']], 2)),
         UnnamedOpetope.Address.fromList(['*', '*', '*', '*'], 1))
Exemple #22
0
 def __str__(self) -> str:
     if self.degeneracy is None:
         if self.nodes is None:
             raise RuntimeError("[Pasting diagram, to string] Both the "
                                "degeneracy and node dict of the pasting "
                                "diagram are None. In valid derivations, "
                                "this should not happen")
         if self.shape == UnnamedOpetope.point().source:
             return "⧫"
         else:
             lines = [
                 str(addr) + " ← " + str(self.nodes[addr])
                 for addr in self.nodes.keys()
             ]
             return "{" + ", ".join(lines) + "}"
     else:
         return "{{" + str(self.degeneracy) + "}}"
Exemple #23
0
 def toTex(self) -> str:
     if self.degeneracy is None:
         if self.nodes is None:
             raise RuntimeError("[Pasting diagram, to TeX] Both the "
                                "degeneracy and node dict of the pasting "
                                "diagram are None. In valid derivations, "
                                "this should not happen")
         if self.shape == UnnamedOpetope.point().source:
             return "\\optZero"
         else:
             lines = [
                 addr.toTex() + " \\sep " + self.nodes[addr]
                 for addr in self.nodes.keys()
             ]
             return "\\opetope{" + " \\\\ ".join(lines) + "}"
     else:
         return "\\degenopetope{" + self.degeneracy + "}"
Exemple #24
0
 def target(self, name: str) -> str:
     """
     Returns the target of the variable whose name is ``name``.
     """
     res = self[name].type.target
     if self[name].type.source.shape == \
             UnnamedOpetope.Point().eval().source:
         raise DerivationError(
             "Context, target of variable",
             "Variable {var} is a point, and do not have a target",
             var=name)
     elif res is None:
         raise RuntimeError(
             "[Context, target of variable] Variable {var} "
             "is not a point, but has no target. In valid "
             "derivations, this should not happen".format(var=name))
     return res.name
Exemple #25
0
 def __init__(self, source: PastingDiagram,
              target: Optional[Variable]) -> None:
     if target is None:
         if source.shape != UnnamedOpetope.Point().eval().source:
             raise DerivationError(
                 "Type, creation",
                 "Source pasting diagram is not a point, but target is "
                 "unspecified")
     elif source.shapeTarget() != target.shape:
         raise DerivationError(
             "Type, creation",
             "Target variable {var} has shape {shape}, should have "
             "{should}",
             var=str(target),
             shape=target.shape,
             should=source.shapeTarget())
     self.source = source
     self.target = target
 def test_shapeTarget(self):
     self.assertEqual(self.a.shapeTarget(),
                      UnnamedOpetope.Point().eval().source)
     self.assertEqual(self.b.shapeTarget(),
                      UnnamedOpetope.Point().eval().source)
     self.assertEqual(self.i1.shapeTarget(),
                      UnnamedOpetope.Arrow().eval().source)
     self.assertEqual(self.i2.shapeTarget(),
                      UnnamedOpetope.Arrow().eval().source)
     self.assertEqual(self.i3.shapeTarget(),
                      UnnamedOpetope.Arrow().eval().source)
     self.assertEqual(self.c.shapeTarget(),
                      UnnamedOpetope.OpetopicInteger(3).eval().source)
Exemple #27
0
 def setUp(self):
     self.a = UnnamedOpetope.Context(0)
     self.b = UnnamedOpetope.Context(2)
     self.c = UnnamedOpetope.Context(2) + \
         (UnnamedOpetope.Address.epsilon(1),
             UnnamedOpetope.Address.epsilon(0))
     self.d = UnnamedOpetope.Context(2) + \
         (UnnamedOpetope.Address.fromList(['*'], 1),
             UnnamedOpetope.Address.epsilon(0))
     self.e = UnnamedOpetope.Context(3) + \
         (UnnamedOpetope.Address.epsilon(2),
             UnnamedOpetope.Address.fromList(['*'], 1))
     self.f = UnnamedOpetope.Context(3) + \
         (UnnamedOpetope.Address.epsilon(1).shift(),
             UnnamedOpetope.Address.epsilon(1))
Exemple #28
0
 def test_shift(self):
     s1 = UnnamedOpetope.shift(UnnamedOpetope.point())
     s2 = UnnamedOpetope.shift(s1)
     self.assertEqual(
         s2.context,
         UnnamedOpetope.Context(2) +
         (UnnamedOpetope.Address.epsilon(0).shift(),
          UnnamedOpetope.Address.epsilon(0)))
     p = UnnamedOpetope.Preopetope.point()
     a = UnnamedOpetope.Preopetope(1)
     a.nodes[UnnamedOpetope.Address.epsilon(0)] = p
     g = UnnamedOpetope.Preopetope(2)
     g.nodes[UnnamedOpetope.Address.epsilon(1)] = a
     self.assertEqual(s1.source, a)
     self.assertEqual(s1.target, p)
     self.assertEqual(s2.source, g)
     self.assertEqual(s2.target, a)
def suniv(seq: UnnamedOpetopicSet.Sequent, suCellName: str, cellName: str,
          addr: UnnamedOpetope.Address, factorizationName: str,
          fillerName: str) -> UnnamedOpetopicSet.Sequent:
    """
    From

    * an address :math:`[p]` (argument ``addr``);
    * a cell :math:`\\alpha : \\forall_{[p]} \\mathbf{P} \\longrightarrow u`
      (with name ``suCellName``);
    * a cell :math:`\\beta : \\mathbf{P'} \\longrightarrow u` (with name
      ``cellName``), where :math:`\\mathbf{P'}` is :math:`\\mathbf{P}` except
      at address :math:`[p]` where it is :math:`s`;

    applies the source universal property of :math:`\\alpha` at :math:`[p]`
    over :math:`\\beta`, thus creating

    * a factorization cell :math:`\\xi : s \\longrightarrow \\mathsf{s}_{[p]}
      \\mathbf{P}`;
    * a filler :math:`A`, target universal, and source universal at
      :math:`\\xi`, i.e. at address :math:`[[p]]`.
    """

    # Inits
    alphatype = seq.context[suCellName].type
    betatype = seq.context[cellName].type
    P = alphatype.source
    Q = betatype.source
    u = alphatype.target

    # Checks & inits
    if seq.pastingDiagram is not None:
        raise DerivationError(
            "Apply source univ. prop.",
            "Sequent expected to not type a pasting diagram")
    elif u is None:
        raise RuntimeError("[Apply source univ. prop.] Source universal cell "
                           "{sucell} is a point. In valid derivations, this "
                           "should not happen".format(sucell=suCellName))
    elif P.nodes is None:
        raise DerivationError(
            "Apply source univ. prop.",
            "Source universal cell {sucell} cannot be degenerate",
            sucell=suCellName)
    elif Q.nodes is None:
        raise DerivationError("Apply source univ. prop.",
                              "Cell {cell} cannot be degenerate",
                              cell=cellName)
    elif addr not in P.nodes.keys():
        raise DerivationError("Apply source univ. prop.",
                              "Address {addr} not in source of {sucell}",
                              addr=addr,
                              sucell=suCellName)
    elif betatype.target != u:
        raise DerivationError(
            "Apply source univ. prop.",
            "Cells {sucell} and {cell} are not compatible: targets differ",
            cell=cellName,
            sucell=suCellName)
    elif P.nodes.keys() != Q.nodes.keys():
        raise DerivationError(
            "Apply source univ. prop.",
            "Cells {sucell} and {cell} are not compatible: source pasting "
            "diagrams do not have the same addresses",
            cell=cellName,
            sucell=suCellName)
    for a in P.nodes.keys():
        if a != addr and P.nodes[a] != Q.nodes[a]:
            raise DerivationError(
                "Apply source univ. prop.",
                "Cells {sucell} and {cell} are not compatible: source pasting "
                "diagrams do not agree on address {a}",
                cell=cellName,
                sucell=suCellName,
                a=a)

    # Derive xi
    xishapeproof = seq.context[Q.source(addr)].type.source.shapeProof
    res = UnnamedOpetopicSet.graft(
        seq,
        UnnamedOpetopicSet.pastingDiagram(UnnamedOpetope.Shift(xishapeproof), {
            UnnamedOpetope.address([], Q.shape.dimension - 1):
            Q.source(addr)
        }))
    res = UnnamedOpetopicSet.shift(res, P.source(addr), factorizationName)

    # Derive A
    omega = UnnamedOpetope.Graft(UnnamedOpetope.Shift(P.shapeProof),
                                 UnnamedOpetope.Shift(xishapeproof),
                                 addr.shift())
    res = UnnamedOpetopicSet.graft(
        res,
        UnnamedOpetopicSet.pastingDiagram(
            omega, {
                UnnamedOpetope.address([], P.shape.dimension): suCellName,
                addr.shift(): factorizationName
            }))
    res = UnnamedOpetopicSet.shift(res, cellName, fillerName)

    # Mark A as source universal at xi and target universal
    rawFillerType = res.context[fillerName].type
    fillerType = Type(rawFillerType.source, rawFillerType.target)
    fillerType.targetUniversal = True
    fillerType.sourceUniversal.add(addr.shift())
    res.context[fillerName].type = fillerType

    # Done
    return res
def tuniv(seq: UnnamedOpetopicSet.Sequent, tuCell: str, cell: str,
          factorizationName: str,
          fillerName: str) -> UnnamedOpetopicSet.Sequent:
    """
    From a target universal cell :math:`\\alpha : \\mathbf{P} \\longrightarrow
    t` (whose name is ``tuCell``), and another cell :math:`\\beta : \\mathbf{P}
    \\longrightarrow u`, creates the universal factorization.
    """
    # Inits
    typealpha = seq.context[tuCell].type
    typebeta = seq.context[cell].type
    P = typealpha.source
    targetalpha = typealpha.target
    targetbeta = typebeta.target

    # Checks
    if seq.pastingDiagram is not None:
        raise DerivationError("Apply target univ. prop.",
                              "Sequent cannot type a pasting diagram")
    elif not isTargetUniversal(typealpha):
        raise DerivationError("Apply target univ. prop.",
                              "First cell is expected to be target universal")
    elif typebeta.source != P:
        raise DerivationError(
            "Apply target univ. prop.",
            "Cells are expected to have the same source pasting diagram")
    elif targetalpha is None or targetbeta is None:
        raise RuntimeError(
            "[Apply target univ. prop.] Target universal cell is a point. In "
            "valid derivations, this should not happen")

    # Derive the factorization cell
    n = targetalpha.shape.dimension
    res = UnnamedOpetopicSet.graft(
        deepcopy(seq),
        UnnamedOpetopicSet.pastingDiagram(
            UnnamedOpetope.Shift(targetalpha.shapeProof),
            {UnnamedOpetope.address([], n): targetalpha.name}))
    res = UnnamedOpetopicSet.shift(res, targetbeta.name, factorizationName)

    # Derive the filler
    res = UnnamedOpetopicSet.graft(
        res,
        UnnamedOpetopicSet.pastingDiagram(
            UnnamedOpetope.Graft(
                UnnamedOpetope.Shift(
                    UnnamedOpetope.Shift(targetalpha.shapeProof)),
                P.shapeProof, UnnamedOpetope.address([[]], n + 1)), {
                    UnnamedOpetope.address([], n + 1): factorizationName,
                    UnnamedOpetope.address([[]], n + 1): tuCell
                }))
    res = UnnamedOpetopicSet.shift(res, cell, fillerName)

    # Mark the filler as target universal and source universal at the facto.
    rawFillerType = res.context[fillerName].type
    fillerType = Type(rawFillerType.source, rawFillerType.target)
    fillerType.targetUniversal = True
    fillerType.sourceUniversal.add(UnnamedOpetope.address([], n + 1))
    res.context[fillerName].type = fillerType

    # Done
    return res