Module docstring
{"# Nat.find and Nat.findGreatest
","### Nat.find ","### Nat.findGreatest "}
{"# Nat.find and Nat.findGreatest
","### Nat.find ","### Nat.findGreatest "}
Nat.findX
definition
: { n // p n ∧ ∀ m < n, ¬p m }
/-- Find the smallest `n` satisfying `p n`. Returns a subtype. -/
protected def findX : { n // p n ∧ ∀ m < n, ¬p m } :=
@WellFounded.fix _ (fun k => (∀ n < k, ¬p n) → { n // p n ∧ ∀ m < n, ¬p m }) lbp (wf_lbp H)
(fun m IH al =>
if pm : p m then ⟨m, pm, al⟩
else
have : ∀ n ≤ m, ¬p n := fun n h =>
Or.elim (Nat.lt_or_eq_of_le h) (al n) fun e => by rw [e]; exact pm
IH _ ⟨rfl, this⟩ fun n h => this n <| Nat.le_of_succ_le_succ h)
0 fun _ h => absurd h (Nat.not_lt_zero _)
Nat.find
definition
: ℕ
/-- If `p` is a (decidable) predicate on `ℕ` and `hp : ∃ (n : ℕ), p n` is a proof that
there exists some natural number satisfying `p`, then `Nat.find hp` is the
smallest natural number satisfying `p`. Note that `Nat.find` is protected,
meaning that you can't just write `find`, even if the `Nat` namespace is open.
The API for `Nat.find` is:
* `Nat.find_spec` is the proof that `Nat.find hp` satisfies `p`.
* `Nat.find_min` is the proof that if `m < Nat.find hp` then `m` does not satisfy `p`.
* `Nat.find_min'` is the proof that if `m` does satisfy `p` then `Nat.find hp ≤ m`.
-/
protected def find : ℕ :=
(Nat.findX H).1
Nat.find_spec
theorem
: p (Nat.find H)
Nat.find_min
theorem
: ∀ {m : ℕ}, m < Nat.find H → ¬p m
Nat.find_min'
theorem
{m : ℕ} (h : p m) : Nat.find H ≤ m
protected theorem find_min' {m : ℕ} (h : p m) : Nat.find H ≤ m :=
Nat.le_of_not_lt fun l => Nat.find_min H l h
Nat.find_eq_iff
theorem
(h : ∃ n : ℕ, p n) : Nat.find h = m ↔ p m ∧ ∀ n < m, ¬p n
lemma find_eq_iff (h : ∃ n : ℕ, p n) : Nat.findNat.find h = m ↔ p m ∧ ∀ n < m, ¬ p n := by
constructor
· rintro rfl
exact ⟨Nat.find_spec h, fun _ ↦ Nat.find_min h⟩
· rintro ⟨hm, hlt⟩
exact le_antisymm (Nat.find_min' h hm) (not_lt.1 <| imp_not_comm.1 (hlt _) <| Nat.find_spec h)
Nat.find_lt_iff
theorem
(h : ∃ n : ℕ, p n) (n : ℕ) : Nat.find h < n ↔ ∃ m < n, p m
@[simp] lemma find_lt_iff (h : ∃ n : ℕ, p n) (n : ℕ) : Nat.findNat.find h < n ↔ ∃ m < n, p m :=
⟨fun h2 ↦ ⟨Nat.find h, h2, Nat.find_spec h⟩,
fun ⟨_, hmn, hm⟩ ↦ Nat.lt_of_le_of_lt (Nat.find_min' h hm) hmn⟩
Nat.find_le_iff
theorem
(h : ∃ n : ℕ, p n) (n : ℕ) : Nat.find h ≤ n ↔ ∃ m ≤ n, p m
@[simp] lemma find_le_iff (h : ∃ n : ℕ, p n) (n : ℕ) : Nat.findNat.find h ≤ n ↔ ∃ m ≤ n, p m := by
simp only [exists_prop, ← Nat.lt_succ_iff, find_lt_iff]
Nat.le_find_iff
theorem
(h : ∃ n : ℕ, p n) (n : ℕ) : n ≤ Nat.find h ↔ ∀ m < n, ¬p m
@[simp] lemma le_find_iff (h : ∃ n : ℕ, p n) (n : ℕ) : n ≤ Nat.find h ↔ ∀ m < n, ¬ p m := by
simp only [← not_lt, find_lt_iff, not_exists, not_and]
Nat.lt_find_iff
theorem
(h : ∃ n : ℕ, p n) (n : ℕ) : n < Nat.find h ↔ ∀ m ≤ n, ¬p m
@[simp] lemma lt_find_iff (h : ∃ n : ℕ, p n) (n : ℕ) : n < Nat.find h ↔ ∀ m ≤ n, ¬ p m := by
simp only [← succ_le_iff, le_find_iff, succ_le_succ_iff]
Nat.find_eq_zero
theorem
(h : ∃ n : ℕ, p n) : Nat.find h = 0 ↔ p 0
@[simp] lemma find_eq_zero (h : ∃ n : ℕ, p n) : Nat.findNat.find h = 0 ↔ p 0 := by simp [find_eq_iff]
Nat.find_mono_of_le
theorem
[DecidablePred q] {x : ℕ} (hx : q x) (hpq : ∀ n ≤ x, q n → p n) :
Nat.find ⟨x, show p x from hpq _ le_rfl hx⟩ ≤ Nat.find ⟨x, hx⟩
/-- If a predicate `q` holds at some `x` and implies `p` up to that `x`, then
the earliest `xq` such that `q xq` is at least the smallest `xp` where `p xp`.
The stronger version of `Nat.find_mono`, since this one needs
implication only up to `Nat.find _` while the other requires `q` implying `p` everywhere. -/
lemma find_mono_of_le [DecidablePred q] {x : ℕ} (hx : q x) (hpq : ∀ n ≤ x, q n → p n) :
Nat.find ⟨x, show p x from hpq _ le_rfl hx⟩ ≤ Nat.find ⟨x, hx⟩ :=
Nat.find_min' _ (hpq _ (Nat.find_min' _ hx) (Nat.find_spec ⟨x, hx⟩))
Nat.find_mono
theorem
[DecidablePred q] (h : ∀ n, q n → p n) {hp : ∃ n, p n} {hq : ∃ n, q n} : Nat.find hp ≤ Nat.find hq
/-- A weak version of `Nat.find_mono_of_le`, requiring `q` implies `p` everywhere.
-/
lemma find_mono [DecidablePred q] (h : ∀ n, q n → p n) {hp : ∃ n, p n} {hq : ∃ n, q n} :
Nat.find hp ≤ Nat.find hq :=
let ⟨_, hq⟩ := hq; find_mono_of_le hq fun _ _ ↦ h _
Nat.find_congr
theorem
[DecidablePred q] {x : ℕ} (hx : p x) (hpq : ∀ n ≤ x, p n ↔ q n) :
Nat.find ⟨x, hx⟩ = Nat.find ⟨x, show q x from hpq _ le_rfl |>.1 hx⟩
/-- If a predicate `p` holds at some `x` and agrees with `q` up to that `x`, then
their `Nat.find` agree. The stronger version of `Nat.find_congr'`, since this one needs
agreement only up to `Nat.find _` while the other requires `p = q`.
Usage of this lemma will likely be via `obtain ⟨x, hx⟩ := hp; apply Nat.find_congr hx` to unify `q`,
or provide it explicitly with `rw [Nat.find_congr (q := q) hx]`.
-/
lemma find_congr [DecidablePred q] {x : ℕ} (hx : p x) (hpq : ∀ n ≤ x, p n ↔ q n) :
Nat.find ⟨x, hx⟩ = Nat.find ⟨x, show q x from hpq _ le_rfl |>.1 hx⟩ :=
le_antisymm (find_mono_of_le (hpq _ le_rfl |>.1 hx) fun _ h ↦ (hpq _ h).mpr)
(find_mono_of_le hx fun _ h ↦ (hpq _ h).mp)
Nat.find_congr'
theorem
[DecidablePred q] {hp : ∃ n, p n} {hq : ∃ n, q n} (hpq : ∀ {n}, p n ↔ q n) : Nat.find hp = Nat.find hq
/-- A weak version of `Nat.find_congr`, requiring `p = q` everywhere. -/
lemma find_congr' [DecidablePred q] {hp : ∃ n, p n} {hq : ∃ n, q n} (hpq : ∀ {n}, p n ↔ q n) :
Nat.find hp = Nat.find hq :=
let ⟨_, hp⟩ := hp; find_congr hp fun _ _ ↦ hpq
Nat.find_le
theorem
{h : ∃ n, p n} (hn : p n) : Nat.find h ≤ n
lemma find_le {h : ∃ n, p n} (hn : p n) : Nat.find h ≤ n :=
(Nat.find_le_iff _ _).2 ⟨n, le_refl _, hn⟩
Nat.find_comp_succ
theorem
(h₁ : ∃ n, p n) (h₂ : ∃ n, p (n + 1)) (h0 : ¬p 0) : Nat.find h₁ = Nat.find h₂ + 1
lemma find_comp_succ (h₁ : ∃ n, p n) (h₂ : ∃ n, p (n + 1)) (h0 : ¬ p 0) :
Nat.find h₁ = Nat.find h₂ + 1 := by
refine (find_eq_iff _).2 ⟨Nat.find_spec h₂, fun n hn ↦ ?_⟩
cases n
exacts [h0, @Nat.find_min (fun n ↦ p (n + 1)) _ h₂ _ (succ_lt_succ_iff.1 hn)]
Nat.find_pos
theorem
(h : ∃ n : ℕ, p n) : 0 < Nat.find h ↔ ¬p 0
lemma find_pos (h : ∃ n : ℕ, p n) : 0 < Nat.find h ↔ ¬p 0 :=
Nat.pos_iff_ne_zero.trans (Nat.find_eq_zero _).not
Nat.find_add
theorem
{hₘ : ∃ m, p (m + n)} {hₙ : ∃ n, p n} (hn : n ≤ Nat.find hₙ) : Nat.find hₘ + n = Nat.find hₙ
lemma find_add {hₘ : ∃ m, p (m + n)} {hₙ : ∃ n, p n} (hn : n ≤ Nat.find hₙ) :
Nat.find hₘ + n = Nat.find hₙ := by
refine le_antisymm ((le_find_iff _ _).2 fun m hm hpm => Nat.not_le.2 hm ?_) ?_
· have hnm : n ≤ m := le_trans hn (find_le hpm)
refine Nat.add_le_of_le_sub hnm (find_le ?_)
rwa [Nat.sub_add_cancel hnm]
· rw [← Nat.sub_le_iff_le_add]
refine (le_find_iff _ _).2 fun m hm hpm => Nat.not_le.2 hm ?_
rw [Nat.sub_le_iff_le_add]
exact find_le hpm
Nat.findGreatest
definition
(P : ℕ → Prop) [DecidablePred P] : ℕ → ℕ
/-- `Nat.findGreatest P n` is the largest `i ≤ bound` such that `P i` holds, or `0` if no such `i`
exists -/
def findGreatest (P : ℕ → Prop) [DecidablePred P] : ℕ → ℕ
| 0 => 0
| n + 1 => if P (n + 1) then n + 1 else Nat.findGreatest P n
Nat.findGreatest_zero
theorem
: Nat.findGreatest P 0 = 0
@[simp] lemma findGreatest_zero : Nat.findGreatest P 0 = 0 := rfl
Nat.findGreatest_succ
theorem
(n : ℕ) : Nat.findGreatest P (n + 1) = if P (n + 1) then n + 1 else Nat.findGreatest P n
lemma findGreatest_succ (n : ℕ) :
Nat.findGreatest P (n + 1) = if P (n + 1) then n + 1 else Nat.findGreatest P n := rfl
Nat.findGreatest_eq
theorem
: ∀ {n}, P n → Nat.findGreatest P n = n
@[simp] lemma findGreatest_eq : ∀ {n}, P n → Nat.findGreatest P n = n
| 0, _ => rfl
| n + 1, h => by simp [Nat.findGreatest, h]
Nat.findGreatest_of_not
theorem
(h : ¬P (n + 1)) : findGreatest P (n + 1) = findGreatest P n
@[simp]
lemma findGreatest_of_not (h : ¬ P (n + 1)) : findGreatest P (n + 1) = findGreatest P n := by
simp [Nat.findGreatest, h]
Nat.findGreatest_eq_iff
theorem
: Nat.findGreatest P k = m ↔ m ≤ k ∧ (m ≠ 0 → P m) ∧ ∀ ⦃n⦄, m < n → n ≤ k → ¬P n
lemma findGreatest_eq_iff :
Nat.findGreatestNat.findGreatest P k = m ↔ m ≤ k ∧ (m ≠ 0 → P m) ∧ ∀ ⦃n⦄, m < n → n ≤ k → ¬P n := by
induction k generalizing m with
| zero =>
rw [eq_comm, Iff.comm]
simp only [zero_eq, Nat.le_zero, ne_eq, findGreatest_zero, and_iff_left_iff_imp]
rintro rfl
exact ⟨fun h ↦ (h rfl).elim, fun n hlt heq ↦ by omega⟩
| succ k ihk =>
by_cases hk : P (k + 1)
· rw [findGreatest_eq hk]
constructor
· rintro rfl
exact ⟨le_refl _, fun _ ↦ hk, fun n hlt hle ↦ by omega⟩
· rintro ⟨hle, h0, hm⟩
rcases Decidable.eq_or_lt_of_le hle with (rfl | hlt)
exacts [rfl, (hm hlt (le_refl _) hk).elim]
· rw [findGreatest_of_not hk, ihk]
constructor
· rintro ⟨hle, hP, hm⟩
refine ⟨le_trans hle k.le_succ, hP, fun n hlt hle ↦ ?_⟩
rcases Decidable.eq_or_lt_of_le hle with (rfl | hlt')
exacts [hk, hm hlt <| Nat.lt_succ_iff.1 hlt']
· rintro ⟨hle, hP, hm⟩
refine ⟨Nat.lt_succ_iff.1 (lt_of_le_of_ne hle ?_), hP,
fun n hlt hle ↦ hm hlt (le_trans hle k.le_succ)⟩
rintro rfl
exact hk (hP k.succ_ne_zero)
Nat.findGreatest_eq_zero_iff
theorem
: Nat.findGreatest P k = 0 ↔ ∀ ⦃n⦄, 0 < n → n ≤ k → ¬P n
lemma findGreatest_eq_zero_iff : Nat.findGreatestNat.findGreatest P k = 0 ↔ ∀ ⦃n⦄, 0 < n → n ≤ k → ¬P n := by
simp [findGreatest_eq_iff]
Nat.findGreatest_pos
theorem
: 0 < Nat.findGreatest P k ↔ ∃ n, 0 < n ∧ n ≤ k ∧ P n
@[simp] lemma findGreatest_pos : 0 < Nat.findGreatest P k ↔ ∃ n, 0 < n ∧ n ≤ k ∧ P n := by
rw [Nat.pos_iff_ne_zero, Ne, findGreatest_eq_zero_iff]; push_neg; rfl
Nat.findGreatest_spec
theorem
(hmb : m ≤ n) (hm : P m) : P (Nat.findGreatest P n)
lemma findGreatest_spec (hmb : m ≤ n) (hm : P m) : P (Nat.findGreatest P n) := by
by_cases h : Nat.findGreatest P n = 0
· cases m
· rwa [h]
exact ((findGreatest_eq_zero_iff.1 h) (zero_lt_succ _) hmb hm).elim
· exact (findGreatest_eq_iff.1 rfl).2.1 h
Nat.findGreatest_le
theorem
(n : ℕ) : Nat.findGreatest P n ≤ n
lemma findGreatest_le (n : ℕ) : Nat.findGreatest P n ≤ n :=
(findGreatest_eq_iff.1 rfl).1
Nat.le_findGreatest
theorem
(hmb : m ≤ n) (hm : P m) : m ≤ Nat.findGreatest P n
lemma le_findGreatest (hmb : m ≤ n) (hm : P m) : m ≤ Nat.findGreatest P n :=
le_of_not_lt fun hlt => (findGreatest_eq_iff.1 rfl).2.2 hlt hmb hm
Nat.findGreatest_mono_right
theorem
(P : ℕ → Prop) [DecidablePred P] {m n} (hmn : m ≤ n) : Nat.findGreatest P m ≤ Nat.findGreatest P n
lemma findGreatest_mono_right (P : ℕ → Prop) [DecidablePred P] {m n} (hmn : m ≤ n) :
Nat.findGreatest P m ≤ Nat.findGreatest P n := by
induction hmn with
| refl => simp
| step hmk ih =>
rw [findGreatest_succ]
split_ifs
· exact le_trans ih <| le_trans (findGreatest_le _) (le_succ _)
· exact ih
Nat.findGreatest_mono_left
theorem
[DecidablePred Q] (hPQ : ∀ n, P n → Q n) (n : ℕ) : Nat.findGreatest P n ≤ Nat.findGreatest Q n
lemma findGreatest_mono_left [DecidablePred Q] (hPQ : ∀ n, P n → Q n) (n : ℕ) :
Nat.findGreatest P n ≤ Nat.findGreatest Q n := by
induction n with
| zero => rfl
| succ n hn =>
by_cases h : P (n + 1)
· rw [findGreatest_eq h, findGreatest_eq (hPQ _ h)]
· rw [findGreatest_of_not h]
exact le_trans hn (Nat.findGreatest_mono_right _ <| le_succ _)
Nat.findGreatest_mono
theorem
[DecidablePred Q] (hPQ : ∀ n, P n → Q n) (hmn : m ≤ n) : Nat.findGreatest P m ≤ Nat.findGreatest Q n
lemma findGreatest_mono [DecidablePred Q] (hPQ : ∀ n, P n → Q n) (hmn : m ≤ n) :
Nat.findGreatest P m ≤ Nat.findGreatest Q n :=
le_trans (Nat.findGreatest_mono_right _ hmn) (findGreatest_mono_left hPQ _)
Nat.findGreatest_is_greatest
theorem
(hk : Nat.findGreatest P n < k) (hkb : k ≤ n) : ¬P k
theorem findGreatest_is_greatest (hk : Nat.findGreatest P n < k) (hkb : k ≤ n) : ¬P k :=
(findGreatest_eq_iff.1 rfl).2.2 hk hkb
Nat.findGreatest_of_ne_zero
theorem
(h : Nat.findGreatest P n = m) (h0 : m ≠ 0) : P m
theorem findGreatest_of_ne_zero (h : Nat.findGreatest P n = m) (h0 : m ≠ 0) : P m :=
(findGreatest_eq_iff.1 h).2.1 h0