l3lab/ntp-mathlib huggingface dataset:
/-- The group homomorphism on units induced by a `MonoidHom`. -/
@[to_additive "The additive homomorphism on `AddUnit`s induced by an `AddMonoidHom`."]
def map (f : M →* N) : Mˣ →* Nˣ :=
  MonoidHom.mk'
    (fun u => ⟨f u.val, f u.inv,
      by rw [← f.map_mul, u.val_inv, f.map_one],
      by 

Proof state:
α : Type u_1
M : Type u
N : Type v
P : Type w
inst✝² : Monoid M
inst✝¹ : Monoid N
inst✝ : Monoid P
f : M →* N
u : Mˣ
⊢ f u.inv * f ↑u = 1

Next tactic:
rw [← f.map_mul, u.inv_val, f.map_one]
@[to_additive (attr := simp)]
theorem map_id : map (MonoidHom.id M) = MonoidHom.id Mˣ := by 

Proof state:
α : Type u_1
M : Type u
N : Type v
P : Type w
inst✝² : Monoid M
inst✝¹ : Monoid N
inst✝ : Monoid P
⊢ map (MonoidHom.id M) = MonoidHom.id Mˣ

Next tactic:
ext
@[to_additive (attr := simp)]
theorem map_id : map (MonoidHom.id M) = MonoidHom.id Mˣ := by ext; 

Proof state:
case h.a
α : Type u_1
M : Type u
N : Type v
P : Type w
inst✝² : Monoid M
inst✝¹ : Monoid N
inst✝ : Monoid P
x✝ : Mˣ
⊢ ↑((map (MonoidHom.id M)) x✝) = ↑((MonoidHom.id Mˣ) x✝)

Next tactic:
rfl
@[field_simps]
theorem _root_.divp_eq_div (a : α) (u : αˣ) : a /ₚ u = a / u :=
  by 

Proof state:
α : Type u_1
M : Type u
N : Type v
P : Type w
inst✝³ : Monoid M
inst✝² : Monoid N
inst✝¹ : Monoid P
inst✝ : DivisionMonoid α
a : α
u : αˣ
⊢ a /ₚ u = a / ↑u

Next tactic:
rw [div_eq_mul_inv, divp, u.val_inv_eq_inv_val]
/-- If a map `g : M → Nˣ` agrees with a homomorphism `f : M →* N`, then
this map is a monoid homomorphism too. -/
@[to_additive
  "If a map `g : M → AddUnits N` agrees with a homomorphism `f : M →+ N`, then this map
  is an AddMonoid homomorphism too."]
def liftRight (f : M →* N) (g : M → Nˣ) (h : ∀ x, ↑(g x) = f x) : M →* Nˣ where
  toFun := g
  map_one' := by 

Proof state:
α : Type u_1
M : Type u
N : Type v
P : Type w
inst✝² : Monoid M
inst✝¹ : Monoid N
inst✝ : Monoid P
f : M →* N
g : M → Nˣ
h : ∀ (x : M), ↑(g x) = f x
⊢ g 1 = 1

Next tactic:
ext
/-- If a map `g : M → Nˣ` agrees with a homomorphism `f : M →* N`, then
this map is a monoid homomorphism too. -/
@[to_additive
  "If a map `g : M → AddUnits N` agrees with a homomorphism `f : M →+ N`, then this map
  is an AddMonoid homomorphism too."]
def liftRight (f : M →* N) (g : M → Nˣ) (h : ∀ x, ↑(g x) = f x) : M →* Nˣ where
  toFun := g
  map_one' := by ext; 

Proof state:
case a
α : Type u_1
M : Type u
N : Type v
P : Type w
inst✝² : Monoid M
inst✝¹ : Monoid N
inst✝ : Monoid P
f : M →* N
g : M → Nˣ
h : ∀ (x : M), ↑(g x) = f x
⊢ ↑(g 1) = ↑1

Next tactic:
dsimp only
/-- If a map `g : M → Nˣ` agrees with a homomorphism `f : M →* N`, then
this map is a monoid homomorphism too. -/
@[to_additive
  "If a map `g : M → AddUnits N` agrees with a homomorphism `f : M →+ N`, then this map
  is an AddMonoid homomorphism too."]
def liftRight (f : M →* N) (g : M → Nˣ) (h : ∀ x, ↑(g x) = f x) : M →* Nˣ where
  toFun := g
  map_one' := by ext; dsimp only; 

Proof state:
case a
α : Type u_1
M : Type u
N : Type v
P : Type w
inst✝² : Monoid M
inst✝¹ : Monoid N
inst✝ : Monoid P
f : M →* N
g : M → Nˣ
h : ∀ (x : M), ↑(g x) = f x
⊢ ↑(g 1) = ↑1

Next tactic:
rw [h 1]
/-- If a map `g : M → Nˣ` agrees with a homomorphism `f : M →* N`, then
this map is a monoid homomorphism too. -/
@[to_additive
  "If a map `g : M → AddUnits N` agrees with a homomorphism `f : M →+ N`, then this map
  is an AddMonoid homomorphism too."]
def liftRight (f : M →* N) (g : M → Nˣ) (h : ∀ x, ↑(g x) = f x) : M →* Nˣ where
  toFun := g
  map_one' := by ext; dsimp only; rw [h 1]; 

Proof state:
case a
α : Type u_1
M : Type u
N : Type v
P : Type w
inst✝² : Monoid M
inst✝¹ : Monoid N
inst✝ : Monoid P
f : M →* N
g : M → Nˣ
h : ∀ (x : M), ↑(g x) = f x
⊢ f 1 = ↑1

Next tactic:
exact f.map_one
/-- If a map `g : M → Nˣ` agrees with a homomorphism `f : M →* N`, then
this map is a monoid homomorphism too. -/
@[to_additive
  "If a map `g : M → AddUnits N` agrees with a homomorphism `f : M →+ N`, then this map
  is an AddMonoid homomorphism too."]
def liftRight (f : M →* N) (g : M → Nˣ) (h : ∀ x, ↑(g x) = f x) : M →* Nˣ where
  toFun := g
  map_one' := by ext; dsimp only; rw [h 1]; exact f.map_one -- Porting note: why is `dsimp` needed?
  map_mul' x y := Units.ext <| by 

Proof state:
α : Type u_1
M : Type u
N : Type v
P : Type w
inst✝² : Monoid M
inst✝¹ : Monoid N
inst✝ : Monoid P
f : M →* N
g : M → Nˣ
h : ∀ (x : M), ↑(g x) = f x
x y : M
⊢ ↑(OneHom.toFun { toFun := g, map_one' := (_ : g 1 = 1) } (x * y)) =
    ↑(OneHom.toFun { toFun := g, map_one' := (_ : g 1 = 1) } x *
        OneHom.toFun { toFun := g, map_one' := (_ : g 1 = 1) } y)

Next tactic:
simp only [h, val_mul, f.map_mul]
@[to_additive (attr := simp)]
theorem mul_liftRight_inv {f : M →* N} {g : M → Nˣ} (h : ∀ x, ↑(g x) = f x) (x) :
    f x * ↑(liftRight f g h x)⁻¹ = 1 :=
  by 

Proof state:
α : Type u_1
M : Type u
N : Type v
P : Type w
inst✝² : Monoid M
inst✝¹ : Monoid N
inst✝ : Monoid P
f : M →* N
g : M → Nˣ
h : ∀ (x : M), ↑(g x) = f x
x : M
⊢ f x * ↑((liftRight f g h) x)⁻¹ = 1

Next tactic:
rw [Units.mul_inv_eq_iff_eq_mul, one_mul, coe_liftRight]
@[to_additive (attr := simp)]
theorem liftRight_inv_mul {f : M →* N} {g : M → Nˣ} (h : ∀ x, ↑(g x) = f x) (x) :
    ↑(liftRight f g h x)⁻¹ * f x = 1 :=
  by 

Proof state:
α : Type u_1
M : Type u
N : Type v
P : Type w
inst✝² : Monoid M
inst✝¹ : Monoid N
inst✝ : Monoid P
f : M →* N
g : M → Nˣ
h : ∀ (x : M), ↑(g x) = f x
x : M
⊢ ↑((liftRight f g h) x)⁻¹ * f x = 1

Next tactic:
rw [Units.inv_mul_eq_iff_eq_mul, mul_one, coe_liftRight]
@[to_additive]
theorem map [MonoidHomClass F M N] (f : F) {x : M} (h : IsUnit x) : IsUnit (f x) := by
  

Proof state:
F : Type u_1
G : Type u_2
α : Type u_3
M : Type u_4
N : Type u_5
inst✝² : Monoid M
inst✝¹ : Monoid N
inst✝ : MonoidHomClass F M N
f : F
x : M
h : IsUnit x
⊢ IsUnit (f x)

Next tactic:
rcases h with ⟨y, rfl⟩
@[to_additive]
theorem map [MonoidHomClass F M N] (f : F) {x : M} (h : IsUnit x) : IsUnit (f x) := by
  rcases h with ⟨y, rfl⟩; 

Proof state:
case intro
F : Type u_1
G : Type u_2
α : Type u_3
M : Type u_4
N : Type u_5
inst✝² : Monoid M
inst✝¹ : Monoid N
inst✝ : MonoidHomClass F M N
f : F
y : Mˣ
⊢ IsUnit (f ↑y)

Next tactic:
exact (Units.map (f : M →* N) y).isUnit
@[to_additive]
theorem of_leftInverse [MonoidHomClass F M N] [MonoidHomClass G N M] {f : F} {x : M} (g : G)
    (hfg : Function.LeftInverse g f) (h : IsUnit (f x)) : IsUnit x := by
  

Proof state:
F : Type u_1
G : Type u_2
α : Type u_3
M : Type u_4
N : Type u_5
inst✝³ : Monoid M
inst✝² : Monoid N
inst✝¹ : MonoidHomClass F M N
inst✝ : MonoidHomClass G N M
f : F
x : M
g : G
hfg : LeftInverse ⇑g ⇑f
h : IsUnit (f x)
⊢ IsUnit x

Next tactic:
simpa only [hfg x] using h.map g
@[to_additive (attr := simp)]
theorem mul_liftRight_inv (f : M →* N) (h : ∀ x, IsUnit (f x)) (x) :
    f x * ↑(IsUnit.liftRight f h x)⁻¹ = 1 := Units.mul_liftRight_inv (by 

Proof state:
F : Type u_1
G : Type u_2
α : Type u_3
M : Type u_4
N : Type u_5
inst✝¹ : Monoid M
inst✝ : Monoid N
f : M →* N
h : ∀ (x : M), IsUnit (f x)
x : M
⊢ ∀ (x : M), ↑(IsUnit.unit (_ : IsUnit (f x))) = f x

Next tactic:
intro
@[to_additive (attr := simp)]
theorem mul_liftRight_inv (f : M →* N) (h : ∀ x, IsUnit (f x)) (x) :
    f x * ↑(IsUnit.liftRight f h x)⁻¹ = 1 := Units.mul_liftRight_inv (by intro; 

Proof state:
F : Type u_1
G : Type u_2
α : Type u_3
M : Type u_4
N : Type u_5
inst✝¹ : Monoid M
inst✝ : Monoid N
f : M →* N
h : ∀ (x : M), IsUnit (f x)
x x✝ : M
⊢ ↑(IsUnit.unit (_ : IsUnit (f x✝))) = f x✝

Next tactic:
rfl
@[to_additive (attr := simp)]
theorem liftRight_inv_mul (f : M →* N) (h : ∀ x, IsUnit (f x)) (x) :
    ↑(IsUnit.liftRight f h x)⁻¹ * f x = 1 := Units.liftRight_inv_mul (by 

Proof state:
F : Type u_1
G : Type u_2
α : Type u_3
M : Type u_4
N : Type u_5
inst✝¹ : Monoid M
inst✝ : Monoid N
f : M →* N
h : ∀ (x : M), IsUnit (f x)
x : M
⊢ ∀ (x : M), ↑(IsUnit.unit (_ : IsUnit (f x))) = f x

Next tactic:
intro
@[to_additive (attr := simp)]
theorem liftRight_inv_mul (f : M →* N) (h : ∀ x, IsUnit (f x)) (x) :
    ↑(IsUnit.liftRight f h x)⁻¹ * f x = 1 := Units.liftRight_inv_mul (by intro; 

Proof state:
F : Type u_1
G : Type u_2
α : Type u_3
M : Type u_4
N : Type u_5
inst✝¹ : Monoid M
inst✝ : Monoid N
f : M →* N
h : ∀ (x : M), IsUnit (f x)
x x✝ : M
⊢ ↑(IsUnit.unit (_ : IsUnit (f x✝))) = f x✝

Next tactic:
rfl
@[to_additive]
protected theorem div_self (h : IsUnit a) : a / a = 1 := by 

Proof state:
F : Type u_1
G : Type u_2
α : Type u_3
M : Type u_4
N : Type u_5
inst✝ : DivisionMonoid α
a b c : α
h : IsUnit a
⊢ a / a = 1

Next tactic:
rw [div_eq_mul_inv, h.mul_inv_cancel]
@[to_additive (attr := simp)]
protected theorem div_mul_cancel (h : IsUnit b) (a : α) : a / b * b = a := by
  

Proof state:
F : Type u_1
G : Type u_2
α : Type u_3
M : Type u_4
N : Type u_5
inst✝ : DivisionMonoid α
a✝ b c : α
h : IsUnit b
a : α
⊢ a / b * b = a

Next tactic:
rw [div_eq_mul_inv, h.inv_mul_cancel_right]
@[to_additive (attr := simp)]
protected theorem mul_div_cancel (h : IsUnit b) (a : α) : a * b / b = a := by
  

Proof state:
F : Type u_1
G : Type u_2
α : Type u_3
M : Type u_4
N : Type u_5
inst✝ : DivisionMonoid α
a✝ b c : α
h : IsUnit b
a : α
⊢ a * b / b = a

Next tactic:
rw [div_eq_mul_inv, h.mul_inv_cancel_right]
@[to_additive]
protected theorem mul_one_div_cancel (h : IsUnit a) : a * (1 / a) = 1 := by 

Proof state:
F : Type u_1
G : Type u_2
α : Type u_3
M : Type u_4
N : Type u_5
inst✝ : DivisionMonoid α
a b c : α
h : IsUnit a
⊢ a * (1 / a) = 1

Next tactic:
simp [h]
@[to_additive]
protected theorem one_div_mul_cancel (h : IsUnit a) : 1 / a * a = 1 := by 

Proof state:
F : Type u_1
G : Type u_2
α : Type u_3
M : Type u_4
N : Type u_5
inst✝ : DivisionMonoid α
a b c : α
h : IsUnit a
⊢ 1 / a * a = 1

Next tactic:
simp [h]
@[to_additive]
theorem inv (h : IsUnit a) : IsUnit a⁻¹ := by
  

Proof state:
F : Type u_1
G : Type u_2
α : Type u_3
M : Type u_4
N : Type u_5
inst✝ : DivisionMonoid α
a b c : α
h : IsUnit a
⊢ IsUnit a⁻¹

Next tactic:
rcases h with ⟨u, hu⟩
@[to_additive]
theorem inv (h : IsUnit a) : IsUnit a⁻¹ := by
  rcases h with ⟨u, hu⟩
  

Proof state:
case intro
F : Type u_1
G : Type u_2
α : Type u_3
M : Type u_4
N : Type u_5
inst✝ : DivisionMonoid α
a b c : α
u : αˣ
hu : ↑u = a
⊢ IsUnit a⁻¹

Next tactic:
rw [← hu, ← Units.val_inv_eq_inv_val]
@[to_additive]
theorem inv (h : IsUnit a) : IsUnit a⁻¹ := by
  rcases h with ⟨u, hu⟩
  rw [← hu, ← Units.val_inv_eq_inv_val]
  

Proof state:
case intro
F : Type u_1
G : Type u_2
α : Type u_3
M : Type u_4
N : Type u_5
inst✝ : DivisionMonoid α
a b c : α
u : αˣ
hu : ↑u = a
⊢ IsUnit ↑u⁻¹

Next tactic:
exact Units.isUnit _
@[to_additive]
theorem div (ha : IsUnit a) (hb : IsUnit b) : IsUnit (a / b) := by
  

Proof state:
F : Type u_1
G : Type u_2
α : Type u_3
M : Type u_4
N : Type u_5
inst✝ : DivisionMonoid α
a b c : α
ha : IsUnit a
hb : IsUnit b
⊢ IsUnit (a / b)

Next tactic:
rw [div_eq_mul_inv]
@[to_additive]
theorem div (ha : IsUnit a) (hb : IsUnit b) : IsUnit (a / b) := by
  rw [div_eq_mul_inv]
  

Proof state:
F : Type u_1
G : Type u_2
α : Type u_3
M : Type u_4
N : Type u_5
inst✝ : DivisionMonoid α
a b c : α
ha : IsUnit a
hb : IsUnit b
⊢ IsUnit (a * b⁻¹)

Next tactic:
exact ha.mul hb.inv
@[to_additive]
protected theorem div_left_inj (h : IsUnit c) : a / c = b / c ↔ a = b := by
  

Proof state:
F : Type u_1
G : Type u_2
α : Type u_3
M : Type u_4
N : Type u_5
inst✝ : DivisionMonoid α
a b c : α
h : IsUnit c
⊢ a / c = b / c ↔ a = b

Next tactic:
simp only [div_eq_mul_inv]
@[to_additive]
protected theorem div_left_inj (h : IsUnit c) : a / c = b / c ↔ a = b := by
  simp only [div_eq_mul_inv]
  

Proof state:
F : Type u_1
G : Type u_2
α : Type u_3
M : Type u_4
N : Type u_5
inst✝ : DivisionMonoid α
a b c : α
h : IsUnit c
⊢ a * c⁻¹ = b * c⁻¹ ↔ a = b

Next tactic:
exact Units.mul_left_inj h.inv.unit'
@[to_additive]
protected theorem div_eq_iff (h : IsUnit b) : a / b = c ↔ a = c * b := by
  

Proof state:
F : Type u_1
G : Type u_2
α : Type u_3
M : Type u_4
N : Type u_5
inst✝ : DivisionMonoid α
a b c : α
h : IsUnit b
⊢ a / b = c ↔ a = c * b

Next tactic:
rw [div_eq_mul_inv, h.mul_inv_eq_iff_eq_mul]
@[to_additive]
protected theorem eq_div_iff (h : IsUnit c) : a = b / c ↔ a * c = b := by
  

Proof state:
F : Type u_1
G : Type u_2
α : Type u_3
M : Type u_4
N : Type u_5
inst✝ : DivisionMonoid α
a b c : α
h : IsUnit c
⊢ a = b / c ↔ a * c = b

Next tactic:
rw [div_eq_mul_inv, h.eq_mul_inv_iff_mul_eq]
/-- The `Group` version of this lemma is `div_mul_cancel'''` -/
@[to_additive "The `AddGroup` version of this lemma is `sub_add_cancel''`"]
protected theorem div_mul_left (h : IsUnit b) : b / (a * b) = 1 / a := by
  

Proof state:
F : Type u_1
G : Type u_2
α : Type u_3
M : Type u_4
N : Type u_5
inst✝ : DivisionMonoid α
a b c : α
h : IsUnit b
⊢ b / (a * b) = 1 / a

Next tactic:
rw [div_eq_mul_inv, mul_inv_rev, h.mul_inv_cancel_left, one_div]
@[to_additive]
protected theorem mul_div_mul_right (h : IsUnit c) (a b : α) : a * c / (b * c) = a / b := by
  

Proof state:
F : Type u_1
G : Type u_2
α : Type u_3
M : Type u_4
N : Type u_5
inst✝ : DivisionMonoid α
a✝ b✝ c : α
h : IsUnit c
a b : α
⊢ a * c / (b * c) = a / b

Next tactic:
simp only [div_eq_mul_inv, mul_inv_rev, mul_assoc, h.mul_inv_cancel_left]
@[to_additive]
protected theorem mul_mul_div (a : α) (h : IsUnit b) : a * b * (1 / b) = a := by 

Proof state:
F : Type u_1
G : Type u_2
α : Type u_3
M : Type u_4
N : Type u_5
inst✝ : DivisionMonoid α
a✝ b c a : α
h : IsUnit b
⊢ a * b * (1 / b) = a

Next tactic:
simp [h]
@[to_additive]
protected theorem div_mul_right (h : IsUnit a) (b : α) : a / (a * b) = 1 / b := by
  

Proof state:
F : Type u_1
G : Type u_2
α : Type u_3
M : Type u_4
N : Type u_5
inst✝ : DivisionCommMonoid α
a b✝ c d : α
h : IsUnit a
b : α
⊢ a / (a * b) = 1 / b

Next tactic:
rw [mul_comm, h.div_mul_left]
@[to_additive]
protected theorem mul_div_cancel_left (h : IsUnit a) (b : α) : a * b / a = b := by
  

Proof state:
F : Type u_1
G : Type u_2
α : Type u_3
M : Type u_4
N : Type u_5
inst✝ : DivisionCommMonoid α
a b✝ c d : α
h : IsUnit a
b : α
⊢ a * b / a = b

Next tactic:
rw [mul_comm, h.mul_div_cancel]
@[to_additive]
protected theorem mul_div_cancel' (h : IsUnit a) (b : α) : a * (b / a) = b := by
  

Proof state:
F : Type u_1
G : Type u_2
α : Type u_3
M : Type u_4
N : Type u_5
inst✝ : DivisionCommMonoid α
a b✝ c d : α
h : IsUnit a
b : α
⊢ a * (b / a) = b

Next tactic:
rw [mul_comm, h.div_mul_cancel]
@[to_additive]
protected theorem mul_div_mul_left (h : IsUnit c) (a b : α) : c * a / (c * b) = a / b := by
  

Proof state:
F : Type u_1
G : Type u_2
α : Type u_3
M : Type u_4
N : Type u_5
inst✝ : DivisionCommMonoid α
a✝ b✝ c d : α
h : IsUnit c
a b : α
⊢ c * a / (c * b) = a / b

Next tactic:
rw [mul_comm c, mul_comm c, h.mul_div_mul_right]
@[to_additive]
protected theorem mul_eq_mul_of_div_eq_div (hb : IsUnit b) (hd : IsUnit d)
    (a c : α) (h : a / b = c / d) : a * d = c * b := by
  

Proof state:
F : Type u_1
G : Type u_2
α : Type u_3
M : Type u_4
N : Type u_5
inst✝ : DivisionCommMonoid α
a✝ b c✝ d : α
hb : IsUnit b
hd : IsUnit d
a c : α
h : a / b = c / d
⊢ a * d = c * b

Next tactic:
rw [← mul_one a, ← hb.div_self, ← mul_comm_div, h, div_mul_eq_mul_div, hd.div_mul_cancel]
@[to_additive]
protected theorem div_eq_div_iff (hb : IsUnit b) (hd : IsUnit d) :
    a / b = c / d ↔ a * d = c * b := by
  

Proof state:
F : Type u_1
G : Type u_2
α : Type u_3
M : Type u_4
N : Type u_5
inst✝ : DivisionCommMonoid α
a b c d : α
hb : IsUnit b
hd : IsUnit d
⊢ a / b = c / d ↔ a * d = c * b

Next tactic:
rw [← (hb.mul hd).mul_left_inj, ← mul_assoc, hb.div_mul_cancel, ← mul_assoc, mul_right_comm,
    hd.div_mul_cancel]
@[to_additive]
protected theorem div_div_cancel (h : IsUnit a) : a / (a / b) = b := by
  

Proof state:
F : Type u_1
G : Type u_2
α : Type u_3
M : Type u_4
N : Type u_5
inst✝ : DivisionCommMonoid α
a b c d : α
h : IsUnit a
⊢ a / (a / b) = b

Next tactic:
rw [div_div_eq_mul_div, h.mul_div_cancel_left]
@[to_additive]
protected theorem div_div_cancel_left (h : IsUnit a) : a / b / a = b⁻¹ := by
  

Proof state:
F : Type u_1
G : Type u_2
α : Type u_3
M : Type u_4
N : Type u_5
inst✝ : DivisionCommMonoid α
a b c d : α
h : IsUnit a
⊢ a / b / a = b⁻¹

Next tactic:
rw [div_eq_mul_inv, div_eq_mul_inv, mul_right_comm, h.mul_inv_cancel, one_mul]
theorem isEquivalent_atTop_lead :
    (fun x => eval x P) ~[atTop] fun x => P.leadingCoeff * x ^ P.natDegree := by
  

Proof state:
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
⊢ (fun x => eval x P) ~[atTop] fun x => leadingCoeff P * x ^ natDegree P

Next tactic:
by_cases h : P = 0
theorem isEquivalent_atTop_lead :
    (fun x => eval x P) ~[atTop] fun x => P.leadingCoeff * x ^ P.natDegree := by
  by_cases h : P = 0
  · 

Proof state:
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

Next tactic:
simp [h, IsEquivalent.refl]
theorem isEquivalent_atTop_lead :
    (fun x => eval x P) ~[atTop] fun x => P.leadingCoeff * x ^ P.natDegree := by
  by_cases h : P = 0
  · simp [h, IsEquivalent.refl]
  · 

Proof state:
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

Next tactic:
simp only [Polynomial.eval_eq_sum_range, sum_range_succ]
theorem isEquivalent_atTop_lead :
    (fun x => eval x P) ~[atTop] fun x => P.leadingCoeff * x ^ P.natDegree := by
  by_cases h : P = 0
  · simp [h, IsEquivalent.refl]
  · simp only [Polynomial.eval_eq_sum_range, sum_range_succ]
    

Proof state:
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

Next tactic:
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
theorem tendsto_atTop_iff_leadingCoeff_nonneg :
    Tendsto (fun x => eval x P) atTop atTop ↔ 0 < P.degree ∧ 0 ≤ P.leadingCoeff := by
  

Proof state:
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
⊢ Tendsto (fun x => eval x P) atTop atTop ↔ 0 < degree P ∧ 0 ≤ leadingCoeff P

Next tactic:
refine' ⟨fun h => _, fun h => tendsto_atTop_of_leadingCoeff_nonneg P h.1 h.2⟩
theorem tendsto_atTop_iff_leadingCoeff_nonneg :
    Tendsto (fun x => eval x P) atTop atTop ↔ 0 < P.degree ∧ 0 ≤ P.leadingCoeff := by
  refine' ⟨fun h => _, fun h => tendsto_atTop_of_leadingCoeff_nonneg P h.1 h.2⟩
  

Proof state:
𝕜 : 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

Next tactic:
have : Tendsto (fun x => P.leadingCoeff * x ^ P.natDegree) atTop atTop :=
    (isEquivalent_atTop_lead P).tendsto_atTop h
theorem tendsto_atTop_iff_leadingCoeff_nonneg :
    Tendsto (fun x => eval x P) atTop atTop ↔ 0 < P.degree ∧ 0 ≤ P.leadingCoeff := by
  refine' ⟨fun h => _, fun h => tendsto_atTop_of_leadingCoeff_nonneg P h.1 h.2⟩
  have : Tendsto (fun x => P.leadingCoeff * x ^ P.natDegree) atTop atTop :=
    (isEquivalent_atTop_lead P).tendsto_atTop h
  

Proof state:
𝕜 : 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

Next tactic:
rw [tendsto_const_mul_pow_atTop_iff, ← pos_iff_ne_zero, natDegree_pos_iff_degree_pos] at this
theorem tendsto_atTop_iff_leadingCoeff_nonneg :
    Tendsto (fun x => eval x P) atTop atTop ↔ 0 < P.degree ∧ 0 ≤ P.leadingCoeff := by
  refine' ⟨fun h => _, fun h => tendsto_atTop_of_leadingCoeff_nonneg P h.1 h.2⟩
  have : Tendsto (fun x => P.leadingCoeff * x ^ P.natDegree) atTop atTop :=
    (isEquivalent_atTop_lead P).tendsto_atTop h
  rw [tendsto_const_mul_pow_atTop_iff, ← pos_iff_ne_zero, natDegree_pos_iff_degree_pos] at this
  

Proof state:
𝕜 : 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

Next tactic:
exact ⟨this.1, this.2.le⟩
theorem tendsto_atBot_iff_leadingCoeff_nonpos :
    Tendsto (fun x => eval x P) atTop atBot ↔ 0 < P.degree ∧ P.leadingCoeff ≤ 0 := by
  

Proof state:
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
⊢ Tendsto (fun x => eval x P) atTop atBot ↔ 0 < degree P ∧ leadingCoeff P ≤ 0

Next tactic:
simp only [← tendsto_neg_atTop_iff, ← eval_neg, tendsto_atTop_iff_leadingCoeff_nonneg,
    degree_neg, leadingCoeff_neg, neg_nonneg]
theorem abs_tendsto_atTop (hdeg : 0 < P.degree) :
    Tendsto (fun x => abs <| eval x P) atTop atTop := by
  

Proof state:
𝕜 : Type u_1
inst✝¹ : NormedLinearOrderedField 𝕜
P Q : 𝕜[X]
inst✝ : OrderTopology 𝕜
hdeg : 0 < degree P
⊢ Tendsto (fun x => |eval x P|) atTop atTop

Next tactic:
rcases le_total 0 P.leadingCoeff with hP | hP
theorem abs_tendsto_atTop (hdeg : 0 < P.degree) :
    Tendsto (fun x => abs <| eval x P) atTop atTop := by
  rcases le_total 0 P.leadingCoeff with hP | hP
  · 

Proof state:
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

Next tactic:
exact tendsto_abs_atTop_atTop.comp (P.tendsto_atTop_of_leadingCoeff_nonneg hdeg hP)
theorem abs_tendsto_atTop (hdeg : 0 < P.degree) :
    Tendsto (fun x => abs <| eval x P) atTop atTop := by
  rcases le_total 0 P.leadingCoeff with hP | hP
  · exact tendsto_abs_atTop_atTop.comp (P.tendsto_atTop_of_leadingCoeff_nonneg hdeg hP)
  · 

Proof state:
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

Next tactic:
exact tendsto_abs_atBot_atTop.comp (P.tendsto_atBot_of_leadingCoeff_nonpos hdeg hP)
theorem abs_isBoundedUnder_iff :
    (IsBoundedUnder (· ≤ ·) atTop fun x => |eval x P|) ↔ P.degree ≤ 0 := by
  

Proof state:
𝕜 : 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

Next tactic:
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))⟩⟩
theorem abs_isBoundedUnder_iff :
    (IsBoundedUnder (· ≤ ·) atTop fun x => |eval x P|) ↔ P.degree ≤ 0 := by
  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))⟩⟩
  

Proof state:
𝕜 : 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

Next tactic:
contrapose! h
theorem abs_isBoundedUnder_iff :
    (IsBoundedUnder (· ≤ ·) atTop fun x => |eval x P|) ↔ P.degree ≤ 0 := by
  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))⟩⟩
  contrapose! h
  

Proof state:
𝕜 : 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|

Next tactic:
exact not_isBoundedUnder_of_tendsto_atTop (abs_tendsto_atTop P h)
theorem tendsto_nhds_iff {c : 𝕜} :
    Tendsto (fun x => eval x P) atTop (𝓝 c) ↔ P.leadingCoeff = c ∧ P.degree ≤ 0 := by
  

Proof state:
𝕜 : 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

Next tactic:
refine' ⟨fun h => _, fun h => _⟩