Skip to content

math_spec.typesetting.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.

LatexFormat #

See :class:math_spec.typesetting.format.Format.

cases_row = ' \\\\ ' class-attribute #

dash = '---' class-attribute #

notation = 'latex' class-attribute #

operators = {name: latex for name, (latex, _) in OPERATOR_SPELLINGS.items()} class-attribute #

suffix = '.tex' class-attribute #

apply(function, argument) #

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

cardinality(inner) #

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

cases(arms) #

Source code in src/math_spec/typesetting/latex.py
def cases(self, arms: list[tuple[str, str]]) -> str:
    rows = self.cases_row.join(f'{value} & {condition}' for value, condition in arms)
    return rf'\begin{{cases}} {rows} \end{{cases}}'

document(blocks, *, standalone) #

Source code in src/math_spec/typesetting/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/typesetting/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/typesetting/latex.py
def escape(self, prose: str) -> str:
    return _escape(prose)

fraction(numerator, denominator) #

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

glossary(title, entries) #

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

greek(name) #

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

italic(name) #

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

joined(parts, operator) #

Source code in src/math_spec/typesetting/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/typesetting/latex.py
def math(self, expression: str) -> str:
    return f'${expression}$'

mono(text) #

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

note(text) #

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

parenthesise(inner) #

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

prose(text) #

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

quoted(label) #

The quotes in text mode, the label itself upright in math mode.

Not one \text{'label'}: MathJax renders \_ inside \text as a literal backslash, and this format is what to_markdown inherits — in math mode the escape works everywhere, which is how every name already prints.

Source code in src/math_spec/typesetting/latex.py
def quoted(self, label: str) -> str:
    r"""The quotes in text mode, the label itself upright in math mode.

    Not one ``\text{'label'}``: MathJax renders ``\_`` inside ``\text``
    as a literal backslash, and this format is what `to_markdown` inherits
    — in math mode the escape works everywhere, which is how every name
    already prints.
    """
    return rf"\text{{'}}{self.upright(label)}\text{{'}}"

script(letter) #

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

section(title, body) #

Source code in src/math_spec/typesetting/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/typesetting/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/typesetting/latex.py
def summation(self, domain: str, body: str) -> str:
    return rf'\sum_{{{domain}}} {body}'

superscript(base, tail) #

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

upright(name) #

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