/- Copyright (c) 2015 Haitao Zhang. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Author : Haitao Zhang -/ import theories.number_theory.primes data algebra.group algebra.group_power algebra.group_bigops import .cyclic .finsubg .hom .perm .action open nat fin list algebra function subtype namespace group section pgroup open finset fintype variables {G S : Type} [ambientG : group G] [deceqG : decidable_eq G] [finS : fintype S] [deceqS : decidable_eq S] include ambientG definition psubg (H : finset G) (p m : nat) : Prop := prime p ∧ card H = p^m include deceqG finS deceqS variables {H : finset G} [subgH : is_finsubg H] include subgH variables {hom : G → perm S} [Hom : is_hom_class hom] include Hom open finset.partition lemma card_mod_eq_of_action_by_psubg {p : nat} : ∀ {m : nat}, psubg H p m → (card S) % p = (card (fixed_points hom H)) % p | 0 := by rewrite [↑psubg, pow_zero]; intro Psubg; rewrite [finsubg_eq_singleton_one_of_card_one (and.right Psubg), fixed_points_of_one] | (succ m) := take Ppsubg, begin rewrite [@orbit_class_equation' G S ambientG finS deceqS hom Hom H subgH], apply add_mod_eq_of_dvd, apply dvd_Sum_of_dvd, intro s Psin, rewrite mem_sep_iff at Psin, cases Psin with Psinorbs Pcardne, esimp [orbits, equiv_classes, orbit_partition] at Psinorbs, rewrite mem_image_iff at Psinorbs, cases Psinorbs with a Pa, cases Pa with Pain Porb, substvars, cases Ppsubg with Pprime PcardH, assert Pdvd : card (orbit hom H a) ∣ p ^ (succ m), rewrite -PcardH, apply dvd_of_eq_mul (finset.card (stab hom H a)), apply orbit_stabilizer_theorem, apply or.elim (eq_one_or_dvd_of_dvd_prime_pow Pprime Pdvd), intro Pcardeq, contradiction, intro Ppdvd, exact Ppdvd end end pgroup section psubg_cosets open finset fintype variables {G : Type} [ambientG : group G] [finG : fintype G] [deceqG : decidable_eq G] include ambientG deceqG finG variables {H : finset G} [finsubgH : is_finsubg H] include finsubgH lemma card_psubg_cosets_mod_eq {p : nat} {m : nat} : psubg H p m → (card (lcoset_type univ H)) % p = card (lcoset_type (normalizer H) H) % p := assume Psubg, by rewrite [-card_aol_fixed_points_eq_card_cosets]; exact card_mod_eq_of_action_by_psubg Psubg end psubg_cosets section cauchy lemma prodl_rotl_eq_one_of_prodl_eq_one {A B : Type} [gB : group B] {f : A → B} : ∀ {l : list A}, Prodl l f = 1 → Prodl (list.rotl l) f = 1 | nil := assume Peq, rfl | (a::l) := begin rewrite [rotl_cons, Prodl_cons f, Prodl_append _ _ f, Prodl_singleton], exact mul_eq_one_of_mul_eq_one end section rotl_peo variables {A : Type} [ambA : group A] include ambA variable [finA : fintype A] include finA variable (A) definition all_prodl_eq_one (n : nat) : list (list A) := map (λ l, cons (Prodl l id)⁻¹ l) (all_lists_of_len n) variable {A} lemma prodl_eq_one_of_mem_all_prodl_eq_one {n : nat} {l : list A} : l ∈ all_prodl_eq_one A n → Prodl l id = 1 := assume Plin, obtain l' Pl' Pl, from exists_of_mem_map Plin, by substvars; rewrite [Prodl_cons id _ l', mul.left_inv] lemma length_of_mem_all_prodl_eq_one {n : nat} {l : list A} : l ∈ all_prodl_eq_one A n → length l = succ n := assume Plin, obtain l' Pl' Pl, from exists_of_mem_map Plin, begin substvars, rewrite [length_cons, length_mem_all_lists Pl'] end lemma nodup_all_prodl_eq_one {n : nat} : nodup (all_prodl_eq_one A n) := nodup_map (take l₁ l₂ Peq, tail_eq_of_cons_eq Peq) nodup_all_lists lemma all_prodl_eq_one_complete {n : nat} : ∀ {l : list A}, length l = succ n → Prodl l id = 1 → l ∈ all_prodl_eq_one A n | nil := assume Pleq, by contradiction | (a::l) := assume Pleq Pprod, begin rewrite length_cons at Pleq, rewrite (Prodl_cons id a l) at Pprod, rewrite [eq_inv_of_mul_eq_one Pprod], apply mem_map, apply mem_all_lists, apply succ.inj Pleq end open fintype lemma length_all_prodl_eq_one {n : nat} : length (@all_prodl_eq_one A _ _ n) = (card A)^n := eq.trans !length_map length_all_lists open fin definition prodseq {n : nat} (s : seq A n) : A := Prodl (upto n) s definition peo [reducible] {n : nat} (s : seq A n) := prodseq s = 1 definition constseq {n : nat} (s : seq A (succ n)) := ∀ i, s i = s !zero lemma prodseq_eq {n :nat} {s : seq A n} : prodseq s = Prodl (fun_to_list s) id := Prodl_map lemma prodseq_eq_pow_of_constseq {n : nat} (s : seq A (succ n)) : constseq s → prodseq s = (s !zero) ^ succ n := assume Pc, assert Pcl : ∀ i, i ∈ upto (succ n) → s i = s !zero, from take i, assume Pin, Pc i, by rewrite [↑prodseq, Prodl_eq_pow_of_const _ Pcl, fin.length_upto] lemma seq_eq_of_constseq_of_eq {n : nat} {s₁ s₂ : seq A (succ n)} : constseq s₁ → constseq s₂ → s₁ !zero = s₂ !zero → s₁ = s₂ := assume Pc₁ Pc₂ Peq, funext take i, by rewrite [Pc₁ i, Pc₂ i, Peq] lemma peo_const_one : ∀ {n : nat}, peo (λ i : fin n, (1 : A)) | 0 := rfl | (succ n) := let s := λ i : fin (succ n), (1 : A) in assert Pconst : constseq s, from take i, rfl, calc prodseq s = (s !zero) ^ succ n : prodseq_eq_pow_of_constseq s Pconst ... = (1 : A) ^ succ n : rfl ... = 1 : algebra.one_pow variable [deceqA : decidable_eq A] include deceqA variable (A) definition peo_seq [reducible] (n : nat) := {s : seq A (succ n) | peo s} definition peo_seq_one (n : nat) : peo_seq A n := tag (λ i : fin (succ n), (1 : A)) peo_const_one definition all_prodseq_eq_one (n : nat) : list (seq A (succ n)) := dmap (λ l, length l = card (fin (succ n))) list_to_fun (all_prodl_eq_one A n) definition all_peo_seqs (n : nat) : list (peo_seq A n) := dmap peo tag (all_prodseq_eq_one A n) variable {A} lemma prodseq_eq_one_of_mem_all_prodseq_eq_one {n : nat} {s : seq A (succ n)} : s ∈ all_prodseq_eq_one A n → prodseq s = 1 := assume Psin, obtain l Pex, from exists_of_mem_dmap Psin, obtain leq Pin Peq, from Pex, by rewrite [prodseq_eq, Peq, list_to_fun_to_list, prodl_eq_one_of_mem_all_prodl_eq_one Pin] lemma all_prodseq_eq_one_complete {n : nat} {s : seq A (succ n)} : prodseq s = 1 → s ∈ all_prodseq_eq_one A n := assume Peq, assert Plin : map s (elems (fin (succ n))) ∈ all_prodl_eq_one A n, from begin apply all_prodl_eq_one_complete, rewrite [length_map], exact length_upto (succ n), rewrite prodseq_eq at Peq, exact Peq end, assert Psin : list_to_fun (map s (elems (fin (succ n)))) (length_map_of_fintype s) ∈ all_prodseq_eq_one A n, from mem_dmap _ Plin, by rewrite [fun_eq_list_to_fun_map s (length_map_of_fintype s)]; apply Psin lemma nodup_all_prodseq_eq_one {n : nat} : nodup (all_prodseq_eq_one A n) := dmap_nodup_of_dinj dinj_list_to_fun nodup_all_prodl_eq_one lemma rotl1_peo_of_peo {n : nat} {s : seq A n} : peo s → peo (rotl_fun 1 s) := begin rewrite [↑peo, *prodseq_eq, seq_rotl_eq_list_rotl], apply prodl_rotl_eq_one_of_prodl_eq_one end section local attribute perm.f [coercion] lemma rotl_perm_peo_of_peo {n : nat} : ∀ {m} {s : seq A n}, peo s → peo (rotl_perm A n m s) | 0 := begin rewrite [↑rotl_perm, rotl_seq_zero], intros, assumption end | (succ m) := take s, assert Pmul : rotl_perm A n (m + 1) s = rotl_fun 1 (rotl_perm A n m s), from calc s ∘ (rotl (m + 1)) = s ∘ ((rotl m) ∘ (rotl 1)) : rotl_compose ... = s ∘ (rotl m) ∘ (rotl 1) : compose.assoc, begin rewrite [-add_one, Pmul], intro P, exact rotl1_peo_of_peo (rotl_perm_peo_of_peo P) end end lemma nodup_all_peo_seqs {n : nat} : nodup (all_peo_seqs A n) := dmap_nodup_of_dinj (dinj_tag peo) nodup_all_prodseq_eq_one lemma all_peo_seqs_complete {n : nat} : ∀ s : peo_seq A n, s ∈ all_peo_seqs A n := take ps, subtype.destruct ps (take s, assume Ps, assert Pin : s ∈ all_prodseq_eq_one A n, from all_prodseq_eq_one_complete Ps, mem_dmap Ps Pin) lemma length_all_peo_seqs {n : nat} : length (all_peo_seqs A n) = (card A)^n := eq.trans (eq.trans (show length (all_peo_seqs A n) = length (all_prodseq_eq_one A n), from assert Pmap : map elt_of (all_peo_seqs A n) = all_prodseq_eq_one A n, from map_dmap_of_inv_of_pos (λ s P, rfl) (λ s, prodseq_eq_one_of_mem_all_prodseq_eq_one), by rewrite [-Pmap, length_map]) (show length (all_prodseq_eq_one A n) = length (all_prodl_eq_one A n), from assert Pmap : map fun_to_list (all_prodseq_eq_one A n) = all_prodl_eq_one A n, from map_dmap_of_inv_of_pos list_to_fun_to_list (λ l Pin, by rewrite [length_of_mem_all_prodl_eq_one Pin, card_fin]), by rewrite [-Pmap, length_map])) length_all_prodl_eq_one definition peo_seq_is_fintype [instance] {n : nat} : fintype (peo_seq A n) := fintype.mk (all_peo_seqs A n) nodup_all_peo_seqs all_peo_seqs_complete lemma card_peo_seq {n : nat} : card (peo_seq A n) = (card A)^n := length_all_peo_seqs section variable (A) local attribute perm.f [coercion] definition rotl_peo_seq (n : nat) (m : nat) (s : peo_seq A n) : peo_seq A n := tag (rotl_perm A (succ n) m (elt_of s)) (rotl_perm_peo_of_peo (has_property s)) variable {A} end lemma rotl_peo_seq_zero {n : nat} : rotl_peo_seq A n 0 = id := funext take s, subtype.eq begin rewrite [↑rotl_peo_seq, ↑rotl_perm, rotl_seq_zero] end lemma rotl_peo_seq_id {n : nat} : rotl_peo_seq A n (succ n) = id := funext take s, subtype.eq begin rewrite [↑rotl_peo_seq, -rotl_perm_pow_eq, rotl_perm_pow_eq_one] end lemma rotl_peo_seq_compose {n i j : nat} : (rotl_peo_seq A n i) ∘ (rotl_peo_seq A n j) = rotl_peo_seq A n (j + i) := funext take s, subtype.eq begin rewrite [↑rotl_peo_seq, ↑rotl_perm, ↑rotl_fun, compose.assoc, rotl_compose] end lemma rotl_peo_seq_mod {n i : nat} : rotl_peo_seq A n i = rotl_peo_seq A n (i % succ n) := funext take s, subtype.eq begin rewrite [↑rotl_peo_seq, rotl_perm_mod] end lemma rotl_peo_seq_inj {n m : nat} : injective (rotl_peo_seq A n m) := take ps₁ ps₂, subtype.destruct ps₁ (λ s₁ P₁, subtype.destruct ps₂ (λ s₂ P₂, assume Peq, tag_eq (rotl_fun_inj (dinj_tag peo _ _ Peq)))) variable (A) definition rotl_perm_ps [reducible] (n : nat) (m : fin (succ n)) : perm (peo_seq A n) := perm.mk (rotl_peo_seq A n m) rotl_peo_seq_inj variable {A} variable {n : nat} lemma rotl_perm_ps_eq {m : fin (succ n)} {s : peo_seq A n} : elt_of (perm.f (rotl_perm_ps A n m) s) = perm.f (rotl_perm A (succ n) m) (elt_of s) := rfl lemma rotl_perm_ps_eq_of_rotl_perm_eq {i j : fin (succ n)} : (rotl_perm A (succ n) i) = (rotl_perm A (succ n) j) → (rotl_perm_ps A n i) = (rotl_perm_ps A n j) := assume Peq, eq_of_feq (funext take s, subtype.eq (by rewrite [*rotl_perm_ps_eq, Peq])) lemma rotl_perm_ps_hom (i j : fin (succ n)) : rotl_perm_ps A n (i+j) = (rotl_perm_ps A n i) * (rotl_perm_ps A n j) := eq_of_feq (begin rewrite [↑rotl_perm_ps, {val (i+j)}val_madd, add.comm, -rotl_peo_seq_mod, -rotl_peo_seq_compose] end) section local attribute group_of_add_group [instance] definition rotl_perm_ps_is_hom [instance] : is_hom_class (rotl_perm_ps A n) := is_hom_class.mk rotl_perm_ps_hom open finset lemma const_of_is_fixed_point {s : peo_seq A n} : is_fixed_point (rotl_perm_ps A n) univ s → constseq (elt_of s) := assume Pfp, take i, begin rewrite [-(Pfp i !mem_univ) at {1}, rotl_perm_ps_eq, ↑rotl_perm, ↑rotl_fun, {i}mk_mod_eq at {2}, rotl_to_zero] end lemma const_of_rotl_fixed_point {s : peo_seq A n} : s ∈ fixed_points (rotl_perm_ps A n) univ → constseq (elt_of s) := assume Psin, take i, begin apply const_of_is_fixed_point, exact is_fixed_point_of_mem_fixed_points Psin end lemma pow_eq_one_of_mem_fixed_points {s : peo_seq A n} : s ∈ fixed_points (rotl_perm_ps A n) univ → (elt_of s !zero)^(succ n) = 1 := assume Psin, eq.trans (eq.symm (prodseq_eq_pow_of_constseq (elt_of s) (const_of_rotl_fixed_point Psin))) (has_property s) lemma peo_seq_one_is_fixed_point : is_fixed_point (rotl_perm_ps A n) univ (peo_seq_one A n) := take h, assume Pin, by esimp [rotl_perm_ps] lemma peo_seq_one_mem_fixed_points : peo_seq_one A n ∈ fixed_points (rotl_perm_ps A n) univ := mem_fixed_points_of_exists_of_is_fixed_point (exists.intro !zero !mem_univ) peo_seq_one_is_fixed_point lemma generator_of_prime_of_dvd_order {p : nat} : prime p → p ∣ card A → ∃ g : A, g ≠ 1 ∧ g^p = 1 := assume Pprime Pdvd, let pp := nat.pred p, spp := nat.succ pp in assert Peq : spp = p, from succ_pred_prime Pprime, assert Ppsubg : psubg (@univ (fin spp) _) spp 1, from and.intro (eq.symm Peq ▸ Pprime) (by rewrite [Peq, card_fin, pow_one]), have (pow_nat (card A) pp) % spp = (card (fixed_points (rotl_perm_ps A pp) univ)) % spp, by rewrite -card_peo_seq; apply card_mod_eq_of_action_by_psubg Ppsubg, have Pcardmod : (pow_nat (card A) pp) % p = (card (fixed_points (rotl_perm_ps A pp) univ)) % p, from Peq ▸ this, have Pfpcardmod : (card (fixed_points (rotl_perm_ps A pp) univ)) % p = 0, from eq.trans (eq.symm Pcardmod) (mod_eq_zero_of_dvd (dvd_pow_of_dvd_of_pos Pdvd (pred_prime_pos Pprime))), have Pfpcardpos : card (fixed_points (rotl_perm_ps A pp) univ) > 0, from card_pos_of_mem peo_seq_one_mem_fixed_points, have Pfpcardgt1 : card (fixed_points (rotl_perm_ps A pp) univ) > 1, from gt_one_of_pos_of_prime_dvd Pprime Pfpcardpos Pfpcardmod, obtain s₁ s₂ Pin₁ Pin₂ Psnes, from exists_two_of_card_gt_one Pfpcardgt1, decidable.by_cases (λ Pe₁ : elt_of s₁ !zero = 1, assert Pne₂ : elt_of s₂ !zero ≠ 1, from assume Pe₂, absurd (subtype.eq (seq_eq_of_constseq_of_eq (const_of_rotl_fixed_point Pin₁) (const_of_rotl_fixed_point Pin₂) (eq.trans Pe₁ (eq.symm Pe₂)))) Psnes, exists.intro (elt_of s₂ !zero) (and.intro Pne₂ (Peq ▸ pow_eq_one_of_mem_fixed_points Pin₂))) (λ Pne, exists.intro (elt_of s₁ !zero) (and.intro Pne (Peq ▸ pow_eq_one_of_mem_fixed_points Pin₁))) end theorem cauchy_theorem {p : nat} : prime p → p ∣ card A → ∃ g : A, order g = p := assume Pprime Pdvd, obtain g Pne Pgpow, from generator_of_prime_of_dvd_order Pprime Pdvd, assert Porder : order g ∣ p, from order_dvd_of_pow_eq_one Pgpow, or.elim (eq_one_or_eq_self_of_prime_of_dvd Pprime Porder) (λ Pe, absurd (eq_one_of_order_eq_one Pe) Pne) (λ Porderp, exists.intro g Porderp) end rotl_peo end cauchy section sylow open finset fintype variables {G : Type} [ambientG : group G] [finG : fintype G] [deceqG : decidable_eq G] include ambientG deceqG finG theorem first_sylow_theorem {p : nat} (Pp : prime p) : ∀ n, p^n ∣ card G → ∃ (H : finset G) (finsubgH : is_finsubg H), card H = p^n | 0 := assume Pdvd, exists.intro (singleton 1) (exists.intro one_is_finsubg (by rewrite [card_singleton, pow_zero])) | (succ n) := assume Pdvd, obtain H PfinsubgH PcardH, from first_sylow_theorem n (pow_dvd_of_pow_succ_dvd Pdvd), assert Ppsubg : psubg H p n, from and.intro Pp PcardH, assert Ppowsucc : p^(succ n) ∣ (card (lcoset_type univ H) * p^n), by rewrite [-PcardH, -(lagrange_theorem' !subset_univ)]; exact Pdvd, assert Ppdvd : p ∣ card (lcoset_type (normalizer H) H), from dvd_of_mod_eq_zero (by rewrite [-(card_psubg_cosets_mod_eq Ppsubg), -dvd_iff_mod_eq_zero]; exact dvd_of_pow_succ_dvd_mul_pow (pos_of_prime Pp) Ppowsucc), obtain J PJ, from cauchy_theorem Pp Ppdvd, exists.intro (fin_coset_Union (cyc J)) (exists.intro _ (by rewrite [pow_succ, -PcardH, -PJ]; apply card_Union_lcosets)) end sylow end group