def normal_form(diagram, normalizer=None, **params): """ Applies normal form to a pregroup diagram of the form `word @ ... @ word >> cups` by normalising the words and the sentences seperately before combining them, so it can be drawn using `grammar.draw`. """ words, is_pregroup = Id(Ty()), True for _, box, right in diagram.layers: if isinstance(box, Word): if right: # word boxes should be tensored left to right. is_pregroup = False break words = words @ box else: break wires = diagram[len(words):] is_pregroup = is_pregroup and all( isinstance(box, Cup) or isinstance(box, Swap) or isinstance(box, Cap) for box in wires.boxes) if not is_pregroup: raise ValueError(messages.expected_pregroup()) norm = lambda d: monoidal.Diagram.normal_form( d, normalizer=normalizer or Diagram.normalize, **params) return norm(words) >> norm(wires)
def draw(diagram, **params): """ Draws a pregroup diagram, i.e. of shape :code:`word @ ... @ word >> cups`. Parameters ---------- width : float, optional Width of the word triangles, default is :code:`2.0`. space : float, optional Space between word triangles, default is :code:`0.5`. textpad : pair of floats, optional Padding between text and wires, default is :code:`(0.1, 0.2)`. draw_type_labels : bool, optional Whether to draw type labels, default is :code:`True`. aspect : string, optional Aspect ratio, one of :code:`['equal', 'auto']`. margins : tuple, optional Margins, default is :code:`(0.05, 0.05)`. fontsize : int, optional Font size for the words, default is :code:`12`. fontsize_types : int, optional Font size for the types, default is :code:`12`. figsize : tuple, optional Figure size. path : str, optional Where to save the image, if :code:`None` we call :code:`plt.show()`. pretty_types : bool, optional Whether to draw type labels with superscript, default is :code:`False`. triangles : bool, optional Whether to draw words as triangular states, default is :code:`False`. Raises ------ ValueError Whenever the input is not a pregroup diagram. """ from discopy.rigid import Swap if not isinstance(diagram, Diagram): raise TypeError(messages.type_err(Diagram, diagram)) words, is_pregroup = Id(Ty()), True for _, box, right in diagram.layers: if isinstance(box, Word): if right: # word boxes should be tensored left to right. is_pregroup = False break words = words @ box else: break cups = diagram[len(words):].foliation().boxes\ if len(words) < len(diagram) else [] is_pregroup = is_pregroup and words and all( isinstance(box, Cup) or isinstance(box, Swap) for s in cups for box in s.boxes) if not is_pregroup: raise ValueError(messages.expected_pregroup()) drawing.pregroup_draw(words, cups, **params)
def test_pregroup_draw_errors(): n = Ty('n') with raises(TypeError): draw(0) with raises(ValueError) as err: draw(Cap(n, n.l)) with raises(ValueError) as err: draw(Cup(n, n.r)) with raises(ValueError) as err: draw(Word('Alice', n) >> Word('Alice', n) @ Id(n)) assert str(err.value) is messages.expected_pregroup()
def draw(diagram, **params): """ Draws a pregroup diagram, i.e. one slice of word boxes followed by any number of slices of cups. Parameters ---------- width : float, optional Width of the word triangles, default is :code:`2.0`. space : float, optional Space between word triangles, default is :code:`0.5`. textpad : pair of floats, optional Padding between text and wires, default is :code:`(0.1, 0.2)`. draw_types : bool, optional Whether to draw type labels, default is :code:`True`. aspect : string, optional Aspect ratio, one of :code:`['equal', 'auto']`. margins : tuple, optional Margins, default is :code:`(0.05, 0.05)`. fontsize : int, optional Font size for the words, default is :code:`12`. fontsize_types : int, optional Font size for the types, default is :code:`12`. figsize : tuple, optional Figure size. path : str, optional Where to save the image, if `None` we call :code:`plt.show()`. Raises ------ ValueError Whenever the input is not a pregroup diagram. """ if not isinstance(diagram, Diagram): raise TypeError(messages.type_err(Diagram, diagram)) words, *cups = diagram.foliation().boxes is_pregroup = all(isinstance(box, Word) for box in words.boxes)\ and all(isinstance(box, Cup) for s in cups for box in s.boxes) if not is_pregroup: raise ValueError(messages.expected_pregroup()) drawing.pregroup_draw(words, cups, **params)