Skip to content

Commit 3fc1358

Browse files
zeramorphickim-em
andcommitted
feat: port Data.Int.Units (#807)
mathlib3 SHA: 62a5626868683c104774de8d85b9855234ac807c I'm a bit confused about the choice of indenting that mathport uses in proofs - I've tried to copy it, but I can't find any documentation to explain a preferred style in Lean 4. I also added a missing `#align` in `Algebra.Group.Units`. Co-authored-by: Scott Morrison <scott.morrison@gmail.com>
1 parent e48be15 commit 3fc1358

File tree

4 files changed

+119
-0
lines changed

4 files changed

+119
-0
lines changed

Mathlib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ import Mathlib.Data.Int.Cast
7979
import Mathlib.Data.Int.Cast.Basic
8080
import Mathlib.Data.Int.Cast.Defs
8181
import Mathlib.Data.Int.Order.Basic
82+
import Mathlib.Data.Int.Units
8283
import Mathlib.Data.KVMap
8384
import Mathlib.Data.LazyList
8485
import Mathlib.Data.List.Basic

Mathlib/Algebra/Group/Units.lean

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,8 @@ namespace IsUnit
614614
theorem mul_iff [CommMonoid M] {x y : M} : IsUnit (x * y) ↔ IsUnit x ∧ IsUnit y :=
615615
fun h => ⟨isUnit_of_mul_isUnit_left h, isUnit_of_mul_isUnit_right h⟩,
616616
fun h => IsUnit.mul h.1 h.2
617+
#align is_unit.mul_iff IsUnit.mul_iff
618+
#align is_add_unit.add_iff IsAddUnit.add_iff
617619

618620
section Monoid
619621

Mathlib/Data/Int/Units.lean

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/-
2+
Copyright (c) 2016 Jeremy Avigad. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Jeremy Avigad
5+
-/
6+
import Mathlib.Data.Nat.Units
7+
import Mathlib.Data.Int.Basic
8+
import Mathlib.Algebra.Ring.Units
9+
10+
/-!
11+
# Lemmas about units in `ℤ`.
12+
-/
13+
14+
15+
namespace Int
16+
17+
/-! ### units -/
18+
19+
@[simp]
20+
theorem units_natAbs (u : ℤˣ) : natAbs u = 1 :=
21+
Units.ext_iff.1 <|
22+
Nat.units_eq_one
23+
⟨natAbs u, natAbs ↑u⁻¹, by rw [← natAbs_mul, Units.mul_inv]; rfl, by
24+
rw [← natAbs_mul, Units.inv_mul]; rfl⟩
25+
#align int.units_nat_abs Int.units_natAbs
26+
27+
theorem units_eq_one_or (u : ℤˣ) : u = 1 ∨ u = -1 := by
28+
simpa only [Units.ext_iff, units_natAbs] using natAbs_eq u
29+
#align int.units_eq_one_or Int.units_eq_one_or
30+
31+
theorem isUnit_eq_one_or {a : ℤ} : IsUnit a → a = 1 ∨ a = -1
32+
| ⟨_, hx⟩ => hx ▸ (units_eq_one_or _).imp (congr_arg Units.val) (congr_arg Units.val)
33+
#align int.is_unit_eq_one_or Int.isUnit_eq_one_or
34+
35+
theorem isUnit_iff {a : ℤ} : IsUnit a ↔ a = 1 ∨ a = -1 := by
36+
refine' ⟨fun h => isUnit_eq_one_or h, fun h => _⟩
37+
rcases h with (rfl | rfl)
38+
· exact isUnit_one
39+
· exact isUnit_one.neg
40+
#align int.is_unit_iff Int.isUnit_iff
41+
42+
theorem isUnit_eq_or_eq_neg {a b : ℤ} (ha : IsUnit a) (hb : IsUnit b) : a = b ∨ a = -b := by
43+
rcases isUnit_eq_one_or hb with (rfl | rfl)
44+
· exact isUnit_eq_one_or ha
45+
· rwa [or_comm, neg_neg, ← isUnit_iff]
46+
#align int.is_unit_eq_or_eq_neg Int.isUnit_eq_or_eq_neg
47+
48+
theorem eq_one_or_neg_one_of_mul_eq_one {z w : ℤ} (h : z * w = 1) : z = 1 ∨ z = -1 :=
49+
isUnit_iff.mp (isUnit_of_mul_eq_one z w h)
50+
#align int.eq_one_or_neg_one_of_mul_eq_one Int.eq_one_or_neg_one_of_mul_eq_one
51+
52+
-- Porting note: this was proven in mathlib3 with `tauto` which hasn't been ported yet
53+
theorem eq_one_or_neg_one_of_mul_eq_one' {z w : ℤ} (h : z * w = 1) :
54+
z = 1 ∧ w = 1 ∨ z = -1 ∧ w = -1 := by
55+
have h' : w * z = 1 := mul_comm z w ▸ h
56+
rcases eq_one_or_neg_one_of_mul_eq_one h with (rfl | rfl) <;>
57+
rcases eq_one_or_neg_one_of_mul_eq_one h' with (rfl | rfl) <;>
58+
try cases h
59+
· exact Or.inl ⟨rfl, rfl⟩
60+
· exact Or.inr ⟨rfl, rfl⟩
61+
#align int.eq_one_or_neg_one_of_mul_eq_one' Int.eq_one_or_neg_one_of_mul_eq_one'
62+
63+
theorem mul_eq_one_iff_eq_one_or_neg_one {z w : ℤ} : z * w = 1 ↔ z = 1 ∧ w = 1 ∨ z = -1 ∧ w = -1 :=
64+
by
65+
refine' ⟨eq_one_or_neg_one_of_mul_eq_one', fun h => Or.elim h (fun H => _) fun H => _⟩ <;>
66+
rcases H with ⟨rfl, rfl⟩ <;>
67+
rfl
68+
#align int.mul_eq_one_iff_eq_one_or_neg_one Int.mul_eq_one_iff_eq_one_or_neg_one
69+
70+
theorem eq_one_or_neg_one_of_mul_eq_neg_one' {z w : ℤ} (h : z * w = -1) :
71+
z = 1 ∧ w = -1 ∨ z = -1 ∧ w = 1 := by
72+
rcases isUnit_eq_one_or (IsUnit.mul_iff.mp (Int.isUnit_iff.mpr (Or.inr h))).1 with (rfl | rfl)
73+
· exact Or.inl ⟨rfl, one_mul w ▸ h⟩
74+
· exact Or.inr ⟨rfl, neg_inj.mp (neg_one_mul w ▸ h)⟩
75+
#align int.eq_one_or_neg_one_of_mul_eq_neg_one' Int.eq_one_or_neg_one_of_mul_eq_neg_one'
76+
77+
theorem mul_eq_neg_one_iff_eq_one_or_neg_one {z w : ℤ} :
78+
z * w = -1 ↔ z = 1 ∧ w = -1 ∨ z = -1 ∧ w = 1 := by
79+
refine' ⟨eq_one_or_neg_one_of_mul_eq_neg_one', fun h => Or.elim h (fun H => _) fun H => _⟩ <;>
80+
rcases H with ⟨rfl, rfl⟩ <;>
81+
rfl
82+
#align int.mul_eq_neg_one_iff_eq_one_or_neg_one Int.mul_eq_neg_one_iff_eq_one_or_neg_one
83+
84+
theorem isUnit_iff_natAbs_eq {n : ℤ} : IsUnit n ↔ n.natAbs = 1 := by
85+
simp [natAbs_eq_iff, isUnit_iff, Nat.cast_zero]
86+
#align int.is_unit_iff_nat_abs_eq Int.isUnit_iff_natAbs_eq
87+
88+
alias isUnit_iff_natAbs_eq ↔ isUnit.natAbs_eq _
89+
90+
-- Porting note: `rw` didn't work on `natAbs_ofNat`, so had to change to `simp`,
91+
-- presumably because `(n : ℤ)` is `Nat.cast` and not just `ofNat`
92+
@[norm_cast]
93+
theorem ofNat_isUnit {n : ℕ} : IsUnit (n : ℤ) ↔ IsUnit n := by
94+
simp [isUnit_iff_natAbs_eq]
95+
#align int.of_nat_is_unit Int.ofNat_isUnit
96+
97+
theorem isUnit_mul_self {a : ℤ} (ha : IsUnit a) : a * a = 1 :=
98+
(isUnit_eq_one_or ha).elim (fun h => h.symm ▸ rfl) fun h => h.symm ▸ rfl
99+
#align int.is_unit_mul_self Int.isUnit_mul_self
100+
101+
-- Porting note: this was proven in mathlib3 with `tidy` which hasn't been ported yet
102+
theorem isUnit_add_isUnit_eq_isUnit_add_isUnit {a b c d : ℤ} (ha : IsUnit a) (hb : IsUnit b)
103+
(hc : IsUnit c) (hd : IsUnit d) : a + b = c + d ↔ a = c ∧ b = d ∨ a = d ∧ b = c := by
104+
rw [isUnit_iff] at ha hb hc hd
105+
cases ha <;> cases hb <;> cases hc <;> cases hd <;>
106+
subst a <;> subst b <;> subst c <;> subst d <;>
107+
simp
108+
#align int.is_unit_add_is_unit_eq_is_unit_add_is_unit Int.isUnit_add_isUnit_eq_isUnit_add_isUnit
109+
110+
theorem eq_one_or_neg_one_of_mul_eq_neg_one {z w : ℤ} (h : z * w = -1) : z = 1 ∨ z = -1 :=
111+
Or.elim (eq_one_or_neg_one_of_mul_eq_neg_one' h) (fun H => Or.inl H.1) fun H => Or.inr H.1
112+
#align int.eq_one_or_neg_one_of_mul_eq_neg_one Int.eq_one_or_neg_one_of_mul_eq_neg_one
113+
114+
end Int

Mathlib/Init/Data/Int/Basic.lean

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ protected theorem neg_eq_neg {a b : ℤ} (h : -a = -b) : a = b := Int.neg_inj.1
8585
#align int.sub_nat_nat_of_lt Int.subNatNat_of_lt
8686
#align int.nat_abs_of_nat Int.natAbs_ofNat
8787

88+
#align int.nat_abs Int.natAbs
89+
8890
@[deprecated natAbs_eq_zero]
8991
theorem eq_zero_of_natAbs_eq_zero : ∀ {a : ℤ}, natAbs a = 0 → a = 0 := natAbs_eq_zero.1
9092
#align int.eq_zero_of_nat_abs_eq_zero Int.eq_zero_of_natAbs_eq_zero

0 commit comments

Comments
 (0)