FM final correction: remove sentinel and carry, reduce modulo 2^N+1
ProvedNLogN.fmFinal_runsLet , a state, and . Assume ZZ has on top (over ), CY has on top (over ), RN has and RF has on top. Then the segment fmFinal runs from to the state where ZZ and CY are popped and
is pushed on ARG, with cost at most . The residue is the canonical one in (Lean's % with positive modulus).
In the Schönhage–Strassen procedure is the Horner value (with a leading sentinel ) and is the final carry, whose weight is ; this step therefore produces the product modulo .
Formalization Note. States are IState NS records with item stacks G : Fin NS → List Item (head = top), input pointer ip and output out; s.upd X L replaces stack X by L; ints A is the list of integer items of A. The named stacks (ARG, PRM, RN, RF, DX, DL, …) are fixed indices in Fin 32. IRuns I iprog p s s' c means that p executes from s to exactly s' with some cost , so costs are upper bounds; the program text iprog and input I are arbitrary unless constrained.
-- Schönhage–Strassen multitape-TM development (NLogN), generated by skeleton subtraction.
import Definitions.Def_IntMul_SS_Defs2
set_option autoImplicit false
set_option relaxedAutoImplicit false
set_option maxHeartbeats 1000000
open NLogN
open IntMul
variable {P : ℕ} {I : List Sym} {iprog : Fin P → IStmt NS P}
theorem NLogN.fmFinal_runs (s : IState NS) (N : ℕ) (z c : ℤ) (LZ LY LN LF : List Item) (hN1 : 1 ≤ N)
(hz : 0 ≤ z ∧ z < 2 ^ (N + 1)) (hc : |c| ≤ 2 ^ N)
(hZ : s.G ZZ = .int z :: LZ) (hY : s.G CY = .int c :: LY)
(hN : s.G RN = .int (2 ^ N) :: LN) (hF : s.G RF = .int (2 ^ N + 1) :: LF) :
IRuns I iprog fmFinal s
(((s.upd ZZ LZ).upd CY LY).upd ARG (.int ((z - 2 ^ N - c) % (2 ^ N + 1)) :: s.G ARG))
(25000 * (N + 3)) := by sorry