Skip to content

Commit

Permalink
feat(data/zmod/basic): chinese remainder theorem (#8356)
Browse files Browse the repository at this point in the history


Co-authored-by: Chris Hughes <33847686+ChrisHughes24@users.noreply.github.com>
  • Loading branch information
ChrisHughes24 and ChrisHughes24 committed Jul 27, 2021
1 parent 65006d2 commit 391746b
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 1 deletion.
18 changes: 18 additions & 0 deletions src/algebra/char_p/basic.lean
Expand Up @@ -428,3 +428,21 @@ begin
end

end

section prod

variables (S : Type v) [semiring R] [semiring S] (p q : ℕ) [char_p R p]

/-- The characteristic of the product of rings is the least common multiple of the
characteristics of the two rings. -/
instance [char_p S q] : char_p (R × S) (nat.lcm p q) :=
{ cast_eq_zero_iff :=
by simp [prod.ext_iff, char_p.cast_eq_zero_iff R p,
char_p.cast_eq_zero_iff S q, nat.lcm_dvd_iff] }

/-- The characteristic of the product of two rings of the same characteristic
is the same as the characteristic of the rings -/
instance prod.char_p [char_p S p] : char_p (R × S) p :=
by convert nat.lcm.char_p R S p p; simp

end prod
20 changes: 20 additions & 0 deletions src/algebra/ring/prod.lean
Expand Up @@ -141,4 +141,24 @@ ring_hom.ext $ λ _, rfl
(ring_hom.snd S R).comp ↑(prod_comm : R × S ≃+* S × R) = ring_hom.fst R S :=
ring_hom.ext $ λ _, rfl

variables (R S) [subsingleton S]

/-- A ring `R` is isomorphic to `R × S` when `S` is the zero ring -/
@[simps] def prod_zero_ring : R ≃+* R × S :=
{ to_fun := λ x, (x, 0),
inv_fun := prod.fst,
map_add' := by simp,
map_mul' := by simp,
left_inv := λ x, rfl,
right_inv := λ x, by cases x; simp }

/-- A ring `R` is isomorphic to `S × R` when `S` is the zero ring -/
@[simps] def zero_ring_prod : R ≃+* S × R :=
{ to_fun := λ x, (0, x),
inv_fun := prod.snd,
map_add' := by simp,
map_mul' := by simp,
left_inv := λ x, rfl,
right_inv := λ x, by cases x; simp }

end ring_equiv
14 changes: 14 additions & 0 deletions src/data/fintype/basic.lean
Expand Up @@ -980,6 +980,20 @@ begin
rwa injective_iff_surjective_of_equiv (equiv_of_card_eq h) }
end

lemma right_inverse_of_left_inverse_of_card_le {f : α → β} {g : β → α}
(hfg : left_inverse f g) (hcard : card α ≤ card β) :
right_inverse f g :=
have hsurj : surjective f, from surjective_iff_has_right_inverse.2 ⟨g, hfg⟩,
right_inverse_of_injective_of_left_inverse
((bijective_iff_surjective_and_card _).2
⟨hsurj, le_antisymm hcard (card_le_of_surjective f hsurj)⟩ ).1
hfg

lemma left_inverse_of_right_inverse_of_card_le {f : α → β} {g : β → α}
(hfg : right_inverse f g) (hcard : card β ≤ card α) :
left_inverse f g :=
right_inverse_of_left_inverse_of_card_le hfg hcard

end fintype

lemma fintype.coe_image_univ [fintype α] [decidable_eq β] {f : α → β} :
Expand Down
13 changes: 13 additions & 0 deletions src/data/int/cast.lean
Expand Up @@ -202,6 +202,19 @@ end cast

end int

namespace prod

variables {α : Type*} {β : Type*} [has_zero α] [has_one α] [has_add α] [has_neg α]
[has_zero β] [has_one β] [has_add β] [has_neg β]

@[simp] lemma fst_int_cast (n : ℤ) : (n : α × β).fst = n :=
by induction n; simp *

@[simp] lemma snd_int_cast (n : ℤ) : (n : α × β).snd = n :=
by induction n; simp *

end prod

open int

namespace add_monoid_hom
Expand Down
13 changes: 13 additions & 0 deletions src/data/nat/cast.lean
Expand Up @@ -239,6 +239,19 @@ end linear_ordered_field

end nat

namespace prod

variables {α : Type*} {β : Type*} [has_zero α] [has_one α] [has_add α]
[has_zero β] [has_one β] [has_add β]

@[simp] lemma fst_nat_cast (n : ℕ) : (n : α × β).fst = n :=
by induction n; simp *

@[simp] lemma snd_nat_cast (n : ℕ) : (n : α × β).snd = n :=
by induction n; simp *

end prod

namespace add_monoid_hom

variables {A B : Type*} [add_monoid A]
Expand Down
10 changes: 10 additions & 0 deletions src/data/nat/gcd.lean
Expand Up @@ -191,6 +191,10 @@ or.elim (eq_zero_or_pos k)
by rw [gcd_mul_lcm, ←gcd_mul_right, mul_comm n k];
exact dvd_gcd (mul_dvd_mul_left _ H2) (mul_dvd_mul_right H1 _))

lemma lcm_dvd_iff {m n k : ℕ} : lcm m n ∣ k ↔ m ∣ k ∧ n ∣ k :=
⟨λ h, ⟨dvd_trans (dvd_lcm_left _ _) h, dvd_trans (dvd_lcm_right _ _) h⟩,
and_imp.2 lcm_dvd⟩

theorem lcm_assoc (m n k : ℕ) : lcm (lcm m n) k = lcm m (lcm n k) :=
dvd_antisymm
(lcm_dvd
Expand Down Expand Up @@ -358,6 +362,12 @@ by simp [coprime]
@[simp] theorem coprime_self (n : ℕ) : coprime n n ↔ n = 1 :=
by simp [coprime]

lemma coprime.eq_of_mul_eq_zero {m n : ℕ} (h : m.coprime n) (hmn : m * n = 0) :
m = 0 ∧ n = 1 ∨ m = 1 ∧ n = 0 :=
(nat.eq_zero_of_mul_eq_zero hmn).imp
(λ hm, ⟨hm, n.coprime_zero_left.mp $ hm ▸ h⟩)
(λ hn, ⟨m.coprime_zero_left.mp $ hn ▸ h.symm, hn⟩)

/-- Represent a divisor of `m * n` as a product of a divisor of `m` and a divisor of `n`. -/
def prod_dvd_and_dvd_of_dvd_prod {m n k : ℕ} (H : k ∣ m * n) :
{ d : {m' // m' ∣ m} × {n' // n' ∣ n} // k = d.1 * d.2 } :=
Expand Down
58 changes: 57 additions & 1 deletion src/data/zmod/basic.lean
Expand Up @@ -83,7 +83,7 @@ instance fintype : Π (n : ℕ) [fact (0 < n)], fintype (zmod n)
| 0 h := false.elim $ nat.not_lt_zero 0 h.1
| (n+1) _ := fin.fintype (n+1)

lemma card (n : ℕ) [fact (0 < n)] : fintype.card (zmod n) = n :=
@[simp] lemma card (n : ℕ) [fact (0 < n)] : fintype.card (zmod n) = n :=
begin
casesI n,
{ exfalso, exact nat.not_lt_zero 0 (fact.out _) },
Expand Down Expand Up @@ -176,6 +176,14 @@ def cast : Π {n : ℕ}, zmod n → R
@[simp] lemma cast_zero : ((0 : zmod n) : R) = 0 :=
by { cases n; refl }

variables {S : Type*} [has_zero S] [has_one S] [has_add S] [has_neg S]

@[simp] lemma _root_.prod.fst_zmod_cast (a : zmod n) : (a : R × S).fst = a :=
by cases n; simp

@[simp] lemma _root_.prod.snd_zmod_cast (a : zmod n) : (a : R × S).snd = a :=
by cases n; simp

end

/-- So-named because the coercion is `nat.cast` into `zmod`. For `nat.cast` into an arbitrary ring,
Expand Down Expand Up @@ -577,6 +585,54 @@ def units_equiv_coprime {n : ℕ} [fact (0 < n)] :
left_inv := λ ⟨_, _, _, _⟩, units.ext (nat_cast_zmod_val _),
right_inv := λ ⟨_, _⟩, by simp }

/-- The **Chinese remainder theorem**. For a pair of coprime natural numbers, `m` and `n`,
the rings `zmod (m * n)` and `zmod m × zmod n` are isomorphic.
See `ideal.quotient_inf_ring_equiv_pi_quotient` for the Chinese remainder theorem for ideals in any
ring.
-/
def chinese_remainder {m n : ℕ} (h : m.coprime n) :
zmod (m * n) ≃+* zmod m × zmod n :=
let to_fun : zmod (m * n) → zmod m × zmod n :=
zmod.cast_hom (show m.lcm n ∣ m * n, by simp [nat.lcm_dvd_iff]) (zmod m × zmod n) in
let inv_fun : zmod m × zmod n → zmod (m * n) :=
λ x, if m * n = 0
then if m = 1
then ring_hom.snd _ _ x
else ring_hom.fst _ _ x
else nat.modeq.chinese_remainder h x.1.val x.2.val in
have inv : function.left_inverse inv_fun to_fun ∧ function.right_inverse inv_fun to_fun :=
if hmn0 : m * n = 0
then begin
rcases h.eq_of_mul_eq_zero hmn0 with ⟨rfl, rfl⟩ | ⟨rfl, rfl⟩;
simp [inv_fun, to_fun, function.left_inverse, function.right_inverse,
ring_hom.eq_int_cast, prod.ext_iff]
end
else
begin
haveI : fact (0 < (m * n)) := ⟨nat.pos_of_ne_zero hmn0⟩,
haveI : fact (0 < m) := ⟨nat.pos_of_ne_zero $ left_ne_zero_of_mul hmn0⟩,
haveI : fact (0 < n) := ⟨nat.pos_of_ne_zero $ right_ne_zero_of_mul hmn0⟩,
have left_inv : function.left_inverse inv_fun to_fun,
{ intro x,
dsimp only [dvd_mul_left, dvd_mul_right, zmod.cast_hom_apply, coe_coe, inv_fun, to_fun],
conv_rhs { rw ← zmod.nat_cast_zmod_val x },
rw [if_neg hmn0, zmod.eq_iff_modeq_nat, ← nat.modeq.modeq_and_modeq_iff_modeq_mul h,
prod.fst_zmod_cast, prod.snd_zmod_cast],
refine
⟨(nat.modeq.chinese_remainder h (x : zmod m).val (x : zmod n).val).2.left.trans _,
(nat.modeq.chinese_remainder h (x : zmod m).val (x : zmod n).val).2.right.trans _⟩,
{ rw [← zmod.eq_iff_modeq_nat, zmod.nat_cast_zmod_val, zmod.nat_cast_val] },
{ rw [← zmod.eq_iff_modeq_nat, zmod.nat_cast_zmod_val, zmod.nat_cast_val] } },
exact ⟨left_inv, fintype.right_inverse_of_left_inverse_of_card_le left_inv (by simp)⟩,
end,
{ to_fun := to_fun,
inv_fun := inv_fun,
map_mul' := ring_hom.map_mul _,
map_add' := ring_hom.map_add _,
left_inv := inv.1,
right_inv := inv.2 }

section totient
open_locale nat

Expand Down

0 comments on commit 391746b

Please sign in to comment.