lean4-htt/src/Init/Data/Nat/Dvd.lean
Leonardo de Moura b26b781992
feat: simprocs for Int and Nat divides predicates (#7078)
This PR implements simprocs for `Int` and `Nat` divides predicates.
2025-02-14 05:43:38 +00:00

141 lines
5.6 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro
-/
prelude
import Init.Data.Nat.Div.Basic
import Init.Meta
namespace Nat
protected theorem dvd_refl (a : Nat) : a a := ⟨1, by simp⟩
protected theorem dvd_zero (a : Nat) : a 0 := ⟨0, by simp⟩
protected theorem dvd_mul_left (a b : Nat) : a b * a := ⟨b, Nat.mul_comm b a⟩
protected theorem dvd_mul_right (a b : Nat) : a a * b := ⟨b, rfl⟩
protected theorem dvd_trans {a b c : Nat} (h₁ : a b) (h₂ : b c) : a c :=
match h₁, h₂ with
| ⟨d, (h₃ : b = a * d)⟩, ⟨e, (h₄ : c = b * e)⟩ =>
⟨d * e, show c = a * (d * e) by simp[h₃,h₄, Nat.mul_assoc]⟩
protected theorem eq_zero_of_zero_dvd {a : Nat} (h : 0 a) : a = 0 :=
let ⟨c, H'⟩ := h; H'.trans c.zero_mul
@[simp] protected theorem zero_dvd {n : Nat} : 0 n ↔ n = 0 :=
⟨Nat.eq_zero_of_zero_dvd, fun h => h.symm ▸ Nat.dvd_zero 0⟩
protected theorem dvd_add {a b c : Nat} (h₁ : a b) (h₂ : a c) : a b + c :=
let ⟨d, hd⟩ := h₁; let ⟨e, he⟩ := h₂; ⟨d + e, by simp [Nat.left_distrib, hd, he]⟩
protected theorem dvd_add_iff_right {k m n : Nat} (h : k m) : k n ↔ k m + n :=
⟨Nat.dvd_add h,
match m, h with
| _, ⟨d, rfl⟩ => fun ⟨e, he⟩ =>
⟨e - d, by rw [Nat.mul_sub_left_distrib, ← he, Nat.add_sub_cancel_left]⟩⟩
protected theorem dvd_add_iff_left {k m n : Nat} (h : k n) : k m ↔ k m + n := by
rw [Nat.add_comm]; exact Nat.dvd_add_iff_right h
theorem dvd_mod_iff {k m n : Nat} (h: k n) : k m % n ↔ k m := by
have := Nat.dvd_add_iff_left (m := m % n) <| Nat.dvd_trans h <| Nat.dvd_mul_right n (m / n)
rwa [mod_add_div] at this
theorem le_of_dvd {m n : Nat} (h : 0 < n) : m n → m ≤ n
| ⟨k, e⟩ => by
revert h
rw [e]
match k with
| 0 => intro hn; simp at hn
| pk+1 =>
intro
have := Nat.mul_le_mul_left m (succ_pos pk)
rwa [Nat.mul_one] at this
protected theorem dvd_antisymm : ∀ {m n : Nat}, m n → n m → m = n
| _, 0, _, h₂ => Nat.eq_zero_of_zero_dvd h₂
| 0, _, h₁, _ => (Nat.eq_zero_of_zero_dvd h₁).symm
| _+1, _+1, h₁, h₂ => Nat.le_antisymm (le_of_dvd (succ_pos _) h₁) (le_of_dvd (succ_pos _) h₂)
theorem pos_of_dvd_of_pos {m n : Nat} (H1 : m n) (H2 : 0 < n) : 0 < m :=
Nat.pos_of_ne_zero fun m0 => Nat.ne_of_gt H2 <| Nat.eq_zero_of_zero_dvd (m0 ▸ H1)
@[simp] protected theorem one_dvd (n : Nat) : 1 n := ⟨n, n.one_mul.symm⟩
theorem eq_one_of_dvd_one {n : Nat} (H : n 1) : n = 1 := Nat.dvd_antisymm H n.one_dvd
theorem mod_eq_zero_of_dvd {m n : Nat} (H : m n) : n % m = 0 := by
let ⟨z, H⟩ := H; rw [H, mul_mod_right]
theorem dvd_of_mod_eq_zero {m n : Nat} (H : n % m = 0) : m n := by
exists n / m
have := (mod_add_div n m).symm
rwa [H, Nat.zero_add] at this
theorem dvd_iff_mod_eq_zero {m n : Nat} : m n ↔ n % m = 0 :=
⟨mod_eq_zero_of_dvd, dvd_of_mod_eq_zero⟩
instance decidable_dvd : @DecidableRel Nat Nat (·∣·) :=
fun _ _ => decidable_of_decidable_of_iff dvd_iff_mod_eq_zero.symm
theorem emod_pos_of_not_dvd {a b : Nat} (h : ¬ a b) : 0 < b % a := by
rw [dvd_iff_mod_eq_zero] at h
exact Nat.pos_of_ne_zero h
protected theorem mul_div_cancel' {n m : Nat} (H : n m) : n * (m / n) = m := by
have := mod_add_div m n
rwa [mod_eq_zero_of_dvd H, Nat.zero_add] at this
protected theorem div_mul_cancel {n m : Nat} (H : n m) : m / n * n = m := by
rw [Nat.mul_comm, Nat.mul_div_cancel' H]
@[simp] theorem mod_mod_of_dvd (a : Nat) (h : c b) : a % b % c = a % c := by
rw (occs := [2]) [← mod_add_div a b]
have ⟨x, h⟩ := h
subst h
rw [Nat.mul_assoc, add_mul_mod_self_left]
protected theorem dvd_of_mul_dvd_mul_left
(kpos : 0 < k) (H : k * m k * n) : m n := by
let ⟨l, H⟩ := H
rw [Nat.mul_assoc] at H
exact ⟨_, Nat.eq_of_mul_eq_mul_left kpos H⟩
protected theorem dvd_of_mul_dvd_mul_right (kpos : 0 < k) (H : m * k n * k) : m n := by
rw [Nat.mul_comm m k, Nat.mul_comm n k] at H; exact Nat.dvd_of_mul_dvd_mul_left kpos H
theorem dvd_sub {k m n : Nat} (H : n ≤ m) (h₁ : k m) (h₂ : k n) : k m - n :=
(Nat.dvd_add_iff_left h₂).2 <| by rwa [Nat.sub_add_cancel H]
protected theorem mul_dvd_mul {a b c d : Nat} : a b → c d → a * c b * d
| ⟨e, he⟩, ⟨f, hf⟩ =>
⟨e * f, by simp [he, hf, Nat.mul_assoc, Nat.mul_left_comm, Nat.mul_comm]⟩
protected theorem mul_dvd_mul_left (a : Nat) (h : b c) : a * b a * c :=
Nat.mul_dvd_mul (Nat.dvd_refl a) h
protected theorem mul_dvd_mul_right (h: a b) (c : Nat) : a * c b * c :=
Nat.mul_dvd_mul h (Nat.dvd_refl c)
@[simp] theorem dvd_one {n : Nat} : n 1 ↔ n = 1 :=
⟨eq_one_of_dvd_one, fun h => h.symm ▸ Nat.dvd_refl _⟩
protected theorem mul_div_assoc (m : Nat) (H : k n) : m * n / k = m * (n / k) := by
match Nat.eq_zero_or_pos k with
| .inl h0 => rw [h0, Nat.div_zero, Nat.div_zero, Nat.mul_zero]
| .inr hpos =>
have h1 : m * n / k = m * (n / k * k) / k := by rw [Nat.div_mul_cancel H]
rw [h1, ← Nat.mul_assoc, Nat.mul_div_cancel _ hpos]
/-! Helper theorems for `dvd` simproc -/
protected theorem dvd_eq_true_of_mod_eq_zero {m n : Nat} (h : n % m == 0) : (m n) = True := by
simp [Nat.dvd_of_mod_eq_zero, eq_of_beq h]
protected theorem dvd_eq_false_of_mod_ne_zero {m n : Nat} (h : n % m != 0) : (m n) = False := by
simp [eq_of_beq] at h
simp [dvd_iff_mod_eq_zero, h]
end Nat