Documentation

HexPolyFp.Compose

Substituting any q into the zero polynomial gives 0.

@[simp]
theorem Hex.FpPoly.compose_C {p : Nat} [ZMod64.Bounds p] (c : ZMod64 p) (q : FpPoly p) :

Substituting q into a constant polynomial leaves the constant fixed.

@[simp]

Substituting q into X returns q; X is the identity of composition.

Composing the constant polynomial 1 with any q yields 1: the multiplicative identity of FpPoly is fixed by substitution. This is the base case for composing an iterated product of linear factors (see compose_primeFieldLinearProduct).

DensePoly.compose f q agrees with the iterative Horner form.

The constant embedding C is additive: C (a + b) = C a + C b.

The constant embedding C turns a difference of scalars into a difference of constant polynomials. Used to push coefficient subtractions through products such as f * (X - C c).

The constant embedding C turns a product of scalars into a product of constant polynomials. Used to normalise constant coefficients when expanding products of linear factors.

Substituting w into a monomial gives the coefficient times a power of w.

This is the monomial case that Polynomial.induction_on' asks for on the Mathlib side, so it is what lets a Mathlib ring homomorphism be identified with the executable substitution.

compose (linearPow X k) w = linearPow w k.

def Hex.FpPoly.composeCoeffPowerSumUpTo {p : Nat} [ZMod64.Bounds p] (coeff : NatZMod64 p) :
NatNatFpPoly pFpPoly p

Recursive sum form of compose. The compose-power-sum Σ_{k=base}^{base+n-1} C(coeff k) · linearPow w k recursively builds up the polynomial substitution: each step adds a single C(coeff base) · linearPow w base term and recurses with base + 1. This shape is matched by Berlekamp's matrix-action sum after replacing linearPow w with the reduced powModMonic columns.

Equations
Instances For
    theorem Hex.FpPoly.composeCoeffPowerSumUpTo_eq {p : Nat} [ZMod64.Bounds p] (coeff : NatZMod64 p) (n base : Nat) (w : FpPoly p) :

    The local FpPoly power-sum accumulator built from linearPow agrees with the shared DensePoly.composeCoeffPowerSumUpTo. Callers use this to transfer the explicit compose-as-sum characterization onto the DensePoly API that downstream files import.

    theorem Hex.FpPoly.compose_eq_coeff_power_sum_upTo_bound {p : Nat} [ZMod64.Bounds p] (f w : FpPoly p) {bound : Nat} (hbound : DensePoly.size f bound) :

    compose f w equals composeCoeffPowerSumUpTo evaluated up to any upper bound that is at least f.size. Out-of-range coefficients of f vanish, so the recursion safely extends past f.size.

    compose distributes over subtraction.

    Substitution is additive. Follows from Hex.FpPoly.compose_sub, since f + h = f - (0 - h) and substitution fixes zero.

    Narrow specialisation needed by the witness-substitution caller: substituting w for X in a - X yields compose a w - w.

    The linearPow X k - X substitution: substituting w for X in linearPow X k - X yields linearPow w k - w.

    theorem Hex.FpPoly.compose_mul_X_sub_C {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] (a : FpPoly p) (c : ZMod64 p) (w : FpPoly p) :
    (a * (X - C c)).compose w = DensePoly.compose a w * (w - C c)

    Composition distributes over multiplication by a linear factor: substituting w into a * (X - C c) gives (compose a w) * (w - C c). This is the inductive step for composing an iterated product of linear factors ∏ (X - C cᵢ) (see compose_foldl_X_sub_C).

    theorem Hex.FpPoly.compose_foldl_X_sub_C {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] (xs : List (ZMod64 p)) (init w : FpPoly p) :
    (List.foldl (fun (acc : DensePoly (ZMod64 p)) (c : ZMod64 p) => acc * (X - C c)) init xs).compose w = List.foldl (fun (acc : DensePoly (ZMod64 p)) (c : ZMod64 p) => acc * (w - C c)) (DensePoly.compose init w) xs

    Substituting w into a left-fold product of linear factors ∏ (X - C c) equals the same fold with each X replaced by w. The transport law underlying composition of the prime-field linear product.

    theorem Hex.FpPoly.compose_primeFieldLinearProduct {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] (w : FpPoly p) :
    (List.foldl (fun (acc : DensePoly (ZMod64 p)) (c : ZMod64 p) => acc * (X - C c)) 1 (ZMod64.values p)).compose w = List.foldl (fun (acc : DensePoly (ZMod64 p)) (c : ZMod64 p) => acc * (w - C c)) 1 (ZMod64.values p)

    Specialisation to the canonical prime-field linear product starting from init = 1: substituting w into the variable form gives the witness form.

    theorem Hex.FpPoly.linearPow_zero_of_pos {p : Nat} [ZMod64.Bounds p] (n : Nat) (hn : 0 < n) :
    linearPow 0 n = 0

    A strictly positive power of the zero polynomial is zero. This discharges the vanishing-coefficient case when substituting into the compose power-sum form for the Frobenius identity.

    @[simp]

    Substituting the polynomial indeterminate into w returns w.

    Together with Hex.FpPoly.compose_X, this says that FpPoly.X is the two-sided identity for polynomial composition.

    Compose-form Frobenius: substituting linearPow X p for X in w yields linearPow w p, over F_p. This is Freshman's dream packaged through the polynomial composition surface: viewed as w = ∑_i a_i X^i, the right-hand side equals ∑_i a_i X^(p·i).