Typeset the math#
to_latex, to_typst and to_markdown print a model as the equations it
stands for, from the file alone. No data binds, and no solver runs.
import math_spec as ms
spec = ms.to_spec('model.yaml') # read and checked once, then printed three ways
print(ms.to_latex(spec)) # amsmath align
print(ms.to_typst(spec)) # compiles without a TeX toolchain
print(ms.to_markdown(spec)) # renders as-is on GitHub
Each function takes what to_spec takes: a path, the YAML, a mapping or a
Spec. The same three formats come from a shell:
python -m math_spec latex model.yaml --symbols model.symbols.yaml --standalone -o model.tex
python -m math_spec typst model.yaml --standalone -o model.typ
python -m math_spec markdown model.yaml
Print a model as math is the recipe, and every construct, as math shows what each construct prints.
Options#
The three functions take the same keywords, and the command line spells each as a flag.
symbols |
--symbols FILE |
How the names print. See symbol tables. Default: derived from the names in the file |
standalone |
--standalone |
Emit a document that compiles. Default: a fragment to include |
legend |
--no-legend |
Print the table of sets, parameters, variables and definitions above the math. Default: on |
numbered |
--no-numbers |
Number the equations. Default: on |
inline_expressions |
--inline-expressions |
Substitute each named expression that the math reads into the equations that read it, instead of defining it once. Default: off |
-o FILE writes to a file instead of stdout.
- The model's
description:opens the document. - A
piecewise:block prints as the variables and constraints it expands into. - A named expression prints its symbol where it is used
and its body once, under a Definitions heading, in declaration order. A
cases:block and a reported entry keep their definition line under eitherinline_expressionssetting. - Wherever the math moves an index, which every
shiftdoes, the document prints a line saying what that notation means. - A model that does not load does not print.
- Lines are not broken. A wide equation runs off the page.
Markdown's delimiters#
to_markdown prints math between the two pairs GitHub and GitLab read
verbatim: $`…`$ inline, and a ```math fence for a block. It never
prints $…$ or $$…$$. For a renderer that reads $…$ alone, print with
to_latex and write that renderer's delimiters around the result.
Descriptions#
A description: is plain prose, with one piece of notation. A name in
backticks, such as `capital_cost`, sets in monospace in every output
format. Everything else is text, and each format escapes whatever its own
syntax would read as markup. The legend prints the description of every
dimension, parameter and variable.
Printing one declaration on its own#
typeset_declaration returns the line the document prints for one named
expression, constraint or variable, with its quantifier and without a document,
a label, a number or math delimiters:
ms.typeset_declaration('model.yaml', 'spend', 'latex')
# \mathit{spend}_{t} = \sum_{g \in \mathcal{G}} \mathit{dispatch}_{t,g} \cdot \mathrm{cost}_{g} \qquad \forall\, t \in \mathcal{T}
ms.typeset_declaration('model.yaml', 'balance', 'latex')
# \sum_{g \in \mathcal{G}} \mathit{dispatch}_{t,g} = \mathrm{load}_{t} \qquad \forall\, t \in \mathcal{T}
It takes what the other functions take, plus the name, the format and an
optional symbols table. A Markdown line arrives without delimiters too, so put
it inside the inline pair:
line = ms.typeset_declaration('model.yaml', 'balance', 'markdown')
print(f'The balance holds: $`{line}`$')
A line on its own has no Definitions section beside it, so the plain named expressions it uses are substituted. A cased expression prints by symbol, and a second call with its name prints its block.
A name that is none of the three kinds is refused with the near miss. A name that is both a constraint and a variable is refused too, because one line can print only one of them.
Symbol tables#
With no table, the symbols are derived from the names in the file, such as \(\mathrm{load}_t\) and \(\mathrm{capacity}_g\). A symbol table makes the output conventional:
symbols = {
'notation': 'latex',
'dimensions': {
'snapshot': {'index': 's', 'set': '\\mathcal{S}'},
'generator': {'index': 'g', 'set': '\\mathcal{G}'},
},
'names': {
'cost': 'c',
'load': '\\ell',
'capacity': '\\bar p',
},
}
ms.to_latex('dispatch.yaml', symbols=symbols)
Pass a dict, a path to a YAML file, or a ms.SymbolTable. As a file:
# dispatch.symbols.yaml
notation: latex
dimensions:
snapshot: { index: s, set: "\\mathcal{S}" }
generator: { index: g, set: "\\mathcal{G}" }
names:
cost: c
load: "\\ell"
capacity: "\\bar p"
| Section | |
|---|---|
notation |
Required. latex or typst: the language the entries are written in |
dimensions |
For each dimension, an index letter and a set symbol. Either may be omitted |
names |
For each parameter, variable or named expression, its symbol |
Every spelling is printed as you wrote it, and nothing translates notation, so rendering a LaTeX table as Typst is refused. A key that names nothing in the model is an error with the near miss.
Nothing in a symbol table changes what the file means. What a declaration is
stays in its own description:.