|
| 1 | +/- |
| 2 | +Copyright (c) 2025 Concordance Inc. dba Harmonic. All rights reserved. |
| 3 | +Released under Apache 2.0 license as described in the file LICENSE. |
| 4 | +Authors: Yury Kudryashov |
| 5 | +-/ |
| 6 | +import Mathlib.Algebra.Order.Floor.Semifield |
| 7 | +import Mathlib.Analysis.MeanInequalities |
| 8 | +import Mathlib.Data.Nat.NthRoot.Defs |
| 9 | +import Mathlib.Tactic.Rify |
| 10 | + |
| 11 | +/-! |
| 12 | +# Lemmas about `Nat.nthRoot` |
| 13 | +
|
| 14 | +In this file we prove that `Nat.nthRoot n a` is indeed the floor of `ⁿ√a`. |
| 15 | +
|
| 16 | +## TODO |
| 17 | +
|
| 18 | +Rewrite the proof of `Nat.nthRoot.lt_pow_go_succ_aux` to avoid dependencies on real numbers, |
| 19 | +so that we can move this file to `Mathlib/Data/Nat/NthRoot`, then to Batteries. |
| 20 | +-/ |
| 21 | + |
| 22 | +namespace Nat |
| 23 | + |
| 24 | +variable {m n a b guess fuel : ℕ} |
| 25 | + |
| 26 | +@[simp] theorem nthRoot_zero_left (a : ℕ) : nthRoot 0 a = 1 := rfl |
| 27 | + |
| 28 | +@[simp] theorem nthRoot_one_left : nthRoot 1 = id := rfl |
| 29 | + |
| 30 | +@[simp] |
| 31 | +theorem nthRoot_zero_right (h : n ≠ 0) : nthRoot n 0 = 0 := by |
| 32 | + rcases n with _|_|_ <;> grind [nthRoot, nthRoot.go] |
| 33 | + |
| 34 | +@[simp] |
| 35 | +theorem nthRoot_one_right : nthRoot n 1 = 1 := by |
| 36 | + rcases n with _|_|_ <;> simp [nthRoot, nthRoot.go, Nat.add_comm 1] |
| 37 | + |
| 38 | +private theorem nthRoot.pow_go_le (hle : guess ≤ fuel) (n a : ℕ) : |
| 39 | + go n a fuel guess ^ (n + 2) ≤ a := by |
| 40 | + induction fuel generalizing guess with |
| 41 | + | zero => |
| 42 | + obtain rfl : guess = 0 := by grind |
| 43 | + simp [go] |
| 44 | + | succ fuel ih => |
| 45 | + rw [go] |
| 46 | + split_ifs with h |
| 47 | + case pos => |
| 48 | + grind |
| 49 | + case neg => |
| 50 | + have : guess ≤ a / guess ^ (n + 1) := by |
| 51 | + linarith only [Nat.mul_le_of_le_div _ _ _ (not_lt.1 h)] |
| 52 | + replace := Nat.mul_le_of_le_div _ _ _ this |
| 53 | + grind |
| 54 | + |
| 55 | +/-- `nthRoot n a ^ n ≤ a` unless both `n` and `a` are zeros. -/ |
| 56 | +@[simp] |
| 57 | +theorem pow_nthRoot_le_iff : nthRoot n a ^ n ≤ a ↔ n ≠ 0 ∨ a ≠ 0 := by |
| 58 | + rcases n with _|_|_ <;> first | grind | simp [nthRoot, nthRoot.pow_go_le] |
| 59 | + |
| 60 | +alias ⟨_, pow_nthRoot_le⟩ := pow_nthRoot_le_iff |
| 61 | + |
| 62 | +/-- |
| 63 | +An auxiliary lemma saying that if `b ≠ 0`, |
| 64 | +then `(a / b ^ n + n * b) / (n + 1) + 1` is a strict upper estimate on `√[n + 1] a`. |
| 65 | +
|
| 66 | +Currently, the proof relies on the weighted AM-GM inequality, |
| 67 | +which increases the dependency closure of this file by a lot. |
| 68 | +
|
| 69 | +A PR proving this inequality by more elementary means is very welcome. |
| 70 | +-/ |
| 71 | +theorem nthRoot.lt_pow_go_succ_aux (hb : b ≠ 0) : |
| 72 | + a < ((a / b ^ n + n * b) / (n + 1) + 1) ^ (n + 1) := by |
| 73 | + rcases Nat.eq_zero_or_pos n with rfl | hn; · simp |
| 74 | + rw [← Nat.add_mul_div_left a, Nat.div_div_eq_div_mul] <;> try positivity |
| 75 | + rify |
| 76 | + calc |
| 77 | + (a : ℝ) = ((a / b ^ n) ^ (1 / (n + 1) : ℝ) * b ^ (n / (n + 1) : ℝ)) ^ (n + 1) := by |
| 78 | + rw [mul_pow, ← Real.rpow_mul_natCast, ← Real.rpow_mul_natCast] <;> try positivity |
| 79 | + simp (disch := positivity) [div_mul_cancel₀] |
| 80 | + _ ≤ ((1 / (n + 1)) * (a / b ^ n) + (n / (n + 1)) * b) ^ (n + 1) := by |
| 81 | + gcongr |
| 82 | + apply Real.geom_mean_le_arith_mean2_weighted <;> try positivity |
| 83 | + simp [field, add_comm] |
| 84 | + _ = ((a + b ^ n * (n * b)) / (b ^ n * (n + 1))) ^ (n + 1) := by |
| 85 | + congr 1 |
| 86 | + field_simp |
| 87 | + _ < _ := by |
| 88 | + gcongr ?_ ^ _ |
| 89 | + convert lt_floor_add_one (R := ℝ) _ using 1 |
| 90 | + norm_cast |
| 91 | + rw [Nat.floor_div_natCast, Nat.floor_natCast] |
| 92 | + |
| 93 | +private theorem nthRoot.lt_pow_go_succ (hlt : a < (guess + 1) ^ (n + 2)) : |
| 94 | + a < (go n a fuel guess + 1) ^ (n + 2) := by |
| 95 | + induction fuel generalizing guess with |
| 96 | + | zero => simpa [go] |
| 97 | + | succ fuel ih => |
| 98 | + rw [go] |
| 99 | + split_ifs with h |
| 100 | + case pos => |
| 101 | + rcases eq_or_ne guess 0 with rfl | hguess |
| 102 | + · grind |
| 103 | + · exact ih <| Nat.nthRoot.lt_pow_go_succ_aux hguess |
| 104 | + case neg => |
| 105 | + assumption |
| 106 | + |
| 107 | +theorem lt_pow_nthRoot_add_one (hn : n ≠ 0) (a : ℕ) : a < (nthRoot n a + 1) ^ n := by |
| 108 | + match n, hn with |
| 109 | + | 1, _ => simp |
| 110 | + | n + 2, hn => |
| 111 | + simp only [nthRoot] |
| 112 | + apply nthRoot.lt_pow_go_succ |
| 113 | + exact a.lt_succ_self.trans_le (Nat.le_self_pow hn _) |
| 114 | + |
| 115 | +@[simp] |
| 116 | +theorem le_nthRoot_iff (hn : n ≠ 0) : a ≤ nthRoot n b ↔ a ^ n ≤ b := by |
| 117 | + cases le_or_gt a (nthRoot n b) with |
| 118 | + | inl hle => |
| 119 | + simp only [hle, true_iff] |
| 120 | + refine le_trans ?_ (pow_nthRoot_le (.inl hn)) |
| 121 | + gcongr |
| 122 | + | inr hlt => |
| 123 | + simp only [hlt.not_ge, false_iff, not_le] |
| 124 | + refine (lt_pow_nthRoot_add_one hn b).trans_le ?_ |
| 125 | + gcongr |
| 126 | + assumption |
| 127 | + |
| 128 | +@[simp] |
| 129 | +theorem nthRoot_lt_iff (hn : n ≠ 0) : nthRoot n a < b ↔ a < b ^ n := by |
| 130 | + simp only [← not_le, le_nthRoot_iff hn] |
| 131 | + |
| 132 | +@[simp] |
| 133 | +theorem nthRoot_pow (hn : n ≠ 0) (a : ℕ) : nthRoot n (a ^ n) = a := by |
| 134 | + refine eq_of_forall_le_iff fun b ↦ ?_ |
| 135 | + rw [le_nthRoot_iff hn] |
| 136 | + exact (Nat.pow_left_strictMono hn).le_iff_le |
| 137 | + |
| 138 | +/-- If `a ^ n ≤ b < (a + 1) ^ n`, then `n` root of `b` equals `a`. -/ |
| 139 | +theorem nthRoot_eq_of_le_of_lt (h₁ : a ^ n ≤ b) (h₂ : b < (a + 1) ^ n) : |
| 140 | + nthRoot n b = a := by |
| 141 | + rcases eq_or_ne n 0 with rfl | hn |
| 142 | + · grind |
| 143 | + simp only [← le_nthRoot_iff hn, ← nthRoot_lt_iff hn] at h₁ h₂ |
| 144 | + grind |
| 145 | + |
| 146 | +theorem exists_pow_eq_iff' (hn : n ≠ 0) : (∃ x, x ^ n = a) ↔ (nthRoot n a) ^ n = a := by |
| 147 | + constructor |
| 148 | + · rintro ⟨x, rfl⟩ |
| 149 | + rw [nthRoot_pow hn] |
| 150 | + · grind |
| 151 | + |
| 152 | +theorem exists_pow_eq_iff : |
| 153 | + (∃ x, x ^ n = a) ↔ ((n = 0 ∧ a = 1) ∨ (n ≠ 0 ∧ (nthRoot n a) ^ n = a)) := by |
| 154 | + rcases eq_or_ne n 0 with rfl | _ <;> grind [exists_pow_eq_iff'] |
| 155 | + |
| 156 | +instance instDecidableExistsPowEq : Decidable (∃ x, x ^ n = a) := |
| 157 | + decidable_of_iff' _ exists_pow_eq_iff |
| 158 | + |
| 159 | +end Nat |
0 commit comments