Horner layers: polynomial register evaluation #
The reduction emitter's variable indices are mixed-radix numerals
(flatVar), and its time budget is p.eval n — both are computed by
iterating the single Horner layer tmp := tmp · X + c over unary
registers. This file builds that layer from the Arith register calculus
and folds it into polyEvalTM.
To keep the time accounting sane across long seqTM chains, every stage
bound is rounded up to the single monotone budget opBudget M, where M
bounds every register value in play. Only the polynomial shape of the final
bound matters (FP quantifies the degree existentially), so all budgets
are deliberately loose.
Main definitions #
TM.opBudget— the uniform per-operation time budgetTM.setConstTM—q := cTM.hornerLayerRegTM—tmp := tmp · X + comp(register addend)TM.hornerLayerConstTM—tmp := tmp · X + c(constant addend)
Main results #
- the
_hoareTimespecification of each machine
One budget bounds every register operation whose values are at most M:
increments, clears, copies, additions, multiply-accumulates, and literal
emissions. Cubic in M because mulAddIntoTM's bound is (product value)
× (per-mark sweep length).
Instances For
q := c (clear, then increment c times).
Equations
- Complexity.TM.setConstTM q c = (Complexity.TM.clearRegTM q).seqTM ((Complexity.TM.incRegTM q).iterTM c)
Instances For
One Horner layer with a register addend:
tmp := tmp · X + comp (scratch tmp2 ends holding the same value).
Equations
- One or more equations did not get rendered due to their size.
Instances For
The (uniform) time budget of one Horner layer.
Equations
Instances For
hornerLayerRegTM Hoare specification. From tmp = v, X = x,
comp = w (and any tmp2 = u), reach tmp = tmp2 = v·x + w with all
other tapes untouched, within layerBudget M steps, provided every value
in play is at most M.
hornerLayerConstTM Hoare specification. From tmp = v, X = x
(and any tmp2 = u), reach tmp = tmp2 = v·x + c.
Horner accumulator over a coefficient list (highest degree first).
Equations
- Complexity.TM.hornerFold x [] x✝ = x✝
- Complexity.TM.hornerFold x (c :: cs) x✝ = Complexity.TM.hornerFold x cs (x✝ * x + c)
Instances For
hornerFold over the empty coefficient list returns the accumulator.
Unfolding lemma: one Horner layer replaces the accumulator a by a * x + c.
The Horner fold of a reversed coefficient window is the polynomial sum.
Every prefix of the Horner fold is bounded by the full coefficient sum
times the dominating power — the hypothesis-discharger for
hornerLayersTM_hoareTime's value cap.
Fold Horner layers (constant addends, highest first) over a register.
Equations
- Complexity.TM.hornerLayersTM X tmp tmp2 cs = Complexity.TM.bigSeqTM (List.map (Complexity.TM.hornerLayerConstTM X tmp tmp2) cs)
Instances For
hornerLayersTM Hoare specification (nonempty coefficient list).
From tmp = v, reach tmp = tmp2 = hornerFold x (c :: cs) v, provided
every intermediate accumulator value is at most M.
The coefficient list of p, highest degree first.
Equations
- Complexity.TM.polyCoeffs p = (List.map p.coeff (List.range (p.natDegree + 1))).reverse
Instances For
The coefficient list of a polynomial is never empty (it has natDegree + 1 entries).
polyCoeffs p has exactly p.natDegree + 1 entries.
The Horner fold computes p.eval.
tmp := p.eval x, reading x from register X (Horner's rule over the
hardwired coefficient list; tmp2 is scratch and ends equal to tmp).
Equations
- Complexity.TM.polyEvalTM X tmp tmp2 p = (Complexity.TM.setConstTM tmp 0).seqTM (Complexity.TM.hornerLayersTM X tmp tmp2 (Complexity.TM.polyCoeffs p))
Instances For
polyEvalTM Hoare specification. From X = x (and any tmp = v,
tmp2 = u), reach tmp = tmp2 = p.eval x, provided M caps x, the
starting scratch values, and every Horner prefix value.