The walk: resolved AST → typeset lines. Written once, for every format.
Everything here is a decision about the math — where a bracket changes the
reading, which dimension a reduction binds, that a mask belongs on the ∀ rather
than in the equation, that a translation shows at the leaf it re-indexes. None
of it is about syntax, so none is duplicated per format.
TranslationPolicy = Literal['plain', 'wrap', 'edge']
module-attribute
Noticed(policies=set(), grouped=False, positions=set(), numeric_coordinates=set())
dataclass
What the equations printed that the legend has to explain.
grouped = False
class-attribute
instance-attribute
numeric_coordinates = field(default_factory=set)
class-attribute
instance-attribute
policies = field(default_factory=set)
class-attribute
instance-attribute
positions = field(default_factory=set)
class-attribute
instance-attribute
Walk(schema, namespace, symbols, fmt)
Walks a validated schema, emitting :class:Lines in one format.
:meth:equations prints every section and returns what it :class:Noticed;
the legend methods take that record, so they can only describe symbols the
equations printed.
Source code in src/math_spec/typesetting/walk.py
| def __init__(self, schema: _ExpandedSpec, namespace: Namespace, symbols: Symbols, fmt: Format) -> None:
self.schema = schema
self.namespace = namespace
self.symbols = symbols
self.format = fmt
self.noticed = Noticed()
|
namespace = namespace
instance-attribute
noticed = Noticed()
instance-attribute
schema = schema
instance-attribute
symbols = symbols
instance-attribute
convention_notes()
What the two faces mean, with the model's own symbols.
Only where the model has both, and quoting only derived symbols: a
table is the author's to write, so a symbol it supplies is not one this
note governs.
Source code in src/math_spec/typesetting/walk.py
| def convention_notes(self) -> list[str]:
"""What the two faces mean, with the model's own symbols.
Only where the model has both, and quoting only derived symbols: a
table is the author's to write, so a symbol it supplies is not one this
note governs.
"""
derived = [
next((n for n in names if n not in self.symbols.overridden), None)
for names in (self.schema.parameters, self.schema.variables)
]
if not all(derived):
return []
given, chosen = (self.format.math(self.symbols.name[n]) for n in derived if n is not None)
return [
f'Upright is what the model is given {self.format.dash} a parameter such as {given}, a coordinate '
f'map, a label {self.format.dash} and italic is what the solver chooses, such as {chosen}. '
f'An index is italic too, being what a quantifier chooses, and a set is script.'
]
|
equations(reported)
Every titled section of equations, and what printing them noticed for the legend.
| PARAMETER |
DESCRIPTION |
reported
|
Whether to append the Reported quantities section — the
entries the objective and constraints never read.
TYPE:
bool
|
Source code in src/math_spec/typesetting/walk.py
| def equations(self, reported: bool) -> tuple[list[tuple[str, list[Line]]], Noticed]:
"""Every titled section of equations, and what printing them noticed for the legend.
Args:
reported: Whether to append the Reported quantities section — the
entries the objective and constraints never read.
"""
sections = [
('Objective', self._objective()),
('Subject to', self._constraints()),
('Definitions', self._definitions()),
('Variable domains', self._variables()),
]
if reported:
sections.append(('Reported quantities', self._reported()))
return sections, self.noticed
|
glossaries(noticed)
Source code in src/math_spec/typesetting/walk.py
| def glossaries(self, noticed: Noticed) -> list[Glossary]:
fmt = self.format
sets = [
self._entry(
self.symbols.set[d],
f'index {fmt.math(self.symbols.index[d])} {fmt.dash} {fmt.mono(d)}{self._coords(d, noticed)}',
block.description,
)
for d, block in self.schema.dimensions.items()
]
parameters = [
self._entry(self.symbols.name[p], f'{fmt.mono(p)}{self._over(list(block.dims))}', block.description)
for p, block in self.schema.parameters.items()
]
variables = [
self._entry(self.symbols.name[v], f'{fmt.mono(v)}{self._over(list(block.foreach))}', block.description)
for v, block in self.schema.variables.items()
]
groups = (Glossary('Sets', sets), Glossary('Parameters', parameters), Glossary('Variables', variables))
return [group for group in groups if group.entries]
|
position_notes(noticed)
A sentence for each positional symbol the model printed; the first says which of pos(t) and t is the position.
Source code in src/math_spec/typesetting/walk.py
| def position_notes(self, noticed: Noticed) -> list[str]:
"""A sentence for each positional symbol the model printed; the first says which of ``pos(t)`` and ``t`` is the position."""
notes = []
if noticed.positions:
index = self.format.math('t')
place = self.format.math(self.format.apply(self._op('position'), 't'))
dash = self.format.dash
notes.append(
f"{place} denotes where index {index} sits along its dimension's own order {dash} the order "
f'{self.format.mono("shift")} walks, not the order labels sort in {dash} counted from '
f'{self.format.math("0")}. The index itself stays the coordinate, so {index} compares against '
f'labels and {place} against positions.'
)
if 'grouped' in noticed.positions:
applied = self._lookup('lookup', 't')
grouped = self.format.math(self.format.apply(self.format.subscript(self._op('position'), [applied]), 't'))
group = self.format.math(self.format.subscript(self.format.script('T'), [applied]))
notes.append(
f'{grouped} counts within the group a lookup puts {self.format.math("t")} in: the subscript names '
f'the map, {group} is the group it lands in, and that group has a first position of its own.'
)
if 'from_end' in noticed.positions:
size = self.format.cardinality(self.format.script('T'))
last = self.format.math(f'{size} {self._op("minus")} {self._number(1)}')
notes.append(
f'{self.format.math(size)} denotes the size of the set being counted along, and a position '
f'counted from the end prints against it {self.format.dash} {last} is the last position, one '
f'less than the size because the first is {self.format.math("0")}.'
)
return notes
|
translation_notes(noticed)
A sentence for each translation symbol the model printed; plain t-k needs none.
Source code in src/math_spec/typesetting/walk.py
| def translation_notes(self, noticed: Noticed) -> list[str]:
"""A sentence for each translation symbol the model printed; plain ``t-k`` needs none."""
notes = []
if 'wrap' in noticed.policies:
cyclic = self.format.math(f't {self._op("cyclic_minus")} k')
notes.append(
f'{cyclic} denotes cyclic translation: index {self.format.math("t-k")} taken modulo the size of '
f'the dimension ({self.format.mono("roll")}). Plain {self.format.math("t-k")} '
f'({self.format.mono("shift")}) has no wraparound {self.format.dash} terms translated past '
f'the edge are simply absent.'
)
if 'edge' in noticed.policies:
filled = self.format.math(f't {self.format.subscript(self._op("edge_minus"), ["v"])} k')
notes.append(
f'{filled} denotes translation with {self.format.math("v")} standing where index '
f'{self.format.math("t-k")} leaves the dimension ({self.format.mono("shift(edge=v)")}), so the row '
f'at that boundary is built and carries {self.format.math("v")} rather than being dropped.'
)
if noticed.grouped:
applied = self._lookup('lookup', 't')
counted = self.format.math(f't {self.format.superscript(self._op("cyclic_minus"), applied)} k')
note = (
f'{counted} denotes a translation counted inside the group a lookup puts {self.format.math("t")} '
f'in ({self.format.mono("shift(by=lookup)")}), so a term never crosses out of its own group.'
)
if 'edge' in noticed.policies:
both = self.format.superscript(self.format.subscript(self._op('edge_minus'), ['v']), applied)
note += (
f' The two modifiers take different slots {self.format.dash} the group above, the fill '
f'below {self.format.dash} so {self.format.math(f"t {both} k")} is both at once.'
)
notes.append(note)
return notes
|