Skip to content

math_spec.typesetting.format

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

The split, and each module's role in it, are in README.md beside this file.

NOTATIONS = frozenset(get_args(Notation)) module-attribute #

Notation = Literal['latex', 'typst'] module-attribute #

OPERATOR_NAMES = frozenset(get_args(OperatorName)) module-attribute #

OPERATOR_SPELLINGS = {'cdot': ('\\cdot', 'dot'), 'plus': ('+', '+'), 'minus': ('-', '-'), 'equal': ('=', '='), 'le': ('\\le', '<='), 'ge': ('\\ge', '>='), 'lt': ('<', '<'), 'gt': ('>', '>'), 'ne': ('\\neq', '!='), 'in': ('\\in', 'in'), 'and': ('\\wedge', 'and'), 'or': ('\\vee', 'or'), 'not': ('\\neg', 'not'), 'false': ('\\bot', 'bot'), 'forall': ('\\forall\\,', 'forall'), 'such_that': ('\\,:\\,', 'colon'), 'infinity': ('\\infty', 'infinity'), 'cyclic_minus': ('\\ominus', 'minus.o'), 'cyclic_plus': ('\\oplus', 'plus.o'), 'edge_minus': ('\\boxminus', 'minus.square'), 'edge_plus': ('\\boxplus', 'plus.square'), 'times': ('\\times', 'times'), 'maps_to': ('\\to', 'arrow.r'), 'reals': ('\\mathbb{R}', 'RR'), 'integers': ('\\mathbb{Z}', 'ZZ'), 'binary_set': ('\\{0, 1\\}', '{0, 1}'), 'sos_set': ('\\mathrm{SOS}', 'upright("SOS")'), 'position': ('\\mathrm{pos}', 'upright("pos")'), 'dual': ('\\lambda', 'lambda'), 'minimize': ('\\min', 'min'), 'maximize': ('\\max', 'max')} module-attribute #

OperatorName = Literal['cdot', 'plus', 'minus', 'equal', 'le', 'ge', 'lt', 'gt', 'ne', 'in', 'and', 'or', 'not', 'false', 'forall', 'such_that', 'infinity', 'cyclic_minus', 'cyclic_plus', 'edge_minus', 'edge_plus', 'times', 'maps_to', 'reals', 'integers', 'binary_set', 'sos_set', 'position', 'dual', 'minimize', 'maximize'] module-attribute #

Entry(symbol, meaning) dataclass #

One legend row: a symbol, and everything opposite it as one string.

meaning instance-attribute #

symbol instance-attribute #

Format #

Bases: Protocol

How one output format spells what a walk emits.

cases_row class-attribute #

dash class-attribute #

notation class-attribute #

operators class-attribute #

apply(function, argument) #

A function applied to an argument: f(x).

Source code in src/math_spec/typesetting/format.py
def apply(self, function: str, argument: str) -> str:
    """A function applied to an argument: ``f(x)``."""
    ...

cardinality(inner) #

An absolute-value fence: |x|.

Source code in src/math_spec/typesetting/format.py
def cardinality(self, inner: str) -> str:
    """An absolute-value fence: ``|x|``."""
    ...

cases(arms) #

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

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

document(blocks, *, standalone) #

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

equations(lines, *, numbered) #

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

escape(prose) #

Author prose — a description: — made safe for this format's text mode.

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

fraction(numerator, denominator) #

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

glossary(title, entries) #

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

greek(name) #

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

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

italic(name) #

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

Source code in src/math_spec/typesetting/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/typesetting/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/typesetting/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/typesetting/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/typesetting/format.py
def note(self, text: str) -> str:
    """A paragraph of plain prose between blocks."""
    ...

parenthesise(inner) #

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

prose(text) #

Words inside math.

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

quoted(label) #

A string value as the file spells it — quoted, so a label reads as data rather than a name.

Source code in src/math_spec/typesetting/format.py
def quoted(self, label: str) -> str:
    """A string value as the file spells it — quoted, so a label reads as data rather than a name."""
    ...

script(letter) #

A set symbol.

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

section(title, body) #

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

subscript(base, indices) #

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

summation(domain, body) #

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

superscript(base, tail) #

Source code in src/math_spec/typesetting/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/typesetting/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 #

aligned_rows(lines, fmt, *, gap) #

One alignment row per line — label, left, right, condition — gap around the relation, trailing empty cells stripped.

Source code in src/math_spec/typesetting/format.py
def aligned_rows(lines: list[Line], fmt: Format, *, gap: str) -> list[str]:
    """One alignment row per line — label, left, right, condition — *gap* around the relation, trailing empty cells stripped."""
    return [
        f'{fmt.prose(line.label) if line.label else ""}{gap}{line.left} & {line.right}{gap}{line.condition}'.rstrip(
            ' &'
        )
        for line in lines
    ]

paragraphs(blocks) #

blocks separated by blank lines, ending in a newline.

Source code in src/math_spec/typesetting/format.py
def paragraphs(blocks: list[str]) -> str:
    """*blocks* separated by blank lines, ending in a newline."""
    return '\n\n'.join(blocks) + '\n'