Skip to content

math_spec.typesetting.walk

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.

PositionForm = Literal['plain', 'grouped', 'from_end'] module-attribute #

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()

format = fmt instance-attribute #

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