-- Mathlib/Computability/AkraBazzi/GrowsPolynomially.lean
lemma eventually_atTop_nonneg_or_nonpos (hf : GrowsPolynomially f) :
    (∀ᶠ x in atTop, 0 ≤ f x) ∨ (∀ᶠ x in atTop, f x ≤ 0)

Proof state:
case intro
f : ℝ → ℝ
hf : GrowsPolynomially f
c₁ : ℝ
left✝¹ : c₁ > 0
c₂ : ℝ
left✝ : c₂ > 0
heq : c₁ = c₂
n₀ : ℝ
hn₀ : ∀ b ≥ n₀, ∀ u ∈ Set.Icc (1 / 2 * b) b, f u = c₂ * f b
⊢ ∀ᶠ (x : ℝ) in atTop, f x = f (n₀ ⊔ 2)

Tactic:
rw [eventually_atTop]

Result:
case intro
f : ℝ → ℝ
hf : GrowsPolynomially f
c₁ : ℝ
left✝¹ : c₁ > 0
c₂ : ℝ
left✝ : c₂ > 0
heq : c₁ = c₂
n₀ : ℝ
hn₀ : ∀ b ≥ n₀, ∀ u ∈ Set.Icc (1 / 2 * b) b, f u = c₂ * f b
⊢ ∃ a, ∀ b ≥ a, f b = f (n₀ ⊔ 2)

Proof state:
f : ℝ → ℝ
hf : GrowsPolynomially f
⊢ 1 / 2 ∈ Set.Ioo 0 1

Tactic:
norm_num

Result:
no goals

Proof state:
f : ℝ → ℝ
hf : GrowsPolynomially f
c₁ : ℝ
left✝¹ : c₁ > 0
c₂ : ℝ
left✝ : c₂ > 0
heq : c₁ = c₂
n₀ : ℝ
hn₀ : ∀ b ≥ n₀, ∀ u ∈ Set.Icc (1 / 2 * b) b, f u = c₂ * f b
n : ℕ
hn : n ≥ 1
hyp_ind : ∀ z ∈ Set.Ico (n₀ ⊔ 2) (2 ^ n * (n₀ ⊔ 2)), f z = f (n₀ ⊔ 2)
z : ℝ
hz : z ∈ Set.Ico (2 ^ n * (n₀ ⊔ 2)) (2 ^ (n + 1) * (n₀ ⊔ 2))
z_nonneg : 0 ≤ z
⊢ 1 * (n₀ ⊔ 2) ≤ 2 ^ n * (n₀ ⊔ 2)

Tactic:
gcongr

Result:
case h
f : ℝ → ℝ
hf : GrowsPolynomially f
c₁ : ℝ
left✝¹ : c₁ > 0
c₂ : ℝ
left✝ : c₂ > 0
heq : c₁ = c₂
n₀ : ℝ
hn₀ : ∀ b ≥ n₀, ∀ u ∈ Set.Icc (1 / 2 * b) b, f u = c₂ * f b
n : ℕ
hn : n ≥ 1
hyp_ind : ∀ z ∈ Set.Ico (n₀ ⊔ 2) (2 ^ n * (n₀ ⊔ 2)), f z = f (n₀ ⊔ 2)
z : ℝ
hz : z ∈ Set.Ico (2 ^ n * (n₀ ⊔ 2)) (2 ^ (n + 1) * (n₀ ⊔ 2))
z_nonneg : 0 ≤ z
⊢ 1 ≤ 2 ^ n

Proof state:
case h
f : ℝ → ℝ
hf : GrowsPolynomially f
c₁ : ℝ
left✝¹ : c₁ > 0
c₂ : ℝ
left✝ : c₂ > 0
heq : c₁ = c₂
n₀ : ℝ
hn₀ : ∀ b ≥ n₀, ∀ u ∈ Set.Icc (1 / 2 * b) b, f u = c₂ * f b
n : ℕ
hn : n ≥ 1
hyp_ind : ∀ z ∈ Set.Ico (n₀ ⊔ 2) (2 ^ n * (n₀ ⊔ 2)), f z = f (n₀ ⊔ 2)
z : ℝ
hz : z ∈ Set.Ico (2 ^ n * (n₀ ⊔ 2)) (2 ^ (n + 1) * (n₀ ⊔ 2))
z_nonneg : 0 ≤ z
⊢ 1 ≤ 2 ^ n

Tactic:
exact one_le_pow₀ (by norm_num : (1 : ℝ) ≤ 2)

Result:
no goals

Proof state:
f : ℝ → ℝ
hf : GrowsPolynomially f
c₁ : ℝ
left✝¹ : c₁ > 0
c₂ : ℝ
left✝ : c₂ > 0
heq : c₁ = c₂
n₀ : ℝ
hn₀ : ∀ b ≥ n₀, ∀ u ∈ Set.Icc (1 / 2 * b) b, f u = c₂ * f b
n : ℕ
hn : n ≥ 1
hyp_ind : ∀ z ∈ Set.Ico (n₀ ⊔ 2) (2 ^ n * (n₀ ⊔ 2)), f z = f (n₀ ⊔ 2)
z : ℝ
hz : z ∈ Set.Ico (2 ^ n * (n₀ ⊔ 2)) (2 ^ (n + 1) * (n₀ ⊔ 2))
z_nonneg : 0 ≤ z
⊢ 1 ≤ 2

Tactic:
norm_num

Result:
no goals

Proof state:
case intro
f : ℝ → ℝ
hf : GrowsPolynomially f
c₁ : ℝ
left✝¹ : c₁ > 0
c₂ : ℝ
left✝ : c₂ > 0
heq : c₁ = c₂
n₀ : ℝ
hn₀ : ∀ b ≥ n₀, ∀ u ∈ Set.Icc (1 / 2 * b) b, f u = c₂ * f b
⊢ ∃ a, ∀ b ≥ a, f b = f (n₀ ⊔ 2)

Tactic:
refine ⟨max n₀ 2, ?_⟩

Result:
case intro
f : ℝ → ℝ
hf : GrowsPolynomially f
c₁ : ℝ
left✝¹ : c₁ > 0
c₂ : ℝ
left✝ : c₂ > 0
heq : c₁ = c₂
n₀ : ℝ
hn₀ : ∀ b ≥ n₀, ∀ u ∈ Set.Icc (1 / 2 * b) b, f u = c₂ * f b
⊢ ∀ b ≥ n₀ ⊔ 2, f b = f (n₀ ⊔ 2)

Proof state:
f : ℝ → ℝ
hf : GrowsPolynomially f
c₁ : ℝ
left✝¹ : c₁ > 0
c₂ : ℝ
left✝ : c₂ > 0
heq : c₁ = c₂
n₀ : ℝ
hn₀ : ∀ b ≥ n₀, ∀ u ∈ Set.Icc (1 / 2 * b) b, f u = c₂ * f b
n : ℕ
hn : n ≥ 1
hyp_ind : ∀ z ∈ Set.Ico (n₀ ⊔ 2) (2 ^ n * (n₀ ⊔ 2)), f z = f (n₀ ⊔ 2)
z : ℝ
hz : z ∈ Set.Ico (2 ^ n * (n₀ ⊔ 2)) (2 ^ (n + 1) * (n₀ ⊔ 2))
z_nonneg : 0 ≤ z
le_2n : n₀ ⊔ 2 ≤ 2 ^ n * (n₀ ⊔ 2)
n₀_le_z : n₀ ≤ z
fz_eq_c₂fz : f z = c₂ * f z
z_to_half_z' : f (1 / 2 * z) = c₂ * f z
z_to_half_z : f (1 / 2 * z) = f z
⊢ f z = f (n₀ ⊔ 2)

Tactic:
have half_z_to_base : f (1/2 * z) = f (max n₀ 2) := by
  refine hyp_ind (1/2 * z) ⟨?lb, ?ub⟩
  case lb =>
    calc max n₀ 2 ≤ ((1 : ℝ)/(2 : ℝ)) * (2 : ℝ) ^ 1 * max n₀ 2 := by simp
                _ ≤ ((1 : ℝ)/(2 : ℝ)) * (2 : ℝ) ^ n * max n₀ 2 := by gcongr; norm_num
                _ ≤ _ := by rw [mul_assoc]; gcongr; exact_mod_cast hz.1
  case ub =>
    have h₁ : (2 : ℝ)^n = ((1 : ℝ)/(2 : ℝ)) * (2 : ℝ)^(n+1) := by
      rw [one_div, pow_add, pow_one]
      ring
    rw [h₁, mul_assoc]
    gcongr
    exact_mod_cast hz.2

Result:
f : ℝ → ℝ
hf : GrowsPolynomially f
c₁ : ℝ
left✝¹ : c₁ > 0
c₂ : ℝ
left✝ : c₂ > 0
heq : c₁ = c₂
n₀ : ℝ
hn₀ : ∀ b ≥ n₀, ∀ u ∈ Set.Icc (1 / 2 * b) b, f u = c₂ * f b
n : ℕ
hn : n ≥ 1
hyp_ind : ∀ z ∈ Set.Ico (n₀ ⊔ 2) (2 ^ n * (n₀ ⊔ 2)), f z = f (n₀ ⊔ 2)
z : ℝ
hz : z ∈ Set.Ico (2 ^ n * (n₀ ⊔ 2)) (2 ^ (n + 1) * (n₀ ⊔ 2))
z_nonneg : 0 ≤ z
le_2n : n₀ ⊔ 2 ≤ 2 ^ n * (n₀ ⊔ 2)
n₀_le_z : n₀ ≤ z
fz_eq_c₂fz : f z = c₂ * f z
z_to_half_z' : f (1 / 2 * z) = c₂ * f z
z_to_half_z : f (1 / 2 * z) = f z
half_z_to_base : f (1 / 2 * z) = f (n₀ ⊔ 2)
⊢ f z = f (n₀ ⊔ 2)

Proof state:
case intro
f : ℝ → ℝ
hf : GrowsPolynomially f
c₁ : ℝ
left✝¹ : c₁ > 0
c₂ : ℝ
left✝ : c₂ > 0
heq : c₁ = c₂
n₀ : ℝ
hn₀ : ∀ b ≥ n₀, ∀ u ∈ Set.Icc (1 / 2 * b) b, f u = c₂ * f b
⊢ ∃ c, ∀ᶠ (x : ℝ) in atTop, f x = c

Tactic:
refine ⟨f (max n₀ 2), ?_⟩

Result:
case intro
f : ℝ → ℝ
hf : GrowsPolynomially f
c₁ : ℝ
left✝¹ : c₁ > 0
c₂ : ℝ
left✝ : c₂ > 0
heq : c₁ = c₂
n₀ : ℝ
hn₀ : ∀ b ≥ n₀, ∀ u ∈ Set.Icc (1 / 2 * b) b, f u = c₂ * f b
⊢ ∀ᶠ (x : ℝ) in atTop, f x = f (n₀ ⊔ 2)

Proof state:
case step
f : ℝ → ℝ
hf : GrowsPolynomially f
c₁ : ℝ
left✝¹ : c₁ > 0
c₂ : ℝ
left✝ : c₂ > 0
heq : c₁ = c₂
n₀ : ℝ
hn₀ : ∀ b ≥ n₀, ∀ u ∈ Set.Icc (1 / 2 * b) b, f u = c₂ * f b
⊢ ∀ n ≥ 1,
    (∀ z ∈ Set.Ico (n₀ ⊔ 2) (2 ^ n * (n₀ ⊔ 2)), f z = f (n₀ ⊔ 2)) →
      ∀ z ∈ Set.Ico (2 ^ n * (n₀ ⊔ 2)) (2 ^ (n + 1) * (n₀ ⊔ 2)), f z = f (n₀ ⊔ 2)

Tactic:
case step =>
  intro n hn hyp_ind z hz
  have z_nonneg : 0 ≤ z := by
    calc (0 : ℝ) ≤ (2 : ℝ)^n * max n₀ 2 := by
                  exact mul_nonneg (pow_nonneg (by norm_num) _) (by norm_num)
            _ ≤ z := by exact_mod_cast hz.1
  have le_2n : max n₀ 2 ≤ (2 : ℝ)^n * max n₀ 2 := by
    nth_rewrite 1 [← one_mul (max n₀ 2)]
    gcongr
    exact one_le_pow₀ (by norm_num : (1 : ℝ) ≤ 2)
  have n₀_le_z : n₀ ≤ z := by
    calc n₀ ≤ max n₀ 2 := by simp
          _ ≤ (2 : ℝ)^n * max n₀ 2 := le_2n
          _ ≤ _ := by exact_mod_cast hz.1
  have fz_eq_c₂fz : f z = c₂ * f z := hn₀ z n₀_le_z z ⟨by linarith, le_rfl⟩
  have z_to_half_z' : f (1/2 * z) = c₂ * f z := hn₀ z n₀_le_z (1/2 * z) ⟨le_rfl, by linarith⟩
  have z_to_half_z : f (1/2 * z) = f z := by rwa [← fz_eq_c₂fz] at z_to_half_z'
  have half_z_to_base : f (1/2 * z) = f (max n₀ 2) := by
    refine hyp_ind (1/2 * z) ⟨?lb, ?ub⟩
    case lb =>
      calc max n₀ 2 ≤ ((1 : ℝ)/(2 : ℝ)) * (2 : ℝ) ^ 1 * max n₀ 2 := by simp
                  _ ≤ ((1 : ℝ)/(2 : ℝ)) * (2 : ℝ) ^ n * max n₀ 2 := by gcongr; norm_num
                  _ ≤ _ := by rw [mul_assoc]; gcongr; exact_mod_cast hz.1
    case ub =>
      have h₁ : (2 : ℝ)^n = ((1 : ℝ)/(2 : ℝ)) * (2 : ℝ)^(n+1) := by
        rw [one_div, pow_add, pow_one]
        ring
      rw [h₁, mul_assoc]
      gcongr
      exact_mod_cast hz.2
  rw [← z_to_half_z, half_z_to_base]

Result:
no goals

Proof state:
f : ℝ → ℝ
hf : GrowsPolynomially f
c₁ : ℝ
left✝¹ : c₁ > 0
c₂ : ℝ
left✝ : c₂ > 0
h : ∀ᶠ (x : ℝ) in atTop, ∀ u ∈ Set.Icc (1 / 2 * x) x, f u ∈ Set.Icc (c₁ * f x) (c₂ * f x)
heq : c₁ = c₂
c : ℝ
hc : ∀ᶠ (x : ℝ) in atTop, f x = c
hpos : 0 ≤ c
⊢ ∀ᶠ (x : ℝ) in atTop, 0 ≤ f x

Tactic:
filter_upwards [hc] with _ hc

Result:
case h
f : ℝ → ℝ
hf : GrowsPolynomially f
c₁ : ℝ
left✝¹ : c₁ > 0
c₂ : ℝ
left✝ : c₂ > 0
h : ∀ᶠ (x : ℝ) in atTop, ∀ u ∈ Set.Icc (1 / 2 * x) x, f u ∈ Set.Icc (c₁ * f x) (c₂ * f x)
heq : c₁ = c₂
c : ℝ
hc✝ : ∀ᶠ (x : ℝ) in atTop, f x = c
hpos : 0 ≤ c
a✝ : ℝ
hc : f a✝ = c
⊢ 0 ≤ f a✝