Skip to content

Commit

Permalink
feat: Port Data.Nat.Order.Lemmas (#927)
Browse files Browse the repository at this point in the history
mathlib3 SHA: 10b4e499f43088dd3bb7b5796184ad5216648ab1

- [x] Depends on #892
- [x] Depends on #907

Co-authored-by: ChrisHughes24 <chrishughes24@gmail.com>
  • Loading branch information
semorrison and ChrisHughes24 committed Dec 12, 2022
1 parent 20a6a92 commit 573c745
Show file tree
Hide file tree
Showing 7 changed files with 271 additions and 27 deletions.
1 change: 1 addition & 0 deletions Mathlib.lean
Expand Up @@ -165,6 +165,7 @@ import Mathlib.Data.Nat.Basic
import Mathlib.Data.Nat.Cast.Basic
import Mathlib.Data.Nat.Cast.Defs
import Mathlib.Data.Nat.Order.Basic
import Mathlib.Data.Nat.Order.Lemmas
import Mathlib.Data.Nat.PSub
import Mathlib.Data.Nat.Units
import Mathlib.Data.Num.Basic
Expand Down
4 changes: 2 additions & 2 deletions Mathlib/Algebra/Order/Positive/Ring.lean
Expand Up @@ -134,7 +134,7 @@ section mul_comm

instance orderedCommMonoid [StrictOrderedCommSemiring R] [Nontrivial R] :
OrderedCommMonoid { x : R // 0 < x } :=
{ Subtype.instPartialOrderSubtype _,
{ Subtype.partialOrder _,
Subtype.coe_injective.commMonoid (Subtype.val) val_one val_mul val_pow with
mul_le_mul_left := fun _ _ hxy c =>
Subtype.coe_le_coe.1 <| mul_le_mul_of_nonneg_left hxy c.2.le }
Expand All @@ -144,7 +144,7 @@ instance orderedCommMonoid [StrictOrderedCommSemiring R] [Nontrivial R] :
ordered cancellative commutative monoid. -/
instance linearOrderedCancelCommMonoid [LinearOrderedCommSemiring R] :
LinearOrderedCancelCommMonoid { x : R // 0 < x } :=
{ Subtype.instLinearOrderSubtype _, Positive.orderedCommMonoid with
{ Subtype.linearOrder _, Positive.orderedCommMonoid with
le_of_mul_le_mul_left := fun a _ _ h => Subtype.coe_le_coe.1 <| (mul_le_mul_left a.2).1 h }
#align subtype.linear_ordered_cancel_comm_monoid Positive.linearOrderedCancelCommMonoid

Expand Down
239 changes: 239 additions & 0 deletions Mathlib/Data/Nat/Order/Lemmas.lean
@@ -0,0 +1,239 @@
/-
Copyright (c) 2014 Floris van Doorn (c) 2016 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Floris van Doorn, Leonardo de Moura, Jeremy Avigad, Mario Carneiro
-/
import Mathlib.Data.Nat.Order.Basic
import Mathlib.Data.Set.Basic
import Mathlib.Algebra.Ring.Divisibility
import Mathlib.Algebra.GroupWithZero.Divisibility

/-!
# Further lemmas about the natural numbers
The distinction between this file and `Mathlib.Data.Nat.Order.Basic` is not particularly clear.
They are separated for now to minimize the porting requirements for tactics during the transition to
mathlib4. After `Mathlib.Data.Rat.Order` has been ported,
please feel free to reorganize these two files.
-/


universe u v

variable {m n k : ℕ}

namespace Nat

/-! ### Sets -/


instance Subtype.orderBot (s : Set ℕ) [DecidablePred (· ∈ s)] [h : Nonempty s] : OrderBot s where
bot := ⟨Nat.find (nonempty_subtype.1 h), Nat.find_spec (nonempty_subtype.1 h)⟩
bot_le x := Nat.find_min' _ x.2
#align nat.subtype.order_bot Nat.Subtype.orderBot

instance Subtype.semilatticeSup (s : Set ℕ) : SemilatticeSup s :=
{ Subtype.linearOrder s, LinearOrder.toLattice with }
#align nat.subtype.semilattice_sup Nat.Subtype.semilatticeSup

theorem Subtype.coe_bot {s : Set ℕ} [DecidablePred (· ∈ s)] [h : Nonempty s] :
((⊥ : s) : ℕ) = Nat.find (nonempty_subtype.1 h) :=
rfl
#align nat.subtype.coe_bot Nat.Subtype.coe_bot

theorem set_eq_univ {S : Set ℕ} : S = Set.univ ↔ 0 ∈ S ∧ ∀ k : ℕ, k ∈ S → k + 1 ∈ S :=
by rintro rfl; simp, fun ⟨h0, hs⟩ => Set.eq_univ_of_forall (set_induction h0 hs)⟩
#align nat.set_eq_univ Nat.set_eq_univ

/-! ### `div` -/


protected theorem lt_div_iff_mul_lt {n d : ℕ} (hnd : d ∣ n) (a : ℕ) : a < n / d ↔ d * a < n := by
rcases d.eq_zero_or_pos with (rfl | hd0); · simp [zero_dvd_iff.mp hnd]
rw [← mul_lt_mul_left hd0, ← Nat.eq_mul_of_div_eq_right hnd rfl]
#align nat.lt_div_iff_mul_lt Nat.lt_div_iff_mul_lt

theorem div_eq_iff_eq_of_dvd_dvd {n x y : ℕ} (hn : n ≠ 0) (hx : x ∣ n) (hy : y ∣ n) :
n / x = n / y ↔ x = y := by
constructor
· intro h
rw [← mul_right_inj' hn]
apply Nat.eq_mul_of_div_eq_left (dvd_mul_of_dvd_left hy x)
rw [eq_comm, mul_comm, Nat.mul_div_assoc _ hy]
exact Nat.eq_mul_of_div_eq_right hx h
· intro h
rw [h]
#align nat.div_eq_iff_eq_of_dvd_dvd Nat.div_eq_iff_eq_of_dvd_dvd

protected theorem div_eq_zero_iff {a b : ℕ} (hb : 0 < b) : a / b = 0 ↔ a < b :=
fun h => by rw [← mod_add_div a b, h, mul_zero, add_zero]; exact mod_lt _ hb, fun h => by
rw [← mul_right_inj' hb.ne', ← @add_left_cancel_iff _ _ _ (a % b), mod_add_div, mod_eq_of_lt h,
mul_zero, add_zero]⟩
#align nat.div_eq_zero_iff Nat.div_eq_zero_iff

protected theorem div_eq_zero {a b : ℕ} (hb : a < b) : a / b = 0 :=
(Nat.div_eq_zero_iff <| (zero_le a).trans_lt hb).mpr hb
#align nat.div_eq_zero Nat.div_eq_zero

/-! ### `mod`, `dvd` -/


@[simp]
protected theorem dvd_one {n : ℕ} : n ∣ 1 ↔ n = 1 :=
⟨eq_one_of_dvd_one, fun e => e.symm ▸ dvd_rfl⟩
#align nat.dvd_one Nat.dvd_one

set_option linter.deprecated false in
@[simp]
protected theorem not_two_dvd_bit1 (n : ℕ) : ¬2 ∣ bit1 n := by
rw [bit1, Nat.dvd_add_right two_dvd_bit0, Nat.dvd_one]
-- Porting note: was `cc`
decide
#align nat.not_two_dvd_bit1 Nat.not_two_dvd_bit1

/-- A natural number `m` divides the sum `m + n` if and only if `m` divides `n`.-/
@[simp]
protected theorem dvd_add_self_left {m n : ℕ} : m ∣ m + n ↔ m ∣ n :=
Nat.dvd_add_right (dvd_refl m)
#align nat.dvd_add_self_left Nat.dvd_add_self_left

/-- A natural number `m` divides the sum `n + m` if and only if `m` divides `n`.-/
@[simp]
protected theorem dvd_add_self_right {m n : ℕ} : m ∣ n + m ↔ m ∣ n :=
Nat.dvd_add_left (dvd_refl m)
#align nat.dvd_add_self_right Nat.dvd_add_self_right

-- TODO: update `nat.dvd_sub` in core
theorem dvd_sub' {k m n : ℕ} (h₁ : k ∣ m) (h₂ : k ∣ n) : k ∣ m - n := by
cases' le_total n m with H H
· exact dvd_sub H h₁ h₂
· rw [tsub_eq_zero_iff_le.mpr H]
exact dvd_zero k
#align nat.dvd_sub' Nat.dvd_sub'

theorem succ_div : ∀ a b : ℕ, (a + 1) / b = a / b + if b ∣ a + 1 then 1 else 0
| a, 0 => by simp
| 0, 1 => by simp
| 0, b + 2 => by
have hb2 : b + 2 > 1 := by simp
simp [ne_of_gt hb2, div_eq_of_lt hb2]
| a + 1, b + 1 => by
rw [Nat.div_eq]
conv_rhs => rw [Nat.div_eq]
by_cases hb_eq_a : b = a + 1
· simp [hb_eq_a, le_refl]
by_cases hb_le_a1 : b ≤ a + 1
· have hb_le_a : b ≤ a := le_of_lt_succ (lt_of_le_of_ne hb_le_a1 hb_eq_a)
have h₁ : 0 < b + 1 ∧ b + 1 ≤ a + 1 + 1 := ⟨succ_pos _, (add_le_add_iff_right _).2 hb_le_a1⟩
have h₂ : 0 < b + 1 ∧ b + 1 ≤ a + 1 := ⟨succ_pos _, (add_le_add_iff_right _).2 hb_le_a⟩
have dvd_iff : b + 1 ∣ a - b + 1 ↔ b + 1 ∣ a + 1 + 1 := by
rw [Nat.dvd_add_iff_left (dvd_refl (b + 1)), ← add_tsub_add_eq_tsub_right a 1 b,
add_comm (_ - _), add_assoc, tsub_add_cancel_of_le (succ_le_succ hb_le_a), add_comm 1]
have wf : a - b < a + 1 := lt_succ_of_le tsub_le_self
rw [if_pos h₁, if_pos h₂, add_tsub_add_eq_tsub_right, ← tsub_add_eq_add_tsub hb_le_a,
have := wf
succ_div (a - b),
add_tsub_add_eq_tsub_right]
simp [dvd_iff, succ_eq_add_one, add_comm 1, add_assoc]
· have hba : ¬b ≤ a := not_le_of_gt (lt_trans (lt_succ_self a) (lt_of_not_ge hb_le_a1))
have hb_dvd_a : ¬b + 1 ∣ a + 2 := fun h =>
hb_le_a1 (le_of_succ_le_succ (le_of_dvd (succ_pos _) h))
simp [hba, hb_le_a1, hb_dvd_a]
#align nat.succ_div Nat.succ_div

theorem succ_div_of_dvd {a b : ℕ} (hba : b ∣ a + 1) : (a + 1) / b = a / b + 1 := by
rw [succ_div, if_pos hba]
#align nat.succ_div_of_dvd Nat.succ_div_of_dvd

theorem succ_div_of_not_dvd {a b : ℕ} (hba : ¬b ∣ a + 1) : (a + 1) / b = a / b := by
rw [succ_div, if_neg hba, add_zero]
#align nat.succ_div_of_not_dvd Nat.succ_div_of_not_dvd

theorem dvd_iff_div_mul_eq (n d : ℕ) : d ∣ n ↔ n / d * d = n :=
fun h => Nat.div_mul_cancel h, fun h => Dvd.intro_left (n / d) h⟩
#align nat.dvd_iff_div_mul_eq Nat.dvd_iff_div_mul_eq

theorem dvd_iff_le_div_mul (n d : ℕ) : d ∣ n ↔ n ≤ n / d * d :=
((dvd_iff_div_mul_eq _ _).trans le_antisymm_iff).trans (and_iff_right (div_mul_le_self n d))
#align nat.dvd_iff_le_div_mul Nat.dvd_iff_le_div_mul

theorem dvd_iff_dvd_dvd (n d : ℕ) : d ∣ n ↔ ∀ k : ℕ, k ∣ d → k ∣ n :=
fun h _ hkd => dvd_trans hkd h, fun h => h _ dvd_rfl⟩
#align nat.dvd_iff_dvd_dvd Nat.dvd_iff_dvd_dvd

theorem dvd_div_of_mul_dvd {a b c : ℕ} (h : a * b ∣ c) : b ∣ c / a :=
if ha : a = 0 then by simp [ha]
else
have ha : 0 < a := Nat.pos_of_ne_zero ha
have h1 : ∃ d, c = a * b * d := h
let ⟨d, hd⟩ := h1
have h2 : c / a = b * d := Nat.div_eq_of_eq_mul_right ha (by simpa [mul_assoc] using hd)
show ∃ d, c / a = b * d from ⟨d, h2⟩
#align nat.dvd_div_of_mul_dvd Nat.dvd_div_of_mul_dvd

@[simp]
theorem dvd_div_iff {a b c : ℕ} (hbc : c ∣ b) : a ∣ b / c ↔ c * a ∣ b :=
fun h => mul_dvd_of_dvd_div hbc h, fun h => dvd_div_of_mul_dvd h⟩
#align nat.dvd_div_iff Nat.dvd_div_iff

@[simp]
theorem div_div_div_eq_div {a b c : ℕ} (dvd : b ∣ a) (dvd2 : a ∣ c) : c / (a / b) / b = c / a :=
match a, b, c with
| 0, _, _ => by simp
| a + 1, 0, _ => by simp at dvd
| a + 1, c + 1, _ => by
have a_split : a + 10 := succ_ne_zero a
have c_split : c + 10 := succ_ne_zero c
rcases dvd2 with ⟨k, rfl⟩
rcases dvd with ⟨k2, pr⟩
have k2_nonzero : k2 ≠ 0 := fun k2_zero => by simp [k2_zero] at pr
rw [Nat.mul_div_cancel_left k (Nat.pos_of_ne_zero a_split), pr,
Nat.mul_div_cancel_left k2 (Nat.pos_of_ne_zero c_split), Nat.mul_comm ((c + 1) * k2) k, ←
Nat.mul_assoc k (c + 1) k2, Nat.mul_div_cancel _ (Nat.pos_of_ne_zero k2_nonzero),
Nat.mul_div_cancel _ (Nat.pos_of_ne_zero c_split)]
#align nat.div_div_div_eq_div Nat.div_div_div_eq_div

/-- If a small natural number is divisible by a larger natural number,
the small number is zero. -/
theorem eq_zero_of_dvd_of_lt {a b : ℕ} (w : a ∣ b) (h : b < a) : b = 0 :=
Nat.eq_zero_of_dvd_of_div_eq_zero w
((Nat.div_eq_zero_iff (lt_of_le_of_lt (zero_le b) h)).mpr h)
#align nat.eq_zero_of_dvd_of_lt Nat.eq_zero_of_dvd_of_lt

@[simp]
theorem mod_div_self (m n : ℕ) : m % n / n = 0 := by
cases n
· exact (m % 0).div_zero
· case succ n => exact Nat.div_eq_zero (m.mod_lt n.succ_pos)
#align nat.mod_div_self Nat.mod_div_self

/-- `n` is not divisible by `a` iff it is between `a * k` and `a * (k + 1)` for some `k`. -/
theorem not_dvd_iff_between_consec_multiples (n : ℕ) {a : ℕ} (ha : 0 < a) :
(∃ k : ℕ, a * k < n ∧ n < a * (k + 1)) ↔ ¬a ∣ n := by
refine'
fun ⟨k, hk1, hk2⟩ => not_dvd_of_between_consec_multiples hk1 hk2, fun han =>
⟨n / a, ⟨lt_of_le_of_ne (mul_div_le n a) _, lt_mul_div_succ _ ha⟩⟩⟩
exact mt (Dvd.intro (n / a)) han
#align nat.not_dvd_iff_between_consec_multiples Nat.not_dvd_iff_between_consec_multiples

/-- Two natural numbers are equal if and only if they have the same multiples. -/
theorem dvd_right_iff_eq {m n : ℕ} : (∀ a : ℕ, m ∣ a ↔ n ∣ a) ↔ m = n :=
fun h => dvd_antisymm ((h _).mpr dvd_rfl) ((h _).mp dvd_rfl), fun h n => by rw [h]⟩
#align nat.dvd_right_iff_eq Nat.dvd_right_iff_eq

/-- Two natural numbers are equal if and only if they have the same divisors. -/
theorem dvd_left_iff_eq {m n : ℕ} : (∀ a : ℕ, a ∣ m ↔ a ∣ n) ↔ m = n :=
fun h => dvd_antisymm ((h _).mp dvd_rfl) ((h _).mpr dvd_rfl), fun h n => by rw [h]⟩
#align nat.dvd_left_iff_eq Nat.dvd_left_iff_eq

/-- `dvd` is injective in the left argument -/
theorem dvd_left_injective : Function.Injective ((· ∣ ·) : ℕ → ℕ → Prop) := fun _ _ h =>
dvd_right_iff_eq.mp fun a => iff_of_eq (congr_fun h a)
#align nat.dvd_left_injective Nat.dvd_left_injective

theorem div_lt_div_of_lt_of_dvd {a b d : ℕ} (hdb : d ∣ b) (h : a < b) : a / d < b / d := by
rw [Nat.lt_div_iff_mul_lt hdb]
exact lt_of_le_of_lt (mul_div_le a d) h
#align nat.div_lt_div_of_lt_of_dvd Nat.div_lt_div_of_lt_of_dvd

end Nat
24 changes: 12 additions & 12 deletions Mathlib/Data/Num/Basic.lean
Expand Up @@ -172,13 +172,13 @@ instance : LT PosNum :=
instance : LE PosNum :=
fun a b => ¬b < a⟩

instance decidableLt : @DecidableRel PosNum (· < ·)
instance decidableLT : @DecidableRel PosNum (· < ·)
| a, b => by dsimp [LT.lt]; infer_instance
#align pos_num.decidable_lt PosNum.decidableLt
#align pos_num.decidable_lt PosNum.decidableLT

instance decidableLe : @DecidableRel PosNum (· ≤ ·)
instance decidableLE : @DecidableRel PosNum (· ≤ ·)
| a, b => by dsimp [LE.le]; infer_instance
#align pos_num.decidable_le PosNum.decidableLe
#align pos_num.decidable_le PosNum.decidableLE

end PosNum

Expand Down Expand Up @@ -302,13 +302,13 @@ instance : LT Num :=
instance : LE Num :=
fun a b => ¬b < a⟩

instance decidableLt : @DecidableRel Num (· < ·)
instance decidableLT : @DecidableRel Num (· < ·)
| a, b => by dsimp [LT.lt]; infer_instance
#align num.decidable_lt Num.decidableLt
#align num.decidable_lt Num.decidableLT

instance decidableLe : @DecidableRel Num (· ≤ ·)
instance decidableLE : @DecidableRel Num (· ≤ ·)
| a, b => by dsimp [LE.le]; infer_instance
#align num.decidable_le Num.decidableLe
#align num.decidable_le Num.decidableLE

/-- Converts a `Num` to a `ZNum`. -/
def toZNum : Num → ZNum
Expand Down Expand Up @@ -543,13 +543,13 @@ instance : LT ZNum :=
instance : LE ZNum :=
fun a b => ¬b < a⟩

instance decidableLt : @DecidableRel ZNum (· < ·)
instance decidableLT : @DecidableRel ZNum (· < ·)
| a, b => by dsimp [LT.lt]; infer_instance
#align znum.decidable_lt ZNum.decidableLt
#align znum.decidable_lt ZNum.decidableLT

instance decidableLe : @DecidableRel ZNum (· ≤ ·)
instance decidableLE : @DecidableRel ZNum (· ≤ ·)
| a, b => by dsimp [LE.le]; infer_instance
#align znum.decidable_le ZNum.decidableLe
#align znum.decidable_le ZNum.decidableLE

end ZNum

Expand Down
8 changes: 4 additions & 4 deletions Mathlib/Init/Algebra/Order.lean
Expand Up @@ -131,7 +131,7 @@ theorem le_of_eq_or_lt {a b : α} (h : a = b ∨ a < b) : a ≤ b := match h wit
| (Or.inl h) => le_of_eq h
| (Or.inr h) => le_of_lt h

instance decidableLt_of_decidableLe [DecidableRel (. ≤ . : α → α → Prop)] :
instance decidableLT_of_decidableLE [DecidableRel (. ≤ . : α → α → Prop)] :
DecidableRel (. < . : α → α → Prop)
| a, b =>
if hab : a ≤ b then
Expand Down Expand Up @@ -165,7 +165,7 @@ theorem le_antisymm_iff {a b : α} : a = b ↔ a ≤ b ∧ b ≤ a :=
theorem lt_of_le_of_ne {a b : α} : a ≤ b → a ≠ b → a < b :=
λ h₁ h₂ => lt_of_le_not_le h₁ $ mt (le_antisymm h₁) h₂

instance decidableEq_of_decidableLe [DecidableRel (. ≤ . : α → α → Prop)] :
instance decidableEq_of_decidableLE [DecidableRel (. ≤ . : α → α → Prop)] :
DecidableEq α
| a, b =>
if hab : a ≤ b then
Expand Down Expand Up @@ -222,10 +222,10 @@ class LinearOrder (α : Type u) extends PartialOrder α, Min α, Max α :=
/-- In a linearly ordered type, we assume the order relations are all decidable. -/
decidable_le : DecidableRel (. ≤ . : α → α → Prop)
/-- In a linearly ordered type, we assume the order relations are all decidable. -/
decidable_eq : DecidableEq α := @decidableEq_of_decidableLe _ _ decidable_le
decidable_eq : DecidableEq α := @decidableEq_of_decidableLE _ _ decidable_le
/-- In a linearly ordered type, we assume the order relations are all decidable. -/
decidable_lt : DecidableRel (. < . : α → α → Prop) :=
@decidableLt_of_decidableLe _ _ decidable_le
@decidableLT_of_decidableLE _ _ decidable_le
min := fun a b => if a ≤ b then a else b
max := fun a b => if a ≤ b then b else a
/-- The minimum function is equivalent to the one you get from `minOfLe`. -/
Expand Down
8 changes: 6 additions & 2 deletions Mathlib/Init/Data/Nat/Lemmas.lean
Expand Up @@ -55,11 +55,15 @@ Nat.strong_induction_on a $ λ n =>

/- mod -/

-- TODO mod_core_congr, mod_def
-- TODO mod_core_congr

#align nat.mod_def Nat.mod_eq

/- div & mod -/

-- TODO div_core_congr, div_def
-- TODO div_core_congr

#align nat.div_def Nat.div_eq

/- div -/

Expand Down

0 comments on commit 573c745

Please sign in to comment.