Python API#
This page documents every name that import math_spec exports, grouped by
task.
Loading#
The module math_spec.program holds the node and declaration classes of a
loaded model. Reading a loaded model documents them.
math_spec.to_spec(model)
#
Load and validate a model definition — the language's front door.
Everything decidable without data is decided here: schema shape, every rule one declaration is held to against the others, every expression and where string, and every macro template.
| PARAMETER | DESCRIPTION |
|---|---|
model
|
A YAML path — a :class: |
| RETURNS | DESCRIPTION |
|---|---|
Spec
|
The schema as the file declares it, |
| RAISES | DESCRIPTION |
|---|---|
LanguageError
|
Anything the language does not accept, a text that is not a mapping of sections included. |
FileNotFoundError
|
A |
Source code in src/math_spec/validation.py
math_spec.Spec
#
Bases: _StrictBlock
The declared math — one YAML file, or one dict, validated. Nothing here has seen data.
A Spec that exists has passed the whole language: constructing one by
any route — to_spec, :meth:model_validate, the constructor — runs
every load-time check, expression pass included, and raises
:class:~math_spec.errors.LanguageError on a model the language refuses.
Holding one is the proof, so nothing downstream checks it again.
The API is the eleven declaration sections plus version and
description, three ways back out — :meth:to_dict for the model as
data, :meth:to_yaml for the file a reviewer reads, :meth:expand for the
same math with its formulations written out — and :attr:program, the
model typed, which every reader after load walks. Everything else on this
class is pydantic's, not a contract this package keeps.
assumptions = {}
class-attribute
instance-attribute
#
constraints = {}
class-attribute
instance-attribute
#
description = None
class-attribute
instance-attribute
#
dimensions = {}
class-attribute
instance-attribute
#
expressions = {}
class-attribute
instance-attribute
#
macros = {}
class-attribute
instance-attribute
#
objective = None
class-attribute
instance-attribute
#
parameters = {}
class-attribute
instance-attribute
#
piecewise = {}
class-attribute
instance-attribute
#
program
cached
property
#
This model typed, section for section — what every reader after load walks.
Computing it is the expression pass, so a model the language refuses
raises here; loading forces it, so every ask on a model in hand is the
one object. It mirrors the model: a piecewise: block still in it is
a curve under program.piecewise and a sos: block a set under
program.sos, and :meth:expand is what writes either out as rows,
so a consumer building rows reads spec.expand(...).program and
refuses a block it does not take.
relations = {}
class-attribute
instance-attribute
#
sos = {}
class-attribute
instance-attribute
#
variables = {}
class-attribute
instance-attribute
#
version = 0
class-attribute
instance-attribute
#
expand(*kinds)
#
This model with its formulations written out as plain variables and constraints.
A formulation states rows rather than being one — piecewise: states
a curve, sos: states which members of a family may be nonzero — and
expanding one writes those rows under names prefixed with the block's
own, then drops the block. The math is the same afterwards, and so is
the data that binds it: neither a set nor a curve emits a parameter,
and a curve's rows sit on where predicates over the file's own.
| PARAMETER | DESCRIPTION |
|---|---|
kinds
|
Which formulations to write out —
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Spec
|
The model those blocks wrote out, or this one where it declares |
Spec
|
none of them. It is a model like any other: :meth: |
Spec
|
it, and the file binds the same data as the one it came from. |
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
kinds names something that is not a formulation. |
Source code in src/math_spec/model.py
model_validate(obj, *, strict=None, extra=None, from_attributes=None, context=None, by_alias=None, by_name=None)
classmethod
#
Validate a mapping, raising this package's exception tree rather than pydantic's.
__init__ is not wrapped the same way, because defining one makes
pydantic run every after-validator twice.
Source code in src/math_spec/model.py
to_dict()
#
to_yaml()
#
The file a reviewer reads — including for a model that never had one.
Typesetting#
math_spec.to_latex(model, **options)
#
Render model as LaTeX (amsmath align). See :func:typeset.
math_spec.to_typst(model, **options)
#
Render model as Typst. See :func:typeset.
math_spec.to_markdown(model, **options)
#
Render model as GitHub-flavoured Markdown. See :func:typeset.
math_spec.typeset(model, fmt, *, symbols=None, standalone=False, legend=True, numbered=True, inline_expressions=False)
#
Render model's math in fmt.
| PARAMETER | DESCRIPTION |
|---|---|
model
|
Anything :func: |
fmt
|
What spells the math — a key of :data:
TYPE:
|
symbols
|
How names print, as a :class:
TYPE:
|
standalone
|
Emit a compilable document rather than a fragment.
TYPE:
|
legend
|
Prepend the sets/parameters/variables table. The model's own
TYPE:
|
numbered
|
Number the equations.
TYPE:
|
inline_expressions
|
Substitute each plain named expression into the equations that use it, rather than printing its symbol there and its definition once. A cased expression is a definition either way: its block is taller than the line it would sit in.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
str
|
The rendered text. |
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
fmt names no format. |
LanguageError
|
A model that does not compile; it does not print. |
SchemaError
|
A symbol table entry naming nothing in the model, or a table written in a notation fmt does not read. |
Source code in src/math_spec/typesetting/__init__.py
math_spec.typeset_declaration(model, name, fmt, *, symbols=None, inline_expressions=True)
#
Render one declaration as the bare line the document prints for it.
The line the whole-model render prints for it — a named expression's
definition, a constraint, an assumption, a piecewise: curve, or a
variable's domain, quantifier included —
with no document, label, equation number or math delimiters around it, for
a math context the caller lays out: a docstring, a table cell. A line on
its own has no Definitions section beside it, so the plain named
expressions it uses are substituted unless inline_expressions says otherwise; a cased
one prints by symbol, and a second call with its name prints its block.
| PARAMETER | DESCRIPTION |
|---|---|
model
|
Anything :func: |
name
|
A named expression, constraint, assumption,
TYPE:
|
fmt
|
What spells the math — a key of :data:
TYPE:
|
symbols
|
How names print; see :func:
TYPE:
|
inline_expressions
|
Substitute the plain named expressions the line uses, so it
stands on its own;
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
str
|
The line, math only. |
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
fmt names no format. |
LanguageError
|
A model that does not compile; it does not print. |
SchemaError
|
name is declared as none of the five, or as two — a constraint may share a variable's name; or a symbol table entry names nothing in the model. |
Source code in src/math_spec/typesetting/__init__.py
math_spec.FORMATS = {'latex': LatexFormat(), 'markdown': MarkdownFormat(), 'typst': TypstFormat()}
module-attribute
#
math_spec.SymbolTable(notation, indices=dict(), sets=dict(), names=dict())
dataclass
#
How a reader wants the model to print — notation only, kept out of the model.
Every entry is a spelling, printed verbatim. notation: says which
language they are written in, and a render in the other one refuses::
notation: latex
dimensions:
snapshot: {index: t, set: "\\mathcal{T}"}
plant: {index: n}
names:
marginal_cost: "c^{\\mathrm{marg}}"
An entry naming nothing in the model is an error naming the near miss.
| ATTRIBUTE | DESCRIPTION |
|---|---|
notation |
The language the entries are written in; :meth:
TYPE:
|
indices = field(default_factory=dict)
class-attribute
instance-attribute
#
names = field(default_factory=dict)
class-attribute
instance-attribute
#
notation
instance-attribute
#
sets = field(default_factory=dict)
class-attribute
instance-attribute
#
checked_against(program)
#
Reject entries naming nothing in program or in what its formulations state, with the near miss.
A name a piecewise: or sos: block emits counts as declared, so
one table spells both readings of a model: the blocks as the file states
them, and the rows :meth:~math_spec.model.Spec.expand writes out.
Source code in src/math_spec/typesetting/symbols.py
load(source)
classmethod
#
A table from a YAML path or the mapping it parses to.
| RAISES | DESCRIPTION |
|---|---|
SchemaError
|
An unknown section, a section or a dimension that is
not a mapping, or a |
Source code in src/math_spec/typesetting/symbols.py
Advice#
math_spec.advice
#
Advice — what is decidable without data and is a note rather than a refusal.
One door, :func:advice, over every pass of that kind.
advice(model)
#
Everything the language advises about model — never an error, decidable without data.
| PARAMETER | DESCRIPTION |
|---|---|
model
|
A YAML path, a mapping, a loaded :class: |
| RETURNS | DESCRIPTION |
|---|---|
Advice
|
The never-an-axis advice in declaration order, then the unboundedness |
...
|
advice; |
Source code in src/math_spec/advice.py
math_spec.Advice(kind, subject, text)
dataclass
#
One thing the language advises about a file it accepts.
Never an error: each is what a half-written model looks like too. A
consumer prints it, or filters on kind and subject; the text is the
language's, so no consumer writes its own.
| ATTRIBUTE | DESCRIPTION |
|---|---|
kind |
The pass that said it.
TYPE:
|
subject |
The declaration it is about — a dimension name, a variable name.
TYPE:
|
text |
The sentence, naming the rewrite.
TYPE:
|
math_spec.AdviceKind = Literal['never-an-axis', 'unbounded']
module-attribute
#
Errors#
math_spec.MathSpecError
#
Bases: ValueError
Base class for every error this package raises on purpose.
math_spec.LanguageError
#
Bases: MathSpecError
The model is not sayable in the language, or does not obey its rules.
math_spec.SchemaError
#
Bases: LanguageError
What a load refuses: an unknown key, a bad dtype, a duplicate YAML key, an unparseable or unresolvable expression.
math_spec.DimensionError
#
Bases: LanguageError
A dim-set rule was violated. Raised at load time, before any data.
Names#
math_spec.BUILTIN_NAMES = frozenset(BUILTINS)
module-attribute
#
math_spec.did_you_mean(name, known, *, label='Declared')
#
The repair clause for an unrecognised name: the near miss, or the set.