-rw-r--r-- 7798 leangoppa-20230726/Goppadecoding/shiftpoly.lean raw
import Mathlib.RingTheory.Polynomial.Basic
import Goppadecoding.poly
import Goppadecoding.diff
namespace Goppadecoding
open Polynomial BigOperators Finset
section shiftpoly
noncomputable def shiftpoly (k: Type _) [Field k] (r: k) (f: k[X]): k[X] :=
aeval (X + C r) f
theorem shiftpoly_zero (k: Type _) [Field k] (r: k):
shiftpoly k r 0 = 0 :=
by unfold shiftpoly; simp only [map_zero]
theorem shiftpoly_one (k: Type _) [Field k] (r: k):
shiftpoly k r 1 = 1 :=
by unfold shiftpoly; simp only [map_one]
theorem shiftpoly_neg (k: Type _) [Field k] (r: k) (g: k[X]):
shiftpoly k r (-g) = - shiftpoly k r g :=
by unfold shiftpoly; simp only [map_neg]
theorem shiftpoly_add (k: Type _) [Field k] (r: k) (f g: k[X]):
shiftpoly k r (f+g) = shiftpoly k r f + shiftpoly k r g :=
by unfold shiftpoly; simp only [map_add]
theorem shiftpoly_sub (k: Type _) [Field k] (r: k) (f g: k[X]):
shiftpoly k r (f-g) = shiftpoly k r f - shiftpoly k r g :=
by unfold shiftpoly; simp only [map_sub]
theorem shiftpoly_mul (k: Type _) [Field k] (r: k) (f g: k[X]):
shiftpoly k r (f*g) = shiftpoly k r f * shiftpoly k r g :=
by unfold shiftpoly; simp only [map_mul]
theorem shiftpoly_C (k: Type _) [Field k] (r c: k):
shiftpoly k r (C c) = C c :=
by
unfold shiftpoly
rw[aeval_C]
unfold algebraMap
unfold Algebra.toRingHom
unfold algebraOfAlgebra
simp only [Algebra.id.map_eq_id, RingHomCompTriple.comp_eq]
theorem shiftpoly_X (k: Type _) [Field k] (r: k):
shiftpoly k r X = X + C r :=
by
unfold shiftpoly
rw[aeval_X]
theorem shiftpoly_X_sub_C (k: Type _) [Field k] (r c: k):
shiftpoly k r (X - C c) = X - C (c - r) :=
by
rw[shiftpoly_sub,shiftpoly_C,shiftpoly_X]
simp only [map_sub]
group
-- could do this via map_sum by setting up more types
theorem shiftpoly_sum (k: Type _) [Field k] (r: k) {U: Type _} [DecidableEq U] {f: U → k[X]}:
∀ (S: Finset U),
shiftpoly k r (∑ s in S, f s) = ∑ s in S, shiftpoly k r (f s) :=
by
apply Finset.induction
. simp only [sum_empty, forall_const, shiftpoly_zero]
intro S s notsinS prevcase
rw[sum_insert,shiftpoly_add]
rw[sum_insert,prevcase]
repeat exact notsinS
-- could do this via map_prod by setting up more types
theorem shiftpoly_prod (k: Type _) [Field k] (r: k) {U: Type _} [DecidableEq U] {f: U → k[X]}:
∀ (S: Finset U),
shiftpoly k r (∏ s in S, f s) = ∏ s in S, shiftpoly k r (f s) :=
by
apply Finset.induction
. simp only [prod_empty, forall_const, shiftpoly_one]
intro S s notsinS prevcase
rw[prod_insert,shiftpoly_mul]
rw[prod_insert,prevcase]
repeat exact notsinS
-- lemma getting towards shiftpoly_degree
theorem shiftpoly_degree_le (k: Type _) [Field k] (r: k) (f: k[X]):
(shiftpoly k r f).degree ≤ f.degree :=
by
by_cases f0: f = 0
. rw[f0]
rw[shiftpoly_zero,degree_zero]
unfold shiftpoly
rw[aeval_eq_sum_range]
calc
_ ≤ (range (f.natDegree + 1)).sup (fun i ↦ (coeff f i • (X + C r) ^ i).degree) := by apply degree_sum_le
_ ≤ f.degree := by
apply Finset.sup_le
intro j jinrange
rw[mem_range] at jinrange
have fdegdeg: f.degree = f.natDegree := degree_eq_natDegree f0
rw[fdegdeg]
calc
_ = degree (C (coeff f j) * (X + C r) ^ j) := by rw[C_mul']
_ ≤ degree ((X + C r) ^ j) := degree_C_mul_le_degree _ _
_ = j := by simp only [degree_pow, degree_X_add_C, nsmul_eq_mul, mul_one]
_ ≤ _ := by norm_cast; exact Nat.lt_succ.mp jinrange
theorem shiftpoly_X_pow_degree (k: Type _) [Field k] (r s: k) (d: ℕ) (snonzero: s ≠ 0):
(shiftpoly k r (C s * X^d)).degree = d :=
by
unfold shiftpoly
simp only [map_mul, aeval_C, map_pow, aeval_X, degree_mul, degree_pow, degree_X_add_C, nsmul_eq_mul, mul_one]
unfold algebraMap
unfold Algebra.toRingHom
unfold algebraOfAlgebra
simp[snonzero]
theorem shiftpoly_degree (k: Type _) [Field k] (r: k) (f: k[X]):
(shiftpoly k r f).degree = f.degree :=
by
by_cases f0: f = 0
. rw[f0]
rw[shiftpoly_zero,degree_zero]
have leadnonzero: f.leadingCoeff ≠ 0 := leadingCoeff_ne_zero.mpr f0
let g := C f.leadingCoeff * X^f.natDegree
have fgdeg: (f-g).degree < f.degree := by
apply degree_sub_lt
. simp only [degree_mul, ne_eq, leadingCoeff_eq_zero, f0, not_false_eq_true, degree_C, degree_pow, degree_X, nsmul_eq_mul, mul_one, zero_add]
exact degree_eq_natDegree f0
. simp only [ne_eq, f0, not_false_eq_true]
. simp only [leadingCoeff_mul, leadingCoeff_C, monic_X_pow, Monic.leadingCoeff, mul_one]
have shiftgdeg: (shiftpoly k r g).degree = f.degree := by calc
_ = (f.natDegree: WithBot ℕ) := shiftpoly_X_pow_degree k r f.leadingCoeff f.natDegree leadnonzero
_ = f.degree := Eq.symm (degree_eq_natDegree f0)
have shiftfgdeg: (shiftpoly k r (f-g)).degree < (shiftpoly k r g).degree := by calc
_ ≤ (f-g).degree := shiftpoly_degree_le k r (f-g)
_ < f.degree := fgdeg
_ = (shiftpoly k r g).degree := shiftgdeg.symm
calc
_ = degree (shiftpoly k r (g+(f-g))) := by group
_ = degree (shiftpoly k r g + shiftpoly k r (f-g)) := by rw[shiftpoly_add]
_ = (shiftpoly k r g).degree := degree_add_eq_if_degree_lt shiftfgdeg
_ = f.degree := shiftgdeg
theorem shiftpoly_monomial (k: Type _) [Field k] (r: k) (n: ℕ) (c: k):
shiftpoly k r (((monomial: ℕ → k →ₗ[k] k[X]) n) c)
= C c * (X + C r)^n :=
by
unfold shiftpoly
rw[aeval_monomial]
apply congr_arg
simp only
theorem shiftpoly_derivative_monomial (k: Type _) [Field k] (r: k) (n: ℕ) (c: k):
(derivative: k[X] →ₗ[k] k[X]) (shiftpoly k r (((monomial: ℕ → k →ₗ[k] k[X]) n) c))
= shiftpoly k r ((derivative: k[X] →ₗ[k] k[X]) (((monomial: ℕ → k →ₗ[k] k[X]) n) c)) :=
by
rw[derivative_monomial]
repeat rw[shiftpoly_monomial]
rw[derivative_mul,derivative_pow]
simp only [derivative_C, zero_mul, map_natCast, ge_iff_le, map_add, derivative_X, add_zero, mul_one, zero_add, map_mul]
rw[mul_assoc]
theorem shiftpoly_diff (k: Type _) [Field k] (r: k) (f: k[X]):
(shiftpoly k r f).diff = shiftpoly k r f.diff :=
by
have fsum: f = ∑ i in range (f.natDegree + 1), (monomial: ℕ → k →ₗ[k] k[X]) i (coeff f i) := as_sum_range f
rw[fsum]
rw[diff,AddHom.toFun_eq_coe,LinearMap.coe_toAddHom]
rw[shiftpoly_sum,derivative_sum,derivative_sum,shiftpoly_sum]
apply sum_congr; simp only
intro x _
rw[shiftpoly_derivative_monomial]
theorem shiftpoly_eval (k: Type _) [Field k] (r c: k) (f: k[X]):
(shiftpoly k r f).eval c = f.eval (c + r) :=
by
have fsum: f = ∑ i in range (f.natDegree + 1), (monomial: ℕ → k →ₗ[k] k[X]) i (coeff f i) := as_sum_range f
rw[fsum]
calc
_ = (shiftpoly k r (∑ i in range (f.natDegree + 1), (monomial: ℕ → k →ₗ[k] k[X]) i (coeff f i))).eval c := rfl
_ = (∑ i in range (f.natDegree + 1), shiftpoly k r ((monomial: ℕ → k →ₗ[k] k[X]) i (coeff f i))).eval c := by rw[shiftpoly_sum]
_ = (∑ i in range (f.natDegree + 1), C (coeff f i) * (X + C r)^i).eval c := by
apply congr_arg
apply sum_congr; simp only
intro i _
rw[shiftpoly_monomial]
_ = ∑ i in range (f.natDegree + 1), ((eval c: k[X] → k) (C (coeff f i) * (X + C r)^i)) := by rw[eval_finset_sum]
_ = ∑ i in range (f.natDegree + 1), (coeff f i) * (c + r)^i := by simp only [eval_mul, eval_C, eval_pow, eval_add, eval_X]
_ = ∑ i in range (f.natDegree + 1), ((eval (c+r): k[X] → k) (C (coeff f i) * X^i)) := by simp only [eval_mul, eval_C, eval_pow, eval_X]
_ = (∑ i in range (f.natDegree + 1), C (coeff f i) * X^i).eval (c+r) := by rw[eval_finset_sum]
_ = _ := by
apply congr_arg
apply sum_congr; simp only
intro i _
rw[C_mul_X_pow_eq_monomial]
end shiftpoly