File: Mathlib/Algebra/Polynomial/Reverse.lean

full_name: Polynomial.revAtFun
code: /-- If `i ≤ N`, then `revAtFun N i` returns `N - i`, otherwise it returns `i`.
This is the map used by the embedding `revAt`.
-/
def revAtFun (N i : ℕ) : ℕ 
goal: ℕ

full_name: Polynomial.revAtFun_invol
code: theorem revAtFun_invol {N i : ℕ} : revAtFun N (revAtFun N i) = i 
goal: Polynomial.revAtFun N (Polynomial.revAtFun N i) = i

full_name: Polynomial.revAtFun_inj
code: theorem revAtFun_inj {N : ℕ} : Function.Injective (revAtFun N) 
goal: Function.Injective (Polynomial.revAtFun N)

full_name: Polynomial.revAt
code: /-- If `i ≤ N`, then `revAt N i` returns `N - i`, otherwise it returns `i`.
Essentially, this embedding is only used for `i ≤ N`.
The advantage of `revAt N i` over `N - i` is that `revAt` is an involution.
-/
def revAt (N : ℕ) : Function.Embedding ℕ ℕ 
goal: ℕ ↪ ℕ

full_name: Polynomial.revAtFun_eq
code: /-- We prefer to use the bundled `revAt` over unbundled `revAtFun`. -/
@[simp]
theorem revAtFun_eq (N i : ℕ) : revAtFun N i = revAt N i 
goal: Polynomial.revAtFun N i = (Polynomial.revAt N) i

full_name: Polynomial.revAt_invol
code: @[simp]
theorem revAt_invol {N i : ℕ} : (revAt N) (revAt N i) = i 
goal: (Polynomial.revAt N) ((Polynomial.revAt N) i) = i

full_name: Polynomial.revAt_le
code: @[simp]
theorem revAt_le {N i : ℕ} (H : i ≤ N) : revAt N i = N - i 
goal: (Polynomial.revAt N) i = N - i

full_name: Polynomial.revAt_eq_self_of_lt
code: lemma revAt_eq_self_of_lt {N i : ℕ} (h : N < i) : revAt N i = i 
goal: (Polynomial.revAt N) i = i

full_name: Polynomial.revAt_add
code: theorem revAt_add {N O n o : ℕ} (hn : n ≤ N) (ho : o ≤ O) :
    revAt (N + O) (n + o) = revAt N n + revAt O o 
goal: (Polynomial.revAt (N + O)) (n + o) = (Polynomial.revAt N) n + (Polynomial.revAt O) o

full_name: Polynomial.revAt_zero
code: theorem revAt_zero (N : ℕ) : revAt N 0 = N 
goal: (Polynomial.revAt N) 0 = N

full_name: Polynomial.reflect
code: /-- `reflect N f` is the polynomial such that `(reflect N f).coeff i = f.coeff (revAt N i)`.
In other words, the terms with exponent `[0, ..., N]` now have exponent `[N, ..., 0]`.

In practice, `reflect` is only used when `N` is at least as large as the degree of `f`.

Eventually, it will be used with `N` exactly equal to the degree of `f`.  -/
noncomputable def reflect (N : ℕ) : R[X] → R[X]
  
goal: Polynomial R → Polynomial R

full_name: Polynomial.reflect_support
code: theorem reflect_support (N : ℕ) (f : R[X]) :
    (reflect N f).support = Finset.image (revAt N) f.support 
goal: (Polynomial.reflect N f).support = Finset.image (⇑(Polynomial.revAt N)) f.support

full_name: Polynomial.coeff_reflect
code: @[simp]
theorem coeff_reflect (N : ℕ) (f : R[X]) (i : ℕ) : coeff (reflect N f) i = f.coeff (revAt N i) 
goal: (Polynomial.reflect N f).coeff i = f.coeff ((Polynomial.revAt N) i)

full_name: Polynomial.reflect_zero
code: @[simp]
theorem reflect_zero {N : ℕ} : reflect N (0 : R[X]) = 0 
goal: Polynomial.reflect N 0 = 0

full_name: Polynomial.reflect_eq_zero_iff
code: @[simp]
theorem reflect_eq_zero_iff {N : ℕ} {f : R[X]} : reflect N (f : R[X]) = 0 ↔ f = 0 
goal: Polynomial.reflect N f = 0 ↔ f = 0

full_name: Polynomial.reflect_add
code: @[simp]
theorem reflect_add (f g : R[X]) (N : ℕ) : reflect N (f + g) = reflect N f + reflect N g 
goal: Polynomial.reflect N (f + g) = Polynomial.reflect N f + Polynomial.reflect N g

full_name: Polynomial.reflect_C_mul
code: @[simp]
theorem reflect_C_mul (f : R[X]) (r : R) (N : ℕ) : reflect N (C r * f) = C r * reflect N f 
goal: Polynomial.reflect N (Polynomial.C r * f) = Polynomial.C r * Polynomial.reflect N f

full_name: Polynomial.reflect_C_mul_X_pow
code: theorem reflect_C_mul_X_pow (N n : ℕ) {c : R} : reflect N (C c * X ^ n) = C c * X ^ revAt N n 
goal: Polynomial.reflect N (Polynomial.C c * Polynomial.X ^ n) = Polynomial.C c * Polynomial.X ^ (Polynomial.revAt N) n

full_name: Polynomial.reflect_C
code: @[simp]
theorem reflect_C (r : R) (N : ℕ) : reflect N (C r) = C r * X ^ N 
goal: Polynomial.reflect N (Polynomial.C r) = Polynomial.C r * Polynomial.X ^ N

full_name: Polynomial.reflect_monomial
code: @[simp]
theorem reflect_monomial (N n : ℕ) : reflect N ((X : R[X]) ^ n) = X ^ revAt N n 
goal: Polynomial.reflect N (Polynomial.X ^ n) = Polynomial.X ^ (Polynomial.revAt N) n

full_name: Polynomial.reflect_one_X
code: @[simp] lemma reflect_one_X : reflect 1 (X : R[X]) = 1 
goal: Polynomial.reflect 1 Polynomial.X = 1

full_name: Polynomial.reflect_mul_induction
code: theorem reflect_mul_induction (cf cg : ℕ) :
    ∀ N O : ℕ,
      ∀ f g : R[X],
        f.support.card ≤ cf.succ →
          g.support.card ≤ cg.succ →
            f.natDegree ≤ N →
              g.natDegree ≤ O → reflect (N + O) (f * g) = reflect N f * reflect O g 
goal: f.support.card ≤ cf.succ →
  g.support.card ≤ cg.succ →
    f.natDegree ≤ N →
      g.natDegree ≤ O → Polynomial.reflect (N + O) (f * g) = Polynomial.reflect N f * Polynomial.reflect O g

full_name: Polynomial.reflect_mul
code: @[simp]
theorem reflect_mul (f g : R[X]) {F G : ℕ} (Ff : f.natDegree ≤ F) (Gg : g.natDegree ≤ G) :
    reflect (F + G) (f * g) = reflect F f * reflect G g 
goal: Polynomial.reflect (F + G) (f * g) = Polynomial.reflect F f * Polynomial.reflect G g

full_name: Polynomial.eval₂_reflect_mul_pow
code: theorem eval₂_reflect_mul_pow (i : R →+* S) (x : S) [Invertible x] (N : ℕ) (f : R[X])
    (hf : f.natDegree ≤ N) : eval₂ i (⅟ x) (reflect N f) * x ^ N = eval₂ i x f 
goal: Polynomial.eval₂ i (⅟x) (Polynomial.reflect N f) * x ^ N = Polynomial.eval₂ i x f

full_name: Polynomial.eval₂_reflect_eq_zero_iff
code: theorem eval₂_reflect_eq_zero_iff (i : R →+* S) (x : S) [Invertible x] (N : ℕ) (f : R[X])
    (hf : f.natDegree ≤ N) : eval₂ i (⅟ x) (reflect N f) = 0 ↔ eval₂ i x f = 0 
goal: Polynomial.eval₂ i (⅟x) (Polynomial.reflect N f) = 0 ↔ Polynomial.eval₂ i x f = 0

full_name: Polynomial.reverse
code: /-- The reverse of a polynomial f is the polynomial obtained by "reading f backwards".
Even though this is not the actual definition, `reverse f = f (1/X) * X ^ f.natDegree`. -/
noncomputable def reverse (f : R[X]) : R[X] 
goal: Polynomial R

full_name: Polynomial.coeff_reverse
code: theorem coeff_reverse (f : R[X]) (n : ℕ) : f.reverse.coeff n = f.coeff (revAt f.natDegree n) 
goal: f.reverse.coeff n = f.coeff ((Polynomial.revAt f.natDegree) n)

full_name: Polynomial.coeff_zero_reverse
code: @[simp]
theorem coeff_zero_reverse (f : R[X]) : coeff (reverse f) 0 = leadingCoeff f 
goal: f.reverse.coeff 0 = f.leadingCoeff

full_name: Polynomial.reverse_zero
code: @[simp]
theorem reverse_zero : reverse (0 : R[X]) = 0 
goal: Polynomial.reverse 0 = 0

full_name: Polynomial.reverse_eq_zero
code: @[simp]
theorem reverse_eq_zero : f.reverse = 0 ↔ f = 0 
goal: f.reverse = 0 ↔ f = 0

full_name: Polynomial.reverse_natDegree_le
code: theorem reverse_natDegree_le (f : R[X]) : f.reverse.natDegree ≤ f.natDegree 
goal: f.reverse.natDegree ≤ f.natDegree

full_name: Polynomial.natDegree_eq_reverse_natDegree_add_natTrailingDegree
code: theorem natDegree_eq_reverse_natDegree_add_natTrailingDegree (f : R[X]) :
    f.natDegree = f.reverse.natDegree + f.natTrailingDegree 
goal: f.natDegree = f.reverse.natDegree + f.natTrailingDegree

full_name: Polynomial.reverse_natDegree
code: theorem reverse_natDegree (f : R[X]) : f.reverse.natDegree = f.natDegree - f.natTrailingDegree 
goal: f.reverse.natDegree = f.natDegree - f.natTrailingDegree

full_name: Polynomial.reverse_leadingCoeff
code: theorem reverse_leadingCoeff (f : R[X]) : f.reverse.leadingCoeff = f.trailingCoeff 
goal: f.reverse.leadingCoeff = f.trailingCoeff

full_name: Polynomial.natTrailingDegree_reverse
code: theorem natTrailingDegree_reverse (f : R[X]) : f.reverse.natTrailingDegree = 0 
goal: f.reverse.natTrailingDegree = 0

full_name: Polynomial.reverse_trailingCoeff
code: theorem reverse_trailingCoeff (f : R[X]) : f.reverse.trailingCoeff = f.leadingCoeff 
goal: f.reverse.trailingCoeff = f.leadingCoeff

full_name: Polynomial.reverse_mul
code: theorem reverse_mul {f g : R[X]} (fg : f.leadingCoeff * g.leadingCoeff ≠ 0) :
    reverse (f * g) = reverse f * reverse g 
goal: (f * g).reverse = f.reverse * g.reverse

full_name: Polynomial.reverse_mul_of_domain
code: @[simp]
theorem reverse_mul_of_domain {R : Type*} [Ring R] [NoZeroDivisors R] (f g : R[X]) :
    reverse (f * g) = reverse f * reverse g 
goal: (f * g).reverse = f.reverse * g.reverse

full_name: Polynomial.trailingCoeff_mul
code: theorem trailingCoeff_mul {R : Type*} [Ring R] [NoZeroDivisors R] (p q : R[X]) :
    (p * q).trailingCoeff = p.trailingCoeff * q.trailingCoeff 
goal: (p * q).trailingCoeff = p.trailingCoeff * q.trailingCoeff

full_name: Polynomial.coeff_one_reverse
code: @[simp]
theorem coeff_one_reverse (f : R[X]) : coeff (reverse f) 1 = nextCoeff f 
goal: f.reverse.coeff 1 = f.nextCoeff

full_name: Polynomial.reverse_C
code: @[simp] lemma reverse_C (t : R) :
    reverse (C t) = C t 
goal: (Polynomial.C t).reverse = Polynomial.C t

full_name: Polynomial.reverse_mul_X
code: @[simp] lemma reverse_mul_X (p : R[X]) : reverse (p * X) = reverse p 
goal: (p * Polynomial.X).reverse = p.reverse

full_name: Polynomial.reverse_X_mul
code: @[simp] lemma reverse_X_mul (p : R[X]) : reverse (X * p) = reverse p 
goal: (Polynomial.X * p).reverse = p.reverse

full_name: Polynomial.reverse_mul_X_pow
code: @[simp] lemma reverse_mul_X_pow (p : R[X]) (n : ℕ) : reverse (p * X ^ n) = reverse p 
goal: (p * Polynomial.X ^ n).reverse = p.reverse

full_name: Polynomial.reverse_X_pow_mul
code: @[simp] lemma reverse_X_pow_mul (p : R[X]) (n : ℕ) : reverse (X ^ n * p) = reverse p 
goal: (Polynomial.X ^ n * p).reverse = p.reverse

full_name: Polynomial.reverse_add_C
code: @[simp] lemma reverse_add_C (p : R[X]) (t : R) :
    reverse (p + C t) = reverse p + C t * X ^ p.natDegree 
goal: (p + Polynomial.C t).reverse = p.reverse + Polynomial.C t * Polynomial.X ^ p.natDegree

full_name: Polynomial.reverse_C_add
code: @[simp] lemma reverse_C_add (p : R[X]) (t : R) :
    reverse (C t + p) = C t * X ^ p.natDegree + reverse p 
goal: (Polynomial.C t + p).reverse = Polynomial.C t * Polynomial.X ^ p.natDegree + p.reverse

full_name: Polynomial.eval₂_reverse_mul_pow
code: theorem eval₂_reverse_mul_pow (i : R →+* S) (x : S) [Invertible x] (f : R[X]) :
    eval₂ i (⅟ x) (reverse f) * x ^ f.natDegree = eval₂ i x f 
goal: Polynomial.eval₂ i (⅟x) f.reverse * x ^ f.natDegree = Polynomial.eval₂ i x f

full_name: Polynomial.eval₂_reverse_eq_zero_iff
code: @[simp]
theorem eval₂_reverse_eq_zero_iff (i : R →+* S) (x : S) [Invertible x] (f : R[X]) :
    eval₂ i (⅟ x) (reverse f) = 0 ↔ eval₂ i x f = 0 
goal: Polynomial.eval₂ i (⅟x) f.reverse = 0 ↔ Polynomial.eval₂ i x f = 0

full_name: Polynomial.reflect_neg
code: @[simp]
theorem reflect_neg (f : R[X]) (N : ℕ) : reflect N (-f) = -reflect N f 
goal: Polynomial.reflect N (-f) = -Polynomial.reflect N f

full_name: Polynomial.reflect_sub
code: @[simp]
theorem reflect_sub (f g : R[X]) (N : ℕ) : reflect N (f - g) = reflect N f - reflect N g 
goal: Polynomial.reflect N (f - g) = Polynomial.reflect N f - Polynomial.reflect N g

full_name: Polynomial.reverse_neg
code: @[simp]
theorem reverse_neg (f : R[X]) : reverse (-f) = -reverse f 
goal: (-f).reverse = -f.reverse