Skip to content

math_spec.typeset.latex

LaTeX (amsmath). The format that lands in a journal.

Verbose source and a toolchain to compile it, in exchange for being the one target a paper actually accepts. CI compiles every example with a two-package TeX, which is also a check that the preamble stays installable from a small one.

CASES_ROW = ' \\\\ ' module-attribute #

LatexFormat #

See :class:math_spec.typeset.format.Format.

dash = '---' class-attribute #

notation = 'latex' class-attribute #

operators = {'cdot': '\\cdot', 'plus': '+', 'minus': '-', 'equal': '=', 'le': '\\le', 'ge': '\\ge', 'lt': '<', 'gt': '>', 'ne': '\\neq', 'in': '\\in', 'and': '\\wedge', 'or': '\\vee', 'not': '\\neg', 'true': '\\top', 'false': '\\bot', 'forall': '\\forall\\,', 'such_that': '\\,:\\,', 'infinity': '\\infty', 'minus_infinity': '-\\infty', 'cyclic_minus': '\\ominus', 'cyclic_plus': '\\oplus', 'edge_minus': '\\boxminus', 'edge_plus': '\\boxplus', 'times': '\\times', 'maps_to': '\\to', 'reals': '\\mathbb{R}', 'integers': '\\mathbb{Z}', 'binary_set': '\\{0, 1\\}', 'sos_set': '\\mathrm{SOS}', 'position': '\\mathrm{pos}', 'minimize': '\\min', 'maximize': '\\max'} class-attribute #

suffix = '.tex' class-attribute #

apply(function, argument) #

Source code in src/math_spec/typeset/latex.py
def apply(self, function: str, argument: str) -> str:
    return f'{function}({argument})'

cardinality(inner) #

Source code in src/math_spec/typeset/latex.py
def cardinality(self, inner: str) -> str:
    return rf'\lvert {inner} \rvert'

cases(arms) #

Source code in src/math_spec/typeset/latex.py
def cases(self, arms: list[tuple[str, str]]) -> str:
    return cases_block(arms, CASES_ROW)

document(blocks, *, standalone) #

Source code in src/math_spec/typeset/latex.py
def document(self, blocks: list[str], *, standalone: bool) -> str:
    body = '\n\n'.join(blocks) + '\n'
    return f'{_PREAMBLE}\n{body}\n\\end{{document}}\n' if standalone else body

equations(lines, *, numbered) #

Source code in src/math_spec/typeset/latex.py
def equations(self, lines: list[Line], *, numbered: bool) -> str:
    environment = 'align' if numbered else 'align*'
    rows = [
        f'{self.prose(line.label) if line.label else ""} && {line.left} & {line.right} && {line.condition}'.rstrip(
            ' &'
        )
        for line in lines
    ]
    body = ' \\\\\n'.join(rows)
    return f'\\begin{{{environment}}}\n{body}\n\\end{{{environment}}}'

escape(prose) #

Source code in src/math_spec/typeset/latex.py
def escape(self, prose: str) -> str:
    return _escape(prose)

fraction(numerator, denominator) #

Source code in src/math_spec/typeset/latex.py
def fraction(self, numerator: str, denominator: str) -> str:
    return rf'\frac{{{numerator}}}{{{denominator}}}'

glossary(title, entries) #

Source code in src/math_spec/typeset/latex.py
def glossary(self, title: str, entries: list[Entry]) -> str:
    rows = '\n'.join(rf'\item[{self.math(e.symbol)}] {e.meaning(self.dash)}' for e in entries)
    return f'\\paragraph{{{title}}}\n\\begin{{description}}\n{rows}\n\\end{{description}}'

greek(name) #

Source code in src/math_spec/typeset/latex.py
def greek(self, name: str) -> str:
    return f'\\{name}'

italic(name) #

Source code in src/math_spec/typeset/latex.py
def italic(self, name: str) -> str:
    return rf'\mathit{{{_escape(name)}}}'

joined(parts, operator) #

Source code in src/math_spec/typeset/latex.py
def joined(self, parts: list[str], operator: str) -> str:
    return f' {operator} '.join(parts) if operator else r',\ '.join(parts)

math(expression) #

Source code in src/math_spec/typeset/latex.py
def math(self, expression: str) -> str:
    return f'${expression}$'

mono(text) #

Source code in src/math_spec/typeset/latex.py
def mono(self, text: str) -> str:
    return rf'\texttt{{{_escape(text)}}}'

note(text) #

Source code in src/math_spec/typeset/latex.py
def note(self, text: str) -> str:
    return f'\\noindent {text}'

parenthesise(inner) #

Source code in src/math_spec/typeset/latex.py
def parenthesise(self, inner: str) -> str:
    return rf'\left( {inner} \right)'

prose(text) #

Source code in src/math_spec/typeset/latex.py
def prose(self, text: str) -> str:
    return rf'\text{{{_escape(text)}}}'

script(letter) #

Source code in src/math_spec/typeset/latex.py
def script(self, letter: str) -> str:
    return rf'\mathcal{{{letter}}}'

section(title, body) #

Source code in src/math_spec/typeset/latex.py
def section(self, title: str, body: str) -> str:
    return f'\\paragraph{{{title}}}\n{body}'

subscript(base, indices) #

Source code in src/math_spec/typeset/latex.py
def subscript(self, base: str, indices: list[str]) -> str:
    return f'{base}_{{{",".join(indices)}}}' if indices else base

summation(domain, body) #

Source code in src/math_spec/typeset/latex.py
def summation(self, domain: str, body: str) -> str:
    return rf'\sum_{{{domain}}} {body}'

superscript(base, tail) #

Source code in src/math_spec/typeset/latex.py
def superscript(self, base: str, tail: str) -> str:
    return f'{base}^{{{tail}}}'

upright(name) #

Source code in src/math_spec/typeset/latex.py
def upright(self, name: str) -> str:
    return rf'\mathrm{{{_escape(name)}}}'

cases_block(arms, separator) #

A cases environment, with separator between the rows.

The separator is a parameter rather than a fixed \\ because Markdown needs a different one and rewriting this string afterwards would go quiet the moment the spelling here changed.

Source code in src/math_spec/typeset/latex.py
def cases_block(arms: list[tuple[str, str]], separator: str) -> str:
    r"""A `cases` environment, with *separator* between the rows.

    The separator is a parameter rather than a fixed ``\\`` because Markdown
    needs a different one and rewriting this string afterwards would go quiet
    the moment the spelling here changed.
    """
    rows = separator.join(rf'{value} & \text{{if }} {condition}' for value, condition in arms)
    return rf'\begin{{cases}} {rows} \end{{cases}}'