[GOAL]
R : Type u₁
L : Type u₂
inst✝² : CommRing R
inst✝¹ : LieRing L
inst✝ : LieAlgebra R L
src✝ : L →ₗ[R] UniversalEnvelopingAlgebra R L := LinearMap.comp (AlgHom.toLinearMap (mkAlgHom R L)) ιₜ
x y : L
⊢ AddHom.toFun
      { toAddHom := src✝.toAddHom,
          map_smul' :=
            (_ :
              ∀ (r : R) (x : L),
                AddHom.toFun src✝.toAddHom (r • x) = ↑(RingHom.id R) r • AddHom.toFun src✝.toAddHom x) }.toAddHom
      ⁅x, y⁆ =
    ⁅AddHom.toFun
        { toAddHom := src✝.toAddHom,
            map_smul' :=
              (_ :
                ∀ (r : R) (x : L),
                  AddHom.toFun src✝.toAddHom (r • x) = ↑(RingHom.id R) r • AddHom.toFun src✝.toAddHom x) }.toAddHom
        x,
      AddHom.toFun
        { toAddHom := src✝.toAddHom,
            map_smul' :=
              (_ :
                ∀ (r : R) (x : L),
                  AddHom.toFun src✝.toAddHom (r • x) = ↑(RingHom.id R) r • AddHom.toFun src✝.toAddHom x) }.toAddHom
        y⁆
[PROOFSTEP]
suffices mkAlgHom R L (ιₜ ⁅x, y⁆ + ιₜ y * ιₜ x) = mkAlgHom R L (ιₜ x * ιₜ y) by rw [AlgHom.map_mul] at this ;
  simp [LieRing.of_associative_ring_bracket, ← this]
[GOAL]
R : Type u₁
L : Type u₂
inst✝² : CommRing R
inst✝¹ : LieRing L
inst✝ : LieAlgebra R L
src✝ : L →ₗ[R] UniversalEnvelopingAlgebra R L := LinearMap.comp (AlgHom.toLinearMap (mkAlgHom R L)) ιₜ
x y : L
this : ↑(mkAlgHom R L) (↑ιₜ ⁅x, y⁆ + ↑ιₜ y * ↑ιₜ x) = ↑(mkAlgHom R L) (↑ιₜ x * ↑ιₜ y)
⊢ AddHom.toFun
      { toAddHom := src✝.toAddHom,
          map_smul' :=
            (_ :
              ∀ (r : R) (x : L),
                AddHom.toFun src✝.toAddHom (r • x) = ↑(RingHom.id R) r • AddHom.toFun src✝.toAddHom x) }.toAddHom
      ⁅x, y⁆ =
    ⁅AddHom.toFun
        { toAddHom := src✝.toAddHom,
            map_smul' :=
              (_ :
                ∀ (r : R) (x : L),
                  AddHom.toFun src✝.toAddHom (r • x) = ↑(RingHom.id R) r • AddHom.toFun src✝.toAddHom x) }.toAddHom
        x,
      AddHom.toFun
        { toAddHom := src✝.toAddHom,
            map_smul' :=
              (_ :
                ∀ (r : R) (x : L),
                  AddHom.toFun src✝.toAddHom (r • x) = ↑(RingHom.id R) r • AddHom.toFun src✝.toAddHom x) }.toAddHom
        y⁆
[PROOFSTEP]
rw [AlgHom.map_mul] at this
[GOAL]
R : Type u₁
L : Type u₂
inst✝² : CommRing R
inst✝¹ : LieRing L
inst✝ : LieAlgebra R L
src✝ : L →ₗ[R] UniversalEnvelopingAlgebra R L := LinearMap.comp (AlgHom.toLinearMap (mkAlgHom R L)) ιₜ
x y : L
this : ↑(mkAlgHom R L) (↑ιₜ ⁅x, y⁆ + ↑ιₜ y * ↑ιₜ x) = ↑(mkAlgHom R L) (↑ιₜ x) * ↑(mkAlgHom R L) (↑ιₜ y)
⊢ AddHom.toFun
      { toAddHom := src✝.toAddHom,
          map_smul' :=
            (_ :
              ∀ (r : R) (x : L),
                AddHom.toFun src✝.toAddHom (r • x) = ↑(RingHom.id R) r • AddHom.toFun src✝.toAddHom x) }.toAddHom
      ⁅x, y⁆ =
    ⁅AddHom.toFun
        { toAddHom := src✝.toAddHom,
            map_smul' :=
              (_ :
                ∀ (r : R) (x : L),
                  AddHom.toFun src✝.toAddHom (r • x) = ↑(RingHom.id R) r • AddHom.toFun src✝.toAddHom x) }.toAddHom
        x,
      AddHom.toFun
        { toAddHom := src✝.toAddHom,
            map_smul' :=
              (_ :
                ∀ (r : R) (x : L),
                  AddHom.toFun src✝.toAddHom (r • x) = ↑(RingHom.id R) r • AddHom.toFun src✝.toAddHom x) }.toAddHom
        y⁆
[PROOFSTEP]
simp [LieRing.of_associative_ring_bracket, ← this]
[GOAL]
R : Type u₁
L : Type u₂
inst✝² : CommRing R
inst✝¹ : LieRing L
inst✝ : LieAlgebra R L
src✝ : L →ₗ[R] UniversalEnvelopingAlgebra R L := LinearMap.comp (AlgHom.toLinearMap (mkAlgHom R L)) ιₜ
x y : L
⊢ ↑(mkAlgHom R L) (↑ιₜ ⁅x, y⁆ + ↑ιₜ y * ↑ιₜ x) = ↑(mkAlgHom R L) (↑ιₜ x * ↑ιₜ y)
[PROOFSTEP]
exact RingQuot.mkAlgHom_rel _ (Rel.lie_compat x y)
[GOAL]
R : Type u₁
L : Type u₂
inst✝⁴ : CommRing R
inst✝³ : LieRing L
inst✝² : LieAlgebra R L
A : Type u₃
inst✝¹ : Ring A
inst✝ : Algebra R A
f✝ f : L →ₗ⁅R⁆ A
⊢ ∀ ⦃x y : TensorAlgebra R L⦄, Rel R L x y → ↑(↑(TensorAlgebra.lift R) ↑f) x = ↑(↑(TensorAlgebra.lift R) ↑f) y
[PROOFSTEP]
intro a b h
[GOAL]
R : Type u₁
L : Type u₂
inst✝⁴ : CommRing R
inst✝³ : LieRing L
inst✝² : LieAlgebra R L
A : Type u₃
inst✝¹ : Ring A
inst✝ : Algebra R A
f✝ f : L →ₗ⁅R⁆ A
a b : TensorAlgebra R L
h : Rel R L a b
⊢ ↑(↑(TensorAlgebra.lift R) ↑f) a = ↑(↑(TensorAlgebra.lift R) ↑f) b
[PROOFSTEP]
induction' h with x y
[GOAL]
case lie_compat
R : Type u₁
L : Type u₂
inst✝⁴ : CommRing R
inst✝³ : LieRing L
inst✝² : LieAlgebra R L
A : Type u₃
inst✝¹ : Ring A
inst✝ : Algebra R A
f✝ f : L →ₗ⁅R⁆ A
a b : TensorAlgebra R L
x y : L
⊢ ↑(↑(TensorAlgebra.lift R) ↑f) (↑ιₜ ⁅x, y⁆ + ↑ιₜ y * ↑ιₜ x) = ↑(↑(TensorAlgebra.lift R) ↑f) (↑ιₜ x * ↑ιₜ y)
[PROOFSTEP]
simp only [LieRing.of_associative_ring_bracket, map_add, TensorAlgebra.lift_ι_apply, LieHom.coe_toLinearMap,
  LieHom.map_lie, map_mul, sub_add_cancel]
[GOAL]
R : Type u₁
L : Type u₂
inst✝⁴ : CommRing R
inst✝³ : LieRing L
inst✝² : LieAlgebra R L
A : Type u₃
inst✝¹ : Ring A
inst✝ : Algebra R A
f✝ f : L →ₗ⁅R⁆ A
⊢ (fun F => LieHom.comp (AlgHom.toLieHom F) (ι R))
      ((fun f =>
          ↑(RingQuot.liftAlgHom R)
            { val := ↑(TensorAlgebra.lift R) ↑f,
              property :=
                (_ :
                  ∀ ⦃a b : TensorAlgebra R L⦄,
                    Rel R L a b → ↑(↑(TensorAlgebra.lift R) ↑f) a = ↑(↑(TensorAlgebra.lift R) ↑f) b) })
        f) =
    f
[PROOFSTEP]
ext
  -- Porting note: was
      -- simp only [ι, mkAlgHom, TensorAlgebra.lift_ι_apply, LieHom.coe_toLinearMap,
      --   LinearMap.toFun_eq_coe, LinearMap.coe_comp, LieHom.coe_comp, AlgHom.coe_toLieHom,
      --   LieHom.coe_mk, Function.comp_apply, AlgHom.toLinearMap_apply,
      --   RingQuot.liftAlgHom_mkAlgHom_apply]
[GOAL]
case h
R : Type u₁
L : Type u₂
inst✝⁴ : CommRing R
inst✝³ : LieRing L
inst✝² : LieAlgebra R L
A : Type u₃
inst✝¹ : Ring A
inst✝ : Algebra R A
f✝ f : L →ₗ⁅R⁆ A
x✝ : L
⊢ ↑((fun F => LieHom.comp (AlgHom.toLieHom F) (ι R))
          ((fun f =>
              ↑(RingQuot.liftAlgHom R)
                { val := ↑(TensorAlgebra.lift R) ↑f,
                  property :=
                    (_ :
                      ∀ ⦃a b : TensorAlgebra R L⦄,
                        Rel R L a b → ↑(↑(TensorAlgebra.lift R) ↑f) a = ↑(↑(TensorAlgebra.lift R) ↑f) b) })
            f))
      x✝ =
    ↑f x✝
[PROOFSTEP]
simp only [LieHom.coe_comp, Function.comp_apply, AlgHom.coe_toLieHom, UniversalEnvelopingAlgebra.ι_apply, mkAlgHom]
[GOAL]
case h
R : Type u₁
L : Type u₂
inst✝⁴ : CommRing R
inst✝³ : LieRing L
inst✝² : LieAlgebra R L
A : Type u₃
inst✝¹ : Ring A
inst✝ : Algebra R A
f✝ f : L →ₗ⁅R⁆ A
x✝ : L
⊢ ↑(↑(RingQuot.liftAlgHom R)
          { val := ↑(TensorAlgebra.lift R) ↑f,
            property :=
              (_ :
                ∀ ⦃a b : TensorAlgebra R L⦄,
                  Rel R L a b → ↑(↑(TensorAlgebra.lift R) ↑f) a = ↑(↑(TensorAlgebra.lift R) ↑f) b) })
      (↑(RingQuot.mkAlgHom R (Rel R L)) (↑ιₜ x✝)) =
    ↑f x✝
[PROOFSTEP]
rw [RingQuot.liftAlgHom_mkAlgHom_apply]
[GOAL]
case h
R : Type u₁
L : Type u₂
inst✝⁴ : CommRing R
inst✝³ : LieRing L
inst✝² : LieAlgebra R L
A : Type u₃
inst✝¹ : Ring A
inst✝ : Algebra R A
f✝ f : L →ₗ⁅R⁆ A
x✝ : L
⊢ ↑(↑(TensorAlgebra.lift R) ↑f) (↑ιₜ x✝) = ↑f x✝
[PROOFSTEP]
simp only [TensorAlgebra.lift_ι_apply, LieHom.coe_toLinearMap]
[GOAL]
R : Type u₁
L : Type u₂
inst✝⁴ : CommRing R
inst✝³ : LieRing L
inst✝² : LieAlgebra R L
A : Type u₃
inst✝¹ : Ring A
inst✝ : Algebra R A
f : L →ₗ⁅R⁆ A
F : UniversalEnvelopingAlgebra R L →ₐ[R] A
⊢ (fun f =>
        ↑(RingQuot.liftAlgHom R)
          { val := ↑(TensorAlgebra.lift R) ↑f,
            property :=
              (_ :
                ∀ ⦃a b : TensorAlgebra R L⦄,
                  Rel R L a b → ↑(↑(TensorAlgebra.lift R) ↑f) a = ↑(↑(TensorAlgebra.lift R) ↑f) b) })
      ((fun F => LieHom.comp (AlgHom.toLieHom F) (ι R)) F) =
    F
[PROOFSTEP]
apply RingQuot.ringQuot_ext'
[GOAL]
case w
R : Type u₁
L : Type u₂
inst✝⁴ : CommRing R
inst✝³ : LieRing L
inst✝² : LieAlgebra R L
A : Type u₃
inst✝¹ : Ring A
inst✝ : Algebra R A
f : L →ₗ⁅R⁆ A
F : UniversalEnvelopingAlgebra R L →ₐ[R] A
⊢ AlgHom.comp
      ((fun f =>
          ↑(RingQuot.liftAlgHom R)
            { val := ↑(TensorAlgebra.lift R) ↑f,
              property :=
                (_ :
                  ∀ ⦃a b : TensorAlgebra R L⦄,
                    Rel R L a b → ↑(↑(TensorAlgebra.lift R) ↑f) a = ↑(↑(TensorAlgebra.lift R) ↑f) b) })
        ((fun F => LieHom.comp (AlgHom.toLieHom F) (ι R)) F))
      (RingQuot.mkAlgHom R (Rel R L)) =
    AlgHom.comp F (RingQuot.mkAlgHom R (Rel R L))
[PROOFSTEP]
ext
  -- Porting note: was
      -- simp only [ι, mkAlgHom, TensorAlgebra.lift_ι_apply, LieHom.coe_toLinearMap,
      --   LinearMap.toFun_eq_coe, LinearMap.coe_comp, LieHom.coe_linearMap_comp,
      --   AlgHom.comp_toLinearMap, Function.comp_apply, AlgHom.toLinearMap_apply,
      --   RingQuot.liftAlgHom_mkAlgHom_apply, AlgHom.coe_toLieHom, LieHom.coe_mk]
[GOAL]
case w.w.h
R : Type u₁
L : Type u₂
inst✝⁴ : CommRing R
inst✝³ : LieRing L
inst✝² : LieAlgebra R L
A : Type u₃
inst✝¹ : Ring A
inst✝ : Algebra R A
f : L →ₗ⁅R⁆ A
F : UniversalEnvelopingAlgebra R L →ₐ[R] A
x✝ : L
⊢ ↑(LinearMap.comp
          (AlgHom.toLinearMap
            (AlgHom.comp
              ((fun f =>
                  ↑(RingQuot.liftAlgHom R)
                    { val := ↑(TensorAlgebra.lift R) ↑f,
                      property :=
                        (_ :
                          ∀ ⦃a b : TensorAlgebra R L⦄,
                            Rel R L a b → ↑(↑(TensorAlgebra.lift R) ↑f) a = ↑(↑(TensorAlgebra.lift R) ↑f) b) })
                ((fun F => LieHom.comp (AlgHom.toLieHom F) (ι R)) F))
              (RingQuot.mkAlgHom R (Rel R L))))
          ιₜ)
      x✝ =
    ↑(LinearMap.comp (AlgHom.toLinearMap (AlgHom.comp F (RingQuot.mkAlgHom R (Rel R L)))) ιₜ) x✝
[PROOFSTEP]
simp [mkAlgHom]
[GOAL]
R : Type u₁
L : Type u₂
inst✝⁴ : CommRing R
inst✝³ : LieRing L
inst✝² : LieAlgebra R L
A : Type u₃
inst✝¹ : Ring A
inst✝ : Algebra R A
f : L →ₗ⁅R⁆ A
x : L
⊢ ↑(↑(lift R) f) (↑(ι R) x) = ↑f x
[PROOFSTEP]
rw [← Function.comp_apply (f := lift R f) (g := ι R) (x := x), ι_comp_lift]
[GOAL]
R : Type u₁
L : Type u₂
inst✝⁴ : CommRing R
inst✝³ : LieRing L
inst✝² : LieAlgebra R L
A : Type u₃
inst✝¹ : Ring A
inst✝ : Algebra R A
f : L →ₗ⁅R⁆ A
x : L
⊢ ↑(↑(lift R) f) (↑(mkAlgHom R L) (↑ιₜ x)) = ↑f x
[PROOFSTEP]
simpa using lift_ι_apply R f x
[GOAL]
R : Type u₁
L : Type u₂
inst✝⁴ : CommRing R
inst✝³ : LieRing L
inst✝² : LieAlgebra R L
A : Type u₃
inst✝¹ : Ring A
inst✝ : Algebra R A
f : L →ₗ⁅R⁆ A
g : UniversalEnvelopingAlgebra R L →ₐ[R] A
⊢ ↑g ∘ ↑(ι R) = ↑f ↔ g = ↑(lift R) f
[PROOFSTEP]
refine' Iff.trans _ (lift R).symm_apply_eq
[GOAL]
R : Type u₁
L : Type u₂
inst✝⁴ : CommRing R
inst✝³ : LieRing L
inst✝² : LieAlgebra R L
A : Type u₃
inst✝¹ : Ring A
inst✝ : Algebra R A
f : L →ₗ⁅R⁆ A
g : UniversalEnvelopingAlgebra R L →ₐ[R] A
⊢ ↑g ∘ ↑(ι R) = ↑f ↔ ↑(lift R).symm g = f
[PROOFSTEP]
constructor
[GOAL]
case mp
R : Type u₁
L : Type u₂
inst✝⁴ : CommRing R
inst✝³ : LieRing L
inst✝² : LieAlgebra R L
A : Type u₃
inst✝¹ : Ring A
inst✝ : Algebra R A
f : L →ₗ⁅R⁆ A
g : UniversalEnvelopingAlgebra R L →ₐ[R] A
⊢ ↑g ∘ ↑(ι R) = ↑f → ↑(lift R).symm g = f
[PROOFSTEP]
intro h
[GOAL]
case mp
R : Type u₁
L : Type u₂
inst✝⁴ : CommRing R
inst✝³ : LieRing L
inst✝² : LieAlgebra R L
A : Type u₃
inst✝¹ : Ring A
inst✝ : Algebra R A
f : L →ₗ⁅R⁆ A
g : UniversalEnvelopingAlgebra R L →ₐ[R] A
h : ↑g ∘ ↑(ι R) = ↑f
⊢ ↑(lift R).symm g = f
[PROOFSTEP]
ext
[GOAL]
case mp.h
R : Type u₁
L : Type u₂
inst✝⁴ : CommRing R
inst✝³ : LieRing L
inst✝² : LieAlgebra R L
A : Type u₃
inst✝¹ : Ring A
inst✝ : Algebra R A
f : L →ₗ⁅R⁆ A
g : UniversalEnvelopingAlgebra R L →ₐ[R] A
h : ↑g ∘ ↑(ι R) = ↑f
x✝ : L
⊢ ↑(↑(lift R).symm g) x✝ = ↑f x✝
[PROOFSTEP]
simp [← h]
[GOAL]
case mpr
R : Type u₁
L : Type u₂
inst✝⁴ : CommRing R
inst✝³ : LieRing L
inst✝² : LieAlgebra R L
A : Type u₃
inst✝¹ : Ring A
inst✝ : Algebra R A
f : L →ₗ⁅R⁆ A
g : UniversalEnvelopingAlgebra R L →ₐ[R] A
⊢ ↑(lift R).symm g = f → ↑g ∘ ↑(ι R) = ↑f
[PROOFSTEP]
intro h
[GOAL]
case mpr
R : Type u₁
L : Type u₂
inst✝⁴ : CommRing R
inst✝³ : LieRing L
inst✝² : LieAlgebra R L
A : Type u₃
inst✝¹ : Ring A
inst✝ : Algebra R A
f : L →ₗ⁅R⁆ A
g : UniversalEnvelopingAlgebra R L →ₐ[R] A
h : ↑(lift R).symm g = f
⊢ ↑g ∘ ↑(ι R) = ↑f
[PROOFSTEP]
ext
[GOAL]
case mpr.h
R : Type u₁
L : Type u₂
inst✝⁴ : CommRing R
inst✝³ : LieRing L
inst✝² : LieAlgebra R L
A : Type u₃
inst✝¹ : Ring A
inst✝ : Algebra R A
f : L →ₗ⁅R⁆ A
g : UniversalEnvelopingAlgebra R L →ₐ[R] A
h : ↑(lift R).symm g = f
x✝ : L
⊢ (↑g ∘ ↑(ι R)) x✝ = ↑f x✝
[PROOFSTEP]
simp [← h]
[GOAL]
R : Type u₁
L : Type u₂
inst✝⁴ : CommRing R
inst✝³ : LieRing L
inst✝² : LieAlgebra R L
A : Type u₃
inst✝¹ : Ring A
inst✝ : Algebra R A
f : L →ₗ⁅R⁆ A
g₁ g₂ : UniversalEnvelopingAlgebra R L →ₐ[R] A
h : LieHom.comp (AlgHom.toLieHom g₁) (ι R) = LieHom.comp (AlgHom.toLieHom g₂) (ι R)
⊢ ↑(lift R).symm g₁ = ↑(lift R).symm g₂
[PROOFSTEP]
ext
[GOAL]
case h
R : Type u₁
L : Type u₂
inst✝⁴ : CommRing R
inst✝³ : LieRing L
inst✝² : LieAlgebra R L
A : Type u₃
inst✝¹ : Ring A
inst✝ : Algebra R A
f : L →ₗ⁅R⁆ A
g₁ g₂ : UniversalEnvelopingAlgebra R L →ₐ[R] A
h : LieHom.comp (AlgHom.toLieHom g₁) (ι R) = LieHom.comp (AlgHom.toLieHom g₂) (ι R)
x✝ : L
⊢ ↑(↑(lift R).symm g₁) x✝ = ↑(↑(lift R).symm g₂) x✝
[PROOFSTEP]
simp [h]


[GOAL]
S : Type u
inst✝ : Semiring S
⊢ pochhammer S 1 = X
[PROOFSTEP]
simp [pochhammer]
[GOAL]
S : Type u
inst✝ : Semiring S
n : ℕ
⊢ pochhammer S (n + 1) = X * comp (pochhammer S n) (X + 1)
[PROOFSTEP]
rw [pochhammer]
[GOAL]
S : Type u
inst✝¹ : Semiring S
T : Type v
inst✝ : Semiring T
f : S →+* T
n : ℕ
⊢ map f (pochhammer S n) = pochhammer T n
[PROOFSTEP]
induction' n with n ih
[GOAL]
case zero
S : Type u
inst✝¹ : Semiring S
T : Type v
inst✝ : Semiring T
f : S →+* T
⊢ map f (pochhammer S Nat.zero) = pochhammer T Nat.zero
[PROOFSTEP]
simp
[GOAL]
case succ
S : Type u
inst✝¹ : Semiring S
T : Type v
inst✝ : Semiring T
f : S →+* T
n : ℕ
ih : map f (pochhammer S n) = pochhammer T n
⊢ map f (pochhammer S (Nat.succ n)) = pochhammer T (Nat.succ n)
[PROOFSTEP]
simp [ih, pochhammer_succ_left, map_comp]
[GOAL]
S : Type u
inst✝ : Semiring S
n k : ℕ
⊢ ↑(eval k (pochhammer ℕ n)) = eval (↑k) (pochhammer S n)
[PROOFSTEP]
rw [← pochhammer_map (algebraMap ℕ S), eval_map, ← eq_natCast (algebraMap ℕ S), eval₂_at_nat_cast, Nat.cast_id,
  eq_natCast]
[GOAL]
S : Type u
inst✝ : Semiring S
n : ℕ
⊢ eval 0 (pochhammer S n) = if n = 0 then 1 else 0
[PROOFSTEP]
cases n
[GOAL]
case zero
S : Type u
inst✝ : Semiring S
⊢ eval 0 (pochhammer S Nat.zero) = if Nat.zero = 0 then 1 else 0
[PROOFSTEP]
simp
[GOAL]
case succ
S : Type u
inst✝ : Semiring S
n✝ : ℕ
⊢ eval 0 (pochhammer S (Nat.succ n✝)) = if Nat.succ n✝ = 0 then 1 else 0
[PROOFSTEP]
simp [X_mul, Nat.succ_ne_zero, pochhammer_succ_left]
[GOAL]
S : Type u
inst✝ : Semiring S
⊢ eval 0 (pochhammer S 0) = 1
[PROOFSTEP]
simp
[GOAL]
S : Type u
inst✝ : Semiring S
n : ℕ
h : n ≠ 0
⊢ eval 0 (pochhammer S n) = 0
[PROOFSTEP]
simp [pochhammer_eval_zero, h]
[GOAL]
S : Type u
inst✝ : Semiring S
n : ℕ
⊢ pochhammer S (n + 1) = pochhammer S n * (X + ↑n)
[PROOFSTEP]
suffices h : pochhammer ℕ (n + 1) = pochhammer ℕ n * (X + (n : ℕ[X]))
[GOAL]
S : Type u
inst✝ : Semiring S
n : ℕ
h : pochhammer ℕ (n + 1) = pochhammer ℕ n * (X + ↑n)
⊢ pochhammer S (n + 1) = pochhammer S n * (X + ↑n)
[PROOFSTEP]
apply_fun Polynomial.map (algebraMap ℕ S) at h
[GOAL]
S : Type u
inst✝ : Semiring S
n : ℕ
h : map (algebraMap ℕ S) (pochhammer ℕ (n + 1)) = map (algebraMap ℕ S) (pochhammer ℕ n * (X + ↑n))
⊢ pochhammer S (n + 1) = pochhammer S n * (X + ↑n)
[PROOFSTEP]
simpa only [pochhammer_map, Polynomial.map_mul, Polynomial.map_add, map_X, Polynomial.map_nat_cast] using h
[GOAL]
case h
S : Type u
inst✝ : Semiring S
n : ℕ
⊢ pochhammer ℕ (n + 1) = pochhammer ℕ n * (X + ↑n)
[PROOFSTEP]
induction' n with n ih
[GOAL]
case h.zero
S : Type u
inst✝ : Semiring S
⊢ pochhammer ℕ (Nat.zero + 1) = pochhammer ℕ Nat.zero * (X + ↑Nat.zero)
[PROOFSTEP]
simp
[GOAL]
case h.succ
S : Type u
inst✝ : Semiring S
n : ℕ
ih : pochhammer ℕ (n + 1) = pochhammer ℕ n * (X + ↑n)
⊢ pochhammer ℕ (Nat.succ n + 1) = pochhammer ℕ (Nat.succ n) * (X + ↑(Nat.succ n))
[PROOFSTEP]
conv_lhs =>
  rw [pochhammer_succ_left, ih, mul_comp, ← mul_assoc, ← pochhammer_succ_left, add_comp, X_comp, nat_cast_comp,
    add_assoc, add_comm (1 : ℕ[X]), ← Nat.cast_succ]
[GOAL]
S : Type u
inst✝ : Semiring S
n : ℕ
ih : pochhammer ℕ (n + 1) = pochhammer ℕ n * (X + ↑n)
| pochhammer ℕ (Nat.succ n + 1)
[PROOFSTEP]
rw [pochhammer_succ_left, ih, mul_comp, ← mul_assoc, ← pochhammer_succ_left, add_comp, X_comp, nat_cast_comp, add_assoc,
    add_comm (1 : ℕ[X]), ← Nat.cast_succ]
[GOAL]
S : Type u
inst✝ : Semiring S
n : ℕ
ih : pochhammer ℕ (n + 1) = pochhammer ℕ n * (X + ↑n)
| pochhammer ℕ (Nat.succ n + 1)
[PROOFSTEP]
rw [pochhammer_succ_left, ih, mul_comp, ← mul_assoc, ← pochhammer_succ_left, add_comp, X_comp, nat_cast_comp, add_assoc,
    add_comm (1 : ℕ[X]), ← Nat.cast_succ]
[GOAL]
S : Type u
inst✝ : Semiring S
n : ℕ
ih : pochhammer ℕ (n + 1) = pochhammer ℕ n * (X + ↑n)
| pochhammer ℕ (Nat.succ n + 1)
[PROOFSTEP]
rw [pochhammer_succ_left, ih, mul_comp, ← mul_assoc, ← pochhammer_succ_left, add_comp, X_comp, nat_cast_comp, add_assoc,
  add_comm (1 : ℕ[X]), ← Nat.cast_succ]
[GOAL]
S✝ : Type u
inst✝¹ : Semiring S✝
S : Type u_1
inst✝ : Semiring S
n : ℕ
k : S
⊢ eval k (pochhammer S (n + 1)) = eval k (pochhammer S n) * (k + ↑n)
[PROOFSTEP]
rw [pochhammer_succ_right, mul_add, eval_add, eval_mul_X, ← Nat.cast_comm, ← C_eq_nat_cast, eval_C_mul, Nat.cast_comm, ←
  mul_add]
[GOAL]
S : Type u
inst✝ : Semiring S
n : ℕ
⊢ comp (pochhammer S (n + 1)) (X + 1) = pochhammer S (n + 1) + (n + 1) • comp (pochhammer S n) (X + 1)
[PROOFSTEP]
suffices (pochhammer ℕ (n + 1)).comp (X + 1) = pochhammer ℕ (n + 1) + (n + 1) * (pochhammer ℕ n).comp (X + 1) by
  simpa [map_comp] using congr_arg (Polynomial.map (Nat.castRingHom S)) this
[GOAL]
S : Type u
inst✝ : Semiring S
n : ℕ
this : comp (pochhammer ℕ (n + 1)) (X + 1) = pochhammer ℕ (n + 1) + (↑n + 1) * comp (pochhammer ℕ n) (X + 1)
⊢ comp (pochhammer S (n + 1)) (X + 1) = pochhammer S (n + 1) + (n + 1) • comp (pochhammer S n) (X + 1)
[PROOFSTEP]
simpa [map_comp] using congr_arg (Polynomial.map (Nat.castRingHom S)) this
[GOAL]
S : Type u
inst✝ : Semiring S
n : ℕ
⊢ comp (pochhammer ℕ (n + 1)) (X + 1) = pochhammer ℕ (n + 1) + (↑n + 1) * comp (pochhammer ℕ n) (X + 1)
[PROOFSTEP]
nth_rw 2 [pochhammer_succ_left]
[GOAL]
S : Type u
inst✝ : Semiring S
n : ℕ
⊢ comp (pochhammer ℕ (n + 1)) (X + 1) = X * comp (pochhammer ℕ n) (X + 1) + (↑n + 1) * comp (pochhammer ℕ n) (X + 1)
[PROOFSTEP]
rw [← add_mul, pochhammer_succ_right ℕ n, mul_comp, mul_comm, add_comp, X_comp, nat_cast_comp, add_comm, ← add_assoc]
[GOAL]
S : Type u
inst✝ : Semiring S
n : ℕ
⊢ (↑n + X + 1) * comp (pochhammer ℕ n) (X + 1) = (X + (↑n + 1)) * comp (pochhammer ℕ n) (X + 1)
[PROOFSTEP]
ring
[GOAL]
S : Type u
inst✝ : Semiring S
p q : S[X]
n : ℕ
⊢ comp (p * (X + ↑n)) q = comp p q * (q + ↑n)
[PROOFSTEP]
rw [mul_add, add_comp, mul_X_comp, ← Nat.cast_comm, nat_cast_mul_comp, Nat.cast_comm, mul_add]
[GOAL]
S : Type u
inst✝ : Semiring S
n m : ℕ
⊢ pochhammer S n * comp (pochhammer S m) (X + ↑n) = pochhammer S (n + m)
[PROOFSTEP]
induction' m with m ih
[GOAL]
case zero
S : Type u
inst✝ : Semiring S
n : ℕ
⊢ pochhammer S n * comp (pochhammer S Nat.zero) (X + ↑n) = pochhammer S (n + Nat.zero)
[PROOFSTEP]
simp
[GOAL]
case succ
S : Type u
inst✝ : Semiring S
n m : ℕ
ih : pochhammer S n * comp (pochhammer S m) (X + ↑n) = pochhammer S (n + m)
⊢ pochhammer S n * comp (pochhammer S (Nat.succ m)) (X + ↑n) = pochhammer S (n + Nat.succ m)
[PROOFSTEP]
rw [pochhammer_succ_right, Polynomial.mul_X_add_nat_cast_comp, ← mul_assoc, ih, Nat.succ_eq_add_one, ← add_assoc,
  pochhammer_succ_right, Nat.cast_add, add_assoc]
[GOAL]
S : Type u
inst✝ : Semiring S
n : ℕ
⊢ eval (n + 1) (pochhammer ℕ 0) = Nat.ascFactorial n 0
[PROOFSTEP]
rw [pochhammer_zero, eval_one, Nat.ascFactorial_zero]
[GOAL]
S : Type u
inst✝ : Semiring S
n t : ℕ
⊢ eval (n + 1) (pochhammer ℕ (t + 1)) = Nat.ascFactorial n (t + 1)
[PROOFSTEP]
rw [pochhammer_succ_right, eval_mul, pochhammer_nat_eq_ascFactorial n t]
[GOAL]
S : Type u
inst✝ : Semiring S
n t : ℕ
⊢ Nat.ascFactorial n t * eval (n + 1) (X + ↑t) = Nat.ascFactorial n (t + 1)
[PROOFSTEP]
simp only [eval_add, eval_X, eval_nat_cast, Nat.cast_id]
[GOAL]
S : Type u
inst✝ : Semiring S
n t : ℕ
⊢ Nat.ascFactorial n t * (n + 1 + t) = Nat.ascFactorial n (t + 1)
[PROOFSTEP]
rw [Nat.ascFactorial_succ, add_right_comm, mul_comm]
[GOAL]
S : Type u
inst✝ : Semiring S
a b : ℕ
⊢ eval a (pochhammer ℕ b) = Nat.descFactorial (a + b - 1) b
[PROOFSTEP]
cases' b with b
[GOAL]
case zero
S : Type u
inst✝ : Semiring S
a : ℕ
⊢ eval a (pochhammer ℕ Nat.zero) = Nat.descFactorial (a + Nat.zero - 1) Nat.zero
[PROOFSTEP]
rw [Nat.descFactorial_zero, pochhammer_zero, Polynomial.eval_one]
[GOAL]
case succ
S : Type u
inst✝ : Semiring S
a b : ℕ
⊢ eval a (pochhammer ℕ (Nat.succ b)) = Nat.descFactorial (a + Nat.succ b - 1) (Nat.succ b)
[PROOFSTEP]
rw [Nat.add_succ, Nat.succ_sub_succ, tsub_zero]
[GOAL]
case succ
S : Type u
inst✝ : Semiring S
a b : ℕ
⊢ eval a (pochhammer ℕ (Nat.succ b)) = Nat.descFactorial (a + b) (Nat.succ b)
[PROOFSTEP]
cases a
[GOAL]
case succ.zero
S : Type u
inst✝ : Semiring S
b : ℕ
⊢ eval Nat.zero (pochhammer ℕ (Nat.succ b)) = Nat.descFactorial (Nat.zero + b) (Nat.succ b)
[PROOFSTEP]
simp only [Nat.zero_eq, ne_eq, Nat.succ_ne_zero, not_false_iff, pochhammer_ne_zero_eval_zero, zero_add,
  Nat.descFactorial_succ, le_refl, tsub_eq_zero_of_le, zero_mul]
[GOAL]
case succ.succ
S : Type u
inst✝ : Semiring S
b n✝ : ℕ
⊢ eval (Nat.succ n✝) (pochhammer ℕ (Nat.succ b)) = Nat.descFactorial (Nat.succ n✝ + b) (Nat.succ b)
[PROOFSTEP]
rw [Nat.succ_add, ← Nat.add_succ, Nat.add_descFactorial_eq_ascFactorial, pochhammer_nat_eq_ascFactorial]
[GOAL]
S : Type u_1
inst✝ : StrictOrderedSemiring S
n : ℕ
s : S
h : 0 < s
⊢ 0 < eval s (pochhammer S n)
[PROOFSTEP]
induction' n with n ih
[GOAL]
case zero
S : Type u_1
inst✝ : StrictOrderedSemiring S
s : S
h : 0 < s
⊢ 0 < eval s (pochhammer S Nat.zero)
[PROOFSTEP]
simp only [Nat.zero_eq, pochhammer_zero, eval_one]
[GOAL]
case zero
S : Type u_1
inst✝ : StrictOrderedSemiring S
s : S
h : 0 < s
⊢ 0 < 1
[PROOFSTEP]
exact zero_lt_one
[GOAL]
case succ
S : Type u_1
inst✝ : StrictOrderedSemiring S
s : S
h : 0 < s
n : ℕ
ih : 0 < eval s (pochhammer S n)
⊢ 0 < eval s (pochhammer S (Nat.succ n))
[PROOFSTEP]
rw [pochhammer_succ_right, mul_add, eval_add, ← Nat.cast_comm, eval_nat_cast_mul, eval_mul_X, Nat.cast_comm, ← mul_add]
[GOAL]
case succ
S : Type u_1
inst✝ : StrictOrderedSemiring S
s : S
h : 0 < s
n : ℕ
ih : 0 < eval s (pochhammer S n)
⊢ 0 < eval s (pochhammer S n) * (s + ↑n)
[PROOFSTEP]
exact mul_pos ih (lt_of_lt_of_le h ((le_add_iff_nonneg_right _).mpr (Nat.cast_nonneg n)))
[GOAL]
S✝ : Type u_1
inst✝¹ : Semiring S✝
r n✝ : ℕ
S : Type u_2
inst✝ : Semiring S
n : ℕ
⊢ eval 1 (pochhammer S n) = ↑n !
[PROOFSTEP]
rw_mod_cast [pochhammer_nat_eq_ascFactorial, Nat.zero_ascFactorial]
[GOAL]
S✝ : Type u_1
inst✝¹ : Semiring S✝
r✝ n✝ : ℕ
S : Type u_2
inst✝ : Semiring S
r n : ℕ
⊢ ↑r ! * eval (↑r + 1) (pochhammer S n) = ↑(r + n)!
[PROOFSTEP]
rw_mod_cast [pochhammer_nat_eq_ascFactorial, Nat.factorial_mul_ascFactorial]
[GOAL]
S : Type u_1
inst✝ : Semiring S
r✝ n r : ℕ
⊢ 0 * eval (0 + 1) (pochhammer ℕ r) = (0 + r) * eval 0 (pochhammer ℕ r)
[PROOFSTEP]
by_cases h : r = 0
[GOAL]
case pos
S : Type u_1
inst✝ : Semiring S
r✝ n r : ℕ
h : r = 0
⊢ 0 * eval (0 + 1) (pochhammer ℕ r) = (0 + r) * eval 0 (pochhammer ℕ r)
[PROOFSTEP]
simp only [h, zero_mul, zero_add]
[GOAL]
case neg
S : Type u_1
inst✝ : Semiring S
r✝ n r : ℕ
h : ¬r = 0
⊢ 0 * eval (0 + 1) (pochhammer ℕ r) = (0 + r) * eval 0 (pochhammer ℕ r)
[PROOFSTEP]
simp only [pochhammer_eval_zero, zero_mul, if_neg h, mul_zero]
[GOAL]
S : Type u_1
inst✝ : Semiring S
r✝ n r k : ℕ
⊢ (k + 1) * eval (k + 1 + 1) (pochhammer ℕ r) = (k + 1 + r) * eval (k + 1) (pochhammer ℕ r)
[PROOFSTEP]
simp only [pochhammer_nat_eq_ascFactorial, Nat.succ_ascFactorial, add_right_comm]
[GOAL]
S : Type u_1
inst✝ : Semiring S
r✝ n✝ r n : ℕ
⊢ ↑n * eval (↑n + 1) (pochhammer S r) = (↑n + ↑r) * eval (↑n) (pochhammer S r)
[PROOFSTEP]
exact_mod_cast congr_arg Nat.cast (pochhammer_nat_eval_succ r n)


[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
⊢ (fun x => eval x P) ~[atTop] fun x => leadingCoeff P * x ^ natDegree P
[PROOFSTEP]
by_cases h : P = 0
[GOAL]
case pos
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
h : P = 0
⊢ (fun x => eval x P) ~[atTop] fun x => leadingCoeff P * x ^ natDegree P
[PROOFSTEP]
simp [h, IsEquivalent.refl]
[GOAL]
case neg
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
h : ¬P = 0
⊢ (fun x => eval x P) ~[atTop] fun x => leadingCoeff P * x ^ natDegree P
[PROOFSTEP]
simp only [Polynomial.eval_eq_sum_range, sum_range_succ]
[GOAL]
case neg
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
h : ¬P = 0
⊢ (fun x =>
      (Finset.sum (range (natDegree P)) fun i => coeff P i * x ^ i) + coeff P (natDegree P) * x ^ natDegree P) ~[atTop]
    fun x => leadingCoeff P * x ^ natDegree P
[PROOFSTEP]
exact
  IsLittleO.add_isEquivalent
    (IsLittleO.sum fun i hi =>
      IsLittleO.const_mul_left
        ((IsLittleO.const_mul_right fun hz => h <| leadingCoeff_eq_zero.mp hz) <|
          isLittleO_pow_pow_atTop_of_lt (mem_range.mp hi))
        _)
    IsEquivalent.refl
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
⊢ Tendsto (fun x => eval x P) atTop atTop ↔ 0 < degree P ∧ 0 ≤ leadingCoeff P
[PROOFSTEP]
refine' ⟨fun h => _, fun h => tendsto_atTop_of_leadingCoeff_nonneg P h.1 h.2⟩
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
h : Tendsto (fun x => eval x P) atTop atTop
⊢ 0 < degree P ∧ 0 ≤ leadingCoeff P
[PROOFSTEP]
have : Tendsto (fun x => P.leadingCoeff * x ^ P.natDegree) atTop atTop := (isEquivalent_atTop_lead P).tendsto_atTop h
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
h : Tendsto (fun x => eval x P) atTop atTop
this : Tendsto (fun x => leadingCoeff P * x ^ natDegree P) atTop atTop
⊢ 0 < degree P ∧ 0 ≤ leadingCoeff P
[PROOFSTEP]
rw [tendsto_const_mul_pow_atTop_iff, ← pos_iff_ne_zero, natDegree_pos_iff_degree_pos] at this
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
h : Tendsto (fun x => eval x P) atTop atTop
this : 0 < degree P ∧ 0 < leadingCoeff P
⊢ 0 < degree P ∧ 0 ≤ leadingCoeff P
[PROOFSTEP]
exact ⟨this.1, this.2.le⟩
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
⊢ Tendsto (fun x => eval x P) atTop atBot ↔ 0 < degree P ∧ leadingCoeff P ≤ 0
[PROOFSTEP]
simp only [← tendsto_neg_atTop_iff, ← eval_neg, tendsto_atTop_iff_leadingCoeff_nonneg, degree_neg, leadingCoeff_neg,
  neg_nonneg]
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : 0 < degree P
⊢ Tendsto (fun x => |eval x P|) atTop atTop
[PROOFSTEP]
cases' le_total 0 P.leadingCoeff with hP hP
[GOAL]
case inl
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : 0 < degree P
hP : 0 ≤ leadingCoeff P
⊢ Tendsto (fun x => |eval x P|) atTop atTop
[PROOFSTEP]
exact tendsto_abs_atTop_atTop.comp (P.tendsto_atTop_of_leadingCoeff_nonneg hdeg hP)
[GOAL]
case inr
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : 0 < degree P
hP : leadingCoeff P ≤ 0
⊢ Tendsto (fun x => |eval x P|) atTop atTop
[PROOFSTEP]
exact tendsto_abs_atBot_atTop.comp (P.tendsto_atBot_of_leadingCoeff_nonpos hdeg hP)
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
⊢ (IsBoundedUnder (fun x x_1 => x ≤ x_1) atTop fun x => |eval x P|) ↔ degree P ≤ 0
[PROOFSTEP]
refine'
  ⟨fun h => _, fun h =>
    ⟨|P.coeff 0|,
      eventually_map.mpr
        (eventually_of_forall
          (forall_imp (fun _ => le_of_eq) fun x =>
            congr_arg abs <| _root_.trans (congr_arg (eval x) (eq_C_of_degree_le_zero h)) eval_C))⟩⟩
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
h : IsBoundedUnder (fun x x_1 => x ≤ x_1) atTop fun x => |eval x P|
⊢ degree P ≤ 0
[PROOFSTEP]
contrapose! h
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
h : 0 < degree P
⊢ ¬IsBoundedUnder (fun x x_1 => x ≤ x_1) atTop fun x => |eval x P|
[PROOFSTEP]
exact not_isBoundedUnder_of_tendsto_atTop (abs_tendsto_atTop P h)
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
c : 𝕜
⊢ Tendsto (fun x => eval x P) atTop (𝓝 c) ↔ leadingCoeff P = c ∧ degree P ≤ 0
[PROOFSTEP]
refine' ⟨fun h => _, fun h => _⟩
[GOAL]
case refine'_1
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
c : 𝕜
h : Tendsto (fun x => eval x P) atTop (𝓝 c)
⊢ leadingCoeff P = c ∧ degree P ≤ 0
[PROOFSTEP]
have := P.isEquivalent_atTop_lead.tendsto_nhds h
[GOAL]
case refine'_1
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
c : 𝕜
h : Tendsto (fun x => eval x P) atTop (𝓝 c)
this : Tendsto (fun x => leadingCoeff P * x ^ natDegree P) atTop (𝓝 c)
⊢ leadingCoeff P = c ∧ degree P ≤ 0
[PROOFSTEP]
by_cases hP : P.leadingCoeff = 0
[GOAL]
case pos
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
c : 𝕜
h : Tendsto (fun x => eval x P) atTop (𝓝 c)
this : Tendsto (fun x => leadingCoeff P * x ^ natDegree P) atTop (𝓝 c)
hP : leadingCoeff P = 0
⊢ leadingCoeff P = c ∧ degree P ≤ 0
[PROOFSTEP]
simp only [hP, zero_mul, tendsto_const_nhds_iff] at this
[GOAL]
case pos
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
c : 𝕜
h : Tendsto (fun x => eval x P) atTop (𝓝 c)
hP : leadingCoeff P = 0
this : 0 = c
⊢ leadingCoeff P = c ∧ degree P ≤ 0
[PROOFSTEP]
refine' ⟨_root_.trans hP this, by simp [leadingCoeff_eq_zero.1 hP]⟩
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
c : 𝕜
h : Tendsto (fun x => eval x P) atTop (𝓝 c)
hP : leadingCoeff P = 0
this : 0 = c
⊢ degree P ≤ 0
[PROOFSTEP]
simp [leadingCoeff_eq_zero.1 hP]
[GOAL]
case neg
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
c : 𝕜
h : Tendsto (fun x => eval x P) atTop (𝓝 c)
this : Tendsto (fun x => leadingCoeff P * x ^ natDegree P) atTop (𝓝 c)
hP : ¬leadingCoeff P = 0
⊢ leadingCoeff P = c ∧ degree P ≤ 0
[PROOFSTEP]
rw [tendsto_const_mul_pow_nhds_iff hP, natDegree_eq_zero_iff_degree_le_zero] at this
[GOAL]
case neg
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
c : 𝕜
h : Tendsto (fun x => eval x P) atTop (𝓝 c)
this : degree P ≤ 0 ∧ leadingCoeff P = c
hP : ¬leadingCoeff P = 0
⊢ leadingCoeff P = c ∧ degree P ≤ 0
[PROOFSTEP]
exact this.symm
[GOAL]
case refine'_2
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
c : 𝕜
h : leadingCoeff P = c ∧ degree P ≤ 0
⊢ Tendsto (fun x => eval x P) atTop (𝓝 c)
[PROOFSTEP]
refine' P.isEquivalent_atTop_lead.symm.tendsto_nhds _
[GOAL]
case refine'_2
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
c : 𝕜
h : leadingCoeff P = c ∧ degree P ≤ 0
⊢ Tendsto (fun x => leadingCoeff P * x ^ natDegree P) atTop (𝓝 c)
[PROOFSTEP]
have : P.natDegree = 0 := natDegree_eq_zero_iff_degree_le_zero.2 h.2
[GOAL]
case refine'_2
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
c : 𝕜
h : leadingCoeff P = c ∧ degree P ≤ 0
this : natDegree P = 0
⊢ Tendsto (fun x => leadingCoeff P * x ^ natDegree P) atTop (𝓝 c)
[PROOFSTEP]
simp only [h.1, this, pow_zero, mul_one]
[GOAL]
case refine'_2
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
c : 𝕜
h : leadingCoeff P = c ∧ degree P ≤ 0
this : natDegree P = 0
⊢ Tendsto (fun x => c) atTop (𝓝 c)
[PROOFSTEP]
exact tendsto_const_nhds
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
⊢ (fun x => eval x P / eval x Q) ~[atTop] fun x =>
    leadingCoeff P / leadingCoeff Q * x ^ (↑(natDegree P) - ↑(natDegree Q))
[PROOFSTEP]
by_cases hP : P = 0
[GOAL]
case pos
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hP : P = 0
⊢ (fun x => eval x P / eval x Q) ~[atTop] fun x =>
    leadingCoeff P / leadingCoeff Q * x ^ (↑(natDegree P) - ↑(natDegree Q))
[PROOFSTEP]
simp [hP, IsEquivalent.refl]
[GOAL]
case neg
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hP : ¬P = 0
⊢ (fun x => eval x P / eval x Q) ~[atTop] fun x =>
    leadingCoeff P / leadingCoeff Q * x ^ (↑(natDegree P) - ↑(natDegree Q))
[PROOFSTEP]
by_cases hQ : Q = 0
[GOAL]
case pos
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hP : ¬P = 0
hQ : Q = 0
⊢ (fun x => eval x P / eval x Q) ~[atTop] fun x =>
    leadingCoeff P / leadingCoeff Q * x ^ (↑(natDegree P) - ↑(natDegree Q))
[PROOFSTEP]
simp [hQ, IsEquivalent.refl]
[GOAL]
case neg
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hP : ¬P = 0
hQ : ¬Q = 0
⊢ (fun x => eval x P / eval x Q) ~[atTop] fun x =>
    leadingCoeff P / leadingCoeff Q * x ^ (↑(natDegree P) - ↑(natDegree Q))
[PROOFSTEP]
refine'
  (P.isEquivalent_atTop_lead.symm.div Q.isEquivalent_atTop_lead.symm).symm.trans
    (EventuallyEq.isEquivalent ((eventually_gt_atTop 0).mono fun x hx => _))
[GOAL]
case neg
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hP : ¬P = 0
hQ : ¬Q = 0
x : 𝕜
hx : 0 < x
⊢ (fun x => leadingCoeff P * x ^ natDegree P / (leadingCoeff Q * x ^ natDegree Q)) x =
    (fun x => leadingCoeff P / leadingCoeff Q * x ^ (↑(natDegree P) - ↑(natDegree Q))) x
[PROOFSTEP]
simp [← div_mul_div_comm, hP, hQ, zpow_sub₀ hx.ne.symm]
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : degree P < degree Q
⊢ Tendsto (fun x => eval x P / eval x Q) atTop (𝓝 0)
[PROOFSTEP]
by_cases hP : P = 0
[GOAL]
case pos
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : degree P < degree Q
hP : P = 0
⊢ Tendsto (fun x => eval x P / eval x Q) atTop (𝓝 0)
[PROOFSTEP]
simp [hP, tendsto_const_nhds]
[GOAL]
case neg
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : degree P < degree Q
hP : ¬P = 0
⊢ Tendsto (fun x => eval x P / eval x Q) atTop (𝓝 0)
[PROOFSTEP]
rw [← natDegree_lt_natDegree_iff hP] at hdeg
[GOAL]
case neg
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : natDegree P < natDegree Q
hP : ¬P = 0
⊢ Tendsto (fun x => eval x P / eval x Q) atTop (𝓝 0)
[PROOFSTEP]
refine' (isEquivalent_atTop_div P Q).symm.tendsto_nhds _
[GOAL]
case neg
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : natDegree P < natDegree Q
hP : ¬P = 0
⊢ Tendsto (fun x => leadingCoeff P / leadingCoeff Q * x ^ (↑(natDegree P) - ↑(natDegree Q))) atTop (𝓝 0)
[PROOFSTEP]
rw [← mul_zero]
[GOAL]
case neg
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : natDegree P < natDegree Q
hP : ¬P = 0
⊢ Tendsto (fun x => leadingCoeff P / leadingCoeff Q * x ^ (↑(natDegree P) - ↑(natDegree Q))) atTop (𝓝 (?neg✝ * 0))
case neg
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : natDegree P < natDegree Q
hP : ¬P = 0
⊢ 𝕜
[PROOFSTEP]
refine' (tendsto_zpow_atTop_zero _).const_mul _
[GOAL]
case neg
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : natDegree P < natDegree Q
hP : ¬P = 0
⊢ ↑(natDegree P) - ↑(natDegree Q) < 0
[PROOFSTEP]
linarith
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hQ : Q ≠ 0
⊢ Tendsto (fun x => eval x P / eval x Q) atTop (𝓝 0) ↔ degree P < degree Q
[PROOFSTEP]
refine' ⟨fun h => _, div_tendsto_zero_of_degree_lt P Q⟩
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hQ : Q ≠ 0
h : Tendsto (fun x => eval x P / eval x Q) atTop (𝓝 0)
⊢ degree P < degree Q
[PROOFSTEP]
by_cases hPQ : P.leadingCoeff / Q.leadingCoeff = 0
[GOAL]
case pos
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hQ : Q ≠ 0
h : Tendsto (fun x => eval x P / eval x Q) atTop (𝓝 0)
hPQ : leadingCoeff P / leadingCoeff Q = 0
⊢ degree P < degree Q
[PROOFSTEP]
simp only [div_eq_mul_inv, inv_eq_zero, mul_eq_zero] at hPQ
[GOAL]
case pos
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hQ : Q ≠ 0
h : Tendsto (fun x => eval x P / eval x Q) atTop (𝓝 0)
hPQ : leadingCoeff P = 0 ∨ leadingCoeff Q = 0
⊢ degree P < degree Q
[PROOFSTEP]
cases' hPQ with hP0 hQ0
[GOAL]
case pos.inl
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hQ : Q ≠ 0
h : Tendsto (fun x => eval x P / eval x Q) atTop (𝓝 0)
hP0 : leadingCoeff P = 0
⊢ degree P < degree Q
[PROOFSTEP]
rw [leadingCoeff_eq_zero.1 hP0, degree_zero]
[GOAL]
case pos.inl
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hQ : Q ≠ 0
h : Tendsto (fun x => eval x P / eval x Q) atTop (𝓝 0)
hP0 : leadingCoeff P = 0
⊢ ⊥ < degree Q
[PROOFSTEP]
exact bot_lt_iff_ne_bot.2 fun hQ' => hQ (degree_eq_bot.1 hQ')
[GOAL]
case pos.inr
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hQ : Q ≠ 0
h : Tendsto (fun x => eval x P / eval x Q) atTop (𝓝 0)
hQ0 : leadingCoeff Q = 0
⊢ degree P < degree Q
[PROOFSTEP]
exact absurd (leadingCoeff_eq_zero.1 hQ0) hQ
[GOAL]
case neg
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hQ : Q ≠ 0
h : Tendsto (fun x => eval x P / eval x Q) atTop (𝓝 0)
hPQ : ¬leadingCoeff P / leadingCoeff Q = 0
⊢ degree P < degree Q
[PROOFSTEP]
have := (isEquivalent_atTop_div P Q).tendsto_nhds h
[GOAL]
case neg
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hQ : Q ≠ 0
h : Tendsto (fun x => eval x P / eval x Q) atTop (𝓝 0)
hPQ : ¬leadingCoeff P / leadingCoeff Q = 0
this : Tendsto (fun x => leadingCoeff P / leadingCoeff Q * x ^ (↑(natDegree P) - ↑(natDegree Q))) atTop (𝓝 0)
⊢ degree P < degree Q
[PROOFSTEP]
rw [tendsto_const_mul_zpow_atTop_nhds_iff hPQ] at this
[GOAL]
case neg
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hQ : Q ≠ 0
h : Tendsto (fun x => eval x P / eval x Q) atTop (𝓝 0)
hPQ : ¬leadingCoeff P / leadingCoeff Q = 0
this :
  ↑(natDegree P) - ↑(natDegree Q) = 0 ∧ leadingCoeff P / leadingCoeff Q = 0 ∨
    ↑(natDegree P) - ↑(natDegree Q) < 0 ∧ 0 = 0
⊢ degree P < degree Q
[PROOFSTEP]
cases' this with h h
[GOAL]
case neg.inl
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hQ : Q ≠ 0
h✝ : Tendsto (fun x => eval x P / eval x Q) atTop (𝓝 0)
hPQ : ¬leadingCoeff P / leadingCoeff Q = 0
h : ↑(natDegree P) - ↑(natDegree Q) = 0 ∧ leadingCoeff P / leadingCoeff Q = 0
⊢ degree P < degree Q
[PROOFSTEP]
exact absurd h.2 hPQ
[GOAL]
case neg.inr
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hQ : Q ≠ 0
h✝ : Tendsto (fun x => eval x P / eval x Q) atTop (𝓝 0)
hPQ : ¬leadingCoeff P / leadingCoeff Q = 0
h : ↑(natDegree P) - ↑(natDegree Q) < 0 ∧ 0 = 0
⊢ degree P < degree Q
[PROOFSTEP]
rw [sub_lt_iff_lt_add, zero_add, Int.ofNat_lt] at h
[GOAL]
case neg.inr
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hQ : Q ≠ 0
h✝ : Tendsto (fun x => eval x P / eval x Q) atTop (𝓝 0)
hPQ : ¬leadingCoeff P / leadingCoeff Q = 0
h : natDegree P < natDegree Q ∧ 0 = 0
⊢ degree P < degree Q
[PROOFSTEP]
exact degree_lt_degree h.1
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : degree P = degree Q
⊢ Tendsto (fun x => eval x P / eval x Q) atTop (𝓝 (leadingCoeff P / leadingCoeff Q))
[PROOFSTEP]
refine' (isEquivalent_atTop_div P Q).symm.tendsto_nhds _
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : degree P = degree Q
⊢ Tendsto (fun x => leadingCoeff P / leadingCoeff Q * x ^ (↑(natDegree P) - ↑(natDegree Q))) atTop
    (𝓝 (leadingCoeff P / leadingCoeff Q))
[PROOFSTEP]
rw [show (P.natDegree : ℤ) = Q.natDegree by simp [hdeg, natDegree]]
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : degree P = degree Q
⊢ ↑(natDegree P) = ↑(natDegree Q)
[PROOFSTEP]
simp [hdeg, natDegree]
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : degree P = degree Q
⊢ Tendsto (fun x => leadingCoeff P / leadingCoeff Q * x ^ (↑(natDegree Q) - ↑(natDegree Q))) atTop
    (𝓝 (leadingCoeff P / leadingCoeff Q))
[PROOFSTEP]
simp [tendsto_const_nhds]
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : degree Q < degree P
hpos : 0 < leadingCoeff P / leadingCoeff Q
⊢ Tendsto (fun x => eval x P / eval x Q) atTop atTop
[PROOFSTEP]
have hQ : Q ≠ 0 := fun h => by
  simp only [h, div_zero, leadingCoeff_zero] at hpos
  exact hpos.false
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : degree Q < degree P
hpos : 0 < leadingCoeff P / leadingCoeff Q
h : Q = 0
⊢ False
[PROOFSTEP]
simp only [h, div_zero, leadingCoeff_zero] at hpos
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : degree Q < degree P
h : Q = 0
hpos : 0 < 0
⊢ False
[PROOFSTEP]
exact hpos.false
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : degree Q < degree P
hpos : 0 < leadingCoeff P / leadingCoeff Q
hQ : Q ≠ 0
⊢ Tendsto (fun x => eval x P / eval x Q) atTop atTop
[PROOFSTEP]
rw [← natDegree_lt_natDegree_iff hQ] at hdeg
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : natDegree Q < natDegree P
hpos : 0 < leadingCoeff P / leadingCoeff Q
hQ : Q ≠ 0
⊢ Tendsto (fun x => eval x P / eval x Q) atTop atTop
[PROOFSTEP]
refine' (isEquivalent_atTop_div P Q).symm.tendsto_atTop _
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : natDegree Q < natDegree P
hpos : 0 < leadingCoeff P / leadingCoeff Q
hQ : Q ≠ 0
⊢ Tendsto (fun x => leadingCoeff P / leadingCoeff Q * x ^ (↑(natDegree P) - ↑(natDegree Q))) atTop atTop
[PROOFSTEP]
apply Tendsto.const_mul_atTop hpos
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : natDegree Q < natDegree P
hpos : 0 < leadingCoeff P / leadingCoeff Q
hQ : Q ≠ 0
⊢ Tendsto (fun x => x ^ (↑(natDegree P) - ↑(natDegree Q))) atTop atTop
[PROOFSTEP]
apply tendsto_zpow_atTop_atTop
[GOAL]
case hn
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : natDegree Q < natDegree P
hpos : 0 < leadingCoeff P / leadingCoeff Q
hQ : Q ≠ 0
⊢ 0 < ↑(natDegree P) - ↑(natDegree Q)
[PROOFSTEP]
linarith
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : degree Q < degree P
hneg : leadingCoeff P / leadingCoeff Q < 0
⊢ Tendsto (fun x => eval x P / eval x Q) atTop atBot
[PROOFSTEP]
have hQ : Q ≠ 0 := fun h => by
  simp only [h, div_zero, leadingCoeff_zero] at hneg
  exact hneg.false
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : degree Q < degree P
hneg : leadingCoeff P / leadingCoeff Q < 0
h : Q = 0
⊢ False
[PROOFSTEP]
simp only [h, div_zero, leadingCoeff_zero] at hneg
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : degree Q < degree P
h : Q = 0
hneg : 0 < 0
⊢ False
[PROOFSTEP]
exact hneg.false
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : degree Q < degree P
hneg : leadingCoeff P / leadingCoeff Q < 0
hQ : Q ≠ 0
⊢ Tendsto (fun x => eval x P / eval x Q) atTop atBot
[PROOFSTEP]
rw [← natDegree_lt_natDegree_iff hQ] at hdeg
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : natDegree Q < natDegree P
hneg : leadingCoeff P / leadingCoeff Q < 0
hQ : Q ≠ 0
⊢ Tendsto (fun x => eval x P / eval x Q) atTop atBot
[PROOFSTEP]
refine' (isEquivalent_atTop_div P Q).symm.tendsto_atBot _
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : natDegree Q < natDegree P
hneg : leadingCoeff P / leadingCoeff Q < 0
hQ : Q ≠ 0
⊢ Tendsto (fun x => leadingCoeff P / leadingCoeff Q * x ^ (↑(natDegree P) - ↑(natDegree Q))) atTop atBot
[PROOFSTEP]
apply Tendsto.neg_const_mul_atTop hneg
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : natDegree Q < natDegree P
hneg : leadingCoeff P / leadingCoeff Q < 0
hQ : Q ≠ 0
⊢ Tendsto (fun x => x ^ (↑(natDegree P) - ↑(natDegree Q))) atTop atTop
[PROOFSTEP]
apply tendsto_zpow_atTop_atTop
[GOAL]
case hn
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : natDegree Q < natDegree P
hneg : leadingCoeff P / leadingCoeff Q < 0
hQ : Q ≠ 0
⊢ 0 < ↑(natDegree P) - ↑(natDegree Q)
[PROOFSTEP]
linarith
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : degree Q < degree P
hQ : Q ≠ 0
⊢ Tendsto (fun x => |eval x P / eval x Q|) atTop atTop
[PROOFSTEP]
by_cases h : 0 ≤ P.leadingCoeff / Q.leadingCoeff
[GOAL]
case pos
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : degree Q < degree P
hQ : Q ≠ 0
h : 0 ≤ leadingCoeff P / leadingCoeff Q
⊢ Tendsto (fun x => |eval x P / eval x Q|) atTop atTop
[PROOFSTEP]
exact tendsto_abs_atTop_atTop.comp (P.div_tendsto_atTop_of_degree_gt Q hdeg hQ h)
[GOAL]
case neg
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : degree Q < degree P
hQ : Q ≠ 0
h : ¬0 ≤ leadingCoeff P / leadingCoeff Q
⊢ Tendsto (fun x => |eval x P / eval x Q|) atTop atTop
[PROOFSTEP]
push_neg at h
[GOAL]
case neg
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : degree Q < degree P
hQ : Q ≠ 0
h : leadingCoeff P / leadingCoeff Q < 0
⊢ Tendsto (fun x => |eval x P / eval x Q|) atTop atTop
[PROOFSTEP]
exact tendsto_abs_atBot_atTop.comp (P.div_tendsto_atBot_of_degree_gt Q hdeg hQ h.le)
[GOAL]
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
h : degree P ≤ degree Q
⊢ (fun x => eval x P) =O[atTop] fun x => eval x Q
[PROOFSTEP]
by_cases hp : P = 0
[GOAL]
case pos
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
h : degree P ≤ degree Q
hp : P = 0
⊢ (fun x => eval x P) =O[atTop] fun x => eval x Q
[PROOFSTEP]
simpa [hp] using isBigO_zero (fun x => eval x Q) atTop
[GOAL]
case neg
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
h : degree P ≤ degree Q
hp : ¬P = 0
⊢ (fun x => eval x P) =O[atTop] fun x => eval x Q
[PROOFSTEP]
have hq : Q ≠ 0 := ne_zero_of_degree_ge_degree h hp
[GOAL]
case neg
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
h : degree P ≤ degree Q
hp : ¬P = 0
hq : Q ≠ 0
⊢ (fun x => eval x P) =O[atTop] fun x => eval x Q
[PROOFSTEP]
have hPQ : ∀ᶠ x : 𝕜 in atTop, eval x Q = 0 → eval x P = 0 :=
  Filter.mem_of_superset (Polynomial.eventually_no_roots Q hq) fun x h h' => absurd h' h
[GOAL]
case neg
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
h : degree P ≤ degree Q
hp : ¬P = 0
hq : Q ≠ 0
hPQ : ∀ᶠ (x : 𝕜) in atTop, eval x Q = 0 → eval x P = 0
⊢ (fun x => eval x P) =O[atTop] fun x => eval x Q
[PROOFSTEP]
cases' le_iff_lt_or_eq.mp h with h h
[GOAL]
case neg.inl
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
h✝ : degree P ≤ degree Q
hp : ¬P = 0
hq : Q ≠ 0
hPQ : ∀ᶠ (x : 𝕜) in atTop, eval x Q = 0 → eval x P = 0
h : degree P < degree Q
⊢ (fun x => eval x P) =O[atTop] fun x => eval x Q
[PROOFSTEP]
exact isBigO_of_div_tendsto_nhds hPQ 0 (div_tendsto_zero_of_degree_lt P Q h)
[GOAL]
case neg.inr
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
h✝ : degree P ≤ degree Q
hp : ¬P = 0
hq : Q ≠ 0
hPQ : ∀ᶠ (x : 𝕜) in atTop, eval x Q = 0 → eval x P = 0
h : degree P = degree Q
⊢ (fun x => eval x P) =O[atTop] fun x => eval x Q
[PROOFSTEP]
exact isBigO_of_div_tendsto_nhds hPQ _ (div_tendsto_leadingCoeff_div_of_degree_eq P Q h)


[GOAL]
p : ℕ
hp : Fact (Nat.Prime p)
a : ZMod p
hap : a ≠ 0
⊢ Multiset.map (fun x => Int.natAbs (valMinAbs (a * ↑x))) (Ico 1 (succ (p / 2))).val =
    Multiset.map (fun a => a) (Ico 1 (succ (p / 2))).val
[PROOFSTEP]
have he : ∀ {x}, x ∈ Ico 1 (p / 2).succ → x ≠ 0 ∧ x ≤ p / 2 := by
  simp (config := { contextual := true }) [Nat.lt_succ_iff, Nat.succ_le_iff, pos_iff_ne_zero]
[GOAL]
p : ℕ
hp : Fact (Nat.Prime p)
a : ZMod p
hap : a ≠ 0
⊢ ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x ≠ 0 ∧ x ≤ p / 2
[PROOFSTEP]
simp (config := { contextual := true }) [Nat.lt_succ_iff, Nat.succ_le_iff, pos_iff_ne_zero]
[GOAL]
p : ℕ
hp : Fact (Nat.Prime p)
a : ZMod p
hap : a ≠ 0
he : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x ≠ 0 ∧ x ≤ p / 2
⊢ Multiset.map (fun x => Int.natAbs (valMinAbs (a * ↑x))) (Ico 1 (succ (p / 2))).val =
    Multiset.map (fun a => a) (Ico 1 (succ (p / 2))).val
[PROOFSTEP]
have hep : ∀ {x}, x ∈ Ico 1 (p / 2).succ → x < p := fun hx =>
  lt_of_le_of_lt (he hx).2 (Nat.div_lt_self hp.1.pos (by decide))
[GOAL]
p : ℕ
hp : Fact (Nat.Prime p)
a : ZMod p
hap : a ≠ 0
he : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x ≠ 0 ∧ x ≤ p / 2
x✝ : ℕ
hx : x✝ ∈ Ico 1 (succ (p / 2))
⊢ 1 < 2
[PROOFSTEP]
decide
[GOAL]
p : ℕ
hp : Fact (Nat.Prime p)
a : ZMod p
hap : a ≠ 0
he : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x ≠ 0 ∧ x ≤ p / 2
hep : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x < p
⊢ Multiset.map (fun x => Int.natAbs (valMinAbs (a * ↑x))) (Ico 1 (succ (p / 2))).val =
    Multiset.map (fun a => a) (Ico 1 (succ (p / 2))).val
[PROOFSTEP]
have hpe : ∀ {x}, x ∈ Ico 1 (p / 2).succ → ¬p ∣ x := fun hx hpx =>
  not_lt_of_ge (le_of_dvd (Nat.pos_of_ne_zero (he hx).1) hpx) (hep hx)
[GOAL]
p : ℕ
hp : Fact (Nat.Prime p)
a : ZMod p
hap : a ≠ 0
he : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x ≠ 0 ∧ x ≤ p / 2
hep : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x < p
hpe : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → ¬p ∣ x
⊢ Multiset.map (fun x => Int.natAbs (valMinAbs (a * ↑x))) (Ico 1 (succ (p / 2))).val =
    Multiset.map (fun a => a) (Ico 1 (succ (p / 2))).val
[PROOFSTEP]
have hmem : ∀ (x : ℕ) (hx : x ∈ Ico 1 (p / 2).succ), (a * x : ZMod p).valMinAbs.natAbs ∈ Ico 1 (p / 2).succ :=
  by
  intro x hx
  simp [hap, CharP.cast_eq_zero_iff (ZMod p) p, hpe hx, lt_succ_iff, succ_le_iff, pos_iff_ne_zero,
    natAbs_valMinAbs_le _]
[GOAL]
p : ℕ
hp : Fact (Nat.Prime p)
a : ZMod p
hap : a ≠ 0
he : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x ≠ 0 ∧ x ≤ p / 2
hep : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x < p
hpe : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → ¬p ∣ x
⊢ ∀ (x : ℕ), x ∈ Ico 1 (succ (p / 2)) → Int.natAbs (valMinAbs (a * ↑x)) ∈ Ico 1 (succ (p / 2))
[PROOFSTEP]
intro x hx
[GOAL]
p : ℕ
hp : Fact (Nat.Prime p)
a : ZMod p
hap : a ≠ 0
he : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x ≠ 0 ∧ x ≤ p / 2
hep : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x < p
hpe : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → ¬p ∣ x
x : ℕ
hx : x ∈ Ico 1 (succ (p / 2))
⊢ Int.natAbs (valMinAbs (a * ↑x)) ∈ Ico 1 (succ (p / 2))
[PROOFSTEP]
simp [hap, CharP.cast_eq_zero_iff (ZMod p) p, hpe hx, lt_succ_iff, succ_le_iff, pos_iff_ne_zero, natAbs_valMinAbs_le _]
[GOAL]
p : ℕ
hp : Fact (Nat.Prime p)
a : ZMod p
hap : a ≠ 0
he : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x ≠ 0 ∧ x ≤ p / 2
hep : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x < p
hpe : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → ¬p ∣ x
hmem : ∀ (x : ℕ), x ∈ Ico 1 (succ (p / 2)) → Int.natAbs (valMinAbs (a * ↑x)) ∈ Ico 1 (succ (p / 2))
⊢ Multiset.map (fun x => Int.natAbs (valMinAbs (a * ↑x))) (Ico 1 (succ (p / 2))).val =
    Multiset.map (fun a => a) (Ico 1 (succ (p / 2))).val
[PROOFSTEP]
have hsurj : ∀ (b : ℕ) (hb : b ∈ Ico 1 (p / 2).succ), ∃ x ∈ Ico 1 (p / 2).succ, b = (a * x : ZMod p).valMinAbs.natAbs :=
  by
  intro b hb
  refine' ⟨(b / a : ZMod p).valMinAbs.natAbs, mem_Ico.mpr ⟨_, _⟩, _⟩
  · apply Nat.pos_of_ne_zero
    simp only [div_eq_mul_inv, hap, CharP.cast_eq_zero_iff (ZMod p) p, hpe hb, not_false_iff, valMinAbs_eq_zero,
      inv_eq_zero, Int.natAbs_eq_zero, Ne.def, _root_.mul_eq_zero, or_self_iff]
  · apply lt_succ_of_le; apply natAbs_valMinAbs_le
  · rw [nat_cast_natAbs_valMinAbs]
    split_ifs
    ·
      erw [mul_div_cancel' _ hap, valMinAbs_def_pos, val_cast_of_lt (hep hb), if_pos (le_of_lt_succ (mem_Ico.1 hb).2),
        Int.natAbs_ofNat]
    ·
      erw [mul_neg, mul_div_cancel' _ hap, natAbs_valMinAbs_neg, valMinAbs_def_pos, val_cast_of_lt (hep hb),
        if_pos (le_of_lt_succ (mem_Ico.1 hb).2), Int.natAbs_ofNat]
[GOAL]
p : ℕ
hp : Fact (Nat.Prime p)
a : ZMod p
hap : a ≠ 0
he : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x ≠ 0 ∧ x ≤ p / 2
hep : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x < p
hpe : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → ¬p ∣ x
hmem : ∀ (x : ℕ), x ∈ Ico 1 (succ (p / 2)) → Int.natAbs (valMinAbs (a * ↑x)) ∈ Ico 1 (succ (p / 2))
⊢ ∀ (b : ℕ), b ∈ Ico 1 (succ (p / 2)) → ∃ x, x ∈ Ico 1 (succ (p / 2)) ∧ b = Int.natAbs (valMinAbs (a * ↑x))
[PROOFSTEP]
intro b hb
[GOAL]
p : ℕ
hp : Fact (Nat.Prime p)
a : ZMod p
hap : a ≠ 0
he : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x ≠ 0 ∧ x ≤ p / 2
hep : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x < p
hpe : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → ¬p ∣ x
hmem : ∀ (x : ℕ), x ∈ Ico 1 (succ (p / 2)) → Int.natAbs (valMinAbs (a * ↑x)) ∈ Ico 1 (succ (p / 2))
b : ℕ
hb : b ∈ Ico 1 (succ (p / 2))
⊢ ∃ x, x ∈ Ico 1 (succ (p / 2)) ∧ b = Int.natAbs (valMinAbs (a * ↑x))
[PROOFSTEP]
refine' ⟨(b / a : ZMod p).valMinAbs.natAbs, mem_Ico.mpr ⟨_, _⟩, _⟩
[GOAL]
case refine'_1
p : ℕ
hp : Fact (Nat.Prime p)
a : ZMod p
hap : a ≠ 0
he : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x ≠ 0 ∧ x ≤ p / 2
hep : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x < p
hpe : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → ¬p ∣ x
hmem : ∀ (x : ℕ), x ∈ Ico 1 (succ (p / 2)) → Int.natAbs (valMinAbs (a * ↑x)) ∈ Ico 1 (succ (p / 2))
b : ℕ
hb : b ∈ Ico 1 (succ (p / 2))
⊢ 1 ≤ Int.natAbs (valMinAbs (↑b / a))
[PROOFSTEP]
apply Nat.pos_of_ne_zero
[GOAL]
case refine'_1.a
p : ℕ
hp : Fact (Nat.Prime p)
a : ZMod p
hap : a ≠ 0
he : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x ≠ 0 ∧ x ≤ p / 2
hep : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x < p
hpe : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → ¬p ∣ x
hmem : ∀ (x : ℕ), x ∈ Ico 1 (succ (p / 2)) → Int.natAbs (valMinAbs (a * ↑x)) ∈ Ico 1 (succ (p / 2))
b : ℕ
hb : b ∈ Ico 1 (succ (p / 2))
⊢ Int.natAbs (valMinAbs (↑b / a)) ≠ 0
[PROOFSTEP]
simp only [div_eq_mul_inv, hap, CharP.cast_eq_zero_iff (ZMod p) p, hpe hb, not_false_iff, valMinAbs_eq_zero,
  inv_eq_zero, Int.natAbs_eq_zero, Ne.def, _root_.mul_eq_zero, or_self_iff]
[GOAL]
case refine'_2
p : ℕ
hp : Fact (Nat.Prime p)
a : ZMod p
hap : a ≠ 0
he : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x ≠ 0 ∧ x ≤ p / 2
hep : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x < p
hpe : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → ¬p ∣ x
hmem : ∀ (x : ℕ), x ∈ Ico 1 (succ (p / 2)) → Int.natAbs (valMinAbs (a * ↑x)) ∈ Ico 1 (succ (p / 2))
b : ℕ
hb : b ∈ Ico 1 (succ (p / 2))
⊢ Int.natAbs (valMinAbs (↑b / a)) < succ (p / 2)
[PROOFSTEP]
apply lt_succ_of_le
[GOAL]
case refine'_2.a
p : ℕ
hp : Fact (Nat.Prime p)
a : ZMod p
hap : a ≠ 0
he : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x ≠ 0 ∧ x ≤ p / 2
hep : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x < p
hpe : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → ¬p ∣ x
hmem : ∀ (x : ℕ), x ∈ Ico 1 (succ (p / 2)) → Int.natAbs (valMinAbs (a * ↑x)) ∈ Ico 1 (succ (p / 2))
b : ℕ
hb : b ∈ Ico 1 (succ (p / 2))
⊢ Int.natAbs (valMinAbs (↑b / a)) ≤ p / 2
[PROOFSTEP]
apply natAbs_valMinAbs_le
[GOAL]
case refine'_3
p : ℕ
hp : Fact (Nat.Prime p)
a : ZMod p
hap : a ≠ 0
he : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x ≠ 0 ∧ x ≤ p / 2
hep : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x < p
hpe : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → ¬p ∣ x
hmem : ∀ (x : ℕ), x ∈ Ico 1 (succ (p / 2)) → Int.natAbs (valMinAbs (a * ↑x)) ∈ Ico 1 (succ (p / 2))
b : ℕ
hb : b ∈ Ico 1 (succ (p / 2))
⊢ b = Int.natAbs (valMinAbs (a * ↑(Int.natAbs (valMinAbs (↑b / a)))))
[PROOFSTEP]
rw [nat_cast_natAbs_valMinAbs]
[GOAL]
case refine'_3
p : ℕ
hp : Fact (Nat.Prime p)
a : ZMod p
hap : a ≠ 0
he : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x ≠ 0 ∧ x ≤ p / 2
hep : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x < p
hpe : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → ¬p ∣ x
hmem : ∀ (x : ℕ), x ∈ Ico 1 (succ (p / 2)) → Int.natAbs (valMinAbs (a * ↑x)) ∈ Ico 1 (succ (p / 2))
b : ℕ
hb : b ∈ Ico 1 (succ (p / 2))
⊢ b = Int.natAbs (valMinAbs (a * if val (↑b / a) ≤ p / 2 then ↑b / a else -(↑b / a)))
[PROOFSTEP]
split_ifs
[GOAL]
case pos
p : ℕ
hp : Fact (Nat.Prime p)
a : ZMod p
hap : a ≠ 0
he : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x ≠ 0 ∧ x ≤ p / 2
hep : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x < p
hpe : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → ¬p ∣ x
hmem : ∀ (x : ℕ), x ∈ Ico 1 (succ (p / 2)) → Int.natAbs (valMinAbs (a * ↑x)) ∈ Ico 1 (succ (p / 2))
b : ℕ
hb : b ∈ Ico 1 (succ (p / 2))
h✝ : val (↑b / a) ≤ p / 2
⊢ b = Int.natAbs (valMinAbs (a * (↑b / a)))
[PROOFSTEP]
erw [mul_div_cancel' _ hap, valMinAbs_def_pos, val_cast_of_lt (hep hb), if_pos (le_of_lt_succ (mem_Ico.1 hb).2),
  Int.natAbs_ofNat]
[GOAL]
case neg
p : ℕ
hp : Fact (Nat.Prime p)
a : ZMod p
hap : a ≠ 0
he : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x ≠ 0 ∧ x ≤ p / 2
hep : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x < p
hpe : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → ¬p ∣ x
hmem : ∀ (x : ℕ), x ∈ Ico 1 (succ (p / 2)) → Int.natAbs (valMinAbs (a * ↑x)) ∈ Ico 1 (succ (p / 2))
b : ℕ
hb : b ∈ Ico 1 (succ (p / 2))
h✝ : ¬val (↑b / a) ≤ p / 2
⊢ b = Int.natAbs (valMinAbs (a * -(↑b / a)))
[PROOFSTEP]
erw [mul_neg, mul_div_cancel' _ hap, natAbs_valMinAbs_neg, valMinAbs_def_pos, val_cast_of_lt (hep hb),
  if_pos (le_of_lt_succ (mem_Ico.1 hb).2), Int.natAbs_ofNat]
[GOAL]
p : ℕ
hp : Fact (Nat.Prime p)
a : ZMod p
hap : a ≠ 0
he : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x ≠ 0 ∧ x ≤ p / 2
hep : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x < p
hpe : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → ¬p ∣ x
hmem : ∀ (x : ℕ), x ∈ Ico 1 (succ (p / 2)) → Int.natAbs (valMinAbs (a * ↑x)) ∈ Ico 1 (succ (p / 2))
hsurj : ∀ (b : ℕ), b ∈ Ico 1 (succ (p / 2)) → ∃ x, x ∈ Ico 1 (succ (p / 2)) ∧ b = Int.natAbs (valMinAbs (a * ↑x))
⊢ Multiset.map (fun x => Int.natAbs (valMinAbs (a * ↑x))) (Ico 1 (succ (p / 2))).val =
    Multiset.map (fun a => a) (Ico 1 (succ (p / 2))).val
[PROOFSTEP]
simp only [← exists_prop] at hsurj
[GOAL]
p : ℕ
hp : Fact (Nat.Prime p)
a : ZMod p
hap : a ≠ 0
he : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x ≠ 0 ∧ x ≤ p / 2
hep : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → x < p
hpe : ∀ {x : ℕ}, x ∈ Ico 1 (succ (p / 2)) → ¬p ∣ x
hmem : ∀ (x : ℕ), x ∈ Ico 1 (succ (p / 2)) → Int.natAbs (valMinAbs (a * ↑x)) ∈ Ico 1 (succ (p / 2))
hsurj : ∀ (b : ℕ), b ∈ Ico 1 (succ (p / 2)) → ∃ x _h, b = Int.natAbs (valMinAbs (a * ↑x))
⊢ Multiset.map (fun x => Int.natAbs (valMinAbs (a * ↑x))) (Ico 1 (succ (p / 2))).val =
    Multiset.map (fun a => a) (Ico 1 (succ (p / 2))).val
[PROOFSTEP]
exact
  Multiset.map_eq_map_of_bij_of_nodup _ _ (Finset.nodup _) (Finset.nodup _)
    (fun x _ => (a * x : ZMod p).valMinAbs.natAbs) hmem (fun _ _ => rfl)
    (inj_on_of_surj_on_of_card_le _ hmem hsurj le_rfl) hsurj
[GOAL]
p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
⊢ ↑(a ^ (p / 2)) * ↑(p / 2)! = ↑(∏ x in Ico 1 (succ (p / 2)), a * ↑x)
[PROOFSTEP]
rw [prod_mul_distrib, ← prod_natCast, prod_Ico_id_eq_factorial, prod_const, card_Ico, succ_sub_one]
[GOAL]
p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
⊢ ↑(a ^ (p / 2)) * ↑(p / 2)! = ↑(a ^ (p / 2) * ↑(p / 2)!)
[PROOFSTEP]
simp
[GOAL]
p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
⊢ ↑(∏ x in Ico 1 (succ (p / 2)), a * ↑x) = ∏ x in Ico 1 (succ (p / 2)), ↑(val (↑a * ↑x))
[PROOFSTEP]
simp
[GOAL]
p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
x✝¹ : ℕ
x✝ : x✝¹ ∈ Ico 1 (succ (p / 2))
⊢ ↑(val (↑a * ↑x✝¹)) = (if val (↑a * ↑x✝¹) ≤ p / 2 then 1 else -1) * ↑(Int.natAbs (valMinAbs (↑a * ↑x✝¹)))
[PROOFSTEP]
simp only [nat_cast_natAbs_valMinAbs]
[GOAL]
p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
x✝¹ : ℕ
x✝ : x✝¹ ∈ Ico 1 (succ (p / 2))
⊢ ↑(val (↑a * ↑x✝¹)) =
    (if val (↑a * ↑x✝¹) ≤ p / 2 then 1 else -1) * if val (↑a * ↑x✝¹) ≤ p / 2 then ↑a * ↑x✝¹ else -(↑a * ↑x✝¹)
[PROOFSTEP]
split_ifs
[GOAL]
case pos
p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
x✝¹ : ℕ
x✝ : x✝¹ ∈ Ico 1 (succ (p / 2))
h✝ : val (↑a * ↑x✝¹) ≤ p / 2
⊢ ↑(val (↑a * ↑x✝¹)) = 1 * (↑a * ↑x✝¹)
[PROOFSTEP]
simp
[GOAL]
case neg
p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
x✝¹ : ℕ
x✝ : x✝¹ ∈ Ico 1 (succ (p / 2))
h✝ : ¬val (↑a * ↑x✝¹) ≤ p / 2
⊢ ↑(val (↑a * ↑x✝¹)) = -1 * -(↑a * ↑x✝¹)
[PROOFSTEP]
simp
[GOAL]
p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
⊢ ∏ x in Ico 1 (succ (p / 2)), (if val (↑a * ↑x) ≤ p / 2 then 1 else -1) * ↑(Int.natAbs (valMinAbs (↑a * ↑x))) =
    (-1) ^ Finset.card (filter (fun x => ¬val (↑a * ↑x) ≤ p / 2) (Ico 1 (succ (p / 2)))) *
      ∏ x in Ico 1 (succ (p / 2)), ↑(Int.natAbs (valMinAbs (↑a * ↑x)))
[PROOFSTEP]
have :
  (∏ x in Ico 1 (p / 2).succ, if (a * x : ZMod p).val ≤ p / 2 then (1 : ZMod p) else -1) =
    ∏ x in (Ico 1 (p / 2).succ).filter fun x : ℕ => ¬(a * x : ZMod p).val ≤ p / 2, -1 :=
  prod_bij_ne_one (fun x _ _ => x) (fun x => by split_ifs <;> simp_all (config := { contextual := true }))
    (fun _ _ _ _ _ _ => id) (fun b h _ => ⟨b, by simp_all [-not_le]⟩) (by intros; split_ifs at * <;> simp_all)
[GOAL]
p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
x : ℕ
⊢ ∀ (h₁ : x ∈ Ico 1 (succ (p / 2))) (h₂ : (if val (↑a * ↑x) ≤ p / 2 then 1 else -1) ≠ 1),
    (fun x x_1 x_2 => x) x h₁ h₂ ∈ filter (fun x => ¬val (↑a * ↑x) ≤ p / 2) (Ico 1 (succ (p / 2)))
[PROOFSTEP]
split_ifs
[GOAL]
case pos
p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
x : ℕ
h✝ : val (↑a * ↑x) ≤ p / 2
⊢ ∀ (h₁ : x ∈ Ico 1 (succ (p / 2))) (h₂ : (if val (↑a * ↑x) ≤ p / 2 then 1 else -1) ≠ 1),
    (fun x x_1 x_2 => x) x h₁ h₂ ∈ filter (fun x => ¬val (↑a * ↑x) ≤ p / 2) (Ico 1 (succ (p / 2)))
[PROOFSTEP]
simp_all (config := { contextual := true })
[GOAL]
case neg
p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
x : ℕ
h✝ : ¬val (↑a * ↑x) ≤ p / 2
⊢ ∀ (h₁ : x ∈ Ico 1 (succ (p / 2))) (h₂ : (if val (↑a * ↑x) ≤ p / 2 then 1 else -1) ≠ 1),
    (fun x x_1 x_2 => x) x h₁ h₂ ∈ filter (fun x => ¬val (↑a * ↑x) ≤ p / 2) (Ico 1 (succ (p / 2)))
[PROOFSTEP]
simp_all (config := { contextual := true })
[GOAL]
p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
b : ℕ
h : b ∈ filter (fun x => ¬val (↑a * ↑x) ≤ p / 2) (Ico 1 (succ (p / 2)))
x✝ : -1 ≠ 1
⊢ ∃ h₁ h₂, b = (fun x x_1 x_2 => x) b h₁ h₂
[PROOFSTEP]
simp_all [-not_le]
[GOAL]
p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
⊢ ∀ (a_1 : ℕ),
    a_1 ∈ Ico 1 (succ (p / 2)) →
      (if val (↑a * ↑a_1) ≤ p / 2 then 1 else -1) ≠ 1 → (if val (↑a * ↑a_1) ≤ p / 2 then 1 else -1) = -1
[PROOFSTEP]
intros
[GOAL]
p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
a✝ : ℕ
h₁✝ : a✝ ∈ Ico 1 (succ (p / 2))
h₂✝ : (if val (↑a * ↑a✝) ≤ p / 2 then 1 else -1) ≠ 1
⊢ (if val (↑a * ↑a✝) ≤ p / 2 then 1 else -1) = -1
[PROOFSTEP]
split_ifs at *
[GOAL]
case pos
p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
a✝ : ℕ
h₁✝ : a✝ ∈ Ico 1 (succ (p / 2))
h✝ : val (↑a * ↑a✝) ≤ p / 2
h₂✝ : 1 ≠ 1
⊢ 1 = -1
[PROOFSTEP]
simp_all
[GOAL]
case neg
p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
a✝ : ℕ
h₁✝ : a✝ ∈ Ico 1 (succ (p / 2))
h✝ : ¬val (↑a * ↑a✝) ≤ p / 2
h₂✝ : -1 ≠ 1
⊢ -1 = -1
[PROOFSTEP]
simp_all
[GOAL]
p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
this :
  (∏ x in Ico 1 (succ (p / 2)), if val (↑a * ↑x) ≤ p / 2 then 1 else -1) =
    ∏ x in filter (fun x => ¬val (↑a * ↑x) ≤ p / 2) (Ico 1 (succ (p / 2))), -1
⊢ ∏ x in Ico 1 (succ (p / 2)), (if val (↑a * ↑x) ≤ p / 2 then 1 else -1) * ↑(Int.natAbs (valMinAbs (↑a * ↑x))) =
    (-1) ^ Finset.card (filter (fun x => ¬val (↑a * ↑x) ≤ p / 2) (Ico 1 (succ (p / 2)))) *
      ∏ x in Ico 1 (succ (p / 2)), ↑(Int.natAbs (valMinAbs (↑a * ↑x)))
[PROOFSTEP]
rw [prod_mul_distrib, this]
[GOAL]
p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
this :
  (∏ x in Ico 1 (succ (p / 2)), if val (↑a * ↑x) ≤ p / 2 then 1 else -1) =
    ∏ x in filter (fun x => ¬val (↑a * ↑x) ≤ p / 2) (Ico 1 (succ (p / 2))), -1
⊢ (∏ x in filter (fun x => ¬val (↑a * ↑x) ≤ p / 2) (Ico 1 (succ (p / 2))), -1) *
      ∏ x in Ico 1 (succ (p / 2)), ↑(Int.natAbs (valMinAbs (↑a * ↑x))) =
    (-1) ^ Finset.card (filter (fun x => ¬val (↑a * ↑x) ≤ p / 2) (Ico 1 (succ (p / 2)))) *
      ∏ x in Ico 1 (succ (p / 2)), ↑(Int.natAbs (valMinAbs (↑a * ↑x)))
[PROOFSTEP]
simp
[GOAL]
p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
⊢ (-1) ^ Finset.card (filter (fun x => ¬val (↑a * ↑x) ≤ p / 2) (Ico 1 (succ (p / 2)))) *
      ∏ x in Ico 1 (succ (p / 2)), ↑(Int.natAbs (valMinAbs (↑a * ↑x))) =
    (-1) ^ Finset.card (filter (fun x => ¬val (↑a * ↑x) ≤ p / 2) (Ico 1 (succ (p / 2)))) * ↑(p / 2)!
[PROOFSTEP]
rw [← prod_natCast, Finset.prod_eq_multiset_prod, Ico_map_valMinAbs_natAbs_eq_Ico_map_id p a hap, ←
  Finset.prod_eq_multiset_prod, prod_Ico_id_eq_factorial]
[GOAL]
p : ℕ
hp : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
⊢ ↑(p / 2)! ≠ 0
[PROOFSTEP]
rw [Ne.def, CharP.cast_eq_zero_iff (ZMod p) p, hp.1.dvd_factorial, not_le]
[GOAL]
p : ℕ
hp : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
⊢ p / 2 < p
[PROOFSTEP]
exact Nat.div_lt_self hp.1.pos (by decide)
[GOAL]
p : ℕ
hp : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
⊢ 1 < 2
[PROOFSTEP]
decide
[GOAL]
p : ℕ
hp : Fact (Nat.Prime p)
a : ℤ
hap : ↑a ≠ 0
⊢ ↑a ^ (p / 2) * ↑(p / 2)! =
    ↑((-1) ^ Finset.card (filter (fun x => p / 2 < val (↑a * ↑x)) (Ico 1 (succ (p / 2))))) * ↑(p / 2)!
[PROOFSTEP]
simpa using gauss_lemma_aux₁ p hap
[GOAL]
p : ℕ
h : Fact (Nat.Prime p)
a : ℤ
hp : p ≠ 2
ha0 : ↑a ≠ 0
⊢ legendreSym p a = (-1) ^ Finset.card (filter (fun x => p / 2 < val (↑a * ↑x)) (Ico 1 (succ (p / 2))))
[PROOFSTEP]
replace hp : Odd p := h.out.odd_of_ne_two hp
[GOAL]
p : ℕ
h : Fact (Nat.Prime p)
a : ℤ
ha0 : ↑a ≠ 0
hp : Odd p
⊢ legendreSym p a = (-1) ^ Finset.card (filter (fun x => p / 2 < val (↑a * ↑x)) (Ico 1 (succ (p / 2))))
[PROOFSTEP]
have :
  (legendreSym p a : ZMod p) =
    (((-1) ^ ((Ico 1 (p / 2).succ).filter fun x : ℕ => p / 2 < (a * x : ZMod p).val).card : ℤ) : ZMod p) :=
  by rw [legendreSym.eq_pow, gauss_lemma_aux p ha0]
[GOAL]
p : ℕ
h : Fact (Nat.Prime p)
a : ℤ
ha0 : ↑a ≠ 0
hp : Odd p
⊢ ↑(legendreSym p a) = ↑((-1) ^ Finset.card (filter (fun x => p / 2 < val (↑a * ↑x)) (Ico 1 (succ (p / 2)))))
[PROOFSTEP]
rw [legendreSym.eq_pow, gauss_lemma_aux p ha0]
[GOAL]
p : ℕ
h : Fact (Nat.Prime p)
a : ℤ
ha0 : ↑a ≠ 0
hp : Odd p
this : ↑(legendreSym p a) = ↑((-1) ^ Finset.card (filter (fun x => p / 2 < val (↑a * ↑x)) (Ico 1 (succ (p / 2)))))
⊢ legendreSym p a = (-1) ^ Finset.card (filter (fun x => p / 2 < val (↑a * ↑x)) (Ico 1 (succ (p / 2))))
[PROOFSTEP]
cases legendreSym.eq_one_or_neg_one p ha0
[GOAL]
case inl
p : ℕ
h : Fact (Nat.Prime p)
a : ℤ
ha0 : ↑a ≠ 0
hp : Odd p
this : ↑(legendreSym p a) = ↑((-1) ^ Finset.card (filter (fun x => p / 2 < val (↑a * ↑x)) (Ico 1 (succ (p / 2)))))
h✝ : legendreSym p a = 1
⊢ legendreSym p a = (-1) ^ Finset.card (filter (fun x => p / 2 < val (↑a * ↑x)) (Ico 1 (succ (p / 2))))
[PROOFSTEP]
cases neg_one_pow_eq_or ℤ ((Ico 1 (p / 2).succ).filter fun x : ℕ => p / 2 < (a * x : ZMod p).val).card
[GOAL]
case inr
p : ℕ
h : Fact (Nat.Prime p)
a : ℤ
ha0 : ↑a ≠ 0
hp : Odd p
this : ↑(legendreSym p a) = ↑((-1) ^ Finset.card (filter (fun x => p / 2 < val (↑a * ↑x)) (Ico 1 (succ (p / 2)))))
h✝ : legendreSym p a = -1
⊢ legendreSym p a = (-1) ^ Finset.card (filter (fun x => p / 2 < val (↑a * ↑x)) (Ico 1 (succ (p / 2))))
[PROOFSTEP]
cases neg_one_pow_eq_or ℤ ((Ico 1 (p / 2).succ).filter fun x : ℕ => p / 2 < (a * x : ZMod p).val).card
[GOAL]
case inl.inl
p : ℕ
h : Fact (Nat.Prime p)
a : ℤ
ha0 : ↑a ≠ 0
hp : Odd p
this : ↑(legendreSym p a) = ↑((-1) ^ Finset.card (filter (fun x => p / 2 < val (↑a * ↑x)) (Ico 1 (succ (p / 2)))))
h✝¹ : legendreSym p a = 1
h✝ : (-1) ^ Finset.card (filter (fun x => p / 2 < val (↑a * ↑x)) (Ico 1 (succ (p / 2)))) = 1
⊢ legendreSym p a = (-1) ^ Finset.card (filter (fun x => p / 2 < val (↑a * ↑x)) (Ico 1 (succ (p / 2))))
[PROOFSTEP]
simp_all [ne_neg_self hp one_ne_zero, (ne_neg_self hp one_ne_zero).symm]
[GOAL]
case inl.inr
p : ℕ
h : Fact (Nat.Prime p)
a : ℤ
ha0 : ↑a ≠ 0
hp : Odd p
this : ↑(legendreSym p a) = ↑((-1) ^ Finset.card (filter (fun x => p / 2 < val (↑a * ↑x)) (Ico 1 (succ (p / 2)))))
h✝¹ : legendreSym p a = 1
h✝ : (-1) ^ Finset.card (filter (fun x => p / 2 < val (↑a * ↑x)) (Ico 1 (succ (p / 2)))) = -1
⊢ legendreSym p a = (-1) ^ Finset.card (filter (fun x => p / 2 < val (↑a * ↑x)) (Ico 1 (succ (p / 2))))
[PROOFSTEP]
simp_all [ne_neg_self hp one_ne_zero, (ne_neg_self hp one_ne_zero).symm]
[GOAL]
case inr.inl
p : ℕ
h : Fact (Nat.Prime p)
a : ℤ
ha0 : ↑a ≠ 0
hp : Odd p
this : ↑(legendreSym p a) = ↑((-1) ^ Finset.card (filter (fun x => p / 2 < val (↑a * ↑x)) (Ico 1 (succ (p / 2)))))
h✝¹ : legendreSym p a = -1
h✝ : (-1) ^ Finset.card (filter (fun x => p / 2 < val (↑a * ↑x)) (Ico 1 (succ (p / 2)))) = 1
⊢ legendreSym p a = (-1) ^ Finset.card (filter (fun x => p / 2 < val (↑a * ↑x)) (Ico 1 (succ (p / 2))))
[PROOFSTEP]
simp_all [ne_neg_self hp one_ne_zero, (ne_neg_self hp one_ne_zero).symm]
[GOAL]
case inr.inr
p : ℕ
h : Fact (Nat.Prime p)
a : ℤ
ha0 : ↑a ≠ 0
hp : Odd p
this : ↑(legendreSym p a) = ↑((-1) ^ Finset.card (filter (fun x => p / 2 < val (↑a * ↑x)) (Ico 1 (succ (p / 2)))))
h✝¹ : legendreSym p a = -1
h✝ : (-1) ^ Finset.card (filter (fun x => p / 2 < val (↑a * ↑x)) (Ico 1 (succ (p / 2)))) = -1
⊢ legendreSym p a = (-1) ^ Finset.card (filter (fun x => p / 2 < val (↑a * ↑x)) (Ico 1 (succ (p / 2))))
[PROOFSTEP]
simp_all [ne_neg_self hp one_ne_zero, (ne_neg_self hp one_ne_zero).symm]
[GOAL]
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp2✝ : Fact (p % 2 = 1)
a : ℕ
hap : ↑a ≠ 0
hp2 : ↑p = ↑1
⊢ ↑(∑ x in Ico 1 (succ (p / 2)), a * x) = ↑(∑ x in Ico 1 (succ (p / 2)), (a * x % p + p * (a * x / p)))
[PROOFSTEP]
simp only [mod_add_div]
[GOAL]
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp2✝ : Fact (p % 2 = 1)
a : ℕ
hap : ↑a ≠ 0
hp2 : ↑p = ↑1
⊢ ↑(∑ x in Ico 1 (succ (p / 2)), (a * x % p + p * (a * x / p))) =
    ↑(∑ x in Ico 1 (succ (p / 2)), val ↑(a * x)) + ↑(∑ x in Ico 1 (succ (p / 2)), a * x / p)
[PROOFSTEP]
simp only [val_nat_cast]
[GOAL]
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp2✝ : Fact (p % 2 = 1)
a : ℕ
hap : ↑a ≠ 0
hp2 : ↑p = ↑1
⊢ ↑(∑ x in Ico 1 (succ (p / 2)), (a * x % p + p * (a * x / p))) =
    ↑(∑ x in Ico 1 (succ (p / 2)), a * x % p) + ↑(∑ x in Ico 1 (succ (p / 2)), a * x / p)
[PROOFSTEP]
simp [sum_add_distrib, mul_sum.symm, Nat.cast_add, Nat.cast_mul, Nat.cast_sum, hp2]
[GOAL]
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp2✝ : Fact (p % 2 = 1)
a : ℕ
hap : ↑a ≠ 0
hp2 : ↑p = ↑1
⊢ ↑(∑ x in Ico 1 (succ (p / 2)), val ↑(a * x)) =
    ∑ x in Ico 1 (succ (p / 2)), ↑(valMinAbs (↑a * ↑x) + ↑(if val (↑a * ↑x) ≤ p / 2 then 0 else p))
[PROOFSTEP]
simp only [(val_eq_ite_valMinAbs _).symm]
[GOAL]
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp2✝ : Fact (p % 2 = 1)
a : ℕ
hap : ↑a ≠ 0
hp2 : ↑p = ↑1
⊢ ↑(∑ x in Ico 1 (succ (p / 2)), val ↑(a * x)) = ∑ x in Ico 1 (succ (p / 2)), ↑↑(val (↑a * ↑x))
[PROOFSTEP]
simp [Nat.cast_sum]
[GOAL]
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp2✝ : Fact (p % 2 = 1)
a : ℕ
hap : ↑a ≠ 0
hp2 : ↑p = ↑1
⊢ ∑ x in Ico 1 (succ (p / 2)), ↑(valMinAbs (↑a * ↑x) + ↑(if val (↑a * ↑x) ≤ p / 2 then 0 else p)) =
    ↑(Finset.card (filter (fun x => p / 2 < val (↑a * ↑x)) (Ico 1 (succ (p / 2))))) +
      ↑(∑ x in Ico 1 (succ (p / 2)), Int.natAbs (valMinAbs (↑a * ↑x)))
[PROOFSTEP]
simp [add_comm, sum_add_distrib, Finset.sum_ite, hp2, Nat.cast_sum]
[GOAL]
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp2✝ : Fact (p % 2 = 1)
a : ℕ
hap : ↑a ≠ 0
hp2 : ↑p = ↑1
⊢ ↑(Finset.card (filter (fun x => p / 2 < val (↑a * ↑x)) (Ico 1 (succ (p / 2))))) +
      ↑(∑ x in Ico 1 (succ (p / 2)), Int.natAbs (valMinAbs (↑a * ↑x))) =
    ↑(Finset.card (filter (fun x => p / 2 < val (↑a * ↑x)) (Ico 1 (succ (p / 2))))) + ↑(∑ x in Ico 1 (succ (p / 2)), x)
[PROOFSTEP]
rw [Finset.sum_eq_multiset_sum, Ico_map_valMinAbs_natAbs_eq_Ico_map_id p a hap, ← Finset.sum_eq_multiset_sum]
[GOAL]
p : ℕ
inst✝¹ : Fact (Nat.Prime p)
inst✝ : Fact (p % 2 = 1)
a : ℕ
ha2✝ : a % 2 = 1
hap : ↑a ≠ 0
ha2 : ↑a = ↑1
⊢ ↑(Finset.card (filter (fun x => p / 2 < val (↑a * ↑x)) (Ico 1 (succ (p / 2))))) -
      ↑(∑ x in Ico 1 (succ (p / 2)), x * a / p) =
    0
[PROOFSTEP]
simpa [add_left_comm, sub_eq_add_neg, Finset.mul_sum.symm, mul_comm, ha2, Nat.cast_sum, add_neg_eq_iff_eq_add.symm,
  neg_eq_self_mod_two, add_assoc] using Eq.symm (eisenstein_lemma_aux₁ p hap)
[GOAL]
a b c : ℕ
hb0 : 0 < b
hc : a / b ≤ c
⊢ a / b = Finset.card (Ico 1 (succ (a / b)))
[PROOFSTEP]
simp
[GOAL]
a b c : ℕ
hb0 : 0 < b
hc : a / b ≤ c
x : ℕ
⊢ x ∈ Ico 1 (succ (a / b)) ↔ x ∈ filter (fun x => x * b ≤ a) (Ico 1 (succ c))
[PROOFSTEP]
have : x * b ≤ a → x ≤ c := fun h => le_trans (by rwa [le_div_iff_mul_le hb0]) hc
[GOAL]
a b c : ℕ
hb0 : 0 < b
hc : a / b ≤ c
x : ℕ
h : x * b ≤ a
⊢ x ≤ a / b
[PROOFSTEP]
rwa [le_div_iff_mul_le hb0]
[GOAL]
a b c : ℕ
hb0 : 0 < b
hc : a / b ≤ c
x : ℕ
this : x * b ≤ a → x ≤ c
⊢ x ∈ Ico 1 (succ (a / b)) ↔ x ∈ filter (fun x => x * b ≤ a) (Ico 1 (succ c))
[PROOFSTEP]
simp [lt_succ_iff, le_div_iff_mul_le hb0]
[GOAL]
a b c : ℕ
hb0 : 0 < b
hc : a / b ≤ c
x : ℕ
this : x * b ≤ a → x ≤ c
⊢ x * b ≤ a → 1 ≤ x → x ≤ c
[PROOFSTEP]
tauto
[GOAL]
p q : ℕ
hp0 : p = 0
⊢ ∑ a in Ico 1 (succ (p / 2)), a * q / p =
    Finset.card (filter (fun x => x.snd * p ≤ x.fst * q) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
[PROOFSTEP]
simp [hp0, Finset.ext_iff]
[GOAL]
p q : ℕ
hp0 : ¬p = 0
⊢ ∑ a in Ico 1 (succ (p / 2)), Finset.card (filter (fun x => x * p ≤ a * q) (Ico 1 (succ (q / 2)))) =
    Finset.card (filter (fun x => x.snd * p ≤ x.fst * q) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
[PROOFSTEP]
rw [← card_sigma]
[GOAL]
p q : ℕ
hp0 : ¬p = 0
⊢ Finset.card (Finset.sigma (Ico 1 (succ (p / 2))) fun a => filter (fun x => x * p ≤ a * q) (Ico 1 (succ (q / 2)))) =
    Finset.card (filter (fun x => x.snd * p ≤ x.fst * q) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
[PROOFSTEP]
exact
  card_congr (fun a _ => ⟨a.1, a.2⟩)
    (by
      simp (config := { contextual := true }) only [mem_filter, mem_sigma, and_self_iff, forall_true_iff, mem_product])
    (fun ⟨_, _⟩ ⟨_, _⟩ => by
      simp (config := { contextual := true }) only [Prod.mk.inj_iff, eq_self_iff_true, and_self_iff, heq_iff_eq,
        forall_true_iff])
    fun ⟨b₁, b₂⟩ h =>
    ⟨⟨b₁, b₂⟩, by
      revert h
      simp (config := { contextual := true }) only [mem_filter, eq_self_iff_true, exists_prop_of_true, mem_sigma,
        and_self_iff, forall_true_iff, mem_product]⟩
[GOAL]
p q : ℕ
hp0 : ¬p = 0
⊢ ∀ (a : (_ : ℕ) × ℕ)
    (ha : a ∈ Finset.sigma (Ico 1 (succ (p / 2))) fun a => filter (fun x => x * p ≤ a * q) (Ico 1 (succ (q / 2)))),
    (fun a x => (a.fst, a.snd)) a ha ∈
      filter (fun x => x.snd * p ≤ x.fst * q) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2)))
[PROOFSTEP]
simp (config := { contextual := true }) only [mem_filter, mem_sigma, and_self_iff, forall_true_iff, mem_product]
[GOAL]
p q : ℕ
hp0 : ¬p = 0
x✝¹ x✝ : (_ : ℕ) × ℕ
fst✝¹ snd✝¹ fst✝ snd✝ : ℕ
⊢ ∀
    (ha :
      { fst := fst✝¹, snd := snd✝¹ } ∈
        Finset.sigma (Ico 1 (succ (p / 2))) fun a => filter (fun x => x * p ≤ a * q) (Ico 1 (succ (q / 2))))
    (hb :
      { fst := fst✝, snd := snd✝ } ∈
        Finset.sigma (Ico 1 (succ (p / 2))) fun a => filter (fun x => x * p ≤ a * q) (Ico 1 (succ (q / 2)))),
    (fun a x => (a.fst, a.snd)) { fst := fst✝¹, snd := snd✝¹ } ha =
        (fun a x => (a.fst, a.snd)) { fst := fst✝, snd := snd✝ } hb →
      { fst := fst✝¹, snd := snd✝¹ } = { fst := fst✝, snd := snd✝ }
[PROOFSTEP]
simp (config := { contextual := true }) only [Prod.mk.inj_iff, eq_self_iff_true, and_self_iff, heq_iff_eq,
  forall_true_iff]
[GOAL]
p q : ℕ
hp0 : ¬p = 0
x✝ : ℕ × ℕ
b₁ b₂ : ℕ
h : (b₁, b₂) ∈ filter (fun x => x.snd * p ≤ x.fst * q) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2)))
⊢ ∃ ha, (fun a x => (a.fst, a.snd)) { fst := b₁, snd := b₂ } ha = (b₁, b₂)
[PROOFSTEP]
revert h
[GOAL]
p q : ℕ
hp0 : ¬p = 0
x✝ : ℕ × ℕ
b₁ b₂ : ℕ
⊢ (b₁, b₂) ∈ filter (fun x => x.snd * p ≤ x.fst * q) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))) →
    ∃ ha, (fun a x => (a.fst, a.snd)) { fst := b₁, snd := b₂ } ha = (b₁, b₂)
[PROOFSTEP]
simp (config := { contextual := true }) only [mem_filter, eq_self_iff_true, exists_prop_of_true, mem_sigma,
  and_self_iff, forall_true_iff, mem_product]
[GOAL]
p q : ℕ
hp : Fact (Nat.Prime p)
hq0 : ↑q ≠ 0
⊢ ∑ a in Ico 1 (succ (p / 2)), a * q / p + ∑ a in Ico 1 (succ (q / 2)), a * p / q = p / 2 * (q / 2)
[PROOFSTEP]
have hswap :
  ((Ico 1 (q / 2).succ ×ˢ Ico 1 (p / 2).succ).filter fun x : ℕ × ℕ => x.2 * q ≤ x.1 * p).card =
    ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ => x.1 * q ≤ x.2 * p).card :=
  card_congr (fun x _ => Prod.swap x)
    (fun ⟨_, _⟩ => by
      simp (config := { contextual := true }) only [mem_filter, and_self_iff, Prod.swap_prod_mk, forall_true_iff,
        mem_product])
    (fun ⟨_, _⟩ ⟨_, _⟩ => by
      simp (config := { contextual := true }) only [Prod.mk.inj_iff, eq_self_iff_true, and_self_iff, Prod.swap_prod_mk,
        forall_true_iff])
    fun ⟨x₁, x₂⟩ h =>
    ⟨⟨x₂, x₁⟩, by
      revert h
      simp (config := { contextual := true }) only [mem_filter, eq_self_iff_true, and_self_iff, exists_prop_of_true,
        Prod.swap_prod_mk, forall_true_iff, mem_product]⟩
[GOAL]
p q : ℕ
hp : Fact (Nat.Prime p)
hq0 : ↑q ≠ 0
x✝ : ℕ × ℕ
fst✝ snd✝ : ℕ
⊢ ∀ (ha : (fst✝, snd✝) ∈ filter (fun x => x.snd * q ≤ x.fst * p) (Ico 1 (succ (q / 2)) ×ˢ Ico 1 (succ (p / 2)))),
    (fun x x_1 => Prod.swap x) (fst✝, snd✝) ha ∈
      filter (fun x => x.fst * q ≤ x.snd * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2)))
[PROOFSTEP]
simp (config := { contextual := true }) only [mem_filter, and_self_iff, Prod.swap_prod_mk, forall_true_iff, mem_product]
[GOAL]
p q : ℕ
hp : Fact (Nat.Prime p)
hq0 : ↑q ≠ 0
x✝¹ x✝ : ℕ × ℕ
fst✝¹ snd✝¹ fst✝ snd✝ : ℕ
⊢ ∀ (ha : (fst✝¹, snd✝¹) ∈ filter (fun x => x.snd * q ≤ x.fst * p) (Ico 1 (succ (q / 2)) ×ˢ Ico 1 (succ (p / 2))))
    (hb : (fst✝, snd✝) ∈ filter (fun x => x.snd * q ≤ x.fst * p) (Ico 1 (succ (q / 2)) ×ˢ Ico 1 (succ (p / 2)))),
    (fun x x_1 => Prod.swap x) (fst✝¹, snd✝¹) ha = (fun x x_1 => Prod.swap x) (fst✝, snd✝) hb →
      (fst✝¹, snd✝¹) = (fst✝, snd✝)
[PROOFSTEP]
simp (config := { contextual := true }) only [Prod.mk.inj_iff, eq_self_iff_true, and_self_iff, Prod.swap_prod_mk,
  forall_true_iff]
[GOAL]
p q : ℕ
hp : Fact (Nat.Prime p)
hq0 : ↑q ≠ 0
x✝ : ℕ × ℕ
x₁ x₂ : ℕ
h : (x₁, x₂) ∈ filter (fun x => x.fst * q ≤ x.snd * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2)))
⊢ ∃ ha, (fun x x_1 => Prod.swap x) (x₂, x₁) ha = (x₁, x₂)
[PROOFSTEP]
revert h
[GOAL]
p q : ℕ
hp : Fact (Nat.Prime p)
hq0 : ↑q ≠ 0
x✝ : ℕ × ℕ
x₁ x₂ : ℕ
⊢ (x₁, x₂) ∈ filter (fun x => x.fst * q ≤ x.snd * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))) →
    ∃ ha, (fun x x_1 => Prod.swap x) (x₂, x₁) ha = (x₁, x₂)
[PROOFSTEP]
simp (config := { contextual := true }) only [mem_filter, eq_self_iff_true, and_self_iff, exists_prop_of_true,
  Prod.swap_prod_mk, forall_true_iff, mem_product]
[GOAL]
p q : ℕ
hp : Fact (Nat.Prime p)
hq0 : ↑q ≠ 0
hswap :
  Finset.card (filter (fun x => x.snd * q ≤ x.fst * p) (Ico 1 (succ (q / 2)) ×ˢ Ico 1 (succ (p / 2)))) =
    Finset.card (filter (fun x => x.fst * q ≤ x.snd * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
⊢ ∑ a in Ico 1 (succ (p / 2)), a * q / p + ∑ a in Ico 1 (succ (q / 2)), a * p / q = p / 2 * (q / 2)
[PROOFSTEP]
have hdisj :
  Disjoint ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ => x.2 * p ≤ x.1 * q)
    ((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ => x.1 * q ≤ x.2 * p) :=
  by
  apply disjoint_filter.2 fun x hx hpq hqp => ?_
  have hxp : x.1 < p :=
    lt_of_le_of_lt (show x.1 ≤ p / 2 by simp_all only [lt_succ_iff, mem_Ico, mem_product])
      (Nat.div_lt_self hp.1.pos (by decide))
  have : (x.1 : ZMod p) = 0 := by simpa [hq0] using congr_arg ((↑) : ℕ → ZMod p) (le_antisymm hpq hqp)
  apply_fun ZMod.val at this
  rw [val_cast_of_lt hxp, val_zero] at this
  simp only [this, nonpos_iff_eq_zero, mem_Ico, one_ne_zero, false_and_iff, mem_product] at hx
[GOAL]
p q : ℕ
hp : Fact (Nat.Prime p)
hq0 : ↑q ≠ 0
hswap :
  Finset.card (filter (fun x => x.snd * q ≤ x.fst * p) (Ico 1 (succ (q / 2)) ×ˢ Ico 1 (succ (p / 2)))) =
    Finset.card (filter (fun x => x.fst * q ≤ x.snd * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
⊢ Disjoint (filter (fun x => x.snd * p ≤ x.fst * q) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
    (filter (fun x => x.fst * q ≤ x.snd * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
[PROOFSTEP]
apply disjoint_filter.2 fun x hx hpq hqp => ?_
[GOAL]
p q : ℕ
hp : Fact (Nat.Prime p)
hq0 : ↑q ≠ 0
hswap :
  Finset.card (filter (fun x => x.snd * q ≤ x.fst * p) (Ico 1 (succ (q / 2)) ×ˢ Ico 1 (succ (p / 2)))) =
    Finset.card (filter (fun x => x.fst * q ≤ x.snd * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
x : ℕ × ℕ
hx : x ∈ Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))
hpq : x.snd * p ≤ x.fst * q
hqp : x.fst * q ≤ x.snd * p
⊢ False
[PROOFSTEP]
have hxp : x.1 < p :=
  lt_of_le_of_lt (show x.1 ≤ p / 2 by simp_all only [lt_succ_iff, mem_Ico, mem_product])
    (Nat.div_lt_self hp.1.pos (by decide))
[GOAL]
p q : ℕ
hp : Fact (Nat.Prime p)
hq0 : ↑q ≠ 0
hswap :
  Finset.card (filter (fun x => x.snd * q ≤ x.fst * p) (Ico 1 (succ (q / 2)) ×ˢ Ico 1 (succ (p / 2)))) =
    Finset.card (filter (fun x => x.fst * q ≤ x.snd * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
x : ℕ × ℕ
hx : x ∈ Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))
hpq : x.snd * p ≤ x.fst * q
hqp : x.fst * q ≤ x.snd * p
⊢ x.fst ≤ p / 2
[PROOFSTEP]
simp_all only [lt_succ_iff, mem_Ico, mem_product]
[GOAL]
p q : ℕ
hp : Fact (Nat.Prime p)
hq0 : ↑q ≠ 0
hswap :
  Finset.card (filter (fun x => x.snd * q ≤ x.fst * p) (Ico 1 (succ (q / 2)) ×ˢ Ico 1 (succ (p / 2)))) =
    Finset.card (filter (fun x => x.fst * q ≤ x.snd * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
x : ℕ × ℕ
hx : x ∈ Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))
hpq : x.snd * p ≤ x.fst * q
hqp : x.fst * q ≤ x.snd * p
⊢ 1 < 2
[PROOFSTEP]
decide
[GOAL]
p q : ℕ
hp : Fact (Nat.Prime p)
hq0 : ↑q ≠ 0
hswap :
  Finset.card (filter (fun x => x.snd * q ≤ x.fst * p) (Ico 1 (succ (q / 2)) ×ˢ Ico 1 (succ (p / 2)))) =
    Finset.card (filter (fun x => x.fst * q ≤ x.snd * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
x : ℕ × ℕ
hx : x ∈ Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))
hpq : x.snd * p ≤ x.fst * q
hqp : x.fst * q ≤ x.snd * p
hxp : x.fst < p
⊢ False
[PROOFSTEP]
have : (x.1 : ZMod p) = 0 := by simpa [hq0] using congr_arg ((↑) : ℕ → ZMod p) (le_antisymm hpq hqp)
[GOAL]
p q : ℕ
hp : Fact (Nat.Prime p)
hq0 : ↑q ≠ 0
hswap :
  Finset.card (filter (fun x => x.snd * q ≤ x.fst * p) (Ico 1 (succ (q / 2)) ×ˢ Ico 1 (succ (p / 2)))) =
    Finset.card (filter (fun x => x.fst * q ≤ x.snd * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
x : ℕ × ℕ
hx : x ∈ Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))
hpq : x.snd * p ≤ x.fst * q
hqp : x.fst * q ≤ x.snd * p
hxp : x.fst < p
⊢ ↑x.fst = 0
[PROOFSTEP]
simpa [hq0] using congr_arg ((↑) : ℕ → ZMod p) (le_antisymm hpq hqp)
[GOAL]
p q : ℕ
hp : Fact (Nat.Prime p)
hq0 : ↑q ≠ 0
hswap :
  Finset.card (filter (fun x => x.snd * q ≤ x.fst * p) (Ico 1 (succ (q / 2)) ×ˢ Ico 1 (succ (p / 2)))) =
    Finset.card (filter (fun x => x.fst * q ≤ x.snd * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
x : ℕ × ℕ
hx : x ∈ Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))
hpq : x.snd * p ≤ x.fst * q
hqp : x.fst * q ≤ x.snd * p
hxp : x.fst < p
this : ↑x.fst = 0
⊢ False
[PROOFSTEP]
apply_fun ZMod.val at this
[GOAL]
p q : ℕ
hp : Fact (Nat.Prime p)
hq0 : ↑q ≠ 0
hswap :
  Finset.card (filter (fun x => x.snd * q ≤ x.fst * p) (Ico 1 (succ (q / 2)) ×ˢ Ico 1 (succ (p / 2)))) =
    Finset.card (filter (fun x => x.fst * q ≤ x.snd * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
x : ℕ × ℕ
hx : x ∈ Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))
hpq : x.snd * p ≤ x.fst * q
hqp : x.fst * q ≤ x.snd * p
hxp : x.fst < p
this : val ↑x.fst = val 0
⊢ False
[PROOFSTEP]
rw [val_cast_of_lt hxp, val_zero] at this
[GOAL]
p q : ℕ
hp : Fact (Nat.Prime p)
hq0 : ↑q ≠ 0
hswap :
  Finset.card (filter (fun x => x.snd * q ≤ x.fst * p) (Ico 1 (succ (q / 2)) ×ˢ Ico 1 (succ (p / 2)))) =
    Finset.card (filter (fun x => x.fst * q ≤ x.snd * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
x : ℕ × ℕ
hx : x ∈ Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))
hpq : x.snd * p ≤ x.fst * q
hqp : x.fst * q ≤ x.snd * p
hxp : x.fst < p
this : x.fst = 0
⊢ False
[PROOFSTEP]
simp only [this, nonpos_iff_eq_zero, mem_Ico, one_ne_zero, false_and_iff, mem_product] at hx
[GOAL]
p q : ℕ
hp : Fact (Nat.Prime p)
hq0 : ↑q ≠ 0
hswap :
  Finset.card (filter (fun x => x.snd * q ≤ x.fst * p) (Ico 1 (succ (q / 2)) ×ˢ Ico 1 (succ (p / 2)))) =
    Finset.card (filter (fun x => x.fst * q ≤ x.snd * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
hdisj :
  Disjoint (filter (fun x => x.snd * p ≤ x.fst * q) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
    (filter (fun x => x.fst * q ≤ x.snd * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
⊢ ∑ a in Ico 1 (succ (p / 2)), a * q / p + ∑ a in Ico 1 (succ (q / 2)), a * p / q = p / 2 * (q / 2)
[PROOFSTEP]
have hunion :
  (((Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ => x.2 * p ≤ x.1 * q) ∪
      (Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ).filter fun x : ℕ × ℕ => x.1 * q ≤ x.2 * p) =
    Ico 1 (p / 2).succ ×ˢ Ico 1 (q / 2).succ :=
  Finset.ext fun x => by
    have := le_total (x.2 * p) (x.1 * q)
    simp only [mem_union, mem_filter, mem_Ico, mem_product]
    tauto
[GOAL]
p q : ℕ
hp : Fact (Nat.Prime p)
hq0 : ↑q ≠ 0
hswap :
  Finset.card (filter (fun x => x.snd * q ≤ x.fst * p) (Ico 1 (succ (q / 2)) ×ˢ Ico 1 (succ (p / 2)))) =
    Finset.card (filter (fun x => x.fst * q ≤ x.snd * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
hdisj :
  Disjoint (filter (fun x => x.snd * p ≤ x.fst * q) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
    (filter (fun x => x.fst * q ≤ x.snd * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
x : ℕ × ℕ
⊢ x ∈
      filter (fun x => x.snd * p ≤ x.fst * q) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))) ∪
        filter (fun x => x.fst * q ≤ x.snd * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))) ↔
    x ∈ Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))
[PROOFSTEP]
have := le_total (x.2 * p) (x.1 * q)
[GOAL]
p q : ℕ
hp : Fact (Nat.Prime p)
hq0 : ↑q ≠ 0
hswap :
  Finset.card (filter (fun x => x.snd * q ≤ x.fst * p) (Ico 1 (succ (q / 2)) ×ˢ Ico 1 (succ (p / 2)))) =
    Finset.card (filter (fun x => x.fst * q ≤ x.snd * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
hdisj :
  Disjoint (filter (fun x => x.snd * p ≤ x.fst * q) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
    (filter (fun x => x.fst * q ≤ x.snd * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
x : ℕ × ℕ
this : x.snd * p ≤ x.fst * q ∨ x.fst * q ≤ x.snd * p
⊢ x ∈
      filter (fun x => x.snd * p ≤ x.fst * q) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))) ∪
        filter (fun x => x.fst * q ≤ x.snd * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))) ↔
    x ∈ Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))
[PROOFSTEP]
simp only [mem_union, mem_filter, mem_Ico, mem_product]
[GOAL]
p q : ℕ
hp : Fact (Nat.Prime p)
hq0 : ↑q ≠ 0
hswap :
  Finset.card (filter (fun x => x.snd * q ≤ x.fst * p) (Ico 1 (succ (q / 2)) ×ˢ Ico 1 (succ (p / 2)))) =
    Finset.card (filter (fun x => x.fst * q ≤ x.snd * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
hdisj :
  Disjoint (filter (fun x => x.snd * p ≤ x.fst * q) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
    (filter (fun x => x.fst * q ≤ x.snd * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
x : ℕ × ℕ
this : x.snd * p ≤ x.fst * q ∨ x.fst * q ≤ x.snd * p
⊢ ((1 ≤ x.fst ∧ x.fst < succ (p / 2)) ∧ 1 ≤ x.snd ∧ x.snd < succ (q / 2)) ∧ x.snd * p ≤ x.fst * q ∨
      ((1 ≤ x.fst ∧ x.fst < succ (p / 2)) ∧ 1 ≤ x.snd ∧ x.snd < succ (q / 2)) ∧ x.fst * q ≤ x.snd * p ↔
    (1 ≤ x.fst ∧ x.fst < succ (p / 2)) ∧ 1 ≤ x.snd ∧ x.snd < succ (q / 2)
[PROOFSTEP]
tauto
[GOAL]
p q : ℕ
hp : Fact (Nat.Prime p)
hq0 : ↑q ≠ 0
hswap :
  Finset.card (filter (fun x => x.snd * q ≤ x.fst * p) (Ico 1 (succ (q / 2)) ×ˢ Ico 1 (succ (p / 2)))) =
    Finset.card (filter (fun x => x.fst * q ≤ x.snd * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
hdisj :
  Disjoint (filter (fun x => x.snd * p ≤ x.fst * q) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
    (filter (fun x => x.fst * q ≤ x.snd * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
hunion :
  filter (fun x => x.snd * p ≤ x.fst * q) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))) ∪
      filter (fun x => x.fst * q ≤ x.snd * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))) =
    Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))
⊢ ∑ a in Ico 1 (succ (p / 2)), a * q / p + ∑ a in Ico 1 (succ (q / 2)), a * p / q = p / 2 * (q / 2)
[PROOFSTEP]
rw [sum_Ico_eq_card_lt, sum_Ico_eq_card_lt, hswap, ← card_disjoint_union hdisj, hunion, card_product]
[GOAL]
p q : ℕ
hp : Fact (Nat.Prime p)
hq0 : ↑q ≠ 0
hswap :
  Finset.card (filter (fun x => x.snd * q ≤ x.fst * p) (Ico 1 (succ (q / 2)) ×ˢ Ico 1 (succ (p / 2)))) =
    Finset.card (filter (fun x => x.fst * q ≤ x.snd * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
hdisj :
  Disjoint (filter (fun x => x.snd * p ≤ x.fst * q) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
    (filter (fun x => x.fst * q ≤ x.snd * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))))
hunion :
  filter (fun x => x.snd * p ≤ x.fst * q) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))) ∪
      filter (fun x => x.fst * q ≤ x.snd * p) (Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))) =
    Ico 1 (succ (p / 2)) ×ˢ Ico 1 (succ (q / 2))
⊢ Finset.card (Ico 1 (succ (p / 2))) * Finset.card (Ico 1 (succ (q / 2))) = p / 2 * (q / 2)
[PROOFSTEP]
simp only [card_Ico, tsub_zero, succ_sub_succ_eq_sub]
[GOAL]
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : p ≠ 2
a : ℕ
ha1 : a % 2 = 1
ha0 : ↑a ≠ 0
⊢ legendreSym p ↑a = (-1) ^ ∑ x in Ico 1 (succ (p / 2)), x * a / p
[PROOFSTEP]
haveI hp' : Fact (p % 2 = 1) := ⟨Nat.Prime.mod_two_eq_one_iff_ne_two.mpr hp⟩
[GOAL]
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : p ≠ 2
a : ℕ
ha1 : a % 2 = 1
ha0 : ↑a ≠ 0
hp' : Fact (p % 2 = 1)
⊢ legendreSym p ↑a = (-1) ^ ∑ x in Ico 1 (succ (p / 2)), x * a / p
[PROOFSTEP]
have ha0' : ((a : ℤ) : ZMod p) ≠ 0 := by norm_cast
[GOAL]
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : p ≠ 2
a : ℕ
ha1 : a % 2 = 1
ha0 : ↑a ≠ 0
hp' : Fact (p % 2 = 1)
⊢ ↑↑a ≠ 0
[PROOFSTEP]
norm_cast
[GOAL]
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : p ≠ 2
a : ℕ
ha1 : a % 2 = 1
ha0 : ↑a ≠ 0
hp' : Fact (p % 2 = 1)
ha0' : ↑↑a ≠ 0
⊢ legendreSym p ↑a = (-1) ^ ∑ x in Ico 1 (succ (p / 2)), x * a / p
[PROOFSTEP]
rw [neg_one_pow_eq_pow_mod_two, gauss_lemma hp ha0', neg_one_pow_eq_pow_mod_two,
  (by norm_cast : ((a : ℤ) : ZMod p) = (a : ZMod p)), show _ = _ from eisenstein_lemma_aux p ha1 ha0]
[GOAL]
p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : p ≠ 2
a : ℕ
ha1 : a % 2 = 1
ha0 : ↑a ≠ 0
hp' : Fact (p % 2 = 1)
ha0' : ↑↑a ≠ 0
⊢ ↑↑a = ↑a
[PROOFSTEP]
norm_cast