You are an expert Lean4 and formal verification agent proving a Lean4 theorem. Your output **must** strictly adhere to the specified format.

### Input Information
You will receive the following components, relevant to the target theorem:
* <used_lib_defs>...</used_lib_defs>: Imported library definitions directly used by the theorem.
* <used_repo_defs>...</used_repo_defs>: Definitions from the local project (but outside the current file), directly or transitively used by the theorem.
* <lib_lemmas>...</lib_lemmas>: Imported library lemmas/theorems that may assist the proof.
* <repo_lemmas>...</repo_lemmas>: Lemmas/theorems defined in the local project outside this file.
* <local_ctx>...</local_ctx>: The local file context (imports, namespaces, definitions, comments, etc.) from the top of the file up to—but not including—the target theorem or any previously defined local lemmas/theorems.
* <target_theorem>...</target_theorem>: The target theorem statement, ending with `:=`.

**Notes**
1. Definitions include their full bodies, but for definitions whose bodies contain proofs, the proof parts are replaced by `admit` (i.e., admit /- proof elided -/), while the rest of the definition is kept unchanged; lemmas include only their statements.
2. You may freely reference any definition or lemma contained in these tags without redefining them.
3. The tags for used definitions and helpful lemmas (used_lib_defs, used_repo_defs, lib_lemmas, repo_lemmas) may be omitted if empty.

### Output Format & Requirements
Your output MUST contain a complete, syntactically correct Lean 4 proof for the target theorem.

**Strict Output Structure:**
<reasoning> 
...
</reasoning> 

<lean4_invented_lemmas>
-- each lemma is a full Lean 4 declaration with a complete proof
...
</lean4_invented_lemmas>

<lean4_proof>
-- Lean 4 proof body of the target theorem
...
</lean4_proof>

**Requirements:**
1. <reasoning> and <lean4_invented_lemmas> are OPTIONAL. Include them only if they aid proof construction.
2. <lean4_proof> MUST contain only the proof body (tactics/terms), starting by "by", NOT the theorem declaration.
3. <lean4_invented_lemmas> (if present) MUST contain syntactically correct lemma declarations that type checks AND complete proof bodies. Defining a lemma using `axiom` is NOT allowed.
4. <reasoning> contains high-level proof planning.
5. If you create a lemma under <lean4_invented_lemmas> whose name is namespaced (e.g., X.Y.Z), you MUST always refer to it using its fully qualified name. Do NOT rely on shortened names. For example, write rw [X.Y.Z], not rw [Z] for invented lemmas.
6. All Lean 4 code MUST be syntactically correct. No `sorry`, `admit`, or non-Lean text. Comments allowed using `--` or `/- ... -/`.
7. Follow the tags and structure EXACTLY. No extra text before, between, or after the sections.
8. Do NOT wrap invented lemmas in a `mutual` block unless they have genuine mutual recursion. Declare each lemma independently.

### Examples are provided here (example input are under "User Prompt", and example assistant response are under "Agent Response"):
Example 1 ------------------- 
User Prompt:
<used_lib_defs>
structure BitVec (w : Nat) where
  /-- Construct a `BitVec w` from a number less than `2^w`.
  O(1), because we use `Fin` as the internal representation of a bitvector. -/
  ofFin ::

  /-- Interpret a bitvector as a number less than `2^w`.
  O(1), because we use `Fin` as the internal representation of a bitvector. -/
  toFin : Fin (hPow 2 w)
</used_lib_defs>

<repo_lemmas>
theorem List.getElem_append_left{α : Type u_1} {l₁ l₂ : List α} {i : Nat} (hn : i < l₁.length) :\n(l₁ ++ l₂)[i] = l₁[i]
</repo_lemmas>

<local_ctx>
import Mathlib.Computability.NFA
import Mathlib.Data.FinEnum
import Mathlib.Data.Rel
import Mathlib.Data.Vector.Basic
import Blase.AutoStructs.ForLean

open Set
open Mathlib
open SetRel

-- this is better because card is defeq to n
instance (α : Type) : Inter (Language α) := ⟨Set.inter⟩
instance (α : Type) : Union (Language α) := ⟨Set.union⟩

/--
The set of `n`-tuples of bit vectors of an arbitrary width.
-/
structure BitVecs (n : Nat) where
  w : Nat
  bvs : List.Vector (BitVec w) n

def BitVecs.cast (bvs : BitVecs n) (h : n = n') : BitVecs n' :=
  { w := bvs.w, bvs := h ▸ bvs.bvs }

abbrev BitVecs.empty : BitVecs n := ⟨0, List.Vector.replicate n .nil⟩
abbrev BitVecs.singleton {w : Nat} (bv : BitVec w) : BitVecs 1 := ⟨w, bv ::ᵥ .nil⟩
abbrev BitVecs.pair {w : Nat} (bv1 bv2 : BitVec w) : BitVecs 2 := ⟨w, bv1 ::ᵥ bv2 ::ᵥ .nil⟩

/--
The set of `n`-tuples of bit vectors of an arbitrary width, encoded as a list of
bit vectors of width `n`. The width of the encoded bit vectors is the length of
the list.
-/
abbrev BitVecs' (n : Nat) := List (BitVec n)

@[simps]
def dec (bvs' : BitVecs' n) : BitVecs n where
  w := bvs'.length
  bvs := List.Vector.ofFn fun k => BitVec.ofFn fun i => bvs'[i].getLsbD k

@[simp]
</local_ctx>

<target_theorem>
lemma dec_snoc n (bvs' : BitVecs' n) (a : BitVec n) :
  dec (bvs' ++ [a]) =
    { w := bvs'.length + 1
      bvs := List.Vector.ofFn fun k =>
        BitVec.cons (a.getLsbD k) ((dec bvs').bvs.get k) } :=
</target_theorem>

Agent Response:
<reasoning> 
The goal is to understand what `dec` does after appending one more bitvector `a` to `bvs'`. By definition, `dec` builds a width `= length` and a vector of bitvectors whose `i`-th bit at position `k` is `bvs'[i].getLsbD k`. So for `bvs' ++ [a]`, we expect the width to increase by 1 and each resulting bitvector to be `BitVec.cons` of the new bit coming from `a`.

First, I use `ext` twice: once on the record to focus on the `bvs` field, and once on the resulting bitvector. This reduces everything to a pointwise statement:
for fixed `k` and `i` with `i < bvs'.length + 1`,
the bit `(bvs' ++ [a])[i].getLsbD k` should match the bit at index `i` of `BitVec.cons (a.getLsbD k) ((dec bvs').bvs.get k)`.

At this point I need a clean description of indexing into `BitVec.cons`: if we have `x : BitVec n`, then `(cons b x)[i]` should give `b` at the new “last” index `n` and `x[i]` otherwise. That motivates an auxiliary lemma `getElem_cons` expressing exactly this behavior, proved via the `testBit`/`toNat` characterization and a case split on `i < n`, `i = n`, `i > n`.

Using `getElem_cons`, the RHS becomes an `if` on whether `i = bvs'.length`. So I split into cases:
- If `i = bvs'.length`, then `(bvs' ++ [a])[i]` is the appended `a`, so both sides reduce to `a.getLsbD k`.
- If `i ≠ bvs'.length`, the bound `i < bvs'.length + 1` forces `i < bvs'.length`. Then `(bvs' ++ [a])[i] = bvs'[i]` by `List.getElem_append_left`, and the RHS takes the “else” branch and likewise gives the bit from `bvs'[i]`. In both subcases, `simp` (plus the definition of `dec`) finishes.

So the whole proof is: `ext` to bit level, unfold `dec` with `simp_all`, rewrite with `getElem_cons`, split on the boundary index `i = length bvs'`, and in the “< length” branch use `List.getElem_append_left` and bounds to line up both sides.
</reasoning> 

<lean4_invented_lemmas>
@[grind =]
theorem getElem_cons {b : Bool} {n} {x : BitVec n} {i : Nat} (h : i < n + 1) :
    (cons b x)[i] = if h : i = n then b else x[i] := by
  simp only [BitVec.getElem_eq_testBit_toNat, BitVec.toNat_cons, Nat.testBit_or]
  rw [Nat.testBit_shiftLeft]
  rcases Nat.lt_trichotomy i n with i_lt_n | i_eq_n | n_lt_i
  · have p1 : ¬(n ≤ i) := by omega
    have p2 : i ≠ n := by omega
    simp [p1, p2]
  · simp only [i_eq_n, ge_iff_le, Nat.le_refl, decide_true, Nat.sub_self, Nat.testBit_zero,
    Bool.true_and, BitVec.testBit_toNat, BitVec.getLsbD_of_ge, Bool.or_false]
    cases b <;> trivial
  · have p1 : i ≠ n := by omega
    have p2 : i - n ≠ 0 := by omega
    simp [p1, p2, Nat.testBit_bool_toNat]
</lean4_invented_lemmas>

<lean4_proof>
by
  ext k i hi <;> simp_all
  rw [getElem_cons]
  split
  next heq => simp_all
  next h =>
    have hlt : i < List.length bvs' := by simp at hi; omega
    rw [List.getElem_append_left hlt]
    simp
</lean4_proof>

### Your task:
<used_lib_defs>
Fin in Init.Prelude
Subspace in Mathlib.Algebra.Module.Submodule.Basic
Set in Mathlib.Data.Set.Defs
Set.Ico in Mathlib.Order.Interval.Set.Defs
Submodule in Mathlib.Algebra.Module.Submodule.Defs
Submodule.span in Mathlib.LinearAlgebra.Span.Defs
Polynomial.C in Mathlib.Algebra.Polynomial.Basic
Nat in Init.Prelude
Fin.castLE in Init.Data.Fin.Basic
Finset in Mathlib.Data.Finset.Defs
Finset.univ in Mathlib.Data.Fintype.Defs
Fintype in Mathlib.Data.Fintype.Defs
Fintype.card in Mathlib.Data.Fintype.Card
IsLinearMap in Mathlib.Algebra.Module.LinearMap.Defs
Polynomial.eval in Mathlib.Algebra.Polynomial.Eval.Defs
CommGroupWithZero in Mathlib.Algebra.GroupWithZero.Defs
Eq in Init.Prelude
NeZero in Init.Data.NeZero
Polynomial in Mathlib.Algebra.Polynomial.Basic
algebraMap in Mathlib.Algebra.Algebra.Defs
LinearIndependent in Mathlib.LinearAlgebra.LinearIndependent.Defs
Set.image in Mathlib.Data.Set.Defs
RingHom in Mathlib.Algebra.Ring.Hom.Defs
RingHom.id in Mathlib.Algebra.Ring.Hom.Defs
Polynomial.rootMultiplicity in Mathlib.Algebra.Polynomial.Div
Function.Injective in Init.Data.Function
Multiset in Mathlib.Data.Multiset.Defs
Multiset.count in Mathlib.Data.Multiset.Count
Multiset.map in Mathlib.Data.Multiset.MapFold
Polynomial.roots in Mathlib.Algebra.Polynomial.Roots
SetLike in Mathlib.Data.SetLike.Basic
DecidableEq in Init.Prelude
Iff in Init.Core
CommRing in Mathlib.Algebra.Ring.Defs
Polynomial.algEquivOfCompEqX in Mathlib.Algebra.Polynomial.AlgebraMap
multiplicity in Mathlib.RingTheory.Multiplicity
EmbeddingLike in Mathlib.Data.FunLike.Embedding
CanLift in Mathlib.Tactic.Lift
Multiset.filter in Mathlib.Data.Multiset.Filter
id in Init.Prelude
Finset.val in Mathlib.Data.Finset.Defs
Set.InjOn in Mathlib.Data.Set.Operations
Subtype in Init.Prelude
Subtype.val in Init.Prelude
Polynomial.X in Mathlib.Algebra.Polynomial.Basic
</used_lib_defs>

<used_repo_defs>
def getBit (k n : Nat) : Nat := (n >>> k) &&& 1
</used_repo_defs>

<lib_lemmas>
Fact.out in Mathlib.Logic.Basic
Fin.le_zero_iff' in Mathlib.Data.Fin.SuccPred
LinearIndependent.injective in Mathlib.LinearAlgebra.LinearIndependent.Defs
Nat.not_lt_zero in Init.Prelude
Set.Ico_eq_empty_iff in Mathlib.Order.Interval.Set.Basic
Set.compl_eq_univ_diff in Mathlib.Order.BooleanAlgebra.Set
Set.empty_subset in Mathlib.Data.Set.Basic
Set.image_empty in Mathlib.Data.Set.Image
Set.image_subset_image_iff in Mathlib.Data.Set.Image
Set.mem_Ico in Mathlib.Order.Interval.Set.Defs
Set.subset_compl_singleton_iff in Mathlib.Order.BooleanAlgebra.Set
Submodule.span_mono in Mathlib.LinearAlgebra.Span.Defs
linearIndependent_iff_notMem_span in Mathlib.LinearAlgebra.LinearIndependent.Defs
Finset.prod_ne_zero_iff in Mathlib.Algebra.BigOperators.GroupWithZero.Finset
Polynomial.eval_C in Mathlib.Algebra.Polynomial.Eval.Defs
Polynomial.eval_X in Mathlib.Algebra.Polynomial.Eval.Defs
Polynomial.eval_prod in Mathlib.Algebra.Polynomial.Eval.Defs
Polynomial.eval_sub in Mathlib.Algebra.Polynomial.Eval.Defs
one_mul in Mathlib.Algebra.Group.Defs
sub_eq_zero in Mathlib.Algebra.Group.Basic
Polynomial.splits_X_sub_C in Mathlib.Algebra.Polynomial.Splits
Polynomial.splits_prod in Mathlib.Algebra.Polynomial.Splits
Finset.prod_eq_zero_iff in Mathlib.Algebra.BigOperators.GroupWithZero.Finset
Polynomial.X_sub_C_ne_zero in Mathlib.Algebra.Polynomial.Degree.Operations
Polynomial.X_ne_zero in Mathlib.Algebra.Polynomial.Basic
Polynomial.coeff_C_zero in Mathlib.Algebra.Polynomial.Basic
Polynomial.coeff_X_zero in Mathlib.Algebra.Polynomial.Basic
Polynomial.coeff_sub in Mathlib.Algebra.Polynomial.Basic
Polynomial.comp_eq_zero_iff in Mathlib.Algebra.Polynomial.Degree.Lemmas
and_false in Init.SimpLemmas
map_neg in Mathlib.Algebra.Group.Hom.Defs
sub_eq_neg_self in Mathlib.Algebra.Group.Basic
zero_sub in Mathlib.Algebra.Group.Defs
EmbeddingLike.map_eq_zero_iff in Mathlib.Algebra.Group.Equiv.Defs
Polynomial.aeval_C in Mathlib.Algebra.Polynomial.AlgebraMap
Polynomial.aeval_X in Mathlib.Algebra.Polynomial.AlgebraMap
Polynomial.algEquivOfCompEqX_apply in Mathlib.Algebra.Polynomial.AlgebraMap
Polynomial.algebraMap_eq in Mathlib.Algebra.Polynomial.AlgebraMap
Polynomial.rootMultiplicity_eq_multiplicity in Mathlib.Algebra.Polynomial.Div
if_false in Init.ByCases
if_true in Init.ByCases
map_sub in Mathlib.Algebra.Group.Hom.Defs
multiplicity_map_eq in Mathlib.RingTheory.Multiplicity
sub_sub_sub_cancel_right in Mathlib.Algebra.Group.Basic
Multiset.countP_eq_card_filter in Mathlib.Data.Multiset.Filter
Multiset.count_map in Mathlib.Data.Multiset.Filter
Multiset.filter_congr in Mathlib.Data.Multiset.Filter
Polynomial.count_roots in Mathlib.Algebra.Polynomial.Roots
Polynomial.ext in Mathlib.Algebra.Polynomial.Basic
add_comm in Mathlib.Algebra.Group.Defs
eq_comm in Init.Core
eq_sub_iff_add_eq in Mathlib.Algebra.Group.Basic
Finset.image_val_of_injOn in Mathlib.Data.Finset.Image
Finset.prod_image in Mathlib.Algebra.BigOperators.Group.Finset.Basic
Polynomial.roots_prod_X_sub_C in Mathlib.Algebra.Polynomial.Roots
Subtype.val_injective in Mathlib.Data.Subtype
CanLift.prf in Mathlib.Tactic.Lift
Multiset.card_singleton in Mathlib.Data.Multiset.ZeroCons
Multiset.card_zero in Mathlib.Data.Multiset.ZeroCons
Multiset.count_filter in Mathlib.Data.Multiset.Filter
Multiset.count_singleton in Mathlib.Data.Multiset.Count
Multiset.count_univ in Mathlib.Data.Fintype.Basic
Multiset.count_zero in Mathlib.Data.Multiset.Count
SetLike.coe_eq_coe in Mathlib.Data.SetLike.Basic
SetLike.mem_coe in Mathlib.Data.SetLike.Basic
imp_false in Init.Core
ite_eq_right_iff in Init.PropLemmas
one_ne_zero in Mathlib.Algebra.NeZero
Fin.zero_le in Init.Data.Fin.Lemmas
Set.Ico_subset_Ico_right in Mathlib.Order.Interval.Set.Basic
Set.image_mono in Mathlib.Data.Set.Image
Set.mem_image_of_mem in Mathlib.Data.Set.Operations
Submodule.add_mem in Mathlib.Algebra.Module.Submodule.Defs
Submodule.smul_mem in Mathlib.Algebra.Module.Submodule.Defs
Submodule.subset_span in Mathlib.LinearAlgebra.Span.Defs
sub_add_cancel in Mathlib.Algebra.Group.Defs
true_and in Init.SimpLemmas
Set.Ico_insert_right in Mathlib.Order.Interval.Set.Basic
Set.image_singleton in Mathlib.Data.Set.Image
Set.image_union in Mathlib.Data.Set.Image
Set.mem_Icc in Mathlib.Order.Interval.Set.Defs
Set.union_singleton in Mathlib.Data.Set.Insert
Submodule.mem_span_singleton in Mathlib.LinearAlgebra.Span.Defs
Submodule.mem_sup in Mathlib.LinearAlgebra.Span.Defs
Submodule.smul_mem_iff in Mathlib.Algebra.Module.Submodule.Basic
Submodule.span_union in Mathlib.LinearAlgebra.Span.Defs
Submodule.sub_mem in Mathlib.Algebra.Module.Submodule.Defs
existsUnique_of_exists_of_unique in Mathlib.Logic.ExistsUnique
sub_smul in Mathlib.Algebra.Module.Defs
sub_sub_sub_cancel_left in Mathlib.Algebra.Group.Basic
Finset.mem_univ in Mathlib.Data.Fintype.Defs
Finset.sum_const_zero in Mathlib.Algebra.BigOperators.Group.Finset.Defs
Finset.sum_ite_eq' in Mathlib.Algebra.BigOperators.Group.Finset.Piecewise
Finset.sum_map_val in Mathlib.Algebra.BigOperators.Group.Finset.Defs
Multiset.count_bind in Mathlib.Data.Multiset.Bind
Multiset.count_map_eq_count' in Mathlib.Data.Multiset.Filter
Polynomial.roots_prod in Mathlib.Algebra.Polynomial.Roots
add_left_injective in Mathlib.Algebra.Group.Defs
and_true in Init.SimpLemmas
eq_iff_iff in Init.Core
forall_const in Init.PropLemmas
if_false_right in Init.PropLemmas
if_neg in Init.Core
if_pos in Init.Core
iff_false in Init.SimpLemmas
implies_true in Init.SimpLemmas
ite_false in Init.SimpLemmas
ite_true in Init.SimpLemmas
ne_eq in Init.SimpLemmas
Polynomial.monic_X_sub_C in Mathlib.Algebra.Polynomial.Monic
Polynomial.monic_prod_of_monic in Mathlib.Algebra.Polynomial.Monic
Polynomial.Monic.comp in Mathlib.Algebra.Polynomial.Monic
Polynomial.Splits.comp_of_degree_le_one in Mathlib.Algebra.Polynomial.Splits
Polynomial.degree_X_sub_C_le in Mathlib.Algebra.Polynomial.Degree.Definitions
Polynomial.eq_prod_roots_of_monic_of_splits_id in Mathlib.Algebra.Polynomial.Splits
Polynomial.natDegree_X in Mathlib.Algebra.Polynomial.Degree.Definitions
Polynomial.natDegree_sub_C in Mathlib.Algebra.Polynomial.Degree.Operations
Polynomial.comp_C in Mathlib.Algebra.Polynomial.Eval.Defs
Polynomial.comp_X in Mathlib.Algebra.Polynomial.Eval.Defs
add_right_inj in Mathlib.Algebra.Group.Defs
sub_eq_add_neg in Mathlib.Algebra.Group.Defs
sub_right_inj in Mathlib.Algebra.Group.Basic
CommGroupWithZero.mul_inv_cancel in Mathlib.Algebra.GroupWithZero.Defs
Fin.mk_lt_of_lt_val in Init.Data.Fin.Lemmas
Finset.card_univ in Mathlib.Data.Fintype.Card
Finset.prod_congr in Mathlib.Algebra.BigOperators.Group.Finset.Basic
Finset.prod_const in Mathlib.Algebra.BigOperators.Group.Finset.Basic
Finset.prod_mul_distrib in Mathlib.Algebra.BigOperators.Group.Finset.Basic
Nat.zero_mod in Init.Data.Nat.Div.Basic
NeZero.one_le in Mathlib.Data.Nat.Cast.NeZero
Polynomial.C_1 in Mathlib.Algebra.Polynomial.Basic
Polynomial.C_comp in Mathlib.Algebra.Polynomial.Eval.Defs
Polynomial.C_mul in Mathlib.Algebra.Polynomial.Basic
Polynomial.C_pow in Mathlib.Algebra.Polynomial.Basic
Polynomial.mul_comp in Mathlib.Algebra.Polynomial.Eval.Defs
Polynomial.pow_comp in Mathlib.Algebra.Polynomial.Eval.Defs
Polynomial.smul_C in Mathlib.Algebra.Polynomial.Basic
Polynomial.smul_eq_C_mul in Mathlib.Algebra.Polynomial.Coeff
Polynomial.sub_comp in Mathlib.Algebra.Polynomial.Eval.Defs
add_sub_cancel_right in Mathlib.Algebra.Group.Defs
algebra_compatible_smul in Mathlib.Algebra.Algebra.Basic
map_mul in Mathlib.Algebra.Group.Hom.Defs
map_pow in Mathlib.Algebra.Group.Hom.Defs
mul_assoc in Mathlib.Algebra.Group.Defs
mul_comm in Mathlib.Algebra.Group.Defs
mul_pow in Mathlib.Algebra.Group.Basic
mul_sub in Mathlib.Algebra.Ring.Defs
one_pow in Mathlib.Algebra.Group.Defs
one_smul in Mathlib.Algebra.Group.Action.Defs
pow_sub₀ in Mathlib.Algebra.GroupWithZero.Units.Basic
smul_assoc in Mathlib.Algebra.Group.Action.Defs
smul_eq_mul in Mathlib.Algebra.Group.Action.Defs
smul_sub in Mathlib.Algebra.GroupWithZero.Action.Defs
</lib_lemmas>

<repo_lemmas>
lemma Fin.lt_succ' (a : Fin r) (h_a_add_1 : a + 1 < r) : a < a + 1

lemma Fin.val_add_one' (a : Fin r) (h_a_add_1 : a + 1 < r) : (a + 1).val = a.val + 1

lemma Fin.le_succ (a : Fin r) (h_a_add_1 : a + 1 < r) : a ≤ a + 1

lemma Fin.le_iff_lt_succ (a b : Fin r) (h_b : b + 1 < r) : a ≤ b ↔ a < b + 1

lemma Fin.val_sub_one (a : Fin r) (h_a_sub_1 : a > 0) : (a - 1).val = a.val - 1

theorem prod_poly_sub_C_eq_poly_pow_card_sub_poly_in_L
  (p : L[X]) :
  (∏ c ∈ (Finset.univ : Finset Fq), (p - Polynomial.C (algebraMap Fq L c))) =
    p^(Fintype.card Fq) - p

theorem prod_X_sub_C_eq_X_pow_card_sub_X_in_L :
  (∏ c ∈ (Finset.univ : Finset Fq), (Polynomial.X - Polynomial.C (algebraMap Fq L c))) =
    Polynomial.X^(Fintype.card Fq) - Polynomial.X

theorem prod_X_sub_C_eq_X_pow_card_sub_X :
  (∏ c ∈ (Finset.univ : Finset Fq), (Polynomial.X - Polynomial.C c)) =
    Polynomial.X^(Fintype.card Fq) - Polynomial.X

theorem linear_map_of_comp_to_linear_map_of_eval (f : L[X])
  (h_f_linear : IsLinearMap (R := Fq) (M := L[X]) (M₂ := L[X])
    (f := fun inner_p ↦ f.comp inner_p)) :
    IsLinearMap (R := Fq) (M := L) (M₂ := L) (f := fun x ↦ f.eval x)
</repo_lemmas>

<local_ctx>
import ArkLib.Data.Nat.Bitwise

import ArkLib.Data.Polynomial.Frobenius

import ArkLib.Data.Polynomial.MonomialBasis

import Mathlib.LinearAlgebra.StdBasis

import Mathlib.Algebra.Polynomial.Degree.Definitions

open Polynomial FiniteDimensional Finset Module

namespace AdditiveNTT

variable {r : ℕ} [NeZero r]

variable {L : Type u} [Field L] [Fintype L] [DecidableEq L]

variable (𝔽q : Type u) [Field 𝔽q] [Fintype 𝔽q]
  [h_Fq_char_prime : Fact (Nat.Prime (ringChar 𝔽q))] [hF₂ : Fact (Fintype.card 𝔽q = 2)]

variable [Algebra 𝔽q L]

variable (h_dim : Module.finrank 𝔽q L = r)

variable (β : Fin r → L) [hβ_lin_indep : Fact (LinearIndependent 𝔽q β)]

section LinearSubspaces

def U (i : Fin r) : Subspace 𝔽q L := Submodule.span 𝔽q (β '' (Set.Ico 0 i))

noncomputable def W (i : Fin r) : L[X] :=
  ∏ u : U 𝔽q β i, (X - C u.val)

end LinearSubspaces

section LinearityOfSubspaceVanishingPolynomials

@[simps!]
noncomputable def algEquivAevalXSubC {R : Type*} [CommRing R] (t : R) : R[X] ≃ₐ[R] R[X] :=
</local_ctx>

<target_theorem>
omit h_Fq_char_prime hF₂ in
lemma inductive_rec_form_W_comp (i : Fin r) (h_i_add_1 : i + 1 < r)
    (h_prev_linear_map : IsLinearMap (R := 𝔽q) (M := L[X]) (M₂ := L[X])
      (f := fun inner_p ↦ (W 𝔽q β i).comp inner_p))
    : ∀ p: L[X], (W 𝔽q β (i + 1)).comp p =
      ((W 𝔽q β i).comp p) ^ Fintype.card 𝔽q -
        C (eval (β i) (W 𝔽q β i)) ^ (Fintype.card 𝔽q - 1) * ((W 𝔽q β i).comp p) :=
</target_theorem>

