Skip to content

math_spec.typeset.format

The seam between what a model says and how a format spells it.

One walk, many formats — the split relational/sinks/ makes at the other end of the pipeline. :mod:math_spec.typeset.walk decides where a bracket is needed, which dimension a reduction binds and where a mask belongs; a :class:Format decides only that a sum is \sum_{…} or sum_(…).

Two rules make the split hold:

  • Everything a walk emits is bare math. No $, no environment; a format wraps it with :meth:Format.math to embed it in prose, so the walk never knows which mode it is in.
  • A format spells; it never decides. No method takes an AST node or a schema. If a format had to look at the model, the question belongs in the walk.

OPERATOR_NAMES = frozenset({'cdot', 'plus', 'minus', 'equal', 'le', 'ge', 'lt', 'gt', 'ne', 'in', 'and', 'or', 'not', 'true', 'false', 'forall', 'such_that', 'infinity', 'minus_infinity', 'cyclic_minus', 'cyclic_plus', 'edge_minus', 'edge_plus', 'times', 'maps_to', 'reals', 'integers', 'binary_set', 'sos_set', 'position', 'minimize', 'maximize'}) module-attribute #

Entry(symbol, name, detail='', description='') dataclass #

One legend row: a symbol, the name it stands for, and what it is.

description = '' class-attribute instance-attribute #

detail = '' class-attribute instance-attribute #

name instance-attribute #

symbol instance-attribute #

meaning(dash) #

Everything opposite the symbol, as one string.

What the row says is the walk's answer, not a spelling, so the three formats differ only in the table cell they put it in — and in how they spell the dash between a name and its description, which is the one piece of punctuation here that is not the same in all three.

Source code in src/math_spec/typeset/format.py
def meaning(self, dash: str) -> str:
    """Everything opposite the symbol, as one string.

    What the row *says* is the walk's answer, not a spelling, so the three
    formats differ only in the table cell they put it in — and in how
    they spell the dash between a name and its description, which is the
    one piece of punctuation here that is not the same in all three.
    """
    return f'{self.name}{self.detail}' + (f' {dash} {self.description}' if self.description else '')

Format #

Bases: Protocol

How one output format spells what a walk emits.

dash class-attribute #

notation class-attribute #

operators class-attribute #

suffix class-attribute #

apply(function, argument) #

A coordinate map applied to an index: bus(g).

Source code in src/math_spec/typeset/format.py
def apply(self, function: str, argument: str) -> str:
    """A coordinate map applied to an index: ``bus(g)``."""
    ...

cardinality(inner) #

How many members a set has: |T|.

A fence rather than an entry in :data:OPERATOR_NAMES, which is a vocabulary of infix spellings — tests/typeset/test_typeset.py compiles every one of them between two operands.

Source code in src/math_spec/typeset/format.py
def cardinality(self, inner: str) -> str:
    """How many members a set has: ``|T|``.

    A fence rather than an entry in :data:`OPERATOR_NAMES`, which is a
    vocabulary of *infix* spellings — ``tests/typeset/test_typeset.py``
    compiles every one of them between two operands.
    """
    ...

cases(arms) #

A value defined by region: (value, condition) per arm.

The arms partition the frame, so every one carries a condition and there is no otherwise-arm to print last. They arrive in the order the file declares them and print in it — nothing depends on the order, but a reader comparing the page to the file does.

Source code in src/math_spec/typeset/format.py
def cases(self, arms: list[tuple[str, str]]) -> str:
    """A value defined by region: ``(value, condition)`` per arm.

    The arms partition the frame, so every one carries a condition and
    there is no otherwise-arm to print last. They arrive in the order the
    file declares them and print in it — nothing depends on the order, but
    a reader comparing the page to the file does.
    """
    ...

document(blocks, *, standalone) #

Source code in src/math_spec/typeset/format.py
def document(self, blocks: list[str], *, standalone: bool) -> str: ...

equations(lines, *, numbered) #

Source code in src/math_spec/typeset/format.py
def equations(self, lines: list[Line], *, numbered: bool) -> str: ...

escape(prose) #

Author prose, made safe for this format's text mode.

Every other atom escapes as it wraps, so what passes through here is what arrives already being prose — a description:. Not :meth:prose, which is words inside math, and not :meth:note, which is handed generated markup too.

Source code in src/math_spec/typeset/format.py
def escape(self, prose: str) -> str:
    """Author prose, made safe for this format's text mode.

    Every other atom escapes as it wraps, so what passes through here is
    what arrives already being prose — a ``description:``. Not
    :meth:`prose`, which is words *inside* math, and not :meth:`note`,
    which is handed generated markup too.
    """
    ...

fraction(numerator, denominator) #

Source code in src/math_spec/typeset/format.py
def fraction(self, numerator: str, denominator: str) -> str: ...

glossary(title, entries) #

Source code in src/math_spec/typeset/format.py
def glossary(self, title: str, entries: list[Entry]) -> str: ...

greek(name) #

A name that is a Greek letter, set as the letter.

The walk decides which names those are; a format only spells one. Lower-case names only — every one of them has a letter in both notations, which the capitals do not.

Source code in src/math_spec/typeset/format.py
def greek(self, name: str) -> str:
    """A name that *is* a Greek letter, set as the letter.

    The walk decides which names those are; a format only spells one.
    Lower-case names only — every one of them has a letter in both
    notations, which the capitals do not.
    """
    ...

italic(name) #

A multi-letter name, set as one italic symbol rather than a product.

Source code in src/math_spec/typeset/format.py
def italic(self, name: str) -> str:
    """A multi-letter name, set as one italic symbol rather than a product."""
    ...

joined(parts, operator) #

a op b op c — the one place inter-term spacing is decided.

Source code in src/math_spec/typeset/format.py
def joined(self, parts: list[str], operator: str) -> str:
    """``a op b op c`` — the one place inter-term spacing is decided."""
    ...

math(expression) #

Wrap bare math for embedding in prose.

Source code in src/math_spec/typeset/format.py
def math(self, expression: str) -> str:
    """Wrap bare math for embedding in prose."""
    ...

mono(text) #

A name exactly as the YAML spells it.

Source code in src/math_spec/typeset/format.py
def mono(self, text: str) -> str:
    """A name exactly as the YAML spells it."""
    ...

note(text) #

A paragraph of plain prose between blocks.

Source code in src/math_spec/typeset/format.py
def note(self, text: str) -> str:
    """A paragraph of plain prose between blocks."""
    ...

parenthesise(inner) #

Source code in src/math_spec/typeset/format.py
def parenthesise(self, inner: str) -> str: ...

prose(text) #

Words inside math.

Source code in src/math_spec/typeset/format.py
def prose(self, text: str) -> str:
    """Words inside math."""
    ...

script(letter) #

A set symbol.

Source code in src/math_spec/typeset/format.py
def script(self, letter: str) -> str:
    """A set symbol."""
    ...

section(title, body) #

Source code in src/math_spec/typeset/format.py
def section(self, title: str, body: str) -> str: ...

subscript(base, indices) #

Source code in src/math_spec/typeset/format.py
def subscript(self, base: str, indices: list[str]) -> str: ...

summation(domain, body) #

Source code in src/math_spec/typeset/format.py
def summation(self, domain: str, body: str) -> str: ...

superscript(base, tail) #

Source code in src/math_spec/typeset/format.py
def superscript(self, base: str, tail: str) -> str: ...

upright(name) #

A qualifier or a function name — upright, because it is not a variable.

Source code in src/math_spec/typeset/format.py
def upright(self, name: str) -> str:
    """A qualifier or a function name — upright, because it is not a variable."""
    ...

Glossary(title, entries) dataclass #

One legend section: its title, and the entries under it.

entries instance-attribute #

title instance-attribute #

Line(label, left, right, condition='') dataclass #

One typeset line of the model, split where a format may align it.

left and right are the two sides of a relation — right carries the relation symbol, so a format aligns on the boundary between them without having to parse anything back out.

condition = '' class-attribute instance-attribute #

label instance-attribute #

left instance-attribute #

right instance-attribute #